diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index df78827534a61..99a7fe5989369 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -640,6 +640,10 @@ public abstract class LayoutInflater { mConstructorArgs[0] = inflaterContext; View result = root; + if (root != null && root.getViewRootImpl() != null) { + root.getViewRootImpl().notifyRendererOfExpensiveFrame(); + } + try { advanceToRootNode(parser); final String name = parser.getName(); @@ -662,6 +666,10 @@ public abstract class LayoutInflater { // Temp is the root view that was found in the xml final View temp = createViewFromTag(root, name, inflaterContext, attrs); + if (root == null && temp != null && temp.getViewRootImpl() != null) { + temp.getViewRootImpl().notifyRendererOfExpensiveFrame(); + } + ViewGroup.LayoutParams params = null; if (root != null) { diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 164a49464051a..9c6e823b549e4 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -594,6 +594,13 @@ public final class ThreadedRenderer extends HardwareRenderer { } } + @Override + public void notifyExpensiveFrame() { + if (isEnabled()) { + super.notifyExpensiveFrame(); + } + } + /** * Updates the light position based on the position of the window. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ea7a64ef5c24a..30e98a4e64f7d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2334,6 +2334,18 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Notifies the HardwareRenderer of an expensive upcoming frame, to + * allow better handling of power and scheduling requirements. + * + * @hide + */ + void notifyRendererOfExpensiveFrame() { + if (mAttachInfo.mThreadedRenderer != null) { + mAttachInfo.mThreadedRenderer.notifyExpensiveFrame(); + } + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void scheduleTraversals() { if (!mTraversalScheduled) { diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index c7c97e0b82b9d..0892a9b14738c 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -991,6 +991,15 @@ public class HardwareRenderer { nNotifyCallbackPending(mNativeProxy); } + /** + * Notifies the hardware renderer about upcoming expensive frames. + * + * @hide + */ + public void notifyExpensiveFrame() { + nNotifyExpensiveFrame(mNativeProxy); + } + /** * b/68769804, b/66945974: For low FPS experiments. * @@ -1551,4 +1560,6 @@ public class HardwareRenderer { private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled); private static native void nNotifyCallbackPending(long nativeProxy); + + private static native void nNotifyExpensiveFrame(long nativeProxy); } diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 0663121a40277..e457c311f6899 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -865,6 +865,11 @@ static void android_view_ThreadedRenderer_notifyCallbackPending(JNIEnv*, jclass, proxy->notifyCallbackPending(); } +static void android_view_ThreadedRenderer_notifyExpensiveFrame(JNIEnv*, jclass, jlong proxyPtr) { + RenderProxy* proxy = reinterpret_cast(proxyPtr); + proxy->notifyExpensiveFrame(); +} + // Plumbs the display density down to DeviceInfo. static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) { // Convert from dpi to density-independent pixels. @@ -1044,6 +1049,8 @@ static const JNINativeMethod gMethods[] = { (void*)android_view_ThreadedRenderer_setRtAnimationsEnabled}, {"nNotifyCallbackPending", "(J)V", (void*)android_view_ThreadedRenderer_notifyCallbackPending}, + {"nNotifyExpensiveFrame", "(J)V", + (void*)android_view_ThreadedRenderer_notifyExpensiveFrame}, }; static JavaVM* mJvm = nullptr; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 64839d0147f8e..b92c90edd1ca4 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -1006,6 +1006,10 @@ void CanvasContext::sendLoadResetHint() { mHintSessionWrapper.sendLoadResetHint(); } +void CanvasContext::sendLoadIncreaseHint() { + mHintSessionWrapper.sendLoadIncreaseHint(); +} + void CanvasContext::setSyncDelayDuration(nsecs_t duration) { mSyncDelayDuration = duration; } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index e875c42e9ebad..d29e12c38d9f8 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -218,6 +218,8 @@ public: void sendLoadResetHint(); + void sendLoadIncreaseHint(); + void setSyncDelayDuration(nsecs_t duration); private: diff --git a/libs/hwui/renderthread/HintSessionWrapper.cpp b/libs/hwui/renderthread/HintSessionWrapper.cpp index 94c9d94a7c261..dece548e9dc19 100644 --- a/libs/hwui/renderthread/HintSessionWrapper.cpp +++ b/libs/hwui/renderthread/HintSessionWrapper.cpp @@ -158,6 +158,11 @@ void HintSessionWrapper::sendLoadResetHint() { mLastFrameNotification = now; } +void HintSessionWrapper::sendLoadIncreaseHint() { + if (!useHintSession()) return; + gAPH_sendHintFn(mHintSession, static_cast(SessionHint::CPU_LOAD_UP)); +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/HintSessionWrapper.h b/libs/hwui/renderthread/HintSessionWrapper.h index fcbc10185255b..c0f7a57bed754 100644 --- a/libs/hwui/renderthread/HintSessionWrapper.h +++ b/libs/hwui/renderthread/HintSessionWrapper.h @@ -33,6 +33,7 @@ public: void updateTargetWorkDuration(long targetDurationNanos); void reportActualWorkDuration(long actualDurationNanos); void sendLoadResetHint(); + void sendLoadIncreaseHint(); private: bool useHintSession(); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 07f5a78fc1ec9..04a6cbd1a5775 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -242,6 +242,10 @@ void RenderProxy::notifyCallbackPending() { mRenderThread.queue().post([this]() { mContext->sendLoadResetHint(); }); } +void RenderProxy::notifyExpensiveFrame() { + mRenderThread.queue().post([this]() { mContext->sendLoadIncreaseHint(); }); +} + void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) { mRenderThread.queue().runSync([&]() { std::lock_guard lock(mRenderThread.getJankDataMutex()); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index a21faa86ed0fe..1064225b69aed 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -110,6 +110,7 @@ public: void stopDrawing(); void notifyFramePending(); void notifyCallbackPending(); + void notifyExpensiveFrame(); void dumpProfileInfo(int fd, int dumpFlags); // Not exported, only used for testing