Loading libs/hwui/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -570,6 +570,7 @@ cc_defaults { "renderthread/VulkanSurface.cpp", "renderthread/RenderProxy.cpp", "renderthread/RenderThread.cpp", "renderthread/HintSessionWrapper.cpp", "service/GraphicsStatsService.cpp", "thread/CommonPool.cpp", "utils/GLUtils.cpp", Loading libs/hwui/FrameInfo.h +1 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ public: set(FrameInfoIndex::AnimationStart) = vsyncTime; set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime; set(FrameInfoIndex::DrawStart) = vsyncTime; set(FrameInfoIndex::FrameStartTime) = vsyncTime; set(FrameInfoIndex::FrameDeadline) = frameDeadline; set(FrameInfoIndex::FrameInterval) = frameInterval; return *this; Loading libs/hwui/renderthread/CanvasContext.cpp +47 −11 Original line number Diff line number Diff line Loading @@ -71,16 +71,19 @@ CanvasContext* ScopedActiveContext::sActiveContext = nullptr; } /* namespace */ CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { RenderNode* rootRenderNode, IContextFactory* contextFactory, int32_t uiThreadId, int32_t renderThreadId) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { case RenderPipelineType::SkiaGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread), uiThreadId, renderThreadId); case RenderPipelineType::SkiaVulkan: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread), uiThreadId, renderThreadId); default: LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; Loading Loading @@ -110,7 +113,8 @@ void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline) std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId, pid_t renderThreadId) : mRenderThread(thread) , mGenerationID(0) , mOpaque(!translucent) Loading @@ -118,7 +122,8 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mJankTracker(&thread.globalProfileData()) , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mContentDrawBounds(0, 0, 0, 0) , mRenderPipeline(std::move(renderPipeline)) { , mRenderPipeline(std::move(renderPipeline)) , mHintSessionWrapper(uiThreadId, renderThreadId) { mRenderThread.cacheManager().registerCanvasContext(this); rootRenderNode->makeRoot(); mRenderNodes.emplace_back(rootRenderNode); Loading Loading @@ -472,16 +477,22 @@ void CanvasContext::notifyFramePending() { mRenderThread.pushBackFrameCallback(this); } std::optional<nsecs_t> CanvasContext::draw() { void CanvasContext::draw() { if (auto grContext = getGrContext()) { if (grContext->abandoned()) { LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw"); return std::nullopt; return; } } SkRect dirty; mDamageAccumulator.finish(&dirty); // reset syncDelayDuration each time we draw nsecs_t syncDelayDuration = mSyncDelayDuration; nsecs_t idleDuration = mIdleDuration; mSyncDelayDuration = 0; mIdleDuration = 0; if (!Properties::isDrawingEnabled() || (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); Loading @@ -498,7 +509,7 @@ std::optional<nsecs_t> CanvasContext::draw() { std::invoke(func, false /* didProduceBuffer */); } mFrameCommitCallbacks.clear(); return std::nullopt; return; } ScopedActiveContext activeContext(this); Loading Loading @@ -650,10 +661,25 @@ std::optional<nsecs_t> CanvasContext::draw() { } } int64_t intendedVsync = mCurrentFrameInfo->get(FrameInfoIndex::IntendedVsync); int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync); if (didDraw) { int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; int64_t actualDuration = frameDuration - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - dequeueBufferDuration - idleDuration; mHintSessionWrapper.reportActualWorkDuration(actualDuration); } mLastDequeueBufferDuration = dequeueBufferDuration; mRenderThread.cacheManager().onFrameCompleted(); return didDraw ? std::make_optional( mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration)) : std::nullopt; return; } void CanvasContext::reportMetricsWithPresentTime() { Loading Loading @@ -766,6 +792,8 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceContro // Called by choreographer to do an RT-driven animation void CanvasContext::doFrame() { if (!mRenderPipeline->isSurfaceReady()) return; mIdleDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mRenderThread.timeLord().computeFrameTimeNanos(); prepareAndDraw(nullptr); } Loading Loading @@ -974,6 +1002,14 @@ void CanvasContext::prepareSurfaceControlForWebview() { } } void CanvasContext::sendLoadResetHint() { mHintSessionWrapper.sendLoadResetHint(); } void CanvasContext::setSyncDelayDuration(nsecs_t duration) { mSyncDelayDuration = duration; } } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ libs/hwui/renderthread/CanvasContext.h +30 −18 Original line number Diff line number Diff line Loading @@ -16,10 +16,26 @@ #pragma once #include <SkBitmap.h> #include <SkRect.h> #include <SkSize.h> #include <cutils/compiler.h> #include <utils/Functor.h> #include <utils/Mutex.h> #include <functional> #include <future> #include <set> #include <string> #include <utility> #include <vector> #include "ColorMode.h" #include "DamageAccumulator.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" #include "HintSessionWrapper.h" #include "IContextFactory.h" #include "IRenderPipeline.h" #include "JankTracker.h" Loading @@ -30,21 +46,6 @@ #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" #include "utils/RingBuffer.h" #include "ColorMode.h" #include <SkBitmap.h> #include <SkRect.h> #include <SkSize.h> #include <cutils/compiler.h> #include <utils/Functor.h> #include <utils/Mutex.h> #include <functional> #include <future> #include <set> #include <string> #include <utility> #include <vector> namespace android { namespace uirenderer { Loading @@ -66,7 +67,8 @@ class Frame; class CanvasContext : public IFrameCallback { public: static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory); IContextFactory* contextFactory, pid_t uiThreadId, pid_t renderThreadId); virtual ~CanvasContext(); /** Loading Loading @@ -138,7 +140,7 @@ public: bool makeCurrent(); void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); // Returns the DequeueBufferDuration. std::optional<nsecs_t> draw(); void draw(); void destroy(); // IFrameCallback, Choreographer-driven frame callback entry point Loading Loading @@ -214,9 +216,14 @@ public: static CanvasContext* getActiveContext(); void sendLoadResetHint(); void setSyncDelayDuration(nsecs_t duration); private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId, pid_t renderThreadId); friend class RegisterFrameCallbackTask; // TODO: Replace with something better for layer & other GL object Loading Loading @@ -330,6 +337,11 @@ private: std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback; std::function<void()> mPrepareSurfaceControlForWebviewCallback; HintSessionWrapper mHintSessionWrapper; nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mSyncDelayDuration = 0; nsecs_t mIdleDuration = 0; }; } /* namespace renderthread */ Loading libs/hwui/renderthread/DrawFrameTask.cpp +6 −153 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ #include "DrawFrameTask.h" #include <dlfcn.h> #include <gui/TraceUtils.h> #include <utils/Log.h> Loading @@ -28,70 +27,11 @@ #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" #include "thread/CommonPool.h" #include "utils/TimeUtils.h" namespace android { namespace uirenderer { namespace renderthread { namespace { typedef APerformanceHintManager* (*APH_getManager)(); typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*, size_t, int64_t); typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t); typedef void (*APH_closeSession)(APerformanceHintSession* session); bool gAPerformanceHintBindingInitialized = false; APH_getManager gAPH_getManagerFn = nullptr; APH_createSession gAPH_createSessionFn = nullptr; APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr; APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr; APH_sendHint gAPH_sendHintFn = nullptr; APH_closeSession gAPH_closeSessionFn = nullptr; void ensureAPerformanceHintBindingInitialized() { if (gAPerformanceHintBindingInitialized) return; void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager"); LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr, "Failed to find required symbol APerformanceHint_getManager!"); gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, "Failed to find required symbol APerformanceHint_createSession!"); gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym( handle_, "APerformanceHint_updateTargetWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_updateTargetWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!"); gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym( handle_, "APerformanceHint_reportActualWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_reportActualWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_reportActualWorkDuration!"); gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint"); LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr, "Failed to find required symbol APerformanceHint_sendHint!"); gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, "Failed to find required symbol APerformanceHint_closeSession!"); gAPerformanceHintBindingInitialized = true; } } // namespace DrawFrameTask::DrawFrameTask() : mRenderThread(nullptr) , mContext(nullptr) Loading @@ -100,13 +40,11 @@ DrawFrameTask::DrawFrameTask() DrawFrameTask::~DrawFrameTask() {} void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, int32_t uiThreadId, int32_t renderThreadId) { void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode) { mRenderThread = thread; mContext = context; mTargetNode = targetNode; mUiThreadId = uiThreadId; mRenderThreadId = renderThreadId; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { Loading Loading @@ -150,11 +88,11 @@ void DrawFrameTask::postAndWait() { void DrawFrameTask::run() { const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)]; ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId); nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued; mContext->setSyncDelayDuration(systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued); bool canUnblockUiThread; bool canDrawThisFrame; bool didDraw = false; { TreeInfo info(TreeInfo::MODE_FULL, *mContext); info.forceDrawFrame = mForceDrawFrame; Loading @@ -175,9 +113,6 @@ void DrawFrameTask::run() { std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback); mFrameCallback = nullptr; mFrameCompleteCallback = nullptr; int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)]; int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)]; int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)]; // From this point on anything in "this" is *UNSAFE TO ACCESS* if (canUnblockUiThread) { Loading @@ -188,18 +123,15 @@ void DrawFrameTask::run() { if (CC_UNLIKELY(frameCallback)) { context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult, frameNr = context->getFrameNumber()]() { auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr)); auto frameCommitCallback = frameCallback(syncResult, frameNr); if (frameCommitCallback) { context->addFrameCommitListener(std::move(frameCommitCallback)); } }); } nsecs_t dequeueBufferDuration = 0; if (CC_LIKELY(canDrawThisFrame)) { std::optional<nsecs_t> drawResult = context->draw(); didDraw = drawResult.has_value(); dequeueBufferDuration = drawResult.value_or(0); context->draw(); } 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. Loading @@ -218,41 +150,6 @@ void DrawFrameTask::run() { if (!canUnblockUiThread) { unblockUiThread(); } if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); constexpr int64_t kSanityCheckLowerBound = 100_us; constexpr int64_t kSanityCheckUpperBound = 10_s; int64_t targetWorkDuration = frameDeadline - intendedVsync; targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; if (targetWorkDuration > kSanityCheckLowerBound && targetWorkDuration < kSanityCheckUpperBound && targetWorkDuration != mLastTargetWorkDuration) { mLastTargetWorkDuration = targetWorkDuration; mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration); } if (didDraw) { int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; int64_t actualDuration = frameDuration - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - dequeueBufferDuration; if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { mHintSessionWrapper->reportActualWorkDuration(actualDuration); } } mLastDequeueBufferDuration = dequeueBufferDuration; } void DrawFrameTask::sendLoadResetHint() { if (!(Properties::useHintManager && Properties::isDrawingEnabled())) return; if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); nsecs_t now = systemTime(); if (now - mLastFrameNotification > kResetHintTimeout) { mHintSessionWrapper->sendHint(SessionHint::CPU_LOAD_RESET); } mLastFrameNotification = now; } bool DrawFrameTask::syncFrameState(TreeInfo& info) { Loading Loading @@ -305,50 +202,6 @@ void DrawFrameTask::unblockUiThread() { mSignal.signal(); } DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) { if (!Properties::useHintManager) return; if (uiThreadId < 0 || renderThreadId < 0) return; ensureAPerformanceHintBindingInitialized(); APerformanceHintManager* manager = gAPH_getManagerFn(); if (!manager) return; std::vector<int32_t> tids = CommonPool::getThreadIds(); tids.push_back(uiThreadId); tids.push_back(renderThreadId); // DrawFrameTask code will always set a target duration before reporting actual durations. // So this is just a placeholder value that's never used. int64_t dummyTargetDurationNanos = 16666667; mHintSession = gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos); } DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() { if (mHintSession) { gAPH_closeSessionFn(mHintSession); } } void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) { if (mHintSession) { gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos); } } void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) { if (mHintSession) { gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos); } } void DrawFrameTask::HintSessionWrapper::sendHint(SessionHint hint) { if (mHintSession && Properties::isDrawingEnabled()) { gAPH_sendHintFn(mHintSession, static_cast<int>(hint)); } } } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ Loading
libs/hwui/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -570,6 +570,7 @@ cc_defaults { "renderthread/VulkanSurface.cpp", "renderthread/RenderProxy.cpp", "renderthread/RenderThread.cpp", "renderthread/HintSessionWrapper.cpp", "service/GraphicsStatsService.cpp", "thread/CommonPool.cpp", "utils/GLUtils.cpp", Loading
libs/hwui/FrameInfo.h +1 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ public: set(FrameInfoIndex::AnimationStart) = vsyncTime; set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime; set(FrameInfoIndex::DrawStart) = vsyncTime; set(FrameInfoIndex::FrameStartTime) = vsyncTime; set(FrameInfoIndex::FrameDeadline) = frameDeadline; set(FrameInfoIndex::FrameInterval) = frameInterval; return *this; Loading
libs/hwui/renderthread/CanvasContext.cpp +47 −11 Original line number Diff line number Diff line Loading @@ -71,16 +71,19 @@ CanvasContext* ScopedActiveContext::sActiveContext = nullptr; } /* namespace */ CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { RenderNode* rootRenderNode, IContextFactory* contextFactory, int32_t uiThreadId, int32_t renderThreadId) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { case RenderPipelineType::SkiaGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread), uiThreadId, renderThreadId); case RenderPipelineType::SkiaVulkan: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread), uiThreadId, renderThreadId); default: LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; Loading Loading @@ -110,7 +113,8 @@ void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline) std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId, pid_t renderThreadId) : mRenderThread(thread) , mGenerationID(0) , mOpaque(!translucent) Loading @@ -118,7 +122,8 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mJankTracker(&thread.globalProfileData()) , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mContentDrawBounds(0, 0, 0, 0) , mRenderPipeline(std::move(renderPipeline)) { , mRenderPipeline(std::move(renderPipeline)) , mHintSessionWrapper(uiThreadId, renderThreadId) { mRenderThread.cacheManager().registerCanvasContext(this); rootRenderNode->makeRoot(); mRenderNodes.emplace_back(rootRenderNode); Loading Loading @@ -472,16 +477,22 @@ void CanvasContext::notifyFramePending() { mRenderThread.pushBackFrameCallback(this); } std::optional<nsecs_t> CanvasContext::draw() { void CanvasContext::draw() { if (auto grContext = getGrContext()) { if (grContext->abandoned()) { LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw"); return std::nullopt; return; } } SkRect dirty; mDamageAccumulator.finish(&dirty); // reset syncDelayDuration each time we draw nsecs_t syncDelayDuration = mSyncDelayDuration; nsecs_t idleDuration = mIdleDuration; mSyncDelayDuration = 0; mIdleDuration = 0; if (!Properties::isDrawingEnabled() || (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); Loading @@ -498,7 +509,7 @@ std::optional<nsecs_t> CanvasContext::draw() { std::invoke(func, false /* didProduceBuffer */); } mFrameCommitCallbacks.clear(); return std::nullopt; return; } ScopedActiveContext activeContext(this); Loading Loading @@ -650,10 +661,25 @@ std::optional<nsecs_t> CanvasContext::draw() { } } int64_t intendedVsync = mCurrentFrameInfo->get(FrameInfoIndex::IntendedVsync); int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync); if (didDraw) { int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; int64_t actualDuration = frameDuration - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - dequeueBufferDuration - idleDuration; mHintSessionWrapper.reportActualWorkDuration(actualDuration); } mLastDequeueBufferDuration = dequeueBufferDuration; mRenderThread.cacheManager().onFrameCompleted(); return didDraw ? std::make_optional( mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration)) : std::nullopt; return; } void CanvasContext::reportMetricsWithPresentTime() { Loading Loading @@ -766,6 +792,8 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceContro // Called by choreographer to do an RT-driven animation void CanvasContext::doFrame() { if (!mRenderPipeline->isSurfaceReady()) return; mIdleDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mRenderThread.timeLord().computeFrameTimeNanos(); prepareAndDraw(nullptr); } Loading Loading @@ -974,6 +1002,14 @@ void CanvasContext::prepareSurfaceControlForWebview() { } } void CanvasContext::sendLoadResetHint() { mHintSessionWrapper.sendLoadResetHint(); } void CanvasContext::setSyncDelayDuration(nsecs_t duration) { mSyncDelayDuration = duration; } } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */
libs/hwui/renderthread/CanvasContext.h +30 −18 Original line number Diff line number Diff line Loading @@ -16,10 +16,26 @@ #pragma once #include <SkBitmap.h> #include <SkRect.h> #include <SkSize.h> #include <cutils/compiler.h> #include <utils/Functor.h> #include <utils/Mutex.h> #include <functional> #include <future> #include <set> #include <string> #include <utility> #include <vector> #include "ColorMode.h" #include "DamageAccumulator.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" #include "HintSessionWrapper.h" #include "IContextFactory.h" #include "IRenderPipeline.h" #include "JankTracker.h" Loading @@ -30,21 +46,6 @@ #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" #include "utils/RingBuffer.h" #include "ColorMode.h" #include <SkBitmap.h> #include <SkRect.h> #include <SkSize.h> #include <cutils/compiler.h> #include <utils/Functor.h> #include <utils/Mutex.h> #include <functional> #include <future> #include <set> #include <string> #include <utility> #include <vector> namespace android { namespace uirenderer { Loading @@ -66,7 +67,8 @@ class Frame; class CanvasContext : public IFrameCallback { public: static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory); IContextFactory* contextFactory, pid_t uiThreadId, pid_t renderThreadId); virtual ~CanvasContext(); /** Loading Loading @@ -138,7 +140,7 @@ public: bool makeCurrent(); void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); // Returns the DequeueBufferDuration. std::optional<nsecs_t> draw(); void draw(); void destroy(); // IFrameCallback, Choreographer-driven frame callback entry point Loading Loading @@ -214,9 +216,14 @@ public: static CanvasContext* getActiveContext(); void sendLoadResetHint(); void setSyncDelayDuration(nsecs_t duration); private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId, pid_t renderThreadId); friend class RegisterFrameCallbackTask; // TODO: Replace with something better for layer & other GL object Loading Loading @@ -330,6 +337,11 @@ private: std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback; std::function<void()> mPrepareSurfaceControlForWebviewCallback; HintSessionWrapper mHintSessionWrapper; nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mSyncDelayDuration = 0; nsecs_t mIdleDuration = 0; }; } /* namespace renderthread */ Loading
libs/hwui/renderthread/DrawFrameTask.cpp +6 −153 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ #include "DrawFrameTask.h" #include <dlfcn.h> #include <gui/TraceUtils.h> #include <utils/Log.h> Loading @@ -28,70 +27,11 @@ #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" #include "thread/CommonPool.h" #include "utils/TimeUtils.h" namespace android { namespace uirenderer { namespace renderthread { namespace { typedef APerformanceHintManager* (*APH_getManager)(); typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*, size_t, int64_t); typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t); typedef void (*APH_closeSession)(APerformanceHintSession* session); bool gAPerformanceHintBindingInitialized = false; APH_getManager gAPH_getManagerFn = nullptr; APH_createSession gAPH_createSessionFn = nullptr; APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr; APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr; APH_sendHint gAPH_sendHintFn = nullptr; APH_closeSession gAPH_closeSessionFn = nullptr; void ensureAPerformanceHintBindingInitialized() { if (gAPerformanceHintBindingInitialized) return; void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager"); LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr, "Failed to find required symbol APerformanceHint_getManager!"); gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, "Failed to find required symbol APerformanceHint_createSession!"); gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym( handle_, "APerformanceHint_updateTargetWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_updateTargetWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!"); gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym( handle_, "APerformanceHint_reportActualWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_reportActualWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_reportActualWorkDuration!"); gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint"); LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr, "Failed to find required symbol APerformanceHint_sendHint!"); gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, "Failed to find required symbol APerformanceHint_closeSession!"); gAPerformanceHintBindingInitialized = true; } } // namespace DrawFrameTask::DrawFrameTask() : mRenderThread(nullptr) , mContext(nullptr) Loading @@ -100,13 +40,11 @@ DrawFrameTask::DrawFrameTask() DrawFrameTask::~DrawFrameTask() {} void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, int32_t uiThreadId, int32_t renderThreadId) { void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode) { mRenderThread = thread; mContext = context; mTargetNode = targetNode; mUiThreadId = uiThreadId; mRenderThreadId = renderThreadId; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { Loading Loading @@ -150,11 +88,11 @@ void DrawFrameTask::postAndWait() { void DrawFrameTask::run() { const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)]; ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId); nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued; mContext->setSyncDelayDuration(systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued); bool canUnblockUiThread; bool canDrawThisFrame; bool didDraw = false; { TreeInfo info(TreeInfo::MODE_FULL, *mContext); info.forceDrawFrame = mForceDrawFrame; Loading @@ -175,9 +113,6 @@ void DrawFrameTask::run() { std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback); mFrameCallback = nullptr; mFrameCompleteCallback = nullptr; int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)]; int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)]; int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)]; // From this point on anything in "this" is *UNSAFE TO ACCESS* if (canUnblockUiThread) { Loading @@ -188,18 +123,15 @@ void DrawFrameTask::run() { if (CC_UNLIKELY(frameCallback)) { context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult, frameNr = context->getFrameNumber()]() { auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr)); auto frameCommitCallback = frameCallback(syncResult, frameNr); if (frameCommitCallback) { context->addFrameCommitListener(std::move(frameCommitCallback)); } }); } nsecs_t dequeueBufferDuration = 0; if (CC_LIKELY(canDrawThisFrame)) { std::optional<nsecs_t> drawResult = context->draw(); didDraw = drawResult.has_value(); dequeueBufferDuration = drawResult.value_or(0); context->draw(); } 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. Loading @@ -218,41 +150,6 @@ void DrawFrameTask::run() { if (!canUnblockUiThread) { unblockUiThread(); } if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); constexpr int64_t kSanityCheckLowerBound = 100_us; constexpr int64_t kSanityCheckUpperBound = 10_s; int64_t targetWorkDuration = frameDeadline - intendedVsync; targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; if (targetWorkDuration > kSanityCheckLowerBound && targetWorkDuration < kSanityCheckUpperBound && targetWorkDuration != mLastTargetWorkDuration) { mLastTargetWorkDuration = targetWorkDuration; mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration); } if (didDraw) { int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; int64_t actualDuration = frameDuration - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - dequeueBufferDuration; if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { mHintSessionWrapper->reportActualWorkDuration(actualDuration); } } mLastDequeueBufferDuration = dequeueBufferDuration; } void DrawFrameTask::sendLoadResetHint() { if (!(Properties::useHintManager && Properties::isDrawingEnabled())) return; if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); nsecs_t now = systemTime(); if (now - mLastFrameNotification > kResetHintTimeout) { mHintSessionWrapper->sendHint(SessionHint::CPU_LOAD_RESET); } mLastFrameNotification = now; } bool DrawFrameTask::syncFrameState(TreeInfo& info) { Loading Loading @@ -305,50 +202,6 @@ void DrawFrameTask::unblockUiThread() { mSignal.signal(); } DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) { if (!Properties::useHintManager) return; if (uiThreadId < 0 || renderThreadId < 0) return; ensureAPerformanceHintBindingInitialized(); APerformanceHintManager* manager = gAPH_getManagerFn(); if (!manager) return; std::vector<int32_t> tids = CommonPool::getThreadIds(); tids.push_back(uiThreadId); tids.push_back(renderThreadId); // DrawFrameTask code will always set a target duration before reporting actual durations. // So this is just a placeholder value that's never used. int64_t dummyTargetDurationNanos = 16666667; mHintSession = gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos); } DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() { if (mHintSession) { gAPH_closeSessionFn(mHintSession); } } void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) { if (mHintSession) { gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos); } } void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) { if (mHintSession) { gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos); } } void DrawFrameTask::HintSessionWrapper::sendHint(SessionHint hint) { if (mHintSession && Properties::isDrawingEnabled()) { gAPH_sendHintFn(mHintSession, static_cast<int>(hint)); } } } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */