Loading libs/gui/BLASTBufferQueue.cpp +68 −22 Original line number Diff line number Diff line Loading @@ -164,8 +164,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name) mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mNumAcquired = 0; mNumFrameAvailable = 0; BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", mSize.width, mSize.height, mFormat, mTransformHint); BQA_LOGV("BLASTBufferQueue created"); } BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, Loading @@ -182,14 +181,14 @@ BLASTBufferQueue::~BLASTBufferQueue() { BQA_LOGE("Applying pending transactions on dtor %d", static_cast<uint32_t>(mPendingTransactions.size())); SurfaceComposerClient::Transaction t; for (auto& [targetFrameNumber, transaction] : mPendingTransactions) { t.merge(std::move(transaction)); } t.apply(); mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); t.setApplyToken(mApplyToken).apply(); } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format, SurfaceComposerClient::Transaction* outTransaction) { LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL"); std::unique_lock _lock{mMutex}; if (mFormat != format) { mFormat = format; Loading @@ -197,21 +196,20 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, } SurfaceComposerClient::Transaction t; const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface); bool applyTransaction = false; // Always update the native object even though they might have the same layer handle, so we can // get the updated transform hint from WM. mSurfaceControl = surface; if (mSurfaceControl != nullptr) { if (setBackpressureFlag) { if (surfaceControlChanged) { BQA_LOGD("Updating SurfaceControl without recreating BBQ"); t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); applyTransaction = true; } mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); } BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format, mTransformHint); Loading @@ -225,11 +223,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, mSize = mRequestedSize; SurfaceComposerClient::Transaction* destFrameTransaction = (outTransaction) ? outTransaction : &t; if (mSurfaceControl != nullptr) { destFrameTransaction->setDestinationFrame(mSurfaceControl, Rect(0, 0, newSize.getWidth(), newSize.getHeight())); } applyTransaction = true; } } Loading Loading @@ -640,7 +636,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // add to shadow queue mNumFrameAvailable++; if (mWaitForTransactionCallback && mNumFrameAvailable == 2) { if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) { acquireAndReleaseBuffer(); } ATRACE_INT(mQueuedBufferTrace.c_str(), Loading Loading @@ -717,7 +713,7 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); return mNumAcquired == maxAcquiredBuffers; return mNumAcquired >= maxAcquiredBuffers; } class BBQSurface : public Surface { Loading Loading @@ -991,4 +987,54 @@ uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { return mLastAcquiredFrameNumber; } void BLASTBufferQueue::abandon() { std::unique_lock _lock{mMutex}; // flush out the shadow queue while (mNumFrameAvailable > 0) { acquireAndReleaseBuffer(); } // Clear submitted buffer states mNumAcquired = 0; mSubmitted.clear(); mPendingRelease.clear(); if (!mPendingTransactions.empty()) { BQA_LOGD("Applying pending transactions on abandon %d", static_cast<uint32_t>(mPendingTransactions.size())); SurfaceComposerClient::Transaction t; mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); t.setApplyToken(mApplyToken).apply(); } // Clear sync states if (mWaitForTransactionCallback) { BQA_LOGD("mWaitForTransactionCallback cleared"); mWaitForTransactionCallback = false; } if (mSyncTransaction != nullptr) { BQA_LOGD("mSyncTransaction cleared mAcquireSingleBuffer=%s", mAcquireSingleBuffer ? "true" : "false"); mSyncTransaction = nullptr; mAcquireSingleBuffer = false; } // abandon buffer queue if (mBufferItemConsumer != nullptr) { mBufferItemConsumer->abandon(); mBufferItemConsumer->setFrameAvailableListener(nullptr); mBufferItemConsumer->setBufferFreedListener(nullptr); mBufferItemConsumer->setBlastBufferQueue(nullptr); } mBufferItemConsumer = nullptr; mConsumer = nullptr; mProducer = nullptr; } bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const { std::unique_lock _lock{mMutex}; return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl); } } // namespace android libs/gui/include/gui/BLASTBufferQueue.h +5 −3 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ public: return mProducer; } sp<Surface> getSurface(bool includeSurfaceControlHandle); bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const; void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; Loading Loading @@ -109,6 +110,7 @@ public: uint32_t getLastTransformHint() const; uint64_t getLastAcquiredFrameNum(); void abandon(); virtual ~BLASTBufferQueue(); Loading Loading @@ -145,15 +147,15 @@ private: std::string mQueuedBufferTrace; sp<SurfaceControl> mSurfaceControl; std::mutex mMutex; mutable std::mutex mMutex; std::condition_variable mCallbackCV; // BufferQueue internally allows 1 more than // the max to be acquired int32_t mMaxAcquiredBuffers = 1; int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0; int32_t mNumAcquired GUARDED_BY(mMutex) = 0; // 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. Loading libs/gui/tests/BLASTBufferQueue_test.cpp +88 −0 Original line number Diff line number Diff line Loading @@ -1069,6 +1069,94 @@ TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) { checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } // This test will currently fail because the old surfacecontrol will steal the last presented buffer // until the old surface control is destroyed. This is not necessarily a bug but to document a // limitation with the update API and to test any changes to make the api more robust. The current // approach for the client is to recreate the blastbufferqueue when the surfacecontrol updates. TEST_F(BLASTBufferQueueTest, DISABLED_DisconnectProducerTest) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); std::vector<sp<SurfaceControl>> surfaceControls; sp<IGraphicBufferProducer> igbProducer; for (int i = 0; i < 10; i++) { sp<SurfaceControl> sc = mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); Transaction() .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(true); surfaceControls.push_back(sc); adapter.update(sc, mDisplayWidth, mDisplayHeight); setUpProducer(adapter, igbProducer); Transaction next; queueBuffer(igbProducer, 0, 255, 0, 0); queueBuffer(igbProducer, 0, 0, 255, 0); adapter.setSyncTransaction(&next, false); queueBuffer(igbProducer, 255, 0, 0, 0); CallbackHelper transactionCallback; next.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()) .apply(); CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); igbProducer->disconnect(NATIVE_WINDOW_API_CPU); } } // See DISABLED_DisconnectProducerTest TEST_F(BLASTBufferQueueTest, DISABLED_UpdateSurfaceControlTest) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); std::vector<sp<SurfaceControl>> surfaceControls; sp<IGraphicBufferProducer> igbProducer; for (int i = 0; i < 10; i++) { sp<SurfaceControl> sc = mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); Transaction() .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(true); surfaceControls.push_back(sc); adapter.update(sc, mDisplayWidth, mDisplayHeight); setUpProducer(adapter, igbProducer); Transaction next; queueBuffer(igbProducer, 0, 255, 0, 0); queueBuffer(igbProducer, 0, 0, 255, 0); adapter.setSyncTransaction(&next, false); queueBuffer(igbProducer, 255, 0, 0, 0); CallbackHelper transactionCallback; next.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()) .apply(); CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } } class TestProducerListener : public BnProducerListener { public: sp<IGraphicBufferProducer> mIgbp; Loading Loading
libs/gui/BLASTBufferQueue.cpp +68 −22 Original line number Diff line number Diff line Loading @@ -164,8 +164,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name) mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mNumAcquired = 0; mNumFrameAvailable = 0; BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", mSize.width, mSize.height, mFormat, mTransformHint); BQA_LOGV("BLASTBufferQueue created"); } BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, Loading @@ -182,14 +181,14 @@ BLASTBufferQueue::~BLASTBufferQueue() { BQA_LOGE("Applying pending transactions on dtor %d", static_cast<uint32_t>(mPendingTransactions.size())); SurfaceComposerClient::Transaction t; for (auto& [targetFrameNumber, transaction] : mPendingTransactions) { t.merge(std::move(transaction)); } t.apply(); mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); t.setApplyToken(mApplyToken).apply(); } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format, SurfaceComposerClient::Transaction* outTransaction) { LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL"); std::unique_lock _lock{mMutex}; if (mFormat != format) { mFormat = format; Loading @@ -197,21 +196,20 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, } SurfaceComposerClient::Transaction t; const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface); bool applyTransaction = false; // Always update the native object even though they might have the same layer handle, so we can // get the updated transform hint from WM. mSurfaceControl = surface; if (mSurfaceControl != nullptr) { if (setBackpressureFlag) { if (surfaceControlChanged) { BQA_LOGD("Updating SurfaceControl without recreating BBQ"); t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); applyTransaction = true; } mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); } BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format, mTransformHint); Loading @@ -225,11 +223,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, mSize = mRequestedSize; SurfaceComposerClient::Transaction* destFrameTransaction = (outTransaction) ? outTransaction : &t; if (mSurfaceControl != nullptr) { destFrameTransaction->setDestinationFrame(mSurfaceControl, Rect(0, 0, newSize.getWidth(), newSize.getHeight())); } applyTransaction = true; } } Loading Loading @@ -640,7 +636,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // add to shadow queue mNumFrameAvailable++; if (mWaitForTransactionCallback && mNumFrameAvailable == 2) { if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) { acquireAndReleaseBuffer(); } ATRACE_INT(mQueuedBufferTrace.c_str(), Loading Loading @@ -717,7 +713,7 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); return mNumAcquired == maxAcquiredBuffers; return mNumAcquired >= maxAcquiredBuffers; } class BBQSurface : public Surface { Loading Loading @@ -991,4 +987,54 @@ uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { return mLastAcquiredFrameNumber; } void BLASTBufferQueue::abandon() { std::unique_lock _lock{mMutex}; // flush out the shadow queue while (mNumFrameAvailable > 0) { acquireAndReleaseBuffer(); } // Clear submitted buffer states mNumAcquired = 0; mSubmitted.clear(); mPendingRelease.clear(); if (!mPendingTransactions.empty()) { BQA_LOGD("Applying pending transactions on abandon %d", static_cast<uint32_t>(mPendingTransactions.size())); SurfaceComposerClient::Transaction t; mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); t.setApplyToken(mApplyToken).apply(); } // Clear sync states if (mWaitForTransactionCallback) { BQA_LOGD("mWaitForTransactionCallback cleared"); mWaitForTransactionCallback = false; } if (mSyncTransaction != nullptr) { BQA_LOGD("mSyncTransaction cleared mAcquireSingleBuffer=%s", mAcquireSingleBuffer ? "true" : "false"); mSyncTransaction = nullptr; mAcquireSingleBuffer = false; } // abandon buffer queue if (mBufferItemConsumer != nullptr) { mBufferItemConsumer->abandon(); mBufferItemConsumer->setFrameAvailableListener(nullptr); mBufferItemConsumer->setBufferFreedListener(nullptr); mBufferItemConsumer->setBlastBufferQueue(nullptr); } mBufferItemConsumer = nullptr; mConsumer = nullptr; mProducer = nullptr; } bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const { std::unique_lock _lock{mMutex}; return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl); } } // namespace android
libs/gui/include/gui/BLASTBufferQueue.h +5 −3 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ public: return mProducer; } sp<Surface> getSurface(bool includeSurfaceControlHandle); bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const; void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; Loading Loading @@ -109,6 +110,7 @@ public: uint32_t getLastTransformHint() const; uint64_t getLastAcquiredFrameNum(); void abandon(); virtual ~BLASTBufferQueue(); Loading Loading @@ -145,15 +147,15 @@ private: std::string mQueuedBufferTrace; sp<SurfaceControl> mSurfaceControl; std::mutex mMutex; mutable std::mutex mMutex; std::condition_variable mCallbackCV; // BufferQueue internally allows 1 more than // the max to be acquired int32_t mMaxAcquiredBuffers = 1; int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0; int32_t mNumAcquired GUARDED_BY(mMutex) = 0; // 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. Loading
libs/gui/tests/BLASTBufferQueue_test.cpp +88 −0 Original line number Diff line number Diff line Loading @@ -1069,6 +1069,94 @@ TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) { checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } // This test will currently fail because the old surfacecontrol will steal the last presented buffer // until the old surface control is destroyed. This is not necessarily a bug but to document a // limitation with the update API and to test any changes to make the api more robust. The current // approach for the client is to recreate the blastbufferqueue when the surfacecontrol updates. TEST_F(BLASTBufferQueueTest, DISABLED_DisconnectProducerTest) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); std::vector<sp<SurfaceControl>> surfaceControls; sp<IGraphicBufferProducer> igbProducer; for (int i = 0; i < 10; i++) { sp<SurfaceControl> sc = mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); Transaction() .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(true); surfaceControls.push_back(sc); adapter.update(sc, mDisplayWidth, mDisplayHeight); setUpProducer(adapter, igbProducer); Transaction next; queueBuffer(igbProducer, 0, 255, 0, 0); queueBuffer(igbProducer, 0, 0, 255, 0); adapter.setSyncTransaction(&next, false); queueBuffer(igbProducer, 255, 0, 0, 0); CallbackHelper transactionCallback; next.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()) .apply(); CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); igbProducer->disconnect(NATIVE_WINDOW_API_CPU); } } // See DISABLED_DisconnectProducerTest TEST_F(BLASTBufferQueueTest, DISABLED_UpdateSurfaceControlTest) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); std::vector<sp<SurfaceControl>> surfaceControls; sp<IGraphicBufferProducer> igbProducer; for (int i = 0; i < 10; i++) { sp<SurfaceControl> sc = mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); Transaction() .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(true); surfaceControls.push_back(sc); adapter.update(sc, mDisplayWidth, mDisplayHeight); setUpProducer(adapter, igbProducer); Transaction next; queueBuffer(igbProducer, 0, 255, 0, 0); queueBuffer(igbProducer, 0, 0, 255, 0); adapter.setSyncTransaction(&next, false); queueBuffer(igbProducer, 255, 0, 0, 0); CallbackHelper transactionCallback; next.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()) .apply(); CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } } class TestProducerListener : public BnProducerListener { public: sp<IGraphicBufferProducer> mIgbp; Loading