diff options
| author | 2021-10-11 13:47:23 +0000 | |
|---|---|---|
| committer | 2021-10-11 13:47:23 +0000 | |
| commit | 048c6517d7a0d114ea9551656bf543f2ac3c4dd0 (patch) | |
| tree | f5d3f7167388fb0f86deb67de52a3a7c5f54e452 | |
| parent | 8ced90529d614cc86f7a31288581e98a506f90cc (diff) | |
| parent | 69058fb42b64794bb86a8ed23693eaf3dcc686ea (diff) | |
Merge "Call release buffer if the buffer is overwritten in the client"
| -rw-r--r-- | libs/gui/BLASTBufferQueue.cpp | 32 | ||||
| -rw-r--r-- | libs/gui/ITransactionCompletedListener.cpp | 3 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 90 | ||||
| -rw-r--r-- | libs/gui/include/gui/BLASTBufferQueue.h | 4 | ||||
| -rw-r--r-- | libs/gui/include/gui/ITransactionCompletedListener.h | 1 | ||||
| -rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 27 | ||||
| -rw-r--r-- | services/surfaceflinger/BufferStateLayer.cpp | 12 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp | 82 |
8 files changed, 199 insertions, 52 deletions
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 2b17616eda..36de581e38 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -162,6 +162,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); + mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); @@ -325,31 +326,23 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence // 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, const ReleaseCallbackId& id, - const sp<Fence>& releaseFence, uint32_t transformHint, - uint32_t currentMaxAcquiredBufferCount) { + const sp<Fence>& releaseFence, + std::optional<uint32_t> currentMaxAcquiredBufferCount) { sp<BLASTBufferQueue> blastBufferQueue = context.promote(); if (blastBufferQueue) { - blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint, - currentMaxAcquiredBufferCount); + blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); } else { ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); } } -void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, - const sp<Fence>& releaseFence, uint32_t transformHint, - uint32_t currentMaxAcquiredBufferCount) { +void BLASTBufferQueue::releaseBufferCallback( + const ReleaseCallbackId& id, const sp<Fence>& releaseFence, + std::optional<uint32_t> currentMaxAcquiredBufferCount) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); - if (mSurfaceControl != nullptr) { - mTransformHint = transformHint; - mSurfaceControl->setTransformHint(transformHint); - mBufferItemConsumer->setTransformHint(mTransformHint); - BQA_LOGV("updated mTransformHint=%d", mTransformHint); - } - // Calculate how many buffers we need to hold before we release them back // to the buffer queue. This will prevent higher latency when we are running // on a lower refresh rate than the max supported. We only do that for EGL @@ -359,8 +352,12 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL; }(); + if (currentMaxAcquiredBufferCount) { + mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount; + } + const auto numPendingBuffersToHold = - isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; + isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0; mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence}); // Release all buffers that are beyond the ones that we need to hold @@ -374,7 +371,7 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, return; } mNumAcquired--; - BQA_LOGV("released %s", id.to_string().c_str()); + BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str()); mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); processNextBufferLocked(false /* useNextTransaction */); @@ -466,8 +463,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, - std::placeholders::_4); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId, releaseBufferCallback); diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 98e8b548bd..aa7ebc9eb3 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -254,11 +254,10 @@ public: } void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, - uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override { + uint32_t currentMaxAcquiredBufferCount) override { callRemoteAsync<decltype( &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, callbackId, releaseFence, - transformHint, currentMaxAcquiredBufferCount); } }; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index aca59b6d3b..2713be060a 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -214,12 +214,6 @@ void TransactionCompletedListener::setReleaseBufferCallback(const ReleaseCallbac mReleaseBufferCallbacks[callbackId] = listener; } -void TransactionCompletedListener::removeReleaseBufferCallback( - const ReleaseCallbackId& callbackId) { - std::scoped_lock<std::mutex> lock(mMutex); - mReleaseBufferCallbacks.erase(callbackId); -} - void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex); @@ -343,7 +337,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence : Fence::NO_FENCE, - surfaceStats.transformHint, surfaceStats.currentMaxAcquiredBufferCount); } } @@ -389,7 +382,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, - sp<Fence> releaseFence, uint32_t transformHint, + sp<Fence> releaseFence, uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { @@ -401,7 +394,11 @@ void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, callbackId.to_string().c_str()); return; } - callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); + std::optional<uint32_t> optionalMaxAcquiredBufferCount = + currentMaxAcquiredBufferCount == UINT_MAX + ? std::nullopt + : std::make_optional<uint32_t>(currentMaxAcquiredBufferCount); + callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( @@ -712,11 +709,34 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const return NO_ERROR; } +void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) { + if (!(state.what & layer_state_t::eBufferChanged)) { + return; + } + + auto listener = state.bufferData.releaseBufferListener; + sp<Fence> fence = + state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE; + if (state.bufferData.releaseBufferEndpoint == + IInterface::asBinder(TransactionCompletedListener::getIInstance())) { + // if the callback is in process, run on a different thread to avoid any lock contigency + // issues in the client. + SurfaceComposerClient::getDefault() + ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId, + fence); + } else { + listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX); + } +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { for (auto const& [handle, composerState] : other.mComposerStates) { if (mComposerStates.count(handle) == 0) { mComposerStates[handle] = composerState; } else { + if (composerState.state.what & layer_state_t::eBufferChanged) { + releaseBufferIfOverwriting(mComposerStates[handle].state); + } mComposerStates[handle].state.merge(composerState.state); } } @@ -1296,7 +1316,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe mStatus = BAD_INDEX; return *this; } - removeReleaseBufferCallback(s); + + releaseBufferIfOverwriting(*s); + BufferData bufferData; bufferData.buffer = buffer; if (frameNumber) { @@ -1321,15 +1343,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } -void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) { - if (!(s->what & layer_state_t::eBufferChanged)) { - return; - } - - auto listener = TransactionCompletedListener::getInstance(); - listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId); -} - void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData, const ReleaseCallbackId& id, ReleaseBufferCallback callback) { @@ -2210,4 +2223,43 @@ status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, return s->captureLayers(captureArgs, captureListener); } +// --------------------------------------------------------------------------------- + +void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId, + sp<Fence> releaseFence) { + std::scoped_lock<std::mutex> lock(mMutex); + if (!mStarted) { + mThread = std::thread(&ReleaseCallbackThread::threadMain, this); + mStarted = true; + } + + mCallbackInfos.emplace(callbackId, std::move(releaseFence)); + mReleaseCallbackPending.notify_one(); +} + +void ReleaseCallbackThread::threadMain() { + const auto listener = TransactionCompletedListener::getInstance(); + std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> callbackInfos; + while (true) { + { + std::unique_lock<std::mutex> lock(mMutex); + callbackInfos = std::move(mCallbackInfos); + mCallbackInfos = {}; + } + + while (!callbackInfos.empty()) { + auto [callbackId, releaseFence] = callbackInfos.front(); + listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX); + callbackInfos.pop(); + } + + { + std::unique_lock<std::mutex> lock(mMutex); + if (mCallbackInfos.size() == 0) { + mReleaseCallbackPending.wait(lock); + } + } + } +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1f517f65d6..49ece6e052 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -91,7 +91,7 @@ public: void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, - uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); + std::optional<uint32_t> currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void applyPendingTransactions(uint64_t frameNumber); @@ -236,6 +236,8 @@ private: // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a // callback for them. std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); + + uint32_t mCurrentMaxAcquiredBufferCount; }; } // namespace android diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 937095c543..0df5822597 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -192,7 +192,6 @@ public: virtual void onTransactionCompleted(ListenerStats stats) = 0; virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, - uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) = 0; }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 82249a32f9..e62c76ed80 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <sys/types.h> #include <set> +#include <thread> #include <unordered_map> #include <unordered_set> @@ -84,7 +85,7 @@ using TransactionCompletedCallback = const std::vector<SurfaceControlStats>& /*stats*/)>; using ReleaseBufferCallback = std::function<void(const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, - uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>; + std::optional<uint32_t> currentMaxAcquiredBufferCount)>; using SurfaceStatsCallback = std::function<void(void* /*context*/, nsecs_t /*latchTime*/, @@ -93,6 +94,22 @@ using SurfaceStatsCallback = // --------------------------------------------------------------------------- +class ReleaseCallbackThread { +public: + void addReleaseCallback(const ReleaseCallbackId, sp<Fence>); + void threadMain(); + +private: + std::thread mThread; + std::mutex mMutex; + bool mStarted GUARDED_BY(mMutex) = false; + std::condition_variable mReleaseCallbackPending; + std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> mCallbackInfos + GUARDED_BY(mMutex); +}; + +// --------------------------------------------------------------------------- + class SurfaceComposerClient : public RefBase { friend class Composer; @@ -350,6 +367,7 @@ public: private: static std::atomic<uint32_t> idCounter; int64_t generateId(); + void releaseBufferIfOverwriting(const layer_state_t& state); protected: std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates; @@ -400,7 +418,6 @@ public: void cacheBuffers(); void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc); void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback); - void removeReleaseBufferCallback(layer_state_t*); public: Transaction(); @@ -625,6 +642,9 @@ public: status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener); status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener); +protected: + ReleaseCallbackThread mReleaseCallbackThread; + private: virtual void onFirstRef(); @@ -725,11 +745,10 @@ public: void removeSurfaceStatsListener(void* context, void* cookie); void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback); - void removeReleaseBufferCallback(const ReleaseCallbackId&); // BnTransactionCompletedListener overrides void onTransactionCompleted(ListenerStats stats) override; - void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint, + void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t currentMaxAcquiredBufferCount) override; // For Testing Only diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 4eeaba154f..099b85b99f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -40,13 +40,13 @@ using PresentState = frametimeline::SurfaceFrame::PresentState; namespace { void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, - const sp<Fence>& releaseFence, uint32_t transformHint, + const sp<Fence>& releaseFence, uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; } listener->onReleaseBuffer({buffer->getId(), framenumber}, - releaseFence ? releaseFence : Fence::NO_FENCE, transformHint, + releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); } } // namespace @@ -64,7 +64,7 @@ BufferStateLayer::~BufferStateLayer() { if (mBufferInfo.mBuffer != nullptr && !isClone()) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, - mBufferInfo.mFence, mTransformHint, + mBufferInfo.mFence, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); } @@ -479,7 +479,7 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, - mDrawingState.acquireFence, mTransformHint, + mDrawingState.acquireFence, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); decrementPendingBufferCount(); @@ -491,9 +491,9 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, } else if (mLastClientCompositionFence != nullptr) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, - mLastClientCompositionFence, mTransformHint, + mLastClientCompositionFence, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); + mOwnerUid)); mLastClientCompositionFence = nullptr; } } diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index 3847a51b7c..e50c2fce56 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -31,7 +31,7 @@ class ReleaseBufferCallbackHelper { public: static void function(void* callbackContext, ReleaseCallbackId callbackId, const sp<Fence>& releaseFence, - uint32_t /*currentMaxAcquiredBufferCount*/) { + std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) { if (!callbackContext) { FAIL() << "failed to get callback context"; } @@ -385,4 +385,84 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) { ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } +TEST_F(ReleaseBufferCallbackTest, DISABLED_SetBuffer_OverwriteBuffers) { + sp<SurfaceControl> layer = createBufferStateLayer(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + sp<GraphicBuffer> firstBuffer = getBuffer(); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + + // Create transaction with a buffer. + Transaction transaction; + transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, + firstBufferCallbackId, releaseCallback->getCallback()); + + sp<GraphicBuffer> secondBuffer = getBuffer(); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + + // Call setBuffer on the same transaction with a different buffer. + transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, + secondBufferCallbackId, releaseCallback->getCallback()); + + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) { + sp<SurfaceControl> layer = createBufferStateLayer(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + sp<GraphicBuffer> firstBuffer = getBuffer(); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + + // Create transaction with a buffer. + Transaction transaction1; + transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, + firstBufferCallbackId, releaseCallback->getCallback()); + + sp<GraphicBuffer> secondBuffer = getBuffer(); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + + // Create a second transaction with a new buffer for the same layer. + Transaction transaction2; + transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, + secondBufferCallbackId, releaseCallback->getCallback()); + + // merge transaction1 into transaction2 so ensure we get a proper buffer release callback. + transaction1.merge(std::move(transaction2)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) { + sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener(); + sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener(); + + TransactionCompletedListener::setInstance(firstCompletedListener); + + sp<SurfaceControl> layer = createBufferStateLayer(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + sp<GraphicBuffer> firstBuffer = getBuffer(); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + + Transaction transaction1; + transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, + firstBufferCallbackId, releaseCallback->getCallback()); + + // Sent a second buffer to allow the first buffer to get released. + sp<GraphicBuffer> secondBuffer = getBuffer(); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + + Transaction transaction2; + transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, + secondBufferCallbackId, releaseCallback->getCallback()); + + // Set a different TransactionCompletedListener to mimic a second process + TransactionCompletedListener::setInstance(secondCompletedListener); + Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply(); + + // Make sure we can still get the release callback even though the merge happened in a different + // process. + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); +} + } // namespace android |