diff options
author | 2022-08-16 19:08:21 +0000 | |
---|---|---|
committer | 2022-08-16 19:08:21 +0000 | |
commit | 44732cde9e19a005def5e110140963a5c2e2f5ae (patch) | |
tree | 9a4deff758bed03ccc5ff838dc55f467c303d762 /libs/gui/BLASTBufferQueue.cpp | |
parent | 896cdca96956b6f14e262380b34a0b04e1214b50 (diff) | |
parent | 91192c8103e78895c57d9da1fc04c8695898580f (diff) |
Merge "DO NOT MERGE - Merge Android 13"
Diffstat (limited to 'libs/gui/BLASTBufferQueue.cpp')
-rw-r--r-- | libs/gui/BLASTBufferQueue.cpp | 521 |
1 files changed, 326 insertions, 195 deletions
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f034642681..dbccf30fae 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -28,6 +28,7 @@ #include <gui/GLConsumer.h> #include <gui/IProducerListener.h> #include <gui/Surface.h> +#include <gui/TraceUtils.h> #include <utils/Singleton.h> #include <utils/Trace.h> @@ -57,6 +58,10 @@ namespace android { #define BQA_LOGE(x, ...) \ ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) +#define BBQ_TRACE(x, ...) \ + ATRACE_FORMAT("%s - %s(f:%u,a:%u)" x, __FUNCTION__, mName.c_str(), mNumFrameAvailable, \ + mNumAcquired, ##__VA_ARGS__) + void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; @@ -127,12 +132,14 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } } -BLASTBufferQueue::BLASTBufferQueue(const std::string& name) +BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame) : mSurfaceControl(nullptr), mSize(1, 1), mRequestedSize(mSize), mFormat(PIXEL_FORMAT_RGBA_8888), - mNextTransaction(nullptr) { + mTransactionReadyCallback(nullptr), + mSyncTransaction(nullptr), + mUpdateDestinationFrame(updateDestinationFrame) { createBufferQueue(&mProducer, &mConsumer); // since the adapter is in the client process, set dequeue timeout // explicitly so that dequeueBuffer will block @@ -155,8 +162,20 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name) ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); + mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mNumAcquired = 0; mNumFrameAvailable = 0; + + TransactionCompletedListener::getInstance()->addQueueStallListener( + [&]() { + std::function<void(bool)> callbackCopy; + { + std::unique_lock _lock{mMutex}; + callbackCopy = mTransactionHangCallback; + } + if (callbackCopy) callbackCopy(true); + }, this); + BQA_LOGV("BLASTBufferQueue created"); } @@ -167,42 +186,49 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont } BLASTBufferQueue::~BLASTBufferQueue() { + TransactionCompletedListener::getInstance()->removeQueueStallListener(this); if (mPendingTransactions.empty()) { return; } 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)); + mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); + // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction + t.setApplyToken(mApplyToken).apply(false, true); + + if (mTransactionReadyCallback) { + mTransactionReadyCallback(mSyncTransaction); } - t.apply(); } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, - int32_t format, SurfaceComposerClient::Transaction* outTransaction) { + int32_t format) { + LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL"); + std::unique_lock _lock{mMutex}; if (mFormat != format) { mFormat = format; mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); } - SurfaceComposerClient::Transaction t; - const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); + const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface); + if (surfaceControlChanged && mSurfaceControl != nullptr) { + BQA_LOGD("Updating SurfaceControl without recreating BBQ"); + } 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) { - t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, - layer_state_t::eEnableBackpressure); - applyTransaction = true; - } - mTransformHint = mSurfaceControl->getTransformHint(); - mBufferItemConsumer->setTransformHint(mTransformHint); + SurfaceComposerClient::Transaction t; + if (surfaceControlChanged) { + 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); @@ -214,18 +240,15 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - SurfaceComposerClient::Transaction* destFrameTransaction = - (outTransaction) ? outTransaction : &t; - if (mSurfaceControl != nullptr) { - destFrameTransaction->setDestinationFrame(mSurfaceControl, - Rect(0, 0, newSize.getWidth(), - newSize.getHeight())); + if (mUpdateDestinationFrame) { + t.setDestinationFrame(mSurfaceControl, Rect(newSize)); + applyTransaction = true; } - applyTransaction = true; } } if (applyTransaction) { - t.setApplyToken(mApplyToken).apply(); + // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction + t.setApplyToken(mApplyToken).apply(false, true); } } @@ -254,7 +277,7 @@ void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, const std::vector<SurfaceControlStats>& stats) { { std::unique_lock _lock{mMutex}; - ATRACE_CALL(); + BBQ_TRACE(); BQA_LOGV("transactionCommittedCallback"); if (!mSurfaceControlsWithPendingCallback.empty()) { sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front(); @@ -273,10 +296,10 @@ void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, // case, we don't actually want to flush the frames in between since they will get // processed and merged with the sync transaction and released earlier than if they // were sent to SF - if (mWaitForTransactionCallback && mNextTransaction == nullptr && + if (mWaitForTransactionCallback && mSyncTransaction == nullptr && currFrameNumber >= mLastAcquiredFrameNumber) { mWaitForTransactionCallback = false; - flushShadowQueueLocked(); + flushShadowQueue(); } } else { BQA_LOGE("Failed to find matching SurfaceControl in transactionCommittedCallback"); @@ -302,12 +325,9 @@ static void transactionCallbackThunk(void* context, nsecs_t latchTime, void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/, const std::vector<SurfaceControlStats>& stats) { - std::function<void(int64_t)> transactionCompleteCallback = nullptr; - uint64_t currFrameNumber = 0; - { std::unique_lock _lock{mMutex}; - ATRACE_CALL(); + BBQ_TRACE(); BQA_LOGV("transactionCallback"); if (!mSurfaceControlsWithPendingCallback.empty()) { @@ -331,28 +351,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.latchTime, stat.frameEventStats.dequeueReadyTime); } - currFrameNumber = stat.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; - } - std::vector<ReleaseCallbackId> staleReleases; - for (const auto& [key, value]: mSubmitted) { - if (currFrameNumber > key.framenumber) { - staleReleases.push_back(key); - } - } - for (const auto& staleRelease : staleReleases) { - releaseBufferCallbackLocked(staleRelease, stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE, - stat.transformHint, stat.currentMaxAcquiredBufferCount); - } } else { BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback"); } @@ -361,13 +359,8 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence "empty."); } - decStrong((void*)transactionCallbackThunk); } - - if (transactionCompleteCallback) { - transactionCompleteCallback(currFrameNumber); - } } // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the @@ -375,19 +368,18 @@ 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::flushShadowQueueLocked() { - BQA_LOGV("flushShadowQueueLocked"); +void BLASTBufferQueue::flushShadowQueue() { + BQA_LOGV("flushShadowQueue"); int numFramesToFlush = mNumFrameAvailable; while (numFramesToFlush > 0) { acquireNextBufferLocked(std::nullopt); @@ -395,31 +387,13 @@ void BLASTBufferQueue::flushShadowQueueLocked() { } } -void BLASTBufferQueue::flushShadowQueue() { - std::unique_lock _lock{mMutex}; - flushShadowQueueLocked(); -} - -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) { + BBQ_TRACE(); std::unique_lock _lock{mMutex}; - releaseBufferCallbackLocked(id, releaseFence, transformHint, currentMaxAcquiredBufferCount); -} - -void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id, - const sp<Fence>& releaseFence, uint32_t transformHint, - uint32_t currentMaxAcquiredBufferCount) { - ATRACE_CALL(); 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 @@ -429,29 +403,21 @@ void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id, return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL; }(); - const auto numPendingBuffersToHold = - isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; - auto rb = ReleasedBuffer{id, releaseFence}; - if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) { - mPendingRelease.emplace_back(rb); + if (currentMaxAcquiredBufferCount) { + mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount; } + const auto numPendingBuffersToHold = + 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 while (mPendingRelease.size() > numPendingBuffersToHold) { - const auto releaseBuffer = mPendingRelease.front(); + const auto releasedBuffer = mPendingRelease.front(); mPendingRelease.pop_front(); - auto it = mSubmitted.find(releaseBuffer.callbackId); - if (it == mSubmitted.end()) { - BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s", - releaseBuffer.callbackId.to_string().c_str()); - return; - } - mNumAcquired--; - BQA_LOGV("released %s", id.to_string().c_str()); - mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); - mSubmitted.erase(it); + releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence); // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let - // onFrameAvailable handle processing them since it will merge with the nextTransaction. + // onFrameAvailable handle processing them since it will merge with the syncTransaction. if (!mWaitForTransactionCallback) { acquireNextBufferLocked(std::nullopt); } @@ -463,9 +429,23 @@ void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id, mCallbackCV.notify_all(); } +void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId, + const sp<Fence>& releaseFence) { + auto it = mSubmitted.find(callbackId); + if (it == mSubmitted.end()) { + BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s", + callbackId.to_string().c_str()); + return; + } + mNumAcquired--; + BBQ_TRACE("frame=%" PRIu64, callbackId.framenumber); + BQA_LOGV("released %s", callbackId.to_string().c_str()); + mBufferItemConsumer->releaseBuffer(it->second, releaseFence); + mSubmitted.erase(it); +} + void BLASTBufferQueue::acquireNextBufferLocked( const std::optional<SurfaceComposerClient::Transaction*> transaction) { - 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 = !transaction; @@ -499,8 +479,10 @@ void BLASTBufferQueue::acquireNextBufferLocked( BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str()); return; } + auto buffer = bufferItem.mGraphicBuffer; mNumFrameAvailable--; + BBQ_TRACE("frame=%" PRIu64, bufferItem.mFrameNumber); if (buffer == nullptr) { mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); @@ -534,7 +516,6 @@ void BLASTBufferQueue::acquireNextBufferLocked( // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); - const bool updateDestinationFrame = mRequestedSize != mSize; mSize = mRequestedSize; Rect crop = computeCrop(bufferItem); mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), @@ -543,38 +524,38 @@ void BLASTBufferQueue::acquireNextBufferLocked( auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, - std::placeholders::_4); - t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback); + 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, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); - t->setAcquireFence(mSurfaceControl, - bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this)); mSurfaceControlsWithPendingCallback.push(mSurfaceControl); - if (updateDestinationFrame) { - t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight())); + if (mUpdateDestinationFrame) { + t->setDestinationFrame(mSurfaceControl, Rect(mSize)); + } else { + const bool ignoreDestinationFrame = + bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE; + t->setFlags(mSurfaceControl, + ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0, + layer_state_t::eIgnoreDestinationFrame); } t->setBufferCrop(mSurfaceControl, crop); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); + t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); if (!bufferItem.mIsAutoTimestamp) { t->setDesiredPresentTime(bufferItem.mTimestamp); } - t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); if (!mNextFrameTimelineInfoQueue.empty()) { t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front()); mNextFrameTimelineInfoQueue.pop(); } - if (mAutoRefresh != bufferItem.mAutoRefresh) { - t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); - mAutoRefresh = bufferItem.mAutoRefresh; - } { std::unique_lock _lock{mTimestampMutex}; auto dequeueTime = mDequeueTimestamps.find(buffer->getId()); @@ -586,23 +567,15 @@ void BLASTBufferQueue::acquireNextBufferLocked( } } - auto mergeTransaction = - [&t, currentFrameNumber = bufferItem.mFrameNumber]( - std::tuple<uint64_t, SurfaceComposerClient::Transaction> pendingTransaction) { - auto& [targetFrameNumber, transaction] = pendingTransaction; - if (currentFrameNumber < targetFrameNumber) { - return false; - } - t->merge(std::move(transaction)); - return true; - }; - - mPendingTransactions.erase(std::remove_if(mPendingTransactions.begin(), - mPendingTransactions.end(), mergeTransaction), - mPendingTransactions.end()); - + mergePendingTransactions(t, bufferItem.mFrameNumber); if (applyTransaction) { - t->setApplyToken(mApplyToken).apply(); + // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction + t->setApplyToken(mApplyToken).apply(false, true); + mAppliedLastTransaction = true; + mLastAppliedFrameNumber = bufferItem.mFrameNumber; + } else { + t->setBufferHasBarrier(mSurfaceControl, mLastAppliedFrameNumber); + mAppliedLastTransaction = false; } BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 @@ -634,61 +607,95 @@ void BLASTBufferQueue::acquireAndReleaseBuffer() { mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence); } -void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { - ATRACE_CALL(); - std::unique_lock _lock{mMutex}; - - const bool nextTransactionSet = mNextTransaction != nullptr; - BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet)); - if (nextTransactionSet) { - if (mWaitForTransactionCallback) { - // We are waiting on a previous sync's transaction callback so allow another sync - // transaction to proceed. - // - // We need to first flush out the transactions that were in between the two syncs. - // We do this by merging them into mNextTransaction so any buffer merging will get - // a release callback invoked. The release callback will be async so we need to wait - // on max acquired to make sure we have the capacity to acquire another buffer. - if (maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGD("waiting to flush shadow queue..."); - mCallbackCV.wait(_lock); - } - while (mNumFrameAvailable > 0) { - // flush out the shadow queue - acquireAndReleaseBuffer(); - } +void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) { + if (mWaitForTransactionCallback && mNumFrameAvailable > 0) { + // We are waiting on a previous sync's transaction callback so allow another sync + // transaction to proceed. + // + // We need to first flush out the transactions that were in between the two syncs. + // We do this by merging them into mSyncTransaction so any buffer merging will get + // a release callback invoked. The release callback will be async so we need to wait + // on max acquired to make sure we have the capacity to acquire another buffer. + if (maxBuffersAcquired(false /* includeExtraAcquire */)) { + BQA_LOGD("waiting to flush shadow queue..."); + mCallbackCV.wait(lock); } - - while (maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGD("waiting for free buffer."); - mCallbackCV.wait(_lock); + while (mNumFrameAvailable > 0) { + // flush out the shadow queue + acquireAndReleaseBuffer(); } } - // add to shadow queue - mNumFrameAvailable++; - if (mWaitForTransactionCallback && mNumFrameAvailable == 2) { - acquireAndReleaseBuffer(); + while (maxBuffersAcquired(false /* includeExtraAcquire */)) { + BQA_LOGD("waiting for free buffer."); + mCallbackCV.wait(lock); } - ATRACE_INT(mQueuedBufferTrace.c_str(), - mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); - - BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - boolToString(nextTransactionSet)); +} - if (nextTransactionSet) { - acquireNextBufferLocked(std::move(mNextTransaction)); +void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { + std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr; + SurfaceComposerClient::Transaction* prevTransaction = nullptr; + { + BBQ_TRACE(); + std::unique_lock _lock{mMutex}; + const bool syncTransactionSet = mTransactionReadyCallback != nullptr; + BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet)); + + if (syncTransactionSet) { + bool mayNeedToWaitForBuffer = true; + // If we are going to re-use the same mSyncTransaction, release the buffer that may + // already be set in the Transaction. This is to allow us a free slot early to continue + // processing a new buffer. + if (!mAcquireSingleBuffer) { + auto bufferData = mSyncTransaction->getAndClearBuffer(mSurfaceControl); + if (bufferData) { + BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64, + bufferData->frameNumber); + releaseBuffer(bufferData->generateReleaseCallbackId(), + bufferData->acquireFence); + // Because we just released a buffer, we know there's no need to wait for a free + // buffer. + mayNeedToWaitForBuffer = false; + } + } - // Only need a commit callback when syncing to ensure the buffer that's synced has been sent - // to SF - incStrong((void*)transactionCommittedCallbackThunk); - mNextTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, - static_cast<void*>(this)); + if (mayNeedToWaitForBuffer) { + flushAndWaitForFreeBuffer(_lock); + } + } - mNextTransaction = nullptr; - mWaitForTransactionCallback = true; - } else if (!mWaitForTransactionCallback) { - acquireNextBufferLocked(std::nullopt); + // add to shadow queue + mNumFrameAvailable++; + if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) { + acquireAndReleaseBuffer(); + } + ATRACE_INT(mQueuedBufferTrace.c_str(), + mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); + + BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " syncTransactionSet=%s", + item.mFrameNumber, boolToString(syncTransactionSet)); + + if (syncTransactionSet) { + acquireNextBufferLocked(mSyncTransaction); + + // Only need a commit callback when syncing to ensure the buffer that's synced has been + // sent to SF + incStrong((void*)transactionCommittedCallbackThunk); + mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, + static_cast<void*>(this)); + mWaitForTransactionCallback = true; + if (mAcquireSingleBuffer) { + prevCallback = mTransactionReadyCallback; + prevTransaction = mSyncTransaction; + mTransactionReadyCallback = nullptr; + mSyncTransaction = nullptr; + } + } else if (!mWaitForTransactionCallback) { + acquireNextBufferLocked(std::nullopt); + } + } + if (prevCallback) { + prevCallback(prevTransaction); } } @@ -707,9 +714,54 @@ void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) { mDequeueTimestamps.erase(bufferId); }; -void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { - std::lock_guard _lock{mMutex}; - mNextTransaction = t; +void BLASTBufferQueue::syncNextTransaction( + std::function<void(SurfaceComposerClient::Transaction*)> callback, + bool acquireSingleBuffer) { + BBQ_TRACE(); + + std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr; + SurfaceComposerClient::Transaction* prevTransaction = nullptr; + + { + std::lock_guard _lock{mMutex}; + // We're about to overwrite the previous call so we should invoke that callback + // immediately. + if (mTransactionReadyCallback) { + prevCallback = mTransactionReadyCallback; + prevTransaction = mSyncTransaction; + } + + mTransactionReadyCallback = callback; + if (callback) { + mSyncTransaction = new SurfaceComposerClient::Transaction(); + } else { + mSyncTransaction = nullptr; + } + mAcquireSingleBuffer = mTransactionReadyCallback ? acquireSingleBuffer : true; + } + + if (prevCallback) { + prevCallback(prevTransaction); + } +} + +void BLASTBufferQueue::stopContinuousSyncTransaction() { + std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr; + SurfaceComposerClient::Transaction* prevTransaction = nullptr; + { + std::lock_guard _lock{mMutex}; + bool invokeCallback = mTransactionReadyCallback && !mAcquireSingleBuffer; + if (invokeCallback) { + prevCallback = mTransactionReadyCallback; + prevTransaction = mSyncTransaction; + } + mTransactionReadyCallback = nullptr; + mSyncTransaction = nullptr; + mAcquireSingleBuffer = true; + } + if (prevCallback) { + prevCallback(prevTransaction); + } } bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { @@ -734,24 +786,13 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } -void BLASTBufferQueue::setTransactionCompleteCallback( - uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) { - std::lock_guard _lock{mMutex}; - if (transactionCompleteCallback == nullptr) { - mTransactionCompleteCallback = nullptr; - } else { - mTransactionCompleteCallback = std::move(transactionCompleteCallback); - mTransactionCompleteFrameNumber = frameNumber; - } -} - // Check if we have acquired the maximum number of buffers. // 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 = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); - return mNumAcquired == maxAcquiredBuffers; + return mNumAcquired >= maxAcquiredBuffers; } class BBQSurface : public Surface { @@ -852,6 +893,41 @@ void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transacti } } +void BLASTBufferQueue::applyPendingTransactions(uint64_t frameNumber) { + std::lock_guard _lock{mMutex}; + + SurfaceComposerClient::Transaction t; + mergePendingTransactions(&t, frameNumber); + // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction + t.setApplyToken(mApplyToken).apply(false, true); +} + +void BLASTBufferQueue::mergePendingTransactions(SurfaceComposerClient::Transaction* t, + uint64_t frameNumber) { + auto mergeTransaction = + [&t, currentFrameNumber = frameNumber]( + std::tuple<uint64_t, SurfaceComposerClient::Transaction> pendingTransaction) { + auto& [targetFrameNumber, transaction] = pendingTransaction; + if (currentFrameNumber < targetFrameNumber) { + return false; + } + t->merge(std::move(transaction)); + return true; + }; + + mPendingTransactions.erase(std::remove_if(mPendingTransactions.begin(), + mPendingTransactions.end(), mergeTransaction), + mPendingTransactions.end()); +} + +SurfaceComposerClient::Transaction* BLASTBufferQueue::gatherPendingTransactions( + uint64_t frameNumber) { + std::lock_guard _lock{mMutex}; + SurfaceComposerClient::Transaction* t = new SurfaceComposerClient::Transaction(); + mergePendingTransactions(t, frameNumber); + return t; +} + // Maintains a single worker thread per process that services a list of runnables. class AsyncWorker : public Singleton<AsyncWorker> { private: @@ -999,4 +1075,59 @@ 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 */); + // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction + t.setApplyToken(mApplyToken).apply(false, true); + } + + // 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 = nullptr; + mConsumer = nullptr; + mProducer = nullptr; +} + +bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const { + std::unique_lock _lock{mMutex}; + return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl); +} + +void BLASTBufferQueue::setTransactionHangCallback(std::function<void(bool)> callback) { + std::unique_lock _lock{mMutex}; + mTransactionHangCallback = callback; +} + } // namespace android |