diff options
Diffstat (limited to 'libs/gui')
| -rw-r--r-- | libs/gui/BLASTBufferQueue.cpp | 107 | ||||
| -rw-r--r-- | libs/gui/ITransactionCompletedListener.cpp | 13 | ||||
| -rw-r--r-- | libs/gui/LayerState.cpp | 17 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 84 | ||||
| -rw-r--r-- | libs/gui/include/gui/BLASTBufferQueue.h | 18 | ||||
| -rw-r--r-- | libs/gui/include/gui/ITransactionCompletedListener.h | 8 | ||||
| -rw-r--r-- | libs/gui/include/gui/LayerState.h | 7 | ||||
| -rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 19 | ||||
| -rw-r--r-- | libs/gui/tests/BLASTBufferQueue_test.cpp | 53 |
9 files changed, 246 insertions, 80 deletions
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 82c9268feb..f778232803 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -169,8 +169,6 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont mNumAcquired = 0; mNumFrameAvailable = 0; - mPendingReleaseItem.item = BufferItem(); - mPendingReleaseItem.releaseFence = nullptr; } BLASTBufferQueue::~BLASTBufferQueue() { @@ -242,7 +240,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence std::unique_lock _lock{mMutex}; ATRACE_CALL(); BQA_LOGV("transactionCallback"); - mInitialCallbackReceived = true; if (!stats.empty()) { mTransformHint = stats[0].transformHint; @@ -255,38 +252,20 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stats[0].frameEventStats.compositorTiming, stats[0].latchTime, stats[0].frameEventStats.dequeueReadyTime); - } - if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) { - if (!stats.empty()) { - mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence; - } else { - BQA_LOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback"); - mPendingReleaseItem.releaseFence = nullptr; + currFrameNumber = stats[0].frameEventStats.frameNumber; + + if (mTransactionCompleteCallback && + currFrameNumber >= mTransactionCompleteFrameNumber) { + if (currFrameNumber > mTransactionCompleteFrameNumber) { + BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 + " than expected=%" PRIu64, + currFrameNumber, mTransactionCompleteFrameNumber); + } + transactionCompleteCallback = std::move(mTransactionCompleteCallback); + mTransactionCompleteFrameNumber = 0; } - mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item, - mPendingReleaseItem.releaseFence - ? mPendingReleaseItem.releaseFence - : Fence::NO_FENCE); - mNumAcquired--; - mPendingReleaseItem.item = BufferItem(); - mPendingReleaseItem.releaseFence = nullptr; - } - - if (mSubmitted.empty()) { - BQA_LOGE("ERROR: callback with no corresponding submitted buffer item"); } - mPendingReleaseItem.item = std::move(mSubmitted.front()); - mSubmitted.pop(); - - processNextBufferLocked(false /* useNextTransaction */); - currFrameNumber = mPendingReleaseItem.item.mFrameNumber; - if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) { - transactionCompleteCallback = std::move(mTransactionCompleteCallback); - mTransactionCompleteFrameNumber = 0; - } - - mCallbackCV.notify_all(); decStrong((void*)transactionCallbackThunk); } @@ -295,15 +274,46 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence } } -void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { +// 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. +// Otherwise, this is a no-op. +static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, uint64_t graphicBufferId, + const sp<Fence>& releaseFence) { + sp<BLASTBufferQueue> blastBufferQueue = context.promote(); + ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s", + graphicBufferId, blastBufferQueue ? "alive" : "dead"); + if (blastBufferQueue) { + blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence); + } +} + +void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, + const sp<Fence>& releaseFence) { ATRACE_CALL(); - BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction)); + std::unique_lock _lock{mMutex}; + BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); + + auto it = mSubmitted.find(graphicBufferId); + if (it == mSubmitted.end()) { + BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, + graphicBufferId); + return; + } + mBufferItemConsumer->releaseBuffer(it->second, releaseFence); + mSubmitted.erase(it); + mNumAcquired--; + processNextBufferLocked(false /* useNextTransaction */); + mCallbackCV.notify_all(); +} + +void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { + ATRACE_CALL(); // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't // include the extra buffer when checking if we can acquire the next buffer. const bool includeExtraAcquire = !useNextTransaction; if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) { - BQA_LOGV("processNextBufferLocked waiting for frame available or callback"); mCallbackCV.notify_all(); return; } @@ -353,7 +363,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } mNumAcquired++; - mSubmitted.push(bufferItem); + mSubmitted[buffer->getId()] = bufferItem; bool needsDisconnect = false; mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect); @@ -369,7 +379,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mLastBufferScalingMode = bufferItem.mScalingMode; mLastAcquiredFrameNumber = bufferItem.mFrameNumber; - t->setBuffer(mSurfaceControl, buffer); + auto releaseBufferCallback = + std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, + std::placeholders::_1, std::placeholders::_2); + t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); @@ -427,9 +440,12 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 - " applyTransaction=%s mTimestamp=%" PRId64 " mPendingTransactions.size=%d", + " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" + " graphicBufferId=%" PRIu64, mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), - bufferItem.mTimestamp, static_cast<uint32_t>(mPendingTransactions.size())); + bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", + static_cast<uint32_t>(mPendingTransactions.size()), + bufferItem.mGraphicBuffer->getId()); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -444,18 +460,17 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { std::unique_lock _lock{mMutex}; const bool nextTransactionSet = mNextTransaction != nullptr; - BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s mFlushShadowQueue=%s", - item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue)); - - if (nextTransactionSet || mFlushShadowQueue) { + if (nextTransactionSet) { while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) { BQA_LOGV("waiting in onFrameAvailable..."); mCallbackCV.wait(_lock); } } - mFlushShadowQueue = false; // add to shadow queue mNumFrameAvailable++; + + BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, + toString(nextTransactionSet)); processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } @@ -514,14 +529,12 @@ void BLASTBufferQueue::setTransactionCompleteCallback( } // Check if we have acquired the maximum number of buffers. -// As a special case, we wait for the first callback before acquiring the second buffer so we -// can ensure the first buffer is presented if multiple buffers are queued in succession. // Consumer can acquire an additional buffer if that buffer is not droppable. Set // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1); - return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1); + return mNumAcquired == maxAcquiredBuffers; } class BBQSurface : public Surface { diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 0ded9361bf..9b5be1f15a 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -27,7 +27,8 @@ namespace { // Anonymous enum class Tag : uint32_t { ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION, - LAST = ON_TRANSACTION_COMPLETED, + ON_RELEASE_BUFFER, + LAST = ON_RELEASE_BUFFER, }; } // Anonymous namespace @@ -122,6 +123,7 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const { for (const auto& data : jankData) { SAFE_PARCEL(output->writeParcelable, data); } + SAFE_PARCEL(output->writeUint64, previousBufferId); return NO_ERROR; } @@ -144,6 +146,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readParcelable, &data); jankData.push_back(data); } + SAFE_PARCEL(input->readUint64, &previousBufferId); return NO_ERROR; } @@ -245,6 +248,12 @@ public: onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED, stats); } + + void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) override { + callRemoteAsync<decltype( + &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, + graphicBufferId, releaseFence); + } }; // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see @@ -263,6 +272,8 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& case Tag::ON_TRANSACTION_COMPLETED: return callLocalAsync(data, reply, &ITransactionCompletedListener::onTransactionCompleted); + case Tag::ON_RELEASE_BUFFER: + return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer); } } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6bb8bf2d5b..7a18ca61fe 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -63,7 +63,8 @@ layer_state_t::layer_state_t() fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), frameTimelineInfo(), - autoRefresh(false) { + autoRefresh(false), + releaseBufferListener(nullptr) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -152,6 +153,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); + SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener)); SAFE_PARCEL(output.writeUint32, blurRegions.size()); for (auto region : blurRegions) { @@ -275,6 +277,12 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); + tmpBinder = nullptr; + SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder); + if (tmpBinder) { + releaseBufferListener = checked_interface_cast<ITransactionCompletedListener>(tmpBinder); + } + uint32_t numRegions = 0; SAFE_PARCEL(input.readUint32, &numRegions); blurRegions.clear(); @@ -543,6 +551,13 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eAutoRefreshChanged; autoRefresh = other.autoRefresh; } + if (other.what & eReleaseBufferListenerChanged) { + if (releaseBufferListener) { + ALOGW("Overriding releaseBufferListener"); + } + what |= eReleaseBufferListenerChanged; + releaseBufferListener = other.releaseBufferListener; + } if (other.what & eStretchChanged) { what |= eStretchChanged; stretchEffect = other.stretchEffect; 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<JankDataListener> } } +void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId, + ReleaseBufferCallback listener) { + std::scoped_lock<std::mutex> lock(mMutex); + mReleaseBufferCallbacks[graphicBufferId] = listener; +} + +void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) { + std::scoped_lock<std::mutex> lock(mMutex); + mReleaseBufferCallbacks.erase(graphicBufferId); +} + void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::lock_guard<std::mutex> 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<Fence> releaseFence) { + ReleaseBufferCallback callback; + { + std::scoped_lock<std::mutex> 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<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) { + const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& 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<uint64_t>(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<SurfaceControl>& sc, const sp<Fence>& fence) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index dd8e714e23..0173ffd68e 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -89,13 +89,14 @@ public: void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); + void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback); void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format); - void flushShadowQueue() { mFlushShadowQueue = true; } + void flushShadowQueue() {} status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineInfo(const FrameTimelineInfo& info); @@ -132,16 +133,10 @@ private: int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); - bool mInitialCallbackReceived GUARDED_BY(mMutex) = false; - struct PendingReleaseItem { - BufferItem item; - sp<Fence> releaseFence; - }; - std::queue<const BufferItem> mSubmitted GUARDED_BY(mMutex); - // Keep a reference to the currently presented buffer so we can release it when the next buffer - // is ready to be presented. - PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex); + // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the + // buffer or the buffer has been presented and a new buffer is ready to be presented. + std::unordered_map<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex); ui::Size mSize GUARDED_BY(mMutex); ui::Size mRequestedSize GUARDED_BY(mMutex); @@ -157,9 +152,6 @@ private: std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>> mPendingTransactions GUARDED_BY(mMutex); - // If set to true, the next queue buffer will wait until the shadow queue has been processed by - // the adapter. - bool mFlushShadowQueue = false; // Last requested auto refresh state set by the producer. The state indicates that the consumer // should acquire the next frame as soon as it can and not wait for a frame to become available. // This is only relevant for shared buffer mode. diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index cb17ceecd3..098760e89d 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -87,13 +87,14 @@ public: SurfaceStats() = default; SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence, uint32_t hint, FrameEventHistoryStats frameEventStats, - std::vector<JankData> jankData) + std::vector<JankData> jankData, uint64_t previousBufferId) : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence), transformHint(hint), eventStats(frameEventStats), - jankData(std::move(jankData)) {} + jankData(std::move(jankData)), + previousBufferId(previousBufferId) {} sp<IBinder> surfaceControl; nsecs_t acquireTime = -1; @@ -101,6 +102,7 @@ public: uint32_t transformHint = 0; FrameEventHistoryStats eventStats; std::vector<JankData> jankData; + uint64_t previousBufferId; }; class TransactionStats : public Parcelable { @@ -139,6 +141,8 @@ public: DECLARE_META_INTERFACE(TransactionCompletedListener) virtual void onTransactionCompleted(ListenerStats stats) = 0; + + virtual void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) = 0; }; class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 183ec40fba..d68a9cfa4a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -100,7 +100,7 @@ struct layer_state_t { eLayerStackChanged = 0x00000080, /* was eCropChanged_legacy, now available 0x00000100, */ eDeferTransaction_legacy = 0x00000200, - /* was ScalingModeChanged, now available 0x00000400, */ + eReleaseBufferListenerChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, eReparentChildren = 0x00001000, /* was eDetachChildren, now available 0x00002000, */ @@ -248,6 +248,11 @@ struct layer_state_t { // Stretch effect to be applied to this layer StretchEffect stretchEffect; + + // Listens to when the buffer is safe to be released. This is used for blast + // layers only. The callback includes a release fence as well as the graphic + // buffer id to identify the buffer. + sp<ITransactionCompletedListener> releaseBufferListener; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 88484c0bbf..f29983cef7 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -80,6 +80,9 @@ using TransactionCompletedCallbackTakesContext = using TransactionCompletedCallback = std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/, const std::vector<SurfaceControlStats>& /*stats*/)>; +using ReleaseBufferCallback = + std::function<void(uint64_t /* graphicsBufferId */, const sp<Fence>& /*releaseFence*/)>; + using SurfaceStatsCallback = std::function<void(void* /*context*/, nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/, @@ -388,6 +391,8 @@ public: void cacheBuffers(); void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc); + void setReleaseBufferCallback(layer_state_t* state, ReleaseBufferCallback callback); + void removeReleaseBufferCallback(layer_state_t* state); public: Transaction(); @@ -471,7 +476,8 @@ public: Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc, bool transformToDisplayInverse); Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame); - Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer); + Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer, + ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId); Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence); Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace); @@ -650,6 +656,8 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex); std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex); + std::unordered_map<uint64_t /* graphicsBufferId */, ReleaseBufferCallback> + mReleaseBufferCallbacks GUARDED_BY(mMutex); std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> mSurfaceStatsListeners GUARDED_BY(mMutex); @@ -683,8 +691,15 @@ public: SurfaceStatsCallback listener); void removeSurfaceStatsListener(void* context, void* cookie); - // Overrides BnTransactionCompletedListener's onTransactionCompleted + void setReleaseBufferCallback(uint64_t /* graphicsBufferId */, ReleaseBufferCallback); + void removeReleaseBufferCallback(uint64_t /* graphicsBufferId */); + + // BnTransactionCompletedListener overrides void onTransactionCompleted(ListenerStats stats) override; + void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp<Fence> releaseFence) override; + +private: + ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */); }; } // namespace android diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 7895e99cc3..fe48d88376 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -73,13 +73,34 @@ public: void waitForCallbacks() { std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; - while (mBlastBufferQueueAdapter->mSubmitted.size() > 0) { + // Wait until all but one of the submitted buffers have been released. + while (mBlastBufferQueueAdapter->mSubmitted.size() > 1) { mBlastBufferQueueAdapter->mCallbackCV.wait(lock); } } + void setTransactionCompleteCallback(int64_t frameNumber) { + mBlastBufferQueueAdapter->setTransactionCompleteCallback(frameNumber, [&](int64_t frame) { + std::unique_lock lock{mMutex}; + mLastTransactionCompleteFrameNumber = frame; + mCallbackCV.notify_all(); + }); + } + + void waitForCallback(int64_t frameNumber) { + std::unique_lock lock{mMutex}; + // Wait until all but one of the submitted buffers have been released. + while (mLastTransactionCompleteFrameNumber < frameNumber) { + mCallbackCV.wait(lock); + } + } + private: sp<BLASTBufferQueue> mBlastBufferQueueAdapter; + + std::mutex mMutex; + std::condition_variable mCallbackCV; + int64_t mLastTransactionCompleteFrameNumber = -1; }; class BLASTBufferQueueTest : public ::testing::Test { @@ -128,7 +149,7 @@ protected: mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB; } - void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) { + void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer) { producer = adapter.getIGraphicBufferProducer(); setUpProducer(producer); } @@ -205,10 +226,10 @@ protected: EXPECT_GE(epsilon, abs(g - *(pixel + 1))); EXPECT_GE(epsilon, abs(b - *(pixel + 2))); } + ASSERT_EQ(false, ::testing::Test::HasFailure()); } } captureBuf->unlock(); - ASSERT_EQ(false, ::testing::Test::HasFailure()); } static status_t captureDisplay(DisplayCaptureArgs& captureArgs, @@ -315,7 +336,8 @@ TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) nsecs_t desiredPresentTime = systemTime() + nsecs_t(5 * 1e8); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -351,7 +373,8 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -396,7 +419,8 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { nullptr, nullptr); ASSERT_EQ(NO_ERROR, ret); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -429,7 +453,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight / 2), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -486,7 +511,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(bufferSideLength, finalCropSideLength), NATIVE_WINDOW_SCALING_MODE_SCALE_CROP, 0, Fence::NO_FENCE); @@ -537,7 +563,8 @@ TEST_F(BLASTBufferQueueTest, CustomProducerListener) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -577,7 +604,7 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { sp<IGraphicBufferProducer> slowIgbProducer; setUpProducer(slowAdapter, slowIgbProducer); nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); - queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay); + queueBuffer(slowIgbProducer, 0 /* r */, 255 /* g */, 0 /* b */, presentTimeDelay); BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> fastIgbProducer; @@ -617,7 +644,8 @@ public: fillQuadrants(buf); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(bufWidth, bufHeight), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, tr, Fence::NO_FENCE); @@ -838,6 +866,7 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { IGraphicBufferProducer::QueueBufferOutput qbOutput; nsecs_t requestedPresentTimeA = 0; nsecs_t postedTimeA = 0; + adapter.setTransactionCompleteCallback(1); setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true); history.applyDelta(qbOutput.frameTimestamps); @@ -848,7 +877,7 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeA); - adapter.waitForCallbacks(); + adapter.waitForCallback(1); // queue another buffer so we query for frame event deltas nsecs_t requestedPresentTimeB = 0; |