From cf1170fbda6ba5dc3d6890c489d7521cdc6fc3b7 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 14 Jul 2021 15:52:19 -0400 Subject: Always submit after texture uploads Ensure GrContext::submit() is always called after either Bitmap#prepareToDraw() or if DrawFrameTask skipped drawing. In either case texture uploads & deletions will be scheduled, but without the submit they won't actually be performed. This can end up running out of RAM. Bug: 189393671 Test: manual test app Change-Id: I57477c64457558487e9e5ec0a979ad9099a8cb2c --- libs/hwui/renderthread/DrawFrameTask.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'libs/hwui/renderthread/DrawFrameTask.cpp') diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 5c4b9019b0ad..db29e342855b 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -130,6 +130,12 @@ void DrawFrameTask::run() { if (CC_LIKELY(canDrawThisFrame)) { dequeueBufferDuration = 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. + // Do them now + if (GrDirectContext* grContext = mRenderThread->getGrContext()) { + grContext->flushAndSubmit(); + } // wait on fences so tasks don't overlap next frame context->waitOnFences(); } -- cgit v1.2.3 From 6a3fc60f4358a49536bb58bf703c97651b2eccba Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Sat, 17 Jul 2021 16:42:13 -0400 Subject: Switch HWUI to use native performance hint API Test: None Bug: 194204196 Change-Id: I80dfdb5d56921c465406cc4534e82738c668d46d --- libs/hwui/renderthread/DrawFrameTask.cpp | 141 +++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 28 deletions(-) (limited to 'libs/hwui/renderthread/DrawFrameTask.cpp') diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index db29e342855b..e7081df2b558 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -16,6 +16,7 @@ #include "DrawFrameTask.h" +#include #include #include #include @@ -26,11 +27,63 @@ #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" +#include "thread/CommonPool.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_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_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_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) @@ -39,17 +92,13 @@ DrawFrameTask::DrawFrameTask() DrawFrameTask::~DrawFrameTask() {} -void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, - RenderNode* targetNode) { +void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, + int32_t uiThreadId, int32_t renderThreadId) { mRenderThread = thread; mContext = context; mTargetNode = targetNode; -} - -void DrawFrameTask::setHintSessionCallbacks(std::function updateTargetWorkDuration, - std::function reportActualWorkDuration) { - mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration); - mReportActualWorkDuration = std::move(reportActualWorkDuration); + mUiThreadId = uiThreadId; + mRenderThreadId = renderThreadId; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -144,27 +193,25 @@ void DrawFrameTask::run() { 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; - int64_t actualDuration = frameDuration - - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - - dequeueBufferDuration; - if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { - mReportActualWorkDuration(actualDuration); - } + if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); + 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; + mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration); } + 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; } @@ -216,6 +263,44 @@ 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 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); + } +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ -- cgit v1.2.3