From 1506b181085e1f2156283d0e7b62fe94a918427f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 22 Feb 2021 14:35:15 -0800 Subject: Introduce release buffer callback for BufferStateLayer Currently BLAST clients use the TransactionCompleted callbacks to determine when to release buffers. The TransactionCompleted callback is overloaded. For transactions without buffers, the callback is called when the transaction is applied on the server. If the Transaction contains one or more buffers, the callback is called when all the buffers are latched and ready to be presented. If we have multiple buffers on multiple transactions, where one or more buffers maybe dropped, the pending callbacks are called together. This may delay signaling the client when a buffer can be released. To fix this, we introduce a new buffer release callback that is called as soon as a buffer is dropped by the server or when a new buffer has been latched and the buffer will no longer be presented. This new callback provides a graphic bufferid to identify the buffer that can be released and a release fence to wait on. BlastBufferQueue has been switched to use this new callback. Other BLAST users continue to use the existing callback. Test: go/wm-smoke Test: atest ReleaseBufferCallbackTest Bug: 178385281 Change-Id: Idd88e4994e543443198a5a8cfa0e3f5f67d5d482 --- services/surfaceflinger/BufferStateLayer.cpp | 54 +++++++++++++++++++++------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'services/surfaceflinger/BufferStateLayer.cpp') diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 96a0c3cd75..89dfb6fb6b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -41,6 +41,16 @@ namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; +namespace { +void callReleaseBufferCallback(const sp& listener, + const sp& buffer, const sp& releaseFence) { + if (!listener) { + return; + } + listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE); +} +} // namespace + // clang-format off const std::array BufferStateLayer::IDENTITY_MATRIX{ 1, 0, 0, 0, @@ -65,7 +75,10 @@ BufferStateLayer::~BufferStateLayer() { // RenderEngine may have been using the buffer as an external texture // after the client uncached the buffer. auto& engine(mFlinger->getRenderEngine()); - engine.unbindExternalTextureBuffer(mBufferInfo.mBuffer->getId()); + const uint64_t bufferId = mBufferInfo.mBuffer->getId(); + engine.unbindExternalTextureBuffer(bufferId); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer, + mBufferInfo.mFence); } } @@ -74,6 +87,7 @@ status_t BufferStateLayer::addReleaseFence(const sp& ch, if (ch == nullptr) { return OK; } + ch->previousBufferId = mPreviousBufferId; if (!ch->previousReleaseFence.get()) { ch->previousReleaseFence = fence; return OK; @@ -190,6 +204,19 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { handle->dequeueReadyTime = dequeueReadyTime; } + // If there are multiple transactions in this frame, set the previous id on the earliest + // transacton. We don't need to pass in the released buffer id to multiple transactions. + // The buffer id does not have to correspond to any particular transaction as long as the + // listening end point is the same but the client expects the first transaction callback that + // replaces the presented buffer to contain the release fence. This follows the same logic. + // see BufferStateLayer::onLayerDisplayed. + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->releasePreviousBuffer) { + handle->previousBufferId = mPreviousBufferId; + break; + } + } + std::vector jankData; jankData.reserve(mPendingJankClassifications.size()); while (!mPendingJankClassifications.empty() @@ -344,8 +371,8 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional dequeueTime, - const FrameTimelineInfo& info) { + std::optional dequeueTime, const FrameTimelineInfo& info, + const sp& releaseBufferListener) { ATRACE_CALL(); if (mCurrentState.buffer) { @@ -353,7 +380,10 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const sp& buffer, const sp& newBuffer) { + if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer && + newBuffer != mDrawingState.buffer) { // If we are about to update mDrawingState.buffer but it has not yet latched - // then we will drop a buffer and should decrement the pending buffer count. - // This logic may not work perfectly in the face of a BufferStateLayer being the - // deferred side of a deferred transaction, but we don't expect this use case. + // then we will drop a buffer and should decrement the pending buffer count and + // call any release buffer callbacks if set. + callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer, + mDrawingState.acquireFence); decrementPendingBufferCount(); } - return Layer::doTransaction(flags); } } // namespace android -- cgit v1.2.3-59-g8ed1b