summaryrefslogtreecommitdiff
path: root/libs/gui/BLASTBufferQueue.cpp
diff options
context:
space:
mode:
author Rob Carr <racarr@google.com> 2021-11-03 21:51:50 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-11-03 21:51:50 +0000
commitfe34457d2e4644d47d1d8047894c7819d5cd34a5 (patch)
tree5f2c720cc5cc32a3bc15862e00ae7006f33d1e4f /libs/gui/BLASTBufferQueue.cpp
parentebff6bd2a8c563376365cd362496fa61e6263096 (diff)
parent2d2150edc25cdd03bdb5b25ec1a4cc5fb7aa0f33 (diff)
Merge "DO NOT MERGE: Move blast sync handling to BBQ" into sc-v2-dev
Diffstat (limited to 'libs/gui/BLASTBufferQueue.cpp')
-rw-r--r--libs/gui/BLASTBufferQueue.cpp160
1 files changed, 135 insertions, 25 deletions
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index e8e664bd76..94864e53f3 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -46,6 +46,8 @@ inline const char* boolToString(bool b) {
namespace android {
// Macros to include adapter info in log messages
+#define BQA_LOGD(x, ...) \
+ ALOGD("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
#define BQA_LOGV(x, ...) \
ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
// enable logs for a single layer
@@ -243,6 +245,67 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
}
}
+static std::optional<SurfaceControlStats> findMatchingStat(
+ const std::vector<SurfaceControlStats>& stats, const sp<SurfaceControl>& sc) {
+ for (auto stat : stats) {
+ if (SurfaceControl::isSameSurface(sc, stat.surfaceControl)) {
+ return stat;
+ }
+ }
+ return std::nullopt;
+}
+
+static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime,
+ const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ if (context == nullptr) {
+ return;
+ }
+ sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
+ bq->transactionCommittedCallback(latchTime, presentFence, stats);
+}
+
+void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/,
+ const sp<Fence>& /*presentFence*/,
+ const std::vector<SurfaceControlStats>& stats) {
+ {
+ std::unique_lock _lock{mMutex};
+ ATRACE_CALL();
+ BQA_LOGV("transactionCommittedCallback");
+ if (!mSurfaceControlsWithPendingCallback.empty()) {
+ sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
+ std::optional<SurfaceControlStats> stat = findMatchingStat(stats, pendingSC);
+ if (stat) {
+ uint64_t currFrameNumber = stat->frameEventStats.frameNumber;
+
+ // We need to check if we were waiting for a transaction callback in order to
+ // process any pending buffers and unblock. It's possible to get transaction
+ // callbacks for previous requests so we need to ensure the frame from this
+ // transaction callback matches the last acquired buffer. Since acquireNextBuffer
+ // will stop processing buffers when mWaitForTransactionCallback is set, we know
+ // that mLastAcquiredFrameNumber is the frame we're waiting on.
+ // We also want to check if mNextTransaction is null because it's possible another
+ // sync request came in while waiting, but it hasn't started processing yet. In that
+ // 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 &&
+ currFrameNumber >= mLastAcquiredFrameNumber) {
+ mWaitForTransactionCallback = false;
+ flushShadowQueueLocked();
+ }
+ } else {
+ BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
+ }
+ } else {
+ BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
+ "empty.");
+ }
+
+ decStrong((void*)transactionCommittedCallbackThunk);
+ }
+}
+
static void transactionCallbackThunk(void* context, nsecs_t latchTime,
const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats) {
@@ -266,12 +329,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
if (!mSurfaceControlsWithPendingCallback.empty()) {
sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
mSurfaceControlsWithPendingCallback.pop();
- bool found = false;
- for (auto stat : stats) {
- if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) {
- continue;
- }
-
+ std::optional<SurfaceControlStats> statsOptional = findMatchingStat(stats, pendingSC);
+ if (statsOptional) {
+ SurfaceControlStats stat = *statsOptional;
mTransformHint = stat.transformHint;
mBufferItemConsumer->setTransformHint(mTransformHint);
BQA_LOGV("updated mTransformHint=%d", mTransformHint);
@@ -299,12 +359,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
transactionCompleteCallback = std::move(mTransactionCompleteCallback);
mTransactionCompleteFrameNumber = 0;
}
-
- found = true;
- break;
- }
-
- if (!found) {
+ } else {
BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
}
} else {
@@ -336,6 +391,20 @@ static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const Relea
}
}
+void BLASTBufferQueue::flushShadowQueueLocked() {
+ BQA_LOGV("flushShadowQueueLocked");
+ int numFramesToFlush = mNumFrameAvailable;
+ while (numFramesToFlush > 0) {
+ acquireNextBufferLocked(std::nullopt);
+ numFramesToFlush--;
+ }
+}
+
+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) {
@@ -377,7 +446,11 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
BQA_LOGV("released %s", id.to_string().c_str());
mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
mSubmitted.erase(it);
- processNextBufferLocked(false /* useNextTransaction */);
+ // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
+ // onFrameAvailable handle processing them since it will merge with the nextTransaction.
+ if (!mWaitForTransactionCallback) {
+ acquireNextBufferLocked(std::nullopt);
+ }
}
ATRACE_INT("PendingRelease", mPendingRelease.size());
@@ -386,13 +459,15 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
mCallbackCV.notify_all();
}
-void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
+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 = !useNextTransaction;
- if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
- mCallbackCV.notify_all();
+ const bool includeExtraAcquire = !transaction;
+ const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire);
+ if (mNumFrameAvailable == 0 || maxAcquired) {
+ BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired));
return;
}
@@ -404,9 +479,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
- if (mNextTransaction != nullptr && useNextTransaction) {
- t = mNextTransaction;
- mNextTransaction = nullptr;
+ if (transaction) {
+ t = *transaction;
applyTransaction = false;
}
@@ -436,7 +510,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
- processNextBufferLocked(useNextTransaction);
+ acquireNextBufferLocked(transaction);
return;
}
@@ -455,6 +529,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
+ incStrong((void*)transactionCommittedCallbackThunk);
const bool sizeHasChanged = mRequestedSize != mSize;
mSize = mRequestedSize;
@@ -475,6 +550,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
t->setAcquireFence(mSurfaceControl,
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
+ t->addTransactionCommittedCallback(transactionCommittedCallbackThunk, static_cast<void*>(this));
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
if (updateDestinationFrame) {
@@ -527,7 +603,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
t->setApplyToken(mApplyToken).apply();
}
- BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
+ BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
" graphicBufferId=%" PRIu64 "%s transform=%d",
mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
@@ -543,17 +619,44 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
return item.mCrop;
}
+void BLASTBufferQueue::acquireAndReleaseBuffer() {
+ BufferItem bufferItem;
+ mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
+ mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+ mNumFrameAvailable--;
+}
+
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) {
- while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
- BQA_LOGV("waiting in onFrameAvailable...");
+ 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();
+ }
+ }
+
+ while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+ BQA_LOGD("waiting for free buffer.");
mCallbackCV.wait(_lock);
}
}
+
// add to shadow queue
mNumFrameAvailable++;
ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -561,7 +664,14 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber,
boolToString(nextTransactionSet));
- processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
+
+ if (nextTransactionSet) {
+ acquireNextBufferLocked(std::move(mNextTransaction));
+ mNextTransaction = nullptr;
+ mWaitForTransactionCallback = true;
+ } else if (!mWaitForTransactionCallback) {
+ acquireNextBufferLocked(std::nullopt);
+ }
}
void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {