diff options
22 files changed, 652 insertions, 125 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; 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<ITransactionCompletedListener>& listener, + const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence) { + if (!listener) { + return; + } + listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE); +} +} // namespace + // clang-format off const std::array<float, 16> 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<CallbackHandle>& 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; jankData.reserve(mPendingJankClassifications.size()); while (!mPendingJankClassifications.empty() @@ -344,8 +371,8 @@ bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional<nsecs_t> dequeueTime, - const FrameTimelineInfo& info) { + std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info, + const sp<ITransactionCompletedListener>& releaseBufferListener) { ATRACE_CALL(); if (mCurrentState.buffer) { @@ -353,7 +380,10 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence if (mCurrentState.buffer != mDrawingState.buffer) { // If mCurrentState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be - // dropped and we should decrement the pending buffer count. + // dropped and we should decrement the pending buffer count and + // call any release buffer callbacks if set. + callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer, + mCurrentState.acquireFence); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX); @@ -361,9 +391,8 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence } } } - mCurrentState.frameNumber = frameNumber; - + mCurrentState.releaseBufferListener = releaseBufferListener; mCurrentState.buffer = buffer; mCurrentState.clientCacheId = clientCacheId; mCurrentState.modified = true; @@ -889,15 +918,16 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } -uint32_t BufferStateLayer::doTransaction(uint32_t flags) { - if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer) { +void BufferStateLayer::bufferMayChange(sp<GraphicBuffer>& 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 diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index ebf40cb6e4..036e8d2e85 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -70,7 +70,8 @@ public: bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info) override; + std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info, + const sp<ITransactionCompletedListener>& transactionListener) override; bool setAcquireFence(const sp<Fence>& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; @@ -111,7 +112,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - uint32_t doTransaction(uint32_t flags) override; + void bufferMayChange(sp<GraphicBuffer>& newBuffer) override; std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } @@ -170,6 +171,9 @@ private: mutable bool mCurrentStateModified = false; bool mReleasePreviousBuffer = false; + + // Stores the last set acquire fence signal time used to populate the callback handle's acquire + // time. nsecs_t mCallbackHandleAcquireTime = -1; std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0015bf27d1..cd3e8add9a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1048,6 +1048,9 @@ uint32_t Layer::doTransaction(uint32_t flags) { c.callbackHandles.push_back(handle); } + // Allow BufferStateLayer to release any unlatched buffers in drawing state. + bufferMayChange(c.buffer); + // Commit the transaction commitTransaction(c); mPendingStatesSnapshot = mPendingStates; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 26d8e7472a..85ff479344 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -312,6 +312,7 @@ public: // When the transaction was posted nsecs_t postTime; + sp<ITransactionCompletedListener> releaseBufferListener; // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync. // If multiple buffers are queued, the prior ones will be dropped, along with the @@ -466,7 +467,8 @@ public: nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */, - const FrameTimelineInfo& /*info*/) { + const FrameTimelineInfo& /*info*/, + const sp<ITransactionCompletedListener>& /* releaseBufferListener */) { return false; }; virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; }; @@ -774,6 +776,12 @@ public: virtual uint32_t doTransaction(uint32_t transactionFlags); /* + * Called before updating the drawing state buffer. Used by BufferStateLayer to release any + * unlatched buffers in the drawing state. + */ + virtual void bufferMayChange(sp<GraphicBuffer>& /* newBuffer */){}; + + /* * Remove relative z for the layer if its relative parent is not part of the * provided layer tree. */ diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index b29c624d00..1d00cc38f2 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -241,7 +241,8 @@ void RefreshRateOverlay::changeRefreshRate(const Fps& fps) { auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), - std::nullopt /* dequeueTime */, FrameTimelineInfo{}); + std::nullopt /* dequeueTime */, FrameTimelineInfo{}, + nullptr /* releaseBufferListener */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -254,7 +255,8 @@ void RefreshRateOverlay::onInvalidate() { auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), - std::nullopt /* dequeueTime */, FrameTimelineInfo{}); + std::nullopt /* dequeueTime */, FrameTimelineInfo{}, + nullptr /* releaseBufferListener */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d048380dd2..61cc8a2ff0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4027,7 +4027,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info)) { + s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info, + s.releaseBufferListener)) { flags |= eTraversalNeeded; } } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index a78510e902..3590e76cb9 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -201,7 +201,8 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& handle->dequeueReadyTime); transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime, handle->previousReleaseFence, - handle->transformHint, eventStats, jankData); + handle->transformHint, eventStats, jankData, + handle->previousBufferId); } return NO_ERROR; } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index a240c824a1..caa8a4fb45 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -50,6 +50,7 @@ public: nsecs_t refreshStartTime = 0; nsecs_t dequeueReadyTime = 0; uint64_t frameNumber = 0; + uint64_t previousBufferId = 0; }; class TransactionCallbackInvoker { diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 78187f7e9d..b96725fa12 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -44,6 +44,7 @@ cc_test { "MultiDisplayLayerBounds_test.cpp", "RefreshRateOverlay_test.cpp", "RelativeZ_test.cpp", + "ReleaseBufferCallback_test.cpp", "ScreenCapture_test.cpp", "SetFrameRate_test.cpp", "SetGeometry_test.cpp", diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index aa1cce2586..158801a705 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #include <sys/epoll.h> #include <gui/DisplayEventReceiver.h> @@ -25,6 +21,8 @@ #include "LayerTransactionTest.h" #include "utils/CallbackUtils.h" +using namespace std::chrono_literals; + namespace android { using android::hardware::graphics::common::V1_1::BufferUsage; @@ -801,7 +799,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime) { } // Try to present 100ms in the future - nsecs_t time = systemTime() + (100 * 1e6); + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -825,7 +823,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { } // Try to present 100ms in the future - nsecs_t time = systemTime() + (100 * 1e6); + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -842,7 +840,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { } // Try to present 33ms after the first frame - time += (33.3 * 1e6); + time += std::chrono::nanoseconds(33ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -870,7 +868,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) { } // Try to present 100ms in the future - nsecs_t time = systemTime() + (100 * 1e6); + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -887,7 +885,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) { } // Try to present 33ms before the previous frame - time -= (33.3 * 1e6); + time -= std::chrono::nanoseconds(33ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -914,7 +912,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Past) { } // Try to present 100ms in the past - nsecs_t time = systemTime() - (100 * 1e6); + nsecs_t time = systemTime() - std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -948,6 +946,3 @@ TEST_F(LayerCallbackTest, ExpectedPresentTime) { } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp new file mode 100644 index 0000000000..fb7d41c81e --- /dev/null +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LayerTransactionTest.h" +#include "utils/CallbackUtils.h" + +using namespace std::chrono_literals; + +namespace android { + +using android::hardware::graphics::common::V1_1::BufferUsage; + +::testing::Environment* const binderEnv = + ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); + +// b/181132765 - disabled until cuttlefish failures are investigated +class ReleaseBufferCallbackHelper { +public: + static void function(void* callbackContext, uint64_t graphicsBufferId, + const sp<Fence>& releaseFence) { + if (!callbackContext) { + FAIL() << "failed to get callback context"; + } + ReleaseBufferCallbackHelper* helper = + static_cast<ReleaseBufferCallbackHelper*>(callbackContext); + std::lock_guard lock(helper->mMutex); + helper->mCallbackDataQueue.emplace(graphicsBufferId, releaseFence); + helper->mConditionVariable.notify_all(); + } + + void getCallbackData(uint64_t* bufferId) { + std::unique_lock lock(mMutex); + if (mCallbackDataQueue.empty()) { + if (!mConditionVariable.wait_for(lock, std::chrono::seconds(3), + [&] { return !mCallbackDataQueue.empty(); })) { + FAIL() << "failed to get releaseBuffer callback"; + } + } + + auto callbackData = mCallbackDataQueue.front(); + mCallbackDataQueue.pop(); + *bufferId = callbackData.first; + } + + void verifyNoCallbacks() { + // Wait to see if there are extra callbacks + std::this_thread::sleep_for(300ms); + + std::lock_guard lock(mMutex); + EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; + mCallbackDataQueue = {}; + } + + android::ReleaseBufferCallback getCallback() { + return std::bind(function, static_cast<void*>(this) /* callbackContext */, + std::placeholders::_1, std::placeholders::_2); + } + + std::mutex mMutex; + std::condition_variable mConditionVariable; + std::queue<std::pair<uint64_t, sp<Fence>>> mCallbackDataQueue; +}; + +class ReleaseBufferCallbackTest : public LayerTransactionTest { +public: + virtual sp<SurfaceControl> createBufferStateLayer() { + return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState); + } + + static void submitBuffer(const sp<SurfaceControl>& layer, sp<GraphicBuffer> buffer, + sp<Fence> fence, CallbackHelper& callback, + ReleaseBufferCallbackHelper& releaseCallback) { + Transaction t; + t.setBuffer(layer, buffer, releaseCallback.getCallback()); + t.setAcquireFence(layer, fence); + t.addTransactionCompletedCallback(callback.function, callback.getContext()); + t.apply(); + } + + static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult) { + CallbackData callbackData; + helper.getCallbackData(&callbackData); + expectedResult.verifyCallbackData(callbackData); + } + + static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback, + uint64_t expectedReleaseBufferId) { + uint64_t actualReleaseBufferId; + releaseCallback.getCallbackData(&actualReleaseBufferId); + EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId); + releaseCallback.verifyNoCallbacks(); + } + static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() { + static std::vector<ReleaseBufferCallbackHelper*> sCallbacks; + sCallbacks.emplace_back(new ReleaseBufferCallbackHelper()); + return sCallbacks.back(); + } + + static sp<GraphicBuffer> getBuffer() { + return new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + } +}; + +TEST_F(ReleaseBufferCallbackTest, DISABLED_PresentBuffer) { + sp<SurfaceControl> layer = createBufferStateLayer(); + CallbackHelper transactionCallback; + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp<GraphicBuffer> firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // if state doesn't change, no release callbacks are expected + Transaction t; + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.apply(); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, ExpectedResult())); + EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // If a presented buffer is replaced, we should emit a release callback for the + // previously presented buffer. + sp<GraphicBuffer> secondBuffer = getBuffer(); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_OffScreenLayer) { + sp<SurfaceControl> layer = createBufferStateLayer(); + + CallbackHelper transactionCallback; + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp<GraphicBuffer> firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + releaseCallback->verifyNoCallbacks(); + + // If a layer is parented offscreen then it should not emit a callback since sf still owns + // the buffer and can render it again. + Transaction t; + t.reparent(layer, nullptr); + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.apply(); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::NOT_RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // If a presented buffer is replaced, we should emit a release callback for the + // previously presented buffer. + sp<GraphicBuffer> secondBuffer = getBuffer(); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::NOT_RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + + // If continue to submit buffer we continue to get release callbacks + sp<GraphicBuffer> thirdBuffer = getBuffer(); + submitBuffer(layer, thirdBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::NOT_RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId())); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_layerdestroy) { + sp<SurfaceControl> layer = createBufferStateLayer(); + CallbackHelper* transactionCallback = new CallbackHelper(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp<GraphicBuffer> firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + } + + // Destroying a currently presenting layer emits a callback. + Transaction t; + t.reparent(layer, nullptr); + t.apply(); + layer = nullptr; + + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); +} + +// Destroying a never presented layer emits a callback. +TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_OffScreenLayerDestroy) { + sp<SurfaceControl> layer = createBufferStateLayer(); + + // make layer offscreen + Transaction t; + t.reparent(layer, nullptr); + t.apply(); + + CallbackHelper* transactionCallback = new CallbackHelper(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // Submitting a buffer does not emit a callback. + sp<GraphicBuffer> firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + } + + // Submitting a second buffer will replace the drawing state buffer and emit a callback. + sp<GraphicBuffer> secondBuffer = getBuffer(); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE( + waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + } + + // Destroying the offscreen layer emits a callback. + layer = nullptr; + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId())); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { + sp<SurfaceControl> layer = createBufferStateLayer(); + CallbackHelper transactionCallback; + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp<GraphicBuffer> firstBuffer = getBuffer(); + + // Try to present 100ms in the future + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); + + Transaction t; + t.setBuffer(layer, firstBuffer, releaseCallback->getCallback()); + t.setAcquireFence(layer, Fence::NO_FENCE); + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.setDesiredPresentTime(time); + t.apply(); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // Dropping frames in transaction queue emits a callback + sp<GraphicBuffer> secondBuffer = getBuffer(); + t.setBuffer(layer, secondBuffer, releaseCallback->getCallback()); + t.setAcquireFence(layer, Fence::NO_FENCE); + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.setDesiredPresentTime(time); + t.apply(); + + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index dbadf75d44..b5ef0a1334 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -123,7 +123,8 @@ public: traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE, /*duration*/ 0)); layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache, - frameNumber, dequeueTime, FrameTimelineInfo{}); + frameNumber, dequeueTime, FrameTimelineInfo{}, + nullptr /* releaseBufferCallback */); commitTransaction(layer.get()); bool computeVisisbleRegions; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 623a5e0608..c75538f476 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -126,7 +126,7 @@ public: auto acquireFence = fenceFactory.createFenceTimeForTest(fence); sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); commitTransaction(layer.get()); @@ -151,7 +151,7 @@ public: auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; @@ -161,7 +161,7 @@ public: sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); nsecs_t end = systemTime(); acquireFence2->signalForTest(12); @@ -199,7 +199,7 @@ public: sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -225,7 +225,7 @@ public: sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -255,7 +255,7 @@ public: sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 3, /*inputEventId*/ 0}); + {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto& bufferSurfaceFrameTX = layer->mCurrentState.bufferSurfaceFrameTX; @@ -353,7 +353,7 @@ public: auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; @@ -361,7 +361,7 @@ public: auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence2->signalForTest(12); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -388,7 +388,7 @@ public: auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame1 = layer->mCurrentState.bufferSurfaceFrameTX; @@ -398,7 +398,8 @@ public: sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}); + {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, + nullptr /* releaseBufferCallback */); auto dropEndTime1 = systemTime(); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -409,7 +410,7 @@ public: sp<GraphicBuffer> buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 2, /*inputEventId*/ 0}); + {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); auto dropEndTime2 = systemTime(); acquireFence3->signalForTest(12); @@ -448,7 +449,8 @@ public: sp<Fence> fence1(new Fence()); sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, + nullptr /* releaseBufferCallback */); layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, 10); |