From cab4afeb64bbc6280990b34bd55270b19218ac04 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 9 May 2023 11:25:22 -0700 Subject: [PATCH] hwui: send TextureView hint to SF So that SF could use this hint when choosing the refresh rate. SF would only try to heuristically calculate the frame rate of a layer when TextureView is updating. This fixes a bug where SF tries to heuristically calculate the frame rate for UI animations but fails due to long frames. Bug: 280249265 Test: Playing a video on Facebook and observe refresh rate Test: go/cb-pcmark Change-Id: I0d54d62b97ff48583fbe3cc0da188fe85810fd5e --- core/java/android/view/TextureView.java | 4 ++++ graphics/java/android/graphics/RenderNode.java | 13 +++++++++++++ libs/hwui/RenderNode.cpp | 3 +++ libs/hwui/RenderNode.h | 4 ++++ libs/hwui/TreeInfo.h | 4 ++++ libs/hwui/jni/android_graphics_RenderNode.cpp | 6 ++++++ libs/hwui/renderthread/CanvasContext.cpp | 7 ++++--- libs/hwui/renderthread/CanvasContext.h | 2 +- libs/hwui/renderthread/DrawFrameTask.cpp | 5 ++++- 9 files changed, 43 insertions(+), 5 deletions(-) diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 15e0cce9af10e..bdd0a9cf653a4 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -206,6 +206,7 @@ public class TextureView extends View { */ public TextureView(@NonNull Context context) { super(context); + mRenderNode.setIsTextureView(); } /** @@ -216,6 +217,7 @@ public class TextureView extends View { */ public TextureView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); + mRenderNode.setIsTextureView(); } /** @@ -229,6 +231,7 @@ public class TextureView extends View { */ public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + mRenderNode.setIsTextureView(); } /** @@ -247,6 +250,7 @@ public class TextureView extends View { public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + mRenderNode.setIsTextureView(); } /** diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index dadbd8d2d1aad..2e91c240d71b0 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -1561,6 +1561,16 @@ public final class RenderNode { return nGetUniqueId(mNativeRenderNode); } + /** + * Captures whether this RenderNote represents a TextureView + * TODO(b/281695725): Clean this up once TextureView use setFrameRate API + * + * @hide + */ + public void setIsTextureView() { + nSetIsTextureView(mNativeRenderNode); + } + /////////////////////////////////////////////////////////////////////////// // Animations /////////////////////////////////////////////////////////////////////////// @@ -1891,4 +1901,7 @@ public final class RenderNode { @CriticalNative private static native long nGetUniqueId(long renderNode); + + @CriticalNative + private static native void nSetIsTextureView(long renderNode); } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index b348a6ecaae44..1c39db3a31bbe 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -152,6 +152,9 @@ void RenderNode::damageSelf(TreeInfo& info) { // TODO: Get this from the display list ops or something info.damageAccumulator->dirty(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX); } + if (!mIsTextureView) { + info.out.solelyTextureViewUpdates = false; + } } } diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index bdc48e91f6cbc..d1e04adcb642d 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -221,6 +221,8 @@ public: int64_t uniqueId() const { return mUniqueId; } + void setIsTextureView() { mIsTextureView = true; } + void markDrawStart(SkCanvas& canvas); void markDrawEnd(SkCanvas& canvas); @@ -290,6 +292,8 @@ private: bool mHasHolePunches; StretchMask mStretchMask; + bool mIsTextureView = false; + // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER public: /** diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 6b8f43946a742..2bff9cb74fa76 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -123,6 +123,10 @@ public: // This is used to post a message to redraw when it is time to draw the // next frame of an AnimatedImageDrawable. nsecs_t animatedImageDelay = kNoAnimatedImageDelay; + // This is used to determine if there were only TextureView updates in this frame. + // This info is passed to SurfaceFlinger to determine whether it should use vsyncIds + // for refresh rate selection. + bool solelyTextureViewUpdates = true; } out; // This flag helps to disable projection for receiver nodes that do not have any backward diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp index 24a785c18711d..8c7b9a4b5e94f 100644 --- a/libs/hwui/jni/android_graphics_RenderNode.cpp +++ b/libs/hwui/jni/android_graphics_RenderNode.cpp @@ -526,6 +526,11 @@ static jlong android_view_RenderNode_getUniqueId(CRITICAL_JNI_PARAMS_COMMA jlong return reinterpret_cast(renderNodePtr)->uniqueId(); } +static void android_view_RenderNode_setIsTextureView( + CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) { + reinterpret_cast(renderNodePtr)->setIsTextureView(); +} + // ---------------------------------------------------------------------------- // RenderProperties - Animations // ---------------------------------------------------------------------------- @@ -844,6 +849,7 @@ static const JNINativeMethod gMethods[] = { {"nSetAllowForceDark", "(JZ)Z", (void*)android_view_RenderNode_setAllowForceDark}, {"nGetAllowForceDark", "(J)Z", (void*)android_view_RenderNode_getAllowForceDark}, {"nGetUniqueId", "(J)J", (void*)android_view_RenderNode_getUniqueId}, + {"nSetIsTextureView", "(J)V", (void*)android_view_RenderNode_setIsTextureView}, }; int register_android_view_RenderNode(JNIEnv* env) { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f60c1f3c6ad83..2bd400dba3468 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -531,7 +531,7 @@ Frame CanvasContext::getFrame() { } } -void CanvasContext::draw() { +void CanvasContext::draw(bool solelyTextureViewUpdates) { if (auto grContext = getGrContext()) { if (grContext->abandoned()) { LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw"); @@ -604,7 +604,8 @@ void CanvasContext::draw() { static_cast(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId)); native_window_set_frame_timeline_info( mNativeSurface->getNativeWindow(), frameCompleteNr, vsyncId, inputEventId, - mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime)); + mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime), + solelyTextureViewUpdates); } } @@ -885,7 +886,7 @@ void CanvasContext::prepareAndDraw(RenderNode* node) { TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node); if (info.out.canDrawThisFrame) { - draw(); + draw(info.out.solelyTextureViewUpdates); } else { // wait on fences so tasks don't overlap next frame waitOnFences(); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index d7215de923759..08e24245d16c9 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -143,7 +143,7 @@ public: bool makeCurrent(); void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); // Returns the DequeueBufferDuration. - void draw(); + void draw(bool solelyTextureViewUpdates); void destroy(); // IFrameCallback, Choreographer-driven frame callback entry point diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index fab2f46e91c3f..53b43ba417d0d 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -98,12 +98,14 @@ void DrawFrameTask::run() { IRenderPipeline* pipeline = mContext->getRenderPipeline(); bool canUnblockUiThread; bool canDrawThisFrame; + bool solelyTextureViewUpdates; { TreeInfo info(TreeInfo::MODE_FULL, *mContext); info.forceDrawFrame = mForceDrawFrame; mForceDrawFrame = false; canUnblockUiThread = syncFrameState(info); canDrawThisFrame = info.out.canDrawThisFrame; + solelyTextureViewUpdates = info.out.solelyTextureViewUpdates; if (mFrameCommitCallback) { mContext->addFrameCommitListener(std::move(mFrameCommitCallback)); @@ -136,7 +138,7 @@ void DrawFrameTask::run() { } if (CC_LIKELY(canDrawThisFrame)) { - context->draw(); + context->draw(solelyTextureViewUpdates); } else { // Do a flush in case syncFrameState performed any texture uploads. Since we skipped // the draw() call, those uploads (or deletes) will end up sitting in the queue. @@ -179,6 +181,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { mLayers[i]->apply(); } } + mLayers.clear(); mContext->setContentDrawBounds(mContentDrawBounds); mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);