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 --- libs/gui/SurfaceComposerClient.cpp | 84 +++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c16a98f42f..11fe49039d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -195,6 +195,17 @@ void TransactionCompletedListener::removeJankListener(const sp } } +void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId, + ReleaseBufferCallback listener) { + std::scoped_lock lock(mMutex); + mReleaseBufferCallbacks[graphicBufferId] = listener; +} + +void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) { + std::scoped_lock lock(mMutex); + mReleaseBufferCallbacks.erase(graphicBufferId); +} + void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp surfaceControl, SurfaceStatsCallback listener) { std::lock_guard lock(mMutex); @@ -275,6 +286,20 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener .surfaceControls[surfaceStats.surfaceControl] ->setTransformHint(surfaceStats.transformHint); } + // If there is buffer id set, we look up any pending client release buffer callbacks + // and call them. This is a performance optimization when we have a transaction + // callback and a release buffer callback happening at the same time to avoid an + // additional ipc call from the server. + if (surfaceStats.previousBufferId) { + ReleaseBufferCallback callback = + popReleaseBufferCallbackLocked(surfaceStats.previousBufferId); + if (callback) { + callback(surfaceStats.previousBufferId, + surfaceStats.previousReleaseFence + ? surfaceStats.previousReleaseFence + : Fence::NO_FENCE); + } + } } callbackFunction(transactionStats.latchTime, transactionStats.presentFence, @@ -297,6 +322,32 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } +void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, + sp releaseFence) { + ReleaseBufferCallback callback; + { + std::scoped_lock lock(mMutex); + callback = popReleaseBufferCallbackLocked(graphicBufferId); + } + if (!callback) { + ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId); + return; + } + callback(graphicBufferId, releaseFence); +} + +ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( + uint64_t graphicBufferId) { + ReleaseBufferCallback callback; + auto itr = mReleaseBufferCallbacks.find(graphicBufferId); + if (itr == mReleaseBufferCallbacks.end()) { + return nullptr; + } + callback = itr->second; + mReleaseBufferCallbacks.erase(itr); + return callback; +} + // --------------------------------------------------------------------------- void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); @@ -1219,17 +1270,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( - const sp& sc, const sp& buffer) { + const sp& sc, const sp& buffer, + ReleaseBufferCallback callback) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } + removeReleaseBufferCallback(s); s->what |= layer_state_t::eBufferChanged; s->buffer = buffer; if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } + setReleaseBufferCallback(s, callback); registerSurfaceControlForCallback(sc); @@ -1237,6 +1291,34 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } +void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) { + if (!s->releaseBufferListener) { + return; + } + + s->what &= ~static_cast(layer_state_t::eReleaseBufferListenerChanged); + s->releaseBufferListener = nullptr; + TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(s->buffer->getId()); +} + +void SurfaceComposerClient::Transaction::setReleaseBufferCallback(layer_state_t* s, + ReleaseBufferCallback callback) { + if (!callback) { + return; + } + + if (!s->buffer) { + ALOGW("Transaction::setReleaseBufferCallback" + "ignored trying to set a callback on a null buffer."); + return; + } + + s->what |= layer_state_t::eReleaseBufferListenerChanged; + s->releaseBufferListener = TransactionCompletedListener::getIInstance(); + auto listener = TransactionCompletedListener::getInstance(); + listener->setReleaseBufferCallback(s->buffer->getId(), callback); +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence( const sp& sc, const sp& fence) { layer_state_t* s = getLayerState(sc); -- cgit v1.2.3-59-g8ed1b