summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matt Buckley <mattbuckley@google.com> 2022-10-18 23:03:59 +0000
committer Matt Buckley <mattbuckley@google.com> 2022-10-27 19:52:52 +0000
commit864ab957bc78cda4a6bb809694abd242cd6d2744 (patch)
treea659dc71f03ded4b6a4b6386bb41b5415b8a168d
parent8a173b6abad979b73b296aebb958aa368e507a41 (diff)
Skip sending HWUI hints when frame does not draw
Sending HWUI ADPF CPU hints when the frame is not drawn can undercount the actual workload duration and lead to inadequate boosting. This patch prevents this by not sending hints when the frame is not drawn. Bug: b/239677101 Test: manual Change-Id: Ia308f59740c83977df02dff6d9f9289f2b8d439e
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp14
-rw-r--r--libs/hwui/renderthread/CanvasContext.h2
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp27
3 files changed, 28 insertions, 15 deletions
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6a0c5a8e499e..d09bc47cf8fd 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<nsecs_t> 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 748ab96d7e06..db96cfb978e9 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<nsecs_t> 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 03f02de98efe..dc7676c08bd7 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -19,6 +19,7 @@
#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>
+
#include <algorithm>
#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<nsecs_t> 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;