From 027b2188473bd48c34cdafad1705abac7fff9356 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Thu, 18 Mar 2021 16:50:38 -0400 Subject: [PATCH] Integrate HWUI with PerformanceHintManager PerformanceHintManager.Session is in java, so add JNI and a HintSessionWrapper class in HardwareRenderer. Then pass the two calls as two std::functions into DrawFrameTask. Note Session is created per HardwareRenderer, not global (per RenderThread). Session includes UI thread, render thread, and the thread pool. Desired duration is from the intended start duration to the frame deadline. Add an actual frame start time to compute Add system properties: debug.hwui.use_hint_manager to enable PerformanceHintManager debug.hwui.target_cpu_time_percent to control percentage of frame time to be used for target cpu duration. Test: Manual test that there are no crashes and values make sense. Bug: 158791282 Change-Id: I83f25433c10daa20033803fb7c4ae45eab34f1d3 --- core/java/android/view/Choreographer.java | 2 +- core/java/android/view/FrameMetrics.java | 23 ++--- graphics/java/android/graphics/FrameInfo.java | 8 +- .../android/graphics/HardwareRenderer.java | 68 +++++++++++-- libs/hwui/FrameInfo.cpp | 29 ++---- libs/hwui/FrameInfo.h | 3 +- libs/hwui/Properties.cpp | 7 ++ libs/hwui/Properties.h | 17 ++++ .../jni/android_graphics_HardwareRenderer.cpp | 95 +++++++++++++++++++ libs/hwui/renderthread/DrawFrameTask.cpp | 29 ++++++ libs/hwui/renderthread/DrawFrameTask.h | 6 ++ libs/hwui/renderthread/RenderProxy.cpp | 6 ++ libs/hwui/renderthread/RenderProxy.h | 2 + libs/hwui/thread/CommonPool.cpp | 26 ++++- libs/hwui/thread/CommonPool.h | 5 + 15 files changed, 278 insertions(+), 48 deletions(-) diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 5c65c659e5766..7b3a8a64fc37d 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -737,7 +737,7 @@ public final class Choreographer { } mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id, - vsyncEventData.frameDeadline); + vsyncEventData.frameDeadline, startNanos); mFrameScheduled = false; mLastFrameTimeNanos = frameTimeNanos; mLastVsyncEventData = vsyncEventData; diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java index eb49e52d50503..9cdf91a55c39d 100644 --- a/core/java/android/view/FrameMetrics.java +++ b/core/java/android/view/FrameMetrics.java @@ -242,18 +242,19 @@ public final class FrameMetrics { int PERFORM_TRAVERSALS_START = 7; int DRAW_START = 8; int FRAME_DEADLINE = 9; - int SYNC_QUEUED = 10; - int SYNC_START = 11; - int ISSUE_DRAW_COMMANDS_START = 12; - int SWAP_BUFFERS = 13; - int FRAME_COMPLETED = 14; - int DEQUEUE_BUFFER_DURATION = 15; - int QUEUE_BUFFER_DURATION = 16; - int GPU_COMPLETED = 17; - int SWAP_BUFFERS_COMPLETED = 18; - int DISPLAY_PRESENT_TIME = 19; + int FRAME_START_TIME = 10; + int SYNC_QUEUED = 11; + int SYNC_START = 12; + int ISSUE_DRAW_COMMANDS_START = 13; + int SWAP_BUFFERS = 14; + int FRAME_COMPLETED = 15; + int DEQUEUE_BUFFER_DURATION = 16; + int QUEUE_BUFFER_DURATION = 17; + int GPU_COMPLETED = 18; + int SWAP_BUFFERS_COMPLETED = 19; + int DISPLAY_PRESENT_TIME = 20; - int FRAME_STATS_COUNT = 20; // must always be last and in sync with + int FRAME_STATS_COUNT = 21; // must always be last and in sync with // FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h } diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java index 189be53a397f1..786c03ba51505 100644 --- a/graphics/java/android/graphics/FrameInfo.java +++ b/graphics/java/android/graphics/FrameInfo.java @@ -87,18 +87,22 @@ public final class FrameInfo { // When the frame needs to be ready by public static final int FRAME_DEADLINE = 9; + // When frame actually started. + public static final int FRAME_START_TIME = 10; + // Must be the last one // This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h - private static final int FRAME_INFO_SIZE = FRAME_DEADLINE + 1; + private static final int FRAME_INFO_SIZE = FRAME_START_TIME + 1; /** checkstyle */ public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId, - long frameDeadline) { + long frameDeadline, long frameStartTime) { frameInfo[FRAME_TIMELINE_VSYNC_ID] = frameTimelineVsyncId; frameInfo[INTENDED_VSYNC] = intendedVsync; frameInfo[VSYNC] = usedVsync; frameInfo[FLAGS] = 0; frameInfo[FRAME_DEADLINE] = frameDeadline; + frameInfo[FRAME_START_TIME] = frameStartTime; } /** checkstyle */ diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index 88cf96a9eb4ea..7589435fc3b7a 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.PerformanceHintManager; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; @@ -165,7 +166,7 @@ public class HardwareRenderer { * to opaque with no light source configured. */ public HardwareRenderer() { - ProcessInitializer.sInstance.initDisplayInfo(); + ProcessInitializer.sInstance.initUsingContext(); mRootNode = RenderNode.adopt(nCreateRootRenderNode()); mRootNode.setClipToBounds(false); mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode); @@ -365,7 +366,8 @@ public class HardwareRenderer { */ public @NonNull FrameRenderRequest setVsyncTime(long vsyncTime) { // TODO(b/168552873): populate vsync Id once available to Choreographer public API - mFrameInfo.setVsync(vsyncTime, vsyncTime, FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE); + mFrameInfo.setVsync(vsyncTime, vsyncTime, FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, + vsyncTime); mFrameInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS); return this; } @@ -835,6 +837,36 @@ public class HardwareRenderer { callback.onPictureCaptured(picture); } + /** called by native */ + static PerformanceHintManager.Session createHintSession(int[] tids) { + PerformanceHintManager performanceHintManager = + ProcessInitializer.sInstance.getHintManager(); + if (performanceHintManager == null) { + return null; + } + // Native code will always set a target duration before reporting actual durations. + // So this is just a placeholder value that's never used. + long targetDurationNanos = 16666667; + return performanceHintManager.createHintSession(tids, targetDurationNanos); + } + + /** called by native */ + static void updateTargetWorkDuration(PerformanceHintManager.Session session, + long targetDurationNanos) { + session.updateTargetWorkDuration(targetDurationNanos); + } + + /** called by native */ + static void reportActualWorkDuration(PerformanceHintManager.Session session, + long actualDurationNanos) { + session.reportActualWorkDuration(actualDurationNanos); + } + + /** called by native */ + static void closeHintSession(PerformanceHintManager.Session session) { + session.close(); + } + /** * Interface used to receive callbacks when a frame is being drawn. * @@ -1071,6 +1103,7 @@ public class HardwareRenderer { private boolean mIsolated = false; private Context mContext; private String mPackageName; + private PerformanceHintManager mPerformanceHintManager; private IGraphicsStats mGraphicsStatsService; private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { @Override @@ -1082,6 +1115,10 @@ public class HardwareRenderer { private ProcessInitializer() { } + synchronized PerformanceHintManager getHintManager() { + return mPerformanceHintManager; + } + synchronized void setPackageName(String name) { if (mInitialized) return; mPackageName = name; @@ -1127,15 +1164,23 @@ public class HardwareRenderer { } } - synchronized void initDisplayInfo() { - if (mDisplayInitialized) return; + synchronized void initUsingContext() { if (mContext == null) return; - // If we're in an isolated sandbox mode then we shouldn't try to communicate with DMS + initDisplayInfo(); + + // HintManager and HintSession are designed to be accessible from isoalted processes + // so not checking for isolated process here. + initHintSession(); + + // Defensively clear out the context in case we were passed a context that can leak + // if we live longer than it, e.g. an activity context. + mContext = null; + } + + private void initDisplayInfo() { + if (mDisplayInitialized) return; if (mIsolated) { - // Defensively clear out the context in case we were passed a context that can leak - // if we live longer than it, e.g. an activity context. - mContext = null; mDisplayInitialized = true; return; } @@ -1167,11 +1212,14 @@ public class HardwareRenderer { display.getRefreshRate(), wideColorDataspace.mNativeDataspace, display.getAppVsyncOffsetNanos(), display.getPresentationDeadlineNanos()); - // Defensively clear out the context - mContext = null; mDisplayInitialized = true; } + private void initHintSession() { + if (mContext == null) return; + mPerformanceHintManager = mContext.getSystemService(PerformanceHintManager.class); + } + private void rotateBuffer() { nRotateProcessStatsBuffer(); requestBuffer(); diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index 2448cc9041043..51fbf363f51c1 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -21,29 +21,16 @@ namespace android { namespace uirenderer { const std::array FrameInfoNames{ - "Flags", - "FrameTimelineVsyncId", - "IntendedVsync", - "Vsync", - "InputEventId", - "HandleInputStart", - "AnimationStart", - "PerformTraversalsStart", - "DrawStart", - "FrameDeadline", - "SyncQueued", - "SyncStart", - "IssueDrawCommandsStart", - "SwapBuffers", - "FrameCompleted", - "DequeueBufferDuration", - "QueueBufferDuration", - "GpuCompleted", - "SwapBuffersCompleted", - "DisplayPresentTime", + "Flags", "FrameTimelineVsyncId", "IntendedVsync", + "Vsync", "InputEventId", "HandleInputStart", + "AnimationStart", "PerformTraversalsStart", "DrawStart", + "FrameDeadline", "FrameStartTime", "SyncQueued", + "SyncStart", "IssueDrawCommandsStart", "SwapBuffers", + "FrameCompleted", "DequeueBufferDuration", "QueueBufferDuration", + "GpuCompleted", "SwapBuffersCompleted", "DisplayPresentTime", }; -static_assert(static_cast(FrameInfoIndex::NumIndexes) == 20, +static_assert(static_cast(FrameInfoIndex::NumIndexes) == 21, "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)"); void FrameInfo::importUiThreadInfo(int64_t* info) { diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index e9b2f4a9bb3be..62ac4ca5fdad5 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -28,7 +28,7 @@ namespace android { namespace uirenderer { -static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 10; +static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 11; enum class FrameInfoIndex { Flags = 0, @@ -41,6 +41,7 @@ enum class FrameInfoIndex { PerformTraversalsStart, DrawStart, FrameDeadline, + FrameStartTime, // End of UI frame info SyncQueued, diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index e58f31fd15eb2..7af0a221d2280 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -81,6 +81,9 @@ bool Properties::isolatedProcess = false; int Properties::contextPriority = 0; float Properties::defaultSdrWhitePoint = 200.f; +bool Properties::useHintManager = true; +int Properties::targetCpuTimePercentage = 70; + bool Properties::load() { bool prevDebugLayersUpdates = debugLayersUpdates; bool prevDebugOverdraw = debugOverdraw; @@ -128,6 +131,10 @@ bool Properties::load() { runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false); + useHintManager = base::GetBoolProperty(PROPERTY_USE_HINT_MANAGER, true); + targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70); + if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70; + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index ea9cbd592d292..1cb87be98051f 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -157,6 +157,20 @@ enum DebugLevel { */ #define PROPERTY_CAPTURE_SKP_FILENAME "debug.hwui.skp_filename" +/** + * Controls whether HWUI will send timing hints to HintManager for + * better CPU scheduling. Accepted values are "true" and "false". + */ +#define PROPERTY_USE_HINT_MANAGER "debug.hwui.use_hint_manager" + +/** + * Percentage of frame time that's used for CPU work. The rest is + * reserved for GPU work. This is used with use_hint_manager to + * provide timing hints to HintManager. Accepted values are + * integer from 1-100. + */ +#define PROPERTY_TARGET_CPU_TIME_PERCENTAGE "debug.hwui.target_cpu_time_percent" + /** * Property for whether this is running in the emulator. */ @@ -253,6 +267,9 @@ public: static float defaultSdrWhitePoint; + static bool useHintManager; + static int targetCpuTimePercentage; + private: static ProfileType sProfileType; static bool sDisableProfileBars; diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index f24ba5c1c8785..bd1da985a33ed 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -34,14 +34,18 @@ #include #include #include +#include #include #include #include #include #include +#include + #include #include +#include #include "android_graphics_HardwareRendererObserver.h" @@ -53,6 +57,10 @@ using namespace android::uirenderer::renderthread; struct { jclass clazz; jmethodID invokePictureCapturedCallback; + jmethodID createHintSession; + jmethodID updateTargetWorkDuration; + jmethodID reportActualWorkDuration; + jmethodID closeHintSession; } gHardwareRenderer; struct { @@ -71,6 +79,14 @@ static JNIEnv* getenv(JavaVM* vm) { return env; } +static bool hasExceptionAndClear(JNIEnv* env) { + if (GraphicsJNI::hasException(env)) { + env->ExceptionClear(); + return true; + } + return false; +} + typedef ANativeWindow* (*ANW_fromSurface)(JNIEnv* env, jobject surface); ANW_fromSurface fromSurface; @@ -120,6 +136,67 @@ private: } }; +class HintSessionWrapper : public LightRefBase { +public: + static sp create(JNIEnv* env, RenderProxy* proxy) { + if (!Properties::useHintManager) return nullptr; + + // Include UI thread (self), render thread, and thread pool. + std::vector tids = CommonPool::getThreadIds(); + tids.push_back(proxy->getRenderThreadTid()); + tids.push_back(pthread_gettid_np(pthread_self())); + + jintArray tidsArray = env->NewIntArray(tids.size()); + if (hasExceptionAndClear(env)) return nullptr; + env->SetIntArrayRegion(tidsArray, 0, tids.size(), reinterpret_cast(tids.data())); + if (hasExceptionAndClear(env)) return nullptr; + jobject session = env->CallStaticObjectMethod( + gHardwareRenderer.clazz, gHardwareRenderer.createHintSession, tidsArray); + if (hasExceptionAndClear(env) || !session) return nullptr; + return new HintSessionWrapper(env, session); + } + + ~HintSessionWrapper() { + if (!mSession) return; + JNIEnv* env = getenv(mVm); + env->CallStaticVoidMethod(gHardwareRenderer.clazz, gHardwareRenderer.closeHintSession, + mSession); + hasExceptionAndClear(env); + env->DeleteGlobalRef(mSession); + mSession = nullptr; + } + + void updateTargetWorkDuration(long targetDurationNanos) { + if (!mSession) return; + JNIEnv* env = getenv(mVm); + env->CallStaticVoidMethod(gHardwareRenderer.clazz, + gHardwareRenderer.updateTargetWorkDuration, mSession, + static_cast(targetDurationNanos)); + hasExceptionAndClear(env); + } + + void reportActualWorkDuration(long actualDurationNanos) { + if (!mSession) return; + JNIEnv* env = getenv(mVm); + env->CallStaticVoidMethod(gHardwareRenderer.clazz, + gHardwareRenderer.reportActualWorkDuration, mSession, + static_cast(actualDurationNanos)); + hasExceptionAndClear(env); + } + +private: + HintSessionWrapper(JNIEnv* env, jobject jobject) { + env->GetJavaVM(&mVm); + if (jobject) { + mSession = env->NewGlobalRef(jobject); + LOG_ALWAYS_FATAL_IF(!mSession, "Failed to make global ref"); + } + } + + JavaVM* mVm = nullptr; + jobject mSession = nullptr; +}; + static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) { RenderProxy::rotateProcessStatsBuffer(); } @@ -147,6 +224,12 @@ static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject claz RootRenderNode* rootRenderNode = reinterpret_cast(rootRenderNodePtr); ContextFactoryImpl factory(rootRenderNode); RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory); + sp wrapper = HintSessionWrapper::create(env, proxy); + if (wrapper) { + proxy->setHintSessionCallbacks( + [wrapper](int64_t nanos) { wrapper->updateTargetWorkDuration(nanos); }, + [wrapper](int64_t nanos) { wrapper->reportActualWorkDuration(nanos); }); + } return (jlong) proxy; } @@ -769,6 +852,18 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) { gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer, "invokePictureCapturedCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V"); + gHardwareRenderer.createHintSession = + GetStaticMethodIDOrDie(env, hardwareRenderer, "createHintSession", + "([I)Landroid/os/PerformanceHintManager$Session;"); + gHardwareRenderer.updateTargetWorkDuration = + GetStaticMethodIDOrDie(env, hardwareRenderer, "updateTargetWorkDuration", + "(Landroid/os/PerformanceHintManager$Session;J)V"); + gHardwareRenderer.reportActualWorkDuration = + GetStaticMethodIDOrDie(env, hardwareRenderer, "reportActualWorkDuration", + "(Landroid/os/PerformanceHintManager$Session;J)V"); + gHardwareRenderer.closeHintSession = + GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession", + "(Landroid/os/PerformanceHintManager$Session;)V"); jclass frameCallbackClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameDrawingCallback"); diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 3408ffda3f9de..7a38a3bc9c05c 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -21,6 +21,7 @@ #include "../DeferredLayerUpdater.h" #include "../DisplayList.h" +#include "../Properties.h" #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" @@ -44,6 +45,12 @@ void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, mTargetNode = targetNode; } +void DrawFrameTask::setHintSessionCallbacks(std::function updateTargetWorkDuration, + std::function reportActualWorkDuration) { + mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration); + mReportActualWorkDuration = std::move(reportActualWorkDuration); +} + void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!"); @@ -102,6 +109,9 @@ void DrawFrameTask::run() { CanvasContext* context = mContext; std::function callback = std::move(mFrameCallback); mFrameCallback = nullptr; + int64_t intendedVsync = mFrameInfo[static_cast(FrameInfoIndex::IntendedVsync)]; + int64_t frameDeadline = mFrameInfo[static_cast(FrameInfoIndex::FrameDeadline)]; + int64_t frameStartTime = mFrameInfo[static_cast(FrameInfoIndex::FrameStartTime)]; // From this point on anything in "this" is *UNSAFE TO ACCESS* if (canUnblockUiThread) { @@ -124,6 +134,25 @@ void DrawFrameTask::run() { if (!canUnblockUiThread) { unblockUiThread(); } + + // These member callbacks are effectively const as they are set once during init, so it's safe + // to use these directly instead of making local copies. + if (mUpdateTargetWorkDuration && mReportActualWorkDuration) { + constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms + constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s + int64_t targetWorkDuration = frameDeadline - intendedVsync; + targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; + if (targetWorkDuration > kSanityCheckLowerBound && + targetWorkDuration < kSanityCheckUpperBound && + targetWorkDuration != mLastTargetWorkDuration) { + mLastTargetWorkDuration = targetWorkDuration; + mUpdateTargetWorkDuration(targetWorkDuration); + } + int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; + if (frameDuration > kSanityCheckLowerBound && frameDuration < kSanityCheckUpperBound) { + mReportActualWorkDuration(frameDuration); + } + } } bool DrawFrameTask::syncFrameState(TreeInfo& info) { diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 696cfaef3cd7b..3bb574aff59b8 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -61,6 +61,8 @@ public: virtual ~DrawFrameTask(); void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode); + void setHintSessionCallbacks(std::function updateTargetWorkDuration, + std::function reportActualWorkDuration); void setContentDrawBounds(int left, int top, int right, int bottom) { mContentDrawBounds.set(left, top, right, bottom); } @@ -107,6 +109,10 @@ private: std::function mFrameCallback; std::function mFrameCompleteCallback; + + nsecs_t mLastTargetWorkDuration = 0; + std::function mUpdateTargetWorkDuration; + std::function mReportActualWorkDuration; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 423cc08189cab..9361abd208525 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -76,6 +76,12 @@ void RenderProxy::setName(const char* name) { mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } +void RenderProxy::setHintSessionCallbacks(std::function updateTargetWorkDuration, + std::function reportActualWorkDuration) { + mDrawFrameTask.setHintSessionCallbacks(std::move(updateTargetWorkDuration), + std::move(reportActualWorkDuration)); +} + void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) { if (window) { ANativeWindow_acquire(window); } mRenderThread.queue().post([this, win = window, enableTimeout]() mutable { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 366d6b5a172c3..8d55d3c55570e 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -71,6 +71,8 @@ public: void setSwapBehavior(SwapBehavior swapBehavior); bool loadSystemProperties(); void setName(const char* name); + void setHintSessionCallbacks(std::function updateTargetWorkDuration, + std::function reportActualWorkDuration); void setSurface(ANativeWindow* window, bool enableTimeout = true); void setSurfaceControl(ASurfaceControl* surfaceControl); diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp index d011bdfe945ea..dc92f9f0d39a2 100644 --- a/libs/hwui/thread/CommonPool.cpp +++ b/libs/hwui/thread/CommonPool.cpp @@ -29,14 +29,23 @@ CommonPool::CommonPool() { ATRACE_CALL(); CommonPool* pool = this; + std::mutex mLock; + std::vector tids(THREAD_COUNT); + std::vector tidConditionVars(THREAD_COUNT); + // Create 2 workers for (int i = 0; i < THREAD_COUNT; i++) { - std::thread worker([pool, i] { + std::thread worker([pool, i, &mLock, &tids, &tidConditionVars] { { std::array name{"hwuiTask"}; snprintf(name.data(), name.size(), "hwuiTask%d", i); auto self = pthread_self(); pthread_setname_np(self, name.data()); + { + std::unique_lock lock(mLock); + tids[i] = pthread_gettid_np(self); + tidConditionVars[i].notify_one(); + } setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND); auto startHook = renderthread::RenderThread::getOnStartHook(); if (startHook) { @@ -47,6 +56,15 @@ CommonPool::CommonPool() { }); worker.detach(); } + { + std::unique_lock lock(mLock); + for (int i = 0; i < THREAD_COUNT; i++) { + while (!tids[i]) { + tidConditionVars[i].wait(lock); + } + } + } + mWorkerThreadIds = std::move(tids); } CommonPool& CommonPool::instance() { @@ -58,6 +76,10 @@ void CommonPool::post(Task&& task) { instance().enqueue(std::move(task)); } +std::vector CommonPool::getThreadIds() { + return instance().mWorkerThreadIds; +} + void CommonPool::enqueue(Task&& task) { std::unique_lock lock(mLock); while (!mWorkQueue.hasSpace()) { @@ -104,4 +126,4 @@ void CommonPool::doWaitForIdle() { } } // namespace uirenderer -} // namespace android \ No newline at end of file +} // namespace android diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h index 7603eeef46928..74f852bd14137 100644 --- a/libs/hwui/thread/CommonPool.h +++ b/libs/hwui/thread/CommonPool.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace android { namespace uirenderer { @@ -97,6 +98,8 @@ public: return task.get_future().get(); }; + static std::vector getThreadIds(); + // For testing purposes only, blocks until all worker threads are parked. static void waitForIdle(); @@ -111,6 +114,8 @@ private: void workerLoop(); + std::vector mWorkerThreadIds; + std::mutex mLock; std::condition_variable mCondition; int mWaitingThreads = 0;