Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 864ab957 authored by Matt Buckley's avatar Matt Buckley
Browse files

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
parent 8a173b6a
Loading
Loading
Loading
Loading
+9 −5
Original line number Original line Diff line number Diff line
@@ -472,11 +472,11 @@ void CanvasContext::notifyFramePending() {
    mRenderThread.pushBackFrameCallback(this);
    mRenderThread.pushBackFrameCallback(this);
}
}


nsecs_t CanvasContext::draw() {
std::optional<nsecs_t> CanvasContext::draw() {
    if (auto grContext = getGrContext()) {
    if (auto grContext = getGrContext()) {
        if (grContext->abandoned()) {
        if (grContext->abandoned()) {
            LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw");
            LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw");
            return 0;
            return std::nullopt;
        }
        }
    }
    }
    SkRect dirty;
    SkRect dirty;
@@ -498,7 +498,7 @@ nsecs_t CanvasContext::draw() {
            std::invoke(func, false /* didProduceBuffer */);
            std::invoke(func, false /* didProduceBuffer */);
        }
        }
        mFrameCommitCallbacks.clear();
        mFrameCommitCallbacks.clear();
        return 0;
        return std::nullopt;
    }
    }


    ScopedActiveContext activeContext(this);
    ScopedActiveContext activeContext(this);
@@ -543,6 +543,8 @@ nsecs_t CanvasContext::draw() {
    }
    }


    bool requireSwap = false;
    bool requireSwap = false;
    bool didDraw = false;

    int error = OK;
    int error = OK;
    bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult.success, windowDirty,
    bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult.success, windowDirty,
                                                mCurrentFrameInfo, &requireSwap);
                                                mCurrentFrameInfo, &requireSwap);
@@ -553,7 +555,7 @@ nsecs_t CanvasContext::draw() {
    mIsDirty = false;
    mIsDirty = false;


    if (requireSwap) {
    if (requireSwap) {
        bool didDraw = true;
        didDraw = true;
        // Handle any swapchain errors
        // Handle any swapchain errors
        error = mNativeSurface->getAndClearError();
        error = mNativeSurface->getAndClearError();
        if (error == TIMED_OUT) {
        if (error == TIMED_OUT) {
@@ -649,7 +651,9 @@ nsecs_t CanvasContext::draw() {
    }
    }


    mRenderThread.cacheManager().onFrameCompleted();
    mRenderThread.cacheManager().onFrameCompleted();
    return mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);
    return didDraw ? std::make_optional(
                             mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration))
                   : std::nullopt;
}
}


void CanvasContext::reportMetricsWithPresentTime() {
void CanvasContext::reportMetricsWithPresentTime() {
+1 −1
Original line number Original line Diff line number Diff line
@@ -138,7 +138,7 @@ public:
    bool makeCurrent();
    bool makeCurrent();
    void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
    void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
    // Returns the DequeueBufferDuration.
    // Returns the DequeueBufferDuration.
    nsecs_t draw();
    std::optional<nsecs_t> draw();
    void destroy();
    void destroy();


    // IFrameCallback, Choreographer-driven frame callback entry point
    // IFrameCallback, Choreographer-driven frame callback entry point
+18 −9
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <dlfcn.h>
#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>
#include <utils/Log.h>

#include <algorithm>
#include <algorithm>


#include "../DeferredLayerUpdater.h"
#include "../DeferredLayerUpdater.h"
@@ -28,6 +29,7 @@
#include "CanvasContext.h"
#include "CanvasContext.h"
#include "RenderThread.h"
#include "RenderThread.h"
#include "thread/CommonPool.h"
#include "thread/CommonPool.h"
#include "utils/TimeUtils.h"


namespace android {
namespace android {
namespace uirenderer {
namespace uirenderer {
@@ -146,6 +148,7 @@ void DrawFrameTask::run() {


    bool canUnblockUiThread;
    bool canUnblockUiThread;
    bool canDrawThisFrame;
    bool canDrawThisFrame;
    bool didDraw = false;
    {
    {
        TreeInfo info(TreeInfo::MODE_FULL, *mContext);
        TreeInfo info(TreeInfo::MODE_FULL, *mContext);
        info.forceDrawFrame = mForceDrawFrame;
        info.forceDrawFrame = mForceDrawFrame;
@@ -188,7 +191,9 @@ void DrawFrameTask::run() {


    nsecs_t dequeueBufferDuration = 0;
    nsecs_t dequeueBufferDuration = 0;
    if (CC_LIKELY(canDrawThisFrame)) {
    if (CC_LIKELY(canDrawThisFrame)) {
        dequeueBufferDuration = context->draw();
        std::optional<nsecs_t> drawResult = context->draw();
        didDraw = drawResult.has_value();
        dequeueBufferDuration = drawResult.value_or(0);
    } else {
    } else {
        // Do a flush in case syncFrameState performed any texture uploads. Since we skipped
        // 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.
        // 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);
    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;
    int64_t targetWorkDuration = frameDeadline - intendedVsync;
    targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
    targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
    if (targetWorkDuration > kSanityCheckLowerBound &&
    if (targetWorkDuration > kSanityCheckLowerBound &&
@@ -219,6 +225,8 @@ void DrawFrameTask::run() {
        mLastTargetWorkDuration = targetWorkDuration;
        mLastTargetWorkDuration = targetWorkDuration;
        mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration);
        mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration);
    }
    }

    if (didDraw) {
        int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
        int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
        int64_t actualDuration = frameDuration -
        int64_t actualDuration = frameDuration -
                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
@@ -226,6 +234,7 @@ void DrawFrameTask::run() {
        if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
        if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
            mHintSessionWrapper->reportActualWorkDuration(actualDuration);
            mHintSessionWrapper->reportActualWorkDuration(actualDuration);
        }
        }
    }


    mLastDequeueBufferDuration = dequeueBufferDuration;
    mLastDequeueBufferDuration = dequeueBufferDuration;
}
}