blast: send back previous release fences
When sending a transaction callback, send a previous release fence
instead of a boolean.
Test: Transaction_test
Bug: 80477568, 120930690
Change-Id: I608fecc3cd31fd92fcfc2abb5fc084c529ee7806
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 1be55e6..ce88d7b 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -39,7 +39,16 @@
if (err != NO_ERROR) {
return err;
}
- return output->writeBool(releasePreviousBuffer);
+ if (previousReleaseFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->write(*previousReleaseFence);
+ } else {
+ err = output->writeBool(false);
+ }
+ return err;
}
status_t SurfaceStats::readFromParcel(const Parcel* input) {
@@ -51,7 +60,19 @@
if (err != NO_ERROR) {
return err;
}
- return input->readBool(&releasePreviousBuffer);
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (hasFence) {
+ previousReleaseFence = new Fence();
+ err = input->read(*previousReleaseFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ return NO_ERROR;
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 8acfa7a..29ab026 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -52,12 +52,12 @@
status_t readFromParcel(const Parcel* input) override;
SurfaceStats() = default;
- SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
- : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
+ : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
- bool releasePreviousBuffer = false;
+ sp<Fence> previousReleaseFence;
};
class TransactionStats : public Parcelable {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e0d9d23..2132f59 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,10 +48,28 @@
// Interface implementation for Layer
// -----------------------------------------------------------------------
void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
- // The transaction completed callback can only be sent if the release fence from the PREVIOUS
- // frame has fired. In practice, we should never actually wait on the previous release fence
- // but we should store it just in case.
- mPreviousReleaseFence = releaseFence;
+ // The previous release fence notifies the client that SurfaceFlinger is done with the previous
+ // buffer that was presented on this layer. The first transaction that came in this frame that
+ // replaced the previous buffer on this layer needs this release fence, because the fence will
+ // let the client know when that previous buffer is removed from the screen.
+ //
+ // Every other transaction on this layer does not need a release fence because no other
+ // Transactions that were set on this layer this frame are going to have their preceeding buffer
+ // removed from the display this frame.
+ //
+ // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
+ // buffer so it doesn't need a previous release fence because the layer still needs the previous
+ // buffer. The second transaction contains a buffer so it needs a previous release fence because
+ // the previous buffer will be released this frame. The third transaction also contains a
+ // buffer. It replaces the buffer in the second transaction. The buffer in the second
+ // transaction will now no longer be presented so it is released immediately and the third
+ // transaction doesn't need a previous release fence.
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer) {
+ handle->previousReleaseFence = releaseFence;
+ break;
+ }
+ }
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -60,7 +78,10 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- return;
+ mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles(
+ mDrawingState.callbackHandles);
+
+ mDrawingState.callbackHandles = {};
}
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -257,14 +278,14 @@
// Notify the transaction completed thread that there is a pending latched callback
// handle
- mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(handle);
// Store so latched time and release fence can be set
mCurrentState.callbackHandles.push_back(handle);
} else { // If this layer will NOT need to be relatched and presented this frame
// Notify the transaction completed thread this handle is done
- mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle);
}
}
@@ -504,9 +525,9 @@
return BAD_VALUE;
}
- mFlinger->getTransactionCompletedThread()
- .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
- mPreviousReleaseFence);
+ for (auto& handle : mDrawingState.callbackHandles) {
+ handle->latchTime = latchTime;
+ }
// Handle sync fences
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index a1a8692..d2b7fe0 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -62,8 +62,7 @@
mThread = std::thread(&TransactionCompletedThread::threadMain, this);
}
-void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
- const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::registerPendingCallbackHandle(const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
sp<IBinder> listener = IInterface::asBinder(handle->listener);
@@ -72,19 +71,10 @@
mPendingTransactions[listener][callbackIds]++;
}
-void TransactionCompletedThread::addLatchedCallbackHandles(
- const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
- const sp<Fence>& previousReleaseFence) {
+void TransactionCompletedThread::addPresentedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles) {
std::lock_guard lock(mMutex);
- // If the previous release fences have not signaled, something as probably gone wrong.
- // Store the fences and check them again before sending a callback.
- if (previousReleaseFence &&
- previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
- ALOGD("release fence from the previous frame has not signaled");
- mPreviousReleaseFences.push_back(previousReleaseFence);
- }
-
for (const auto& handle : handles) {
auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
auto& pendingCallbacks = listener->second;
@@ -101,17 +91,16 @@
ALOGE("there are more latched callbacks than there were registered callbacks");
}
- addCallbackHandle(handle, latchTime);
+ addCallbackHandle(handle);
}
}
-void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
addCallbackHandle(handle);
}
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
- nsecs_t latchTime) {
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
const sp<IBinder> listener = IInterface::asBinder(handle->listener);
// If we don't already have a reference to this listener, linkToDeath so we get a notification
@@ -128,9 +117,9 @@
listenerStats.listener = handle->listener;
auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
- transactionStats.latchTime = latchTime;
+ transactionStats.latchTime = handle->latchTime;
transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
- handle->releasePreviousBuffer);
+ handle->previousReleaseFence);
}
void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
@@ -151,15 +140,6 @@
while (mKeepRunning) {
mConditionVariable.wait(mMutex);
- // We should never hit this case. The release fences from the previous frame should have
- // signaled long before the current frame is presented.
- for (const auto& fence : mPreviousReleaseFences) {
- status_t status = fence->wait(100);
- if (status != NO_ERROR) {
- ALOGE("previous release fence has not signaled, err %d", status);
- }
- }
-
// For each listener
auto it = mListenerStats.begin();
while (it != mListenerStats.end()) {
@@ -200,7 +180,6 @@
if (mPresentFence) {
mPresentFence.clear();
- mPreviousReleaseFences.clear();
}
}
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 1612f69..f49306d 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -40,7 +40,9 @@
sp<IBinder> surfaceControl;
bool releasePreviousBuffer = false;
+ sp<Fence> previousReleaseFence;
nsecs_t acquireTime = -1;
+ nsecs_t latchTime = -1;
};
class TransactionCompletedThread {
@@ -54,14 +56,13 @@
// layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
// a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
// presented.
- void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
- // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
- void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
- const sp<Fence>& previousReleaseFence);
+ void registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
+ // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
+ void addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
- void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+ void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
void addPresentFence(const sp<Fence>& presentFence);
@@ -70,8 +71,7 @@
private:
void threadMain();
- void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
- REQUIRES(mMutex);
+ void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
class ThreadDeathRecipient : public IBinder::DeathRecipient {
public:
@@ -110,7 +110,6 @@
bool mKeepRunning GUARDED_BY(mMutex) = true;
sp<Fence> mPresentFence GUARDED_BY(mMutex);
- std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
};
} // namespace android
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ef6999d..9339761 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2542,6 +2542,7 @@
enum PreviousBuffer {
NOT_RELEASED = 0,
RELEASED,
+ UNKNOWN,
};
void reset() {
@@ -2596,14 +2597,19 @@
: mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+ const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";
ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
- ASSERT_EQ(releasePreviousBuffer,
- mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
- << "bad previous buffer released";
+
+ if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+ ASSERT_NE(previousReleaseFence, nullptr)
+ << "failed to set release prev buffer fence";
+ } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+ ASSERT_EQ(previousReleaseFence, nullptr)
+ << "should not have set released prev buffer fence";
+ }
}
private:
@@ -3177,13 +3183,11 @@
Transaction transaction;
CallbackHelper callback;
std::vector<ExpectedResult> expectedResults(50);
- ExpectedResult::PreviousBuffer previousBufferResult =
- ExpectedResult::PreviousBuffer::NOT_RELEASED;
for (auto& expected : expectedResults) {
expected.reset();
expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED, previousBufferResult);
- previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::UNKNOWN);
int err = fillTransaction(transaction, &callback, layer);
if (err) {