diff options
Diffstat (limited to 'libs/hwui/renderthread/DrawFrameTask.cpp')
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 145 |
1 files changed, 139 insertions, 6 deletions
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 1e593388d063..e7081df2b558 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -16,19 +16,74 @@ #include "DrawFrameTask.h" +#include <dlfcn.h> +#include <gui/TraceUtils.h> #include <utils/Log.h> -#include <utils/Trace.h> +#include <algorithm> #include "../DeferredLayerUpdater.h" #include "../DisplayList.h" +#include "../Properties.h" #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) @@ -37,11 +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; + mUiThreadId = uiThreadId; + mRenderThreadId = renderThreadId; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -82,7 +139,9 @@ void DrawFrameTask::postAndWait() { } void DrawFrameTask::run() { - ATRACE_NAME("DrawFrame"); + const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)]; + ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId); + nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued; bool canUnblockUiThread; bool canDrawThisFrame; @@ -101,6 +160,9 @@ void DrawFrameTask::run() { CanvasContext* context = mContext; std::function<void(int64_t)> callback = std::move(mFrameCallback); mFrameCallback = 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) { @@ -113,9 +175,16 @@ void DrawFrameTask::run() { [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); }); } + nsecs_t dequeueBufferDuration = 0; if (CC_LIKELY(canDrawThisFrame)) { - context->draw(); + 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(); } @@ -123,12 +192,38 @@ void DrawFrameTask::run() { if (!canUnblockUiThread) { unblockUiThread(); } + + 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; } bool DrawFrameTask::syncFrameState(TreeInfo& info) { ATRACE_CALL(); int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)]; - mRenderThread->timeLord().vsyncReceived(vsync); + int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)]; + int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)]; + int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)]; + int64_t frameInterval = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameInterval)]; + mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId, frameDeadline, + frameInterval); bool canDraw = mContext->makeCurrent(); mContext->unpinImages(); @@ -168,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<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); + } +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ |