BufferQueueProducer: queueBuffer() CPU throttling only in async mode
BufferQueueProducer throttles an EGL client in queueBuffer() until
the GPU has finished the previous frame. This behavior was intended
to solve some issues with "swap interval 0" (aka async mode) but
was performed all the time.
In turn, is prevented a "well behaved" applications from throttling
itself, because it would be throttled by BufferQueueProduced
before it could get a chance to do so. From the app perspective,
eglSwapBuffers() would block.
Here we perform the throttling only in async mode, as was the
original intention. Applications that don't pace themselves,
will still be blocked in dequeueBuffer() eventually, albeit,
not necessarily in eglSwapBuffers().
Fix: 359252619
Test: manually tested on pixel8 using AGI and filament sample app
Flag: com.android.graphics.libgui.flags.bq_producer_throttles_only_async_mode
Change-Id: Ie73848fbf609061bb6feceba5b5c5ad86ec8e07c
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index a4d105d..da74e9c 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -45,7 +45,10 @@
#include <system/window.h>
+#include <com_android_graphics_libgui_flags.h>
+
namespace android {
+using namespace com::android::graphics::libgui;
// Macros for include BufferQueueCore information in log messages
#define BQ_LOGV(x, ...) \
@@ -924,6 +927,7 @@
uint64_t currentFrameNumber = 0;
BufferItem item;
int connectedApi;
+ bool enableEglCpuThrottling = true;
sp<Fence> lastQueuedFence;
{ // Autolock scope
@@ -1097,6 +1101,9 @@
VALIDATE_CONSISTENCY();
connectedApi = mCore->mConnectedApi;
+ if (flags::bq_producer_throttles_only_async_mode()) {
+ enableEglCpuThrottling = mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock;
+ }
lastQueuedFence = std::move(mLastQueueBufferFence);
mLastQueueBufferFence = std::move(acquireFence);
@@ -1142,7 +1149,7 @@
}
// Wait without lock held
- if (connectedApi == NATIVE_WINDOW_API_EGL) {
+ if (connectedApi == NATIVE_WINDOW_API_EGL && enableEglCpuThrottling) {
// Waiting here allows for two full buffers to be queued but not a
// third. In the event that frames take varying time, this makes a
// small trade-off in favor of latency rather than throughput.