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/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);