Add back render-ahead support
Currently only supported in the EGL path.
Vulkan support Coming Soon
Bug: 127822449
Test: trace of hwuimacro
Change-Id: Iac2b039e11d964aab5b8ca1bdf2a5430b187e2ea
diff --git a/libs/hwui/HWUIProperties.sysprop b/libs/hwui/HWUIProperties.sysprop
index 42191ca..34aeaae 100644
--- a/libs/hwui/HWUIProperties.sysprop
+++ b/libs/hwui/HWUIProperties.sysprop
@@ -7,3 +7,10 @@
scope: Public
access: Readonly
}
+prop {
+ api_name: "render_ahead"
+ type: Integer
+ prop_name: "ro.hwui.render_ahead"
+ scope: Public
+ access: Readonly
+}
\ No newline at end of file
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 046ffc4..9b1f259 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -67,6 +67,7 @@
bool Properties::isolatedProcess = false;
int Properties::contextPriority = 0;
+int Properties::defaultRenderAhead = 0;
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {
@@ -129,6 +130,13 @@
enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
+ defaultRenderAhead = std::max(0, std::min(2, property_get_int(PROPERTY_RENDERAHEAD,
+ render_ahead().value_or(0))));
+
+ if (defaultRenderAhead && sRenderPipelineType == RenderPipelineType::SkiaVulkan) {
+ ALOGW("hwui.render_ahead of %d ignored because pipeline is skiavk", defaultRenderAhead);
+ }
+
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
}
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 0a7f4e7..3e91c63 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -167,6 +167,8 @@
#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled"
+#define PROPERTY_RENDERAHEAD "debug.hwui.render_ahead"
+
///////////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////////
@@ -251,6 +253,8 @@
ANDROID_API static int contextPriority;
+ static int defaultRenderAhead;
+
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index baa41c1..4808d68 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -111,6 +111,7 @@
rootRenderNode->makeRoot();
mRenderNodes.emplace_back(rootRenderNode);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
+ setRenderAheadDepth(Properties::defaultRenderAhead);
}
CanvasContext::~CanvasContext() {
@@ -159,6 +160,7 @@
if (hasSurface) {
mHaveNewSurface = true;
mSwapHistory.clear();
+ applyRenderAheadSettings();
} else {
mRenderThread.removeFrameCallback(this);
mGenerationID++;
@@ -423,6 +425,12 @@
waitOnFences();
+ if (mRenderAheadDepth) {
+ auto presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
+ (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1));
+ native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+ }
+
bool requireSwap = false;
bool didSwap =
mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
@@ -636,6 +644,28 @@
return width == mLastFrameWidth && height == mLastFrameHeight;
}
+void CanvasContext::applyRenderAheadSettings() {
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ // TODO: Fix SkiaVulkan's assumptions on buffer counts. And SIGBUS crashes.
+ mRenderAheadDepth = 0;
+ return;
+ }
+ if (mNativeSurface) {
+ native_window_set_buffer_count(mNativeSurface.get(), 3 + mRenderAheadDepth);
+ if (!mRenderAheadDepth) {
+ native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO);
+ }
+ }
+}
+
+void CanvasContext::setRenderAheadDepth(int renderAhead) {
+ if (renderAhead < 0 || renderAhead > 2 || renderAhead == mRenderAheadDepth) {
+ return;
+ }
+ mRenderAheadDepth = renderAhead;
+ applyRenderAheadSettings();
+}
+
SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
// can't rely on prior content of window if viewport size changes
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index abca342..4a3119a 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -204,6 +204,8 @@
return mUseForceDark;
}
+ void setRenderAheadDepth(int renderAhead);
+
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -217,6 +219,7 @@
bool isSwapChainStuffed();
bool surfaceRequiresRedraw();
+ void applyRenderAheadSettings();
SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
@@ -235,6 +238,7 @@
// painted onto its surface.
bool mIsDirty = false;
SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default;
+ int mRenderAheadDepth = 0;
struct SwapHistory {
SkRect damage;
nsecs_t vsyncTime;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 16240b4..b58bab1 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -312,6 +312,12 @@
mRenderThread.queue().post([this, enable]() { mContext->setForceDark(enable); });
}
+void RenderProxy::setRenderAheadDepth(int renderAhead) {
+ mRenderThread.queue().post([ context = mContext, renderAhead ] {
+ context->setRenderAheadDepth(renderAhead);
+ });
+}
+
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
SkBitmap* bitmap) {
auto& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a1a5551..a0f08cb 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -123,6 +123,23 @@
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API void setForceDark(bool enable);
+ /**
+ * Sets a render-ahead depth on the backing renderer. This will increase latency by
+ * <swapInterval> * renderAhead and increase memory usage by (3 + renderAhead) * <resolution>.
+ * In return the renderer will be less susceptible to jitter, resulting in a smoother animation.
+ *
+ * Not recommended to use in response to anything touch driven, but for canned animations
+ * where latency is not a concern careful use may be beneficial.
+ *
+ * Note that when increasing this there will be a frame gap of N frames where N is
+ * renderAhead - <current renderAhead>. When decreasing this if there are any pending
+ * frames they will retain their prior renderAhead value, so it will take a few frames
+ * for the decrease to flush through.
+ *
+ * @param renderAhead How far to render ahead, must be in the range [0..2]
+ */
+ ANDROID_API void setRenderAheadDepth(int renderAhead);
+
ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
int bottom, SkBitmap* bitmap);
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index 91022cf..74a039b 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -38,6 +38,7 @@
int count = 0;
int reportFrametimeWeight = 0;
bool renderOffscreen = true;
+ int renderAhead = 0;
};
template <class T>
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index b45dbc8..aa579ad 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -154,6 +154,11 @@
proxy->resetProfileInfo();
proxy->fence();
+ if (opts.renderAhead) {
+ usleep(33000);
+ }
+ proxy->setRenderAheadDepth(opts.renderAhead);
+
ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
nsecs_t start = systemTime(CLOCK_MONOTONIC);
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 174a140..88d33c3 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -69,6 +69,7 @@
are offscreen rendered
--benchmark_format Set output format. Possible values are tabular, json, csv
--renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
+ --render-ahead=NUM Sets how far to render-ahead. Must be 0 (default), 1, or 2.
)");
}
@@ -170,6 +171,7 @@
Onscreen,
Offscreen,
Renderer,
+ RenderAhead,
};
}
@@ -185,6 +187,7 @@
{"onscreen", no_argument, nullptr, LongOpts::Onscreen},
{"offscreen", no_argument, nullptr, LongOpts::Offscreen},
{"renderer", required_argument, nullptr, LongOpts::Renderer},
+ {"render-ahead", required_argument, nullptr, LongOpts::RenderAhead},
{0, 0, 0, 0}};
static const char* SHORT_OPTIONS = "c:r:h";
@@ -283,6 +286,16 @@
gOpts.renderOffscreen = true;
break;
+ case LongOpts::RenderAhead:
+ if (!optarg) {
+ error = true;
+ }
+ gOpts.renderAhead = atoi(optarg);
+ if (gOpts.renderAhead < 0 || gOpts.renderAhead > 2) {
+ error = true;
+ }
+ break;
+
case 'h':
printHelp();
exit(EXIT_SUCCESS);