Loading libs/gui/BLASTBufferQueue.cpp +151 −10 Original line number Diff line number Diff line Loading @@ -22,11 +22,14 @@ #include <com_android_graphics_libgui_flags.h> #include <cutils/atomic.h> #include <ftl/fake_guard.h> #include <gui/BLASTBufferQueue.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> #include <sys/epoll.h> #include <sys/eventfd.h> #include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> Loading Loading @@ -74,6 +77,12 @@ namespace android { std::unique_lock _lock{mutex}; \ base::ScopedLockAssertion assumeLocked(mutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK = [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {}; #endif void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; Loading Loading @@ -215,6 +224,12 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati }, this); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer; gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer); mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer)); #endif BQA_LOGV("BLASTBufferQueue created"); } Loading Loading @@ -244,6 +259,9 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::onFirstRef() { // safe default, most producers are expected to override this mProducer->setMaxDequeuedBufferCount(2); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this)); #endif } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, Loading @@ -269,6 +287,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, if (surfaceControlChanged) { t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer); #endif applyTransaction = true; } mTransformHint = mSurfaceControl->getTransformHint(); Loading Loading @@ -386,6 +407,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.latchTime, stat.frameEventStats.dequeueReadyTime); } #if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) auto currFrameNumber = stat.frameEventStats.frameNumber; std::vector<ReleaseCallbackId> staleReleases; for (const auto& [key, value]: mSubmitted) { Loading @@ -401,6 +423,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.currentMaxAcquiredBufferCount, true /* fakeRelease */); } #endif } else { BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback"); } Loading @@ -411,6 +434,15 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence } } void BLASTBufferQueue::flushShadowQueue() { BQA_LOGV("flushShadowQueue"); int numFramesToFlush = mNumFrameAvailable; while (numFramesToFlush > 0) { acquireNextBufferLocked(std::nullopt); numFramesToFlush--; } } // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the // BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. Loading @@ -428,15 +460,6 @@ ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() { }; } void BLASTBufferQueue::flushShadowQueue() { BQA_LOGV("flushShadowQueue"); int numFramesToFlush = mNumFrameAvailable; while (numFramesToFlush > 0) { acquireNextBufferLocked(std::nullopt); numFramesToFlush--; } } void BLASTBufferQueue::releaseBufferCallback( const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { Loading Loading @@ -611,7 +634,12 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) ReleaseBufferCallback releaseBufferCallback = applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk(); #else auto releaseBufferCallback = makeReleaseBufferCallbackThunk(); #endif sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; nsecs_t dequeueTime = -1; Loading Loading @@ -1224,7 +1252,120 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceCon void BLASTBufferQueue::setTransactionHangCallback( std::function<void(const std::string&)> callback) { std::lock_guard _lock{mMutex}; mTransactionHangCallback = callback; mTransactionHangCallback = std::move(callback); } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint) : mEndpoint{std::move(endpoint)} { mEpollFd = android::base::unique_fd{epoll_create1(0)}; LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(), "Failed to create buffer release epoll file descriptor. errno=%d " "message='%s'", errno, strerror(errno)); epoll_event registerEndpointFd{}; registerEndpointFd.events = EPOLLIN; registerEndpointFd.data.fd = mEndpoint->getFd(); status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register buffer release consumer file descriptor with epoll. " "errno=%d message='%s'", errno, strerror(errno)); mEventFd = android::base::unique_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF(!mEventFd.ok(), "Failed to create buffer release event file descriptor. errno=%d " "message='%s'", errno, strerror(errno)); epoll_event registerEventFd{}; registerEventFd.events = EPOLLIN; registerEventFd.data.fd = mEventFd.get(); status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEventFd.get(), ®isterEventFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register buffer release event file descriptor with epoll. " "errno=%d message='%s'", errno, strerror(errno)); } BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=( BufferReleaseReader&& other) { if (this != &other) { ftl::FakeGuard guard{mMutex}; ftl::FakeGuard otherGuard{other.mMutex}; mEndpoint = std::move(other.mEndpoint); mEpollFd = std::move(other.mEpollFd); mEventFd = std::move(other.mEventFd); } return *this; } status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, sp<Fence>& outFence, uint32_t& outMaxAcquiredBufferCount) { epoll_event event{}; while (true) { int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */); if (eventCount == 1) { break; } if (eventCount == -1 && errno != EINTR) { ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno, strerror(errno)); } } if (event.data.fd == mEventFd.get()) { uint64_t value; if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) { ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno)); } return WOULD_BLOCK; } std::lock_guard lock{mMutex}; return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); } void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() { uint64_t value = 1; if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) { ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno)); } } void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) { mRunning = std::make_shared<std::atomic_bool>(true); mReader = bbq->mBufferReleaseReader; std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() { pthread_setname_np(pthread_self(), "BufferReleaseThread"); while (*running) { ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount); status != OK) { continue; } sp<BLASTBufferQueue> bbq = weakBbq.promote(); if (!bbq) { return; } bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); } }).detach(); } BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() { *mRunning = false; mReader->interruptBlockingRead(); } #endif } // namespace android libs/gui/include/gui/BLASTBufferQueue.h +45 −0 Original line number Diff line number Diff line Loading @@ -315,6 +315,51 @@ private: std::function<void(const std::string&)> mTransactionHangCallback; std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) class BufferReleaseReader { public: BufferReleaseReader() = default; BufferReleaseReader(std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint>); BufferReleaseReader& operator=(BufferReleaseReader&&); // Block until we can read a buffer release message. // // Returns: // * OK if a ReleaseCallbackId and Fence were successfully read. // * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead. // * UNKNOWN_ERROR if something went wrong. status_t readBlocking(ReleaseCallbackId& outId, sp<Fence>& outReleaseFence, uint32_t& outMaxAcquiredBufferCount); // Signals the reader's eventfd to wake up any threads waiting on readBlocking. void interruptBlockingRead(); private: std::mutex mMutex; std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mEndpoint GUARDED_BY(mMutex); android::base::unique_fd mEpollFd; android::base::unique_fd mEventFd; }; // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to // the client. See BBQBufferQueueProducer::dequeueBuffer for details. std::shared_ptr<BufferReleaseReader> mBufferReleaseReader; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer; class BufferReleaseThread { public: BufferReleaseThread() = default; ~BufferReleaseThread(); void start(const sp<BLASTBufferQueue>&); private: std::shared_ptr<std::atomic_bool> mRunning; std::shared_ptr<BufferReleaseReader> mReader; }; BufferReleaseThread mBufferReleaseThread; #endif }; } // namespace android Loading services/surfaceflinger/Layer.cpp +19 −4 Original line number Diff line number Diff line Loading @@ -1951,15 +1951,24 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence) { if (!listener) { if (!listener && !mBufferReleaseChannel) { return; } SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); ReleaseCallbackId callbackId{buffer->getId(), framenumber}; const sp<Fence>& fence = releaseFence ? releaseFence : Fence::NO_FENCE; uint32_t currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); if (listener) { listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount); } if (mBufferReleaseChannel) { mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount); } } sp<CallbackHandle> Layer::findCallbackHandle() { Loading Loading @@ -2077,6 +2086,7 @@ void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->bufferReleaseChannel = mBufferReleaseChannel; handle->transformHint = mTransformHint; handle->dequeueReadyTime = dequeueReadyTime; handle->currentMaxAcquiredBufferCount = Loading Loading @@ -3508,6 +3518,11 @@ bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thre return haveTrustedPresentationListener; } void Layer::setBufferReleaseChannel( const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel) { mBufferReleaseChannel = channel; } void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } Loading services/surfaceflinger/Layer.h +3 −0 Original line number Diff line number Diff line Loading @@ -537,6 +537,7 @@ public: }; BufferInfo mBufferInfo; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel; // implements compositionengine::LayerFE const compositionengine::LayerFECompositionState* getCompositionState() const; Loading Loading @@ -724,6 +725,8 @@ public: bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, TrustedPresentationListener const& listener); void setBufferReleaseChannel( const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel); // Creates a new handle each time, so we only expect // this to be called once. Loading services/surfaceflinger/SurfaceFlinger.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -5063,6 +5063,10 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f } } if (what & layer_state_t::eBufferReleaseChannelChanged) { layer->setBufferReleaseChannel(s.bufferReleaseChannel); } const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence()); bool willPresentCurrentTransaction = requestedLayerState && (requestedLayerState->hasReadyFrame() || Loading Loading
libs/gui/BLASTBufferQueue.cpp +151 −10 Original line number Diff line number Diff line Loading @@ -22,11 +22,14 @@ #include <com_android_graphics_libgui_flags.h> #include <cutils/atomic.h> #include <ftl/fake_guard.h> #include <gui/BLASTBufferQueue.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> #include <sys/epoll.h> #include <sys/eventfd.h> #include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> Loading Loading @@ -74,6 +77,12 @@ namespace android { std::unique_lock _lock{mutex}; \ base::ScopedLockAssertion assumeLocked(mutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK = [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {}; #endif void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; Loading Loading @@ -215,6 +224,12 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati }, this); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer; gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer); mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer)); #endif BQA_LOGV("BLASTBufferQueue created"); } Loading Loading @@ -244,6 +259,9 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::onFirstRef() { // safe default, most producers are expected to override this mProducer->setMaxDequeuedBufferCount(2); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this)); #endif } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, Loading @@ -269,6 +287,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, if (surfaceControlChanged) { t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer); #endif applyTransaction = true; } mTransformHint = mSurfaceControl->getTransformHint(); Loading Loading @@ -386,6 +407,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.latchTime, stat.frameEventStats.dequeueReadyTime); } #if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) auto currFrameNumber = stat.frameEventStats.frameNumber; std::vector<ReleaseCallbackId> staleReleases; for (const auto& [key, value]: mSubmitted) { Loading @@ -401,6 +423,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.currentMaxAcquiredBufferCount, true /* fakeRelease */); } #endif } else { BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback"); } Loading @@ -411,6 +434,15 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence } } void BLASTBufferQueue::flushShadowQueue() { BQA_LOGV("flushShadowQueue"); int numFramesToFlush = mNumFrameAvailable; while (numFramesToFlush > 0) { acquireNextBufferLocked(std::nullopt); numFramesToFlush--; } } // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the // BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. Loading @@ -428,15 +460,6 @@ ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() { }; } void BLASTBufferQueue::flushShadowQueue() { BQA_LOGV("flushShadowQueue"); int numFramesToFlush = mNumFrameAvailable; while (numFramesToFlush > 0) { acquireNextBufferLocked(std::nullopt); numFramesToFlush--; } } void BLASTBufferQueue::releaseBufferCallback( const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { Loading Loading @@ -611,7 +634,12 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) ReleaseBufferCallback releaseBufferCallback = applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk(); #else auto releaseBufferCallback = makeReleaseBufferCallbackThunk(); #endif sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; nsecs_t dequeueTime = -1; Loading Loading @@ -1224,7 +1252,120 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceCon void BLASTBufferQueue::setTransactionHangCallback( std::function<void(const std::string&)> callback) { std::lock_guard _lock{mMutex}; mTransactionHangCallback = callback; mTransactionHangCallback = std::move(callback); } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint) : mEndpoint{std::move(endpoint)} { mEpollFd = android::base::unique_fd{epoll_create1(0)}; LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(), "Failed to create buffer release epoll file descriptor. errno=%d " "message='%s'", errno, strerror(errno)); epoll_event registerEndpointFd{}; registerEndpointFd.events = EPOLLIN; registerEndpointFd.data.fd = mEndpoint->getFd(); status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register buffer release consumer file descriptor with epoll. " "errno=%d message='%s'", errno, strerror(errno)); mEventFd = android::base::unique_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); LOG_ALWAYS_FATAL_IF(!mEventFd.ok(), "Failed to create buffer release event file descriptor. errno=%d " "message='%s'", errno, strerror(errno)); epoll_event registerEventFd{}; registerEventFd.events = EPOLLIN; registerEventFd.data.fd = mEventFd.get(); status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEventFd.get(), ®isterEventFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register buffer release event file descriptor with epoll. " "errno=%d message='%s'", errno, strerror(errno)); } BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=( BufferReleaseReader&& other) { if (this != &other) { ftl::FakeGuard guard{mMutex}; ftl::FakeGuard otherGuard{other.mMutex}; mEndpoint = std::move(other.mEndpoint); mEpollFd = std::move(other.mEpollFd); mEventFd = std::move(other.mEventFd); } return *this; } status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, sp<Fence>& outFence, uint32_t& outMaxAcquiredBufferCount) { epoll_event event{}; while (true) { int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */); if (eventCount == 1) { break; } if (eventCount == -1 && errno != EINTR) { ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno, strerror(errno)); } } if (event.data.fd == mEventFd.get()) { uint64_t value; if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) { ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno)); } return WOULD_BLOCK; } std::lock_guard lock{mMutex}; return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); } void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() { uint64_t value = 1; if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) { ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno)); } } void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) { mRunning = std::make_shared<std::atomic_bool>(true); mReader = bbq->mBufferReleaseReader; std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() { pthread_setname_np(pthread_self(), "BufferReleaseThread"); while (*running) { ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount); status != OK) { continue; } sp<BLASTBufferQueue> bbq = weakBbq.promote(); if (!bbq) { return; } bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); } }).detach(); } BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() { *mRunning = false; mReader->interruptBlockingRead(); } #endif } // namespace android
libs/gui/include/gui/BLASTBufferQueue.h +45 −0 Original line number Diff line number Diff line Loading @@ -315,6 +315,51 @@ private: std::function<void(const std::string&)> mTransactionHangCallback; std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) class BufferReleaseReader { public: BufferReleaseReader() = default; BufferReleaseReader(std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint>); BufferReleaseReader& operator=(BufferReleaseReader&&); // Block until we can read a buffer release message. // // Returns: // * OK if a ReleaseCallbackId and Fence were successfully read. // * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead. // * UNKNOWN_ERROR if something went wrong. status_t readBlocking(ReleaseCallbackId& outId, sp<Fence>& outReleaseFence, uint32_t& outMaxAcquiredBufferCount); // Signals the reader's eventfd to wake up any threads waiting on readBlocking. void interruptBlockingRead(); private: std::mutex mMutex; std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mEndpoint GUARDED_BY(mMutex); android::base::unique_fd mEpollFd; android::base::unique_fd mEventFd; }; // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to // the client. See BBQBufferQueueProducer::dequeueBuffer for details. std::shared_ptr<BufferReleaseReader> mBufferReleaseReader; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer; class BufferReleaseThread { public: BufferReleaseThread() = default; ~BufferReleaseThread(); void start(const sp<BLASTBufferQueue>&); private: std::shared_ptr<std::atomic_bool> mRunning; std::shared_ptr<BufferReleaseReader> mReader; }; BufferReleaseThread mBufferReleaseThread; #endif }; } // namespace android Loading
services/surfaceflinger/Layer.cpp +19 −4 Original line number Diff line number Diff line Loading @@ -1951,15 +1951,24 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence) { if (!listener) { if (!listener && !mBufferReleaseChannel) { return; } SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); ReleaseCallbackId callbackId{buffer->getId(), framenumber}; const sp<Fence>& fence = releaseFence ? releaseFence : Fence::NO_FENCE; uint32_t currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); if (listener) { listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount); } if (mBufferReleaseChannel) { mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount); } } sp<CallbackHandle> Layer::findCallbackHandle() { Loading Loading @@ -2077,6 +2086,7 @@ void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->bufferReleaseChannel = mBufferReleaseChannel; handle->transformHint = mTransformHint; handle->dequeueReadyTime = dequeueReadyTime; handle->currentMaxAcquiredBufferCount = Loading Loading @@ -3508,6 +3518,11 @@ bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thre return haveTrustedPresentationListener; } void Layer::setBufferReleaseChannel( const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel) { mBufferReleaseChannel = channel; } void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } Loading
services/surfaceflinger/Layer.h +3 −0 Original line number Diff line number Diff line Loading @@ -537,6 +537,7 @@ public: }; BufferInfo mBufferInfo; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel; // implements compositionengine::LayerFE const compositionengine::LayerFECompositionState* getCompositionState() const; Loading Loading @@ -724,6 +725,8 @@ public: bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, TrustedPresentationListener const& listener); void setBufferReleaseChannel( const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel); // Creates a new handle each time, so we only expect // this to be called once. Loading
services/surfaceflinger/SurfaceFlinger.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -5063,6 +5063,10 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f } } if (what & layer_state_t::eBufferReleaseChannelChanged) { layer->setBufferReleaseChannel(s.bufferReleaseChannel); } const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence()); bool willPresentCurrentTransaction = requestedLayerState && (requestedLayerState->hasReadyFrame() || Loading