summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ady Abraham <adyabr@google.com> 2021-06-15 16:56:21 -0700
committer Ady Abraham <adyabr@google.com> 2021-06-17 16:43:54 -0700
commit899dcdb63ad9cb81d1987e89be08dc9603aad89b (patch)
treece6ea8bb20845f18d901fab94e2ba9027d2757db
parent0bde6b5a9837ab96484c988bb3f148d0b9b3ab4e (diff)
SF: change acquired buffers based on the current refresh rate
BLASTBufferQueue set the max acquired buffers based on SF vsync configuration (sf.duration and app.duration). This is calculated based on the max supported refresh rate on the device, and it turn is propogated to apps via min_undequeued_buffers to the app could allocate enough buffers for maintaining the pipeline SF expects. This leads to a higher latency when the device is running in a lower refresh rate as there are more buffers on the buffer queue then required. In this change we are holding on the these "extra buffers" and not releasing them back to the buffer queue so the app would use the number of buffers it needs based on the current refresh rate, and to avoid having unnecessary long latency. Bug: 188553729 Test: Run backpressure based game on 60Hz and 120Hz and collect systraces Change-Id: I9d4e6278f0ddd28008ac437ab0576aa79d05166a
-rw-r--r--libs/gui/BLASTBufferQueue.cpp52
-rw-r--r--libs/gui/ISurfaceComposer.cpp17
-rw-r--r--libs/gui/ITransactionCompletedListener.cpp10
-rw-r--r--libs/gui/SurfaceComposerClient.cpp11
-rw-r--r--libs/gui/include/gui/BLASTBufferQueue.h11
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h21
-rw-r--r--libs/gui/include/gui/ITransactionCompletedListener.h10
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h4
-rw-r--r--libs/gui/tests/Surface_test.cpp2
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp21
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp8
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp37
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h10
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.cpp5
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.h1
-rw-r--r--services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp5
-rw-r--r--services/surfaceflinger/tests/unittests/SchedulerTest.cpp12
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h6
18 files changed, 155 insertions, 88 deletions
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 8024482531..52d3fa33f0 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -159,9 +159,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
mBufferItemConsumer->setBlastBufferQueue(this);
- int extraBufferCount = 0;
- ComposerService::getComposerService()->getExtraBufferCount(&extraBufferCount);
- mMaxAcquiredBuffers = 1 + extraBufferCount;
+ ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
mTransformHint = mSurfaceControl->getTransformHint();
@@ -308,18 +306,20 @@ 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, uint64_t graphicBufferId,
- const sp<Fence>& releaseFence, uint32_t transformHint) {
+ const sp<Fence>& releaseFence, uint32_t transformHint,
+ uint32_t currentMaxAcquiredBufferCount) {
sp<BLASTBufferQueue> blastBufferQueue = context.promote();
ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s",
graphicBufferId, blastBufferQueue ? "alive" : "dead");
if (blastBufferQueue) {
- blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint);
+ blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint,
+ currentMaxAcquiredBufferCount);
}
}
void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId,
- const sp<Fence>& releaseFence,
- uint32_t transformHint) {
+ const sp<Fence>& releaseFence, uint32_t transformHint,
+ uint32_t currentMaxAcquiredBufferCount) {
ATRACE_CALL();
std::unique_lock _lock{mMutex};
BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId);
@@ -330,15 +330,36 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId,
mBufferItemConsumer->setTransformHint(mTransformHint);
}
- auto it = mSubmitted.find(graphicBufferId);
- if (it == mSubmitted.end()) {
- BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64,
- graphicBufferId);
- return;
+ // 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
+ // clients as others don't care about latency
+ const bool isEGL = [&] {
+ const auto it = mSubmitted.find(graphicBufferId);
+ return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
+ }();
+
+ const auto numPendingBuffersToHold =
+ isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
+ mPendingRelease.emplace_back(ReleasedBuffer{graphicBufferId, releaseFence});
+
+ // Release all buffers that are beyond the ones that we need to hold
+ while (mPendingRelease.size() > numPendingBuffersToHold) {
+ const auto releaseBuffer = mPendingRelease.front();
+ mPendingRelease.pop_front();
+ auto it = mSubmitted.find(releaseBuffer.bufferId);
+ if (it == mSubmitted.end()) {
+ BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64,
+ graphicBufferId);
+ return;
+ }
+
+ mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
+ mSubmitted.erase(it);
}
- mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
- mSubmitted.erase(it);
+ ATRACE_INT("PendingRelease", mPendingRelease.size());
+
mNumAcquired--;
processNextBufferLocked(false /* useNextTransaction */);
mCallbackCV.notify_all();
@@ -420,7 +441,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
- std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
+ std::placeholders::_4);
t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback);
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 71e18a97c9..0d7795e1ba 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1215,16 +1215,17 @@ public:
return reply.readInt32();
}
- status_t getExtraBufferCount(int* extraBuffers) const override {
+ status_t getMaxAcquiredBufferCount(int* buffers) const override {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply);
+ status_t err =
+ remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
if (err != NO_ERROR) {
- ALOGE("getExtraBufferCount failed to read data: %s (%d)", strerror(-err), err);
+ ALOGE("getMaxAcquiredBufferCount failed to read data: %s (%d)", strerror(-err), err);
return err;
}
- return reply.readInt32(extraBuffers);
+ return reply.readInt32(buffers);
}
};
@@ -2069,14 +2070,14 @@ status_t BnSurfaceComposer::onTransact(
SAFE_PARCEL(reply->writeInt32, priority);
return NO_ERROR;
}
- case GET_EXTRA_BUFFER_COUNT: {
+ case GET_MAX_ACQUIRED_BUFFER_COUNT: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int extraBuffers = 0;
- int err = getExtraBufferCount(&extraBuffers);
+ int buffers = 0;
+ int err = getMaxAcquiredBufferCount(&buffers);
if (err != NO_ERROR) {
return err;
}
- SAFE_PARCEL(reply->writeInt32, extraBuffers);
+ SAFE_PARCEL(reply->writeInt32, buffers);
return NO_ERROR;
}
case OVERRIDE_HDR_TYPES: {
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 63d07ba1fb..17499ecd50 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -119,6 +119,7 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const {
SAFE_PARCEL(output->writeBool, false);
}
SAFE_PARCEL(output->writeUint32, transformHint);
+ SAFE_PARCEL(output->writeUint32, currentMaxAcquiredBufferCount);
SAFE_PARCEL(output->writeParcelable, eventStats);
SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
for (const auto& data : jankData) {
@@ -138,6 +139,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) {
SAFE_PARCEL(input->read, *previousReleaseFence);
}
SAFE_PARCEL(input->readUint32, &transformHint);
+ SAFE_PARCEL(input->readUint32, &currentMaxAcquiredBufferCount);
SAFE_PARCEL(input->readParcelable, &eventStats);
int32_t jankData_size = 0;
@@ -251,11 +253,13 @@ public:
stats);
}
- void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
- uint32_t transformHint) override {
+ void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence, uint32_t transformHint,
+ uint32_t currentMaxAcquiredBufferCount) override {
callRemoteAsync<decltype(
&ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
- graphicBufferId, releaseFence, transformHint);
+ graphicBufferId, releaseFence,
+ transformHint,
+ currentMaxAcquiredBufferCount);
}
};
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 660c5bd97d..c69435d328 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -328,7 +328,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
surfaceStats.previousReleaseFence
? surfaceStats.previousReleaseFence
: Fence::NO_FENCE,
- surfaceStats.transformHint);
+ surfaceStats.transformHint,
+ surfaceStats.currentMaxAcquiredBufferCount);
}
}
}
@@ -364,9 +365,9 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener
}
}
-void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId,
- sp<Fence> releaseFence,
- uint32_t transformHint) {
+void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
+ uint32_t transformHint,
+ uint32_t currentMaxAcquiredBufferCount) {
ReleaseBufferCallback callback;
{
std::scoped_lock<std::mutex> lock(mMutex);
@@ -376,7 +377,7 @@ void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId,
ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId);
return;
}
- callback(graphicBufferId, releaseFence, transformHint);
+ callback(graphicBufferId, releaseFence, transformHint, currentMaxAcquiredBufferCount);
}
ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index d63425e41b..0981e760a5 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -90,7 +90,7 @@ public:
void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence,
- uint32_t transformHint);
+ uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void setTransactionCompleteCallback(uint64_t frameNumber,
@@ -141,6 +141,15 @@ private:
// buffer or the buffer has been presented and a new buffer is ready to be presented.
std::unordered_map<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex);
+ // Keep a queue of the released buffers instead of immediately releasing
+ // the buffers back to the buffer queue. This would be controlled by SF
+ // setting the max acquired buffer count.
+ struct ReleasedBuffer {
+ uint64_t bufferId;
+ sp<Fence> releaseFence;
+ };
+ std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
+
ui::Size mSize GUARDED_BY(mMutex);
ui::Size mRequestedSize GUARDED_BY(mMutex);
int32_t mFormat GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 439d90ad10..2a3f6a43d9 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -537,22 +537,21 @@ public:
virtual int getGPUContextPriority() = 0;
/**
- * Gets the extra buffers a client would need to allocate if it passes
- * the Choreographer#getVsyncId with its buffers.
- *
- * When Choreographer#getVsyncId is passed to SurfaceFlinger, it is used
- * as an indication of when to latch the buffer. SurfaceFlinger will make
- * sure that it will give the app at least the time configured as the
- * 'appDuration' before trying to latch the buffer.
+ * Gets the number of buffers SurfaceFlinger would need acquire. This number
+ * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the
+ * client could allocate enough buffers to match SF expectations of the
+ * pipeline depth. SurfaceFlinger will make sure that it will give the app at
+ * least the time configured as the 'appDuration' before trying to latch
+ * the buffer.
*
* The total buffers needed for a given configuration is basically the
* numbers of vsyncs a single buffer is used across the stack. For the default
* configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger
* and 1 vsync by the display. The extra buffers are calculated as the
- * number of additional buffers on top of the 3 buffers already allocated
- * by the app.
+ * number of additional buffers on top of the 2 buffers already present
+ * in MIN_UNDEQUEUED_BUFFERS.
*/
- virtual status_t getExtraBufferCount(int* extraBuffers) const = 0;
+ virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0;
};
// ----------------------------------------------------------------------------
@@ -615,7 +614,7 @@ public:
SET_FRAME_TIMELINE_INFO,
ADD_TRANSACTION_TRACE_LISTENER,
GET_GPU_CONTEXT_PRIORITY,
- GET_EXTRA_BUFFER_COUNT,
+ GET_MAX_ACQUIRED_BUFFER_COUNT,
GET_DYNAMIC_DISPLAY_INFO,
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 3bfeef1922..d286c34ec8 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -101,12 +101,14 @@ public:
SurfaceStats() = default;
SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
- uint32_t hint, FrameEventHistoryStats frameEventStats,
- std::vector<JankData> jankData, uint64_t previousBufferId)
+ uint32_t hint, uint32_t currentMaxAcquiredBuffersCount,
+ FrameEventHistoryStats frameEventStats, std::vector<JankData> jankData,
+ uint64_t previousBufferId)
: surfaceControl(sc),
acquireTime(time),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
+ currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount),
eventStats(frameEventStats),
jankData(std::move(jankData)),
previousBufferId(previousBufferId) {}
@@ -115,6 +117,7 @@ public:
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ uint32_t currentMaxAcquiredBufferCount = 0;
FrameEventHistoryStats eventStats;
std::vector<JankData> jankData;
uint64_t previousBufferId;
@@ -159,7 +162,8 @@ public:
virtual void onTransactionCompleted(ListenerStats stats) = 0;
virtual void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence,
- uint32_t transformHint) = 0;
+ uint32_t transformHint,
+ uint32_t currentMaxAcquiredBufferCount) = 0;
};
class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 5aa132cd92..fa91bfa010 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -83,7 +83,7 @@ using TransactionCompletedCallback =
const std::vector<SurfaceControlStats>& /*stats*/)>;
using ReleaseBufferCallback =
std::function<void(uint64_t /* graphicsBufferId */, const sp<Fence>& /*releaseFence*/,
- uint32_t transformHint)>;
+ uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>;
using SurfaceStatsCallback =
std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
@@ -729,7 +729,7 @@ public:
// BnTransactionCompletedListener overrides
void onTransactionCompleted(ListenerStats stats) override;
void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp<Fence> releaseFence,
- uint32_t transformHint) override;
+ uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override;
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index b8d34c3160..59b0c04bc3 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -902,7 +902,7 @@ public:
int getGPUContextPriority() override { return 0; };
- status_t getExtraBufferCount(int* /*extraBuffers*/) const override { return NO_ERROR; }
+ status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index d68a0e0b47..955c2f88b0 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -44,12 +44,12 @@ using PresentState = frametimeline::SurfaceFrame::PresentState;
namespace {
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence,
- uint32_t transformHint) {
+ uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) {
if (!listener) {
return;
}
listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE,
- transformHint);
+ transformHint, currentMaxAcquiredBufferCount);
}
} // namespace
@@ -75,7 +75,9 @@ BufferStateLayer::~BufferStateLayer() {
if (mBufferInfo.mBuffer != nullptr && !isClone()) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence,
- mTransformHint);
+ mTransformHint,
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+ mOwnerUid));
}
}
@@ -199,6 +201,8 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
handle->dequeueReadyTime = dequeueReadyTime;
+ handle->currentMaxAcquiredBufferCount =
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
}
// If there are multiple transactions in this frame, set the previous id on the earliest
@@ -429,9 +433,10 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex
// dropped and we should decrement the pending buffer count and
// call any release buffer callbacks if set.
callReleaseBufferCallback(mCurrentState.releaseBufferListener,
- mCurrentState.buffer->getBuffer(),
- mCurrentState.acquireFence,
- mTransformHint);
+ mCurrentState.buffer->getBuffer(), mCurrentState.acquireFence,
+ mTransformHint,
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+ mOwnerUid));
decrementPendingBufferCount();
if (mCurrentState.bufferSurfaceFrameTX != nullptr) {
addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX);
@@ -951,7 +956,9 @@ void BufferStateLayer::bufferMayChange(const sp<GraphicBuffer>& newBuffer) {
// call any release buffer callbacks if set.
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence,
- mTransformHint);
+ mTransformHint,
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+ mOwnerUid));
decrementPendingBufferCount();
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4b8cbfb621..e0b364020b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -205,6 +205,10 @@ std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
}
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
+ if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ return std::nullopt;
+ }
+
std::lock_guard lock(mFrameRateOverridesMutex);
{
const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
@@ -224,10 +228,6 @@ std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
}
bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
- return true;
- }
-
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return true;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c1d28b1746..a39ae5819d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5247,7 +5247,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
case CAPTURE_DISPLAY:
case SET_FRAME_TIMELINE_INFO:
case GET_GPU_CONTEXT_PRIORITY:
- case GET_EXTRA_BUFFER_COUNT: {
+ case GET_MAX_ACQUIRED_BUFFER_COUNT: {
// This is not sensitive information, so should not require permission control.
return OK;
}
@@ -6800,25 +6800,38 @@ int SurfaceFlinger::getGPUContextPriority() {
return getRenderEngine().getContextPriority();
}
-int SurfaceFlinger::calculateExtraBufferCount(Fps maxSupportedRefreshRate,
- std::chrono::nanoseconds presentLatency) {
- auto pipelineDepth = presentLatency.count() / maxSupportedRefreshRate.getPeriodNsecs();
- if (presentLatency.count() % maxSupportedRefreshRate.getPeriodNsecs()) {
+int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
+ std::chrono::nanoseconds presentLatency) {
+ auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
+ if (presentLatency.count() % refreshRate.getPeriodNsecs()) {
pipelineDepth++;
}
- return std::max(0ll, pipelineDepth - 2);
+ return std::max(1ll, pipelineDepth - 1);
}
-status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const {
+status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max;
- const auto vsyncConfig =
- mVsyncConfiguration->getConfigsForRefreshRate(maxSupportedRefreshRate).late;
- const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
-
- *extraBuffers = calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+ *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate);
return NO_ERROR;
}
+int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
+ const auto refreshRate = [&] {
+ const auto frameRateOverride = mScheduler->getFrameRateOverride(uid);
+ if (frameRateOverride.has_value()) {
+ return frameRateOverride.value();
+ }
+ return mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+ }();
+ return getMaxAcquiredBufferCountForRefreshRate(refreshRate);
+}
+
+int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const {
+ const auto vsyncConfig = mVsyncConfiguration->getConfigsForRefreshRate(refreshRate).late;
+ const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
+ return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
+}
+
void SurfaceFlinger::TransactionState::traverseStatesWithBuffers(
std::function<void(const layer_state_t&)> visitor) {
for (const auto& state : states) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a3fa8d654f..22d17eb153 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -708,7 +708,7 @@ private:
int getGPUContextPriority() override;
- status_t getExtraBufferCount(int* extraBuffers) const override;
+ status_t getMaxAcquiredBufferCount(int* buffers) const override;
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -923,6 +923,8 @@ private:
size_t getMaxTextureSize() const;
size_t getMaxViewportDims() const;
+ int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
+
/*
* Display and layer stack management
*/
@@ -1062,6 +1064,7 @@ private:
// Calculates the expected present time for this frame. For negative offsets, performs a
// correction using the predicted vsync for the next frame instead.
+
nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const;
/*
@@ -1177,8 +1180,9 @@ private:
std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
REQUIRES(mStateLock);
- static int calculateExtraBufferCount(Fps maxSupportedRefreshRate,
- std::chrono::nanoseconds presentLatency);
+ static int calculateMaxAcquiredBufferCount(Fps refreshRate,
+ std::chrono::nanoseconds presentLatency);
+ int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
sp<StartPropertySetThread> mStartPropertySetThread;
surfaceflinger::Factory& mFactory;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 4f4c02be6c..fdf16a797f 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -235,8 +235,9 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>&
handle->dequeueReadyTime);
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
handle->previousReleaseFence,
- handle->transformHint, eventStats, jankData,
- handle->previousBufferId);
+ handle->transformHint,
+ handle->currentMaxAcquiredBufferCount,
+ eventStats, jankData, handle->previousBufferId);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 184b15103e..444bec646e 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -45,6 +45,7 @@ public:
nsecs_t acquireTime = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
+ uint32_t currentMaxAcquiredBufferCount = 0;
std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
CompositorTiming compositorTiming;
nsecs_t refreshStartTime = 0;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index fb7d41c81e..5aa809dc8b 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -30,7 +30,8 @@ using android::hardware::graphics::common::V1_1::BufferUsage;
class ReleaseBufferCallbackHelper {
public:
static void function(void* callbackContext, uint64_t graphicsBufferId,
- const sp<Fence>& releaseFence) {
+ const sp<Fence>& releaseFence,
+ uint32_t /*currentMaxAcquiredBufferCount*/) {
if (!callbackContext) {
FAIL() << "failed to get callback context";
}
@@ -66,7 +67,7 @@ public:
android::ReleaseBufferCallback getCallback() {
return std::bind(function, static_cast<void*>(this) /* callbackContext */,
- std::placeholders::_1, std::placeholders::_2);
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}
std::mutex mMutex;
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 423d0ccbff..f680d802e6 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -210,14 +210,14 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
}
-TEST_F(SchedulerTest, calculateExtraBufferCount) {
- EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 30ms));
- EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(90), 30ms));
- EXPECT_EQ(2, mFlinger.calculateExtraBufferCount(Fps(120), 30ms));
+TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
+ EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 30ms));
+ EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(90), 30ms));
+ EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(Fps(120), 30ms));
- EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(60), 40ms));
+ EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 40ms));
- EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms));
+ EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 10ms));
}
MATCHER(Is120Hz, "") {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d78f36cd27..b363146e10 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -391,9 +391,9 @@ public:
auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
- auto calculateExtraBufferCount(Fps maxSupportedRefreshRate,
- std::chrono::nanoseconds presentLatency) const {
- return SurfaceFlinger::calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+ auto calculateMaxAcquiredBufferCount(Fps refreshRate,
+ std::chrono::nanoseconds presentLatency) const {
+ return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
/* ------------------------------------------------------------------------