diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 6a0c5a8e499e8..d09bc47cf8fd7 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -472,11 +472,11 @@ void CanvasContext::notifyFramePending() { mRenderThread.pushBackFrameCallback(this); } -nsecs_t CanvasContext::draw() { +std::optional CanvasContext::draw() { if (auto grContext = getGrContext()) { if (grContext->abandoned()) { LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw"); - return 0; + return std::nullopt; } } SkRect dirty; @@ -498,7 +498,7 @@ nsecs_t CanvasContext::draw() { std::invoke(func, false /* didProduceBuffer */); } mFrameCommitCallbacks.clear(); - return 0; + return std::nullopt; } ScopedActiveContext activeContext(this); @@ -543,6 +543,8 @@ nsecs_t CanvasContext::draw() { } bool requireSwap = false; + bool didDraw = false; + int error = OK; bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult.success, windowDirty, mCurrentFrameInfo, &requireSwap); @@ -553,7 +555,7 @@ nsecs_t CanvasContext::draw() { mIsDirty = false; if (requireSwap) { - bool didDraw = true; + didDraw = true; // Handle any swapchain errors error = mNativeSurface->getAndClearError(); if (error == TIMED_OUT) { @@ -649,7 +651,9 @@ nsecs_t CanvasContext::draw() { } mRenderThread.cacheManager().onFrameCompleted(); - return mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); + return didDraw ? std::make_optional( + mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration)) + : std::nullopt; } void CanvasContext::reportMetricsWithPresentTime() { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 748ab96d7e06c..db96cfb978e9e 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -138,7 +138,7 @@ public: bool makeCurrent(); void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); // Returns the DequeueBufferDuration. - nsecs_t draw(); + std::optional draw(); void destroy(); // IFrameCallback, Choreographer-driven frame callback entry point diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 03f02de98efe7..dc7676c08bd7c 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -19,6 +19,7 @@ #include #include #include + #include #include "../DeferredLayerUpdater.h" @@ -28,6 +29,7 @@ #include "CanvasContext.h" #include "RenderThread.h" #include "thread/CommonPool.h" +#include "utils/TimeUtils.h" namespace android { namespace uirenderer { @@ -146,6 +148,7 @@ void DrawFrameTask::run() { bool canUnblockUiThread; bool canDrawThisFrame; + bool didDraw = false; { TreeInfo info(TreeInfo::MODE_FULL, *mContext); info.forceDrawFrame = mForceDrawFrame; @@ -188,7 +191,9 @@ void DrawFrameTask::run() { nsecs_t dequeueBufferDuration = 0; if (CC_LIKELY(canDrawThisFrame)) { - dequeueBufferDuration = context->draw(); + std::optional drawResult = context->draw(); + didDraw = drawResult.has_value(); + dequeueBufferDuration = drawResult.value_or(0); } 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. @@ -209,8 +214,9 @@ void DrawFrameTask::run() { } if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); - constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms - constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s + + 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 && @@ -219,12 +225,15 @@ void DrawFrameTask::run() { 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); + + 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;