Loading libs/gui/BLASTBufferQueue.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -371,7 +371,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mPendingTransactions.end()); if (applyTransaction) { t->apply(); t->setApplyToken(mApplyToken).apply(); } BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 Loading libs/gui/SurfaceComposerClient.cpp +18 −3 Original line number Diff line number Diff line Loading @@ -396,7 +396,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) { mFrameTimelineVsyncId(other.mFrameTimelineVsyncId), mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; Loading Loading @@ -427,7 +428,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); const int64_t frameTimelineVsyncId = parcel->readInt64(); sp<IBinder> applyToken; parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast<size_t>(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; Loading Loading @@ -505,6 +507,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; mInputWindowCommands = inputWindowCommands; mApplyToken = applyToken; return NO_ERROR; } Loading Loading @@ -532,6 +535,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); parcel->writeInt64(mFrameTimelineVsyncId); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { displayState.write(*parcel); Loading Loading @@ -607,6 +611,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; mApplyToken = other.mApplyToken; // When merging vsync Ids we take the oldest one if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && Loading Loading @@ -635,6 +640,7 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = 0; mIsAutoTimestamp = true; mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; mApplyToken = nullptr; } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { Loading Loading @@ -763,7 +769,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; } sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sp<IBinder> applyToken = mApplyToken ? mApplyToken : IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, Loading Loading @@ -1579,6 +1588,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoR return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken( const sp<IBinder>& applyToken) { mApplyToken = applyToken; return *this; } // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { Loading libs/gui/include/gui/BLASTBufferQueue.h +4 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,10 @@ private: std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr; uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0}; // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. const sp<IBinder> mApplyToken = new BBinder(); }; } // namespace android Loading libs/gui/include/gui/SurfaceComposerClient.h +9 −0 Original line number Diff line number Diff line Loading @@ -388,6 +388,10 @@ public: // The vsync Id provided by Choreographer.getVsyncId int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; // If not null, transactions will be queued up using this token otherwise a common token // per process will be used. sp<IBinder> mApplyToken = nullptr; InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; Loading Loading @@ -555,6 +559,11 @@ public: // in shared buffer mode. Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh); // Queues up transactions using this token in SurfaceFlinger. By default, all transactions // from a client are placed on the same queue. This can be used to prevent multiple // transactions from blocking each other. Transaction& setApplyToken(const sp<IBinder>& token); status_t setDisplaySurface(const sp<IBinder>& token, const sp<IGraphicBufferProducer>& bufferProducer); Loading libs/gui/tests/BLASTBufferQueue_test.cpp +61 −0 Original line number Diff line number Diff line Loading @@ -221,6 +221,32 @@ protected: return captureResults.result; } void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b, nsecs_t presentTimeDelay) { int slot; sp<Fence> fence; sp<GraphicBuffer> buf; auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf)); uint32_t* bufData; buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), reinterpret_cast<void**>(&bufData)); fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b); buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; nsecs_t timestampNanos = systemTime() + presentTimeDelay; IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight / 2), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); igbp->queueBuffer(slot, input, &qbOutput); } sp<SurfaceComposerClient> mClient; sp<ISurfaceComposer> mComposer; Loading Loading @@ -528,6 +554,41 @@ TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) { ASSERT_EQ(queuesToNativeWindow, 1); } TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { sp<SurfaceControl> bgSurface = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); ASSERT_NE(nullptr, bgSurface.get()); Transaction t; t.setLayerStack(bgSurface, 0) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1) .apply(); BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> slowIgbProducer; setUpProducer(slowAdapter, slowIgbProducer); nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay); BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> fastIgbProducer; setUpProducer(fastAdapter, fastIgbProducer); uint8_t r = 255; uint8_t g = 0; uint8_t b = 0; queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */); fastAdapter.waitForCallbacks(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { Loading Loading
libs/gui/BLASTBufferQueue.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -371,7 +371,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mPendingTransactions.end()); if (applyTransaction) { t->apply(); t->setApplyToken(mApplyToken).apply(); } BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 Loading
libs/gui/SurfaceComposerClient.cpp +18 −3 Original line number Diff line number Diff line Loading @@ -396,7 +396,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) { mFrameTimelineVsyncId(other.mFrameTimelineVsyncId), mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; Loading Loading @@ -427,7 +428,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); const int64_t frameTimelineVsyncId = parcel->readInt64(); sp<IBinder> applyToken; parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast<size_t>(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; Loading Loading @@ -505,6 +507,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; mInputWindowCommands = inputWindowCommands; mApplyToken = applyToken; return NO_ERROR; } Loading Loading @@ -532,6 +535,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); parcel->writeInt64(mFrameTimelineVsyncId); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { displayState.write(*parcel); Loading Loading @@ -607,6 +611,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; mApplyToken = other.mApplyToken; // When merging vsync Ids we take the oldest one if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && Loading Loading @@ -635,6 +640,7 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = 0; mIsAutoTimestamp = true; mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; mApplyToken = nullptr; } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { Loading Loading @@ -763,7 +769,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; } sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sp<IBinder> applyToken = mApplyToken ? mApplyToken : IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, Loading Loading @@ -1579,6 +1588,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoR return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken( const sp<IBinder>& applyToken) { mApplyToken = applyToken; return *this; } // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { Loading
libs/gui/include/gui/BLASTBufferQueue.h +4 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,10 @@ private: std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr; uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0}; // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. const sp<IBinder> mApplyToken = new BBinder(); }; } // namespace android Loading
libs/gui/include/gui/SurfaceComposerClient.h +9 −0 Original line number Diff line number Diff line Loading @@ -388,6 +388,10 @@ public: // The vsync Id provided by Choreographer.getVsyncId int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; // If not null, transactions will be queued up using this token otherwise a common token // per process will be used. sp<IBinder> mApplyToken = nullptr; InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; Loading Loading @@ -555,6 +559,11 @@ public: // in shared buffer mode. Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh); // Queues up transactions using this token in SurfaceFlinger. By default, all transactions // from a client are placed on the same queue. This can be used to prevent multiple // transactions from blocking each other. Transaction& setApplyToken(const sp<IBinder>& token); status_t setDisplaySurface(const sp<IBinder>& token, const sp<IGraphicBufferProducer>& bufferProducer); Loading
libs/gui/tests/BLASTBufferQueue_test.cpp +61 −0 Original line number Diff line number Diff line Loading @@ -221,6 +221,32 @@ protected: return captureResults.result; } void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b, nsecs_t presentTimeDelay) { int slot; sp<Fence> fence; sp<GraphicBuffer> buf; auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf)); uint32_t* bufData; buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), reinterpret_cast<void**>(&bufData)); fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b); buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; nsecs_t timestampNanos = systemTime() + presentTimeDelay; IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight / 2), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); igbp->queueBuffer(slot, input, &qbOutput); } sp<SurfaceComposerClient> mClient; sp<ISurfaceComposer> mComposer; Loading Loading @@ -528,6 +554,41 @@ TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) { ASSERT_EQ(queuesToNativeWindow, 1); } TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { sp<SurfaceControl> bgSurface = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); ASSERT_NE(nullptr, bgSurface.get()); Transaction t; t.setLayerStack(bgSurface, 0) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1) .apply(); BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> slowIgbProducer; setUpProducer(slowAdapter, slowIgbProducer); nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay); BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> fastIgbProducer; setUpProducer(fastAdapter, fastIgbProducer); uint8_t r = 255; uint8_t g = 0; uint8_t b = 0; queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */); fastAdapter.waitForCallbacks(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { Loading