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

Commit e08798d6 authored by Matt Buckley's avatar Matt Buckley Committed by Android (Google) Code Review
Browse files

Merge "Refactor HintSessionWrapper and move into CanvasContext"

parents c82e25e1 e9023cf4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -570,6 +570,7 @@ cc_defaults {
                "renderthread/VulkanSurface.cpp",
                "renderthread/RenderProxy.cpp",
                "renderthread/RenderThread.cpp",
                "renderthread/HintSessionWrapper.cpp",
                "service/GraphicsStatsService.cpp",
                "thread/CommonPool.cpp",
                "utils/GLUtils.cpp",
+1 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ public:
        set(FrameInfoIndex::AnimationStart) = vsyncTime;
        set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime;
        set(FrameInfoIndex::DrawStart) = vsyncTime;
        set(FrameInfoIndex::FrameStartTime) = vsyncTime;
        set(FrameInfoIndex::FrameDeadline) = frameDeadline;
        set(FrameInfoIndex::FrameInterval) = frameInterval;
        return *this;
+47 −11
Original line number Diff line number Diff line
@@ -71,16 +71,19 @@ CanvasContext* ScopedActiveContext::sActiveContext = nullptr;
} /* namespace */

CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
                                     RenderNode* rootRenderNode, IContextFactory* contextFactory) {
                                     RenderNode* rootRenderNode, IContextFactory* contextFactory,
                                     int32_t uiThreadId, int32_t renderThreadId) {
    auto renderType = Properties::getRenderPipelineType();

    switch (renderType) {
        case RenderPipelineType::SkiaGL:
            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
                                     std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
                                     std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread),
                                     uiThreadId, renderThreadId);
        case RenderPipelineType::SkiaVulkan:
            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
                                     std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
                                     std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread),
                                     uiThreadId, renderThreadId);
        default:
            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
            break;
@@ -110,7 +113,8 @@ void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {

CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                             IContextFactory* contextFactory,
                             std::unique_ptr<IRenderPipeline> renderPipeline)
                             std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId,
                             pid_t renderThreadId)
        : mRenderThread(thread)
        , mGenerationID(0)
        , mOpaque(!translucent)
@@ -118,7 +122,8 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
        , mJankTracker(&thread.globalProfileData())
        , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
        , mContentDrawBounds(0, 0, 0, 0)
        , mRenderPipeline(std::move(renderPipeline)) {
        , mRenderPipeline(std::move(renderPipeline))
        , mHintSessionWrapper(uiThreadId, renderThreadId) {
    mRenderThread.cacheManager().registerCanvasContext(this);
    rootRenderNode->makeRoot();
    mRenderNodes.emplace_back(rootRenderNode);
@@ -472,16 +477,22 @@ void CanvasContext::notifyFramePending() {
    mRenderThread.pushBackFrameCallback(this);
}

std::optional<nsecs_t> CanvasContext::draw() {
void CanvasContext::draw() {
    if (auto grContext = getGrContext()) {
        if (grContext->abandoned()) {
            LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw");
            return std::nullopt;
            return;
        }
    }
    SkRect dirty;
    mDamageAccumulator.finish(&dirty);

    // reset syncDelayDuration each time we draw
    nsecs_t syncDelayDuration = mSyncDelayDuration;
    nsecs_t idleDuration = mIdleDuration;
    mSyncDelayDuration = 0;
    mIdleDuration = 0;

    if (!Properties::isDrawingEnabled() ||
        (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) {
        mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
@@ -498,7 +509,7 @@ std::optional<nsecs_t> CanvasContext::draw() {
            std::invoke(func, false /* didProduceBuffer */);
        }
        mFrameCommitCallbacks.clear();
        return std::nullopt;
        return;
    }

    ScopedActiveContext activeContext(this);
@@ -650,10 +661,25 @@ std::optional<nsecs_t> CanvasContext::draw() {
        }
    }

    int64_t intendedVsync = mCurrentFrameInfo->get(FrameInfoIndex::IntendedVsync);
    int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline);
    int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);

    mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync);

    if (didDraw) {
        int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
        int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
        int64_t actualDuration = frameDuration -
                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
                                 dequeueBufferDuration - idleDuration;
        mHintSessionWrapper.reportActualWorkDuration(actualDuration);
    }

    mLastDequeueBufferDuration = dequeueBufferDuration;

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

void CanvasContext::reportMetricsWithPresentTime() {
@@ -766,6 +792,8 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceContro
// Called by choreographer to do an RT-driven animation
void CanvasContext::doFrame() {
    if (!mRenderPipeline->isSurfaceReady()) return;
    mIdleDuration =
            systemTime(SYSTEM_TIME_MONOTONIC) - mRenderThread.timeLord().computeFrameTimeNanos();
    prepareAndDraw(nullptr);
}

@@ -974,6 +1002,14 @@ void CanvasContext::prepareSurfaceControlForWebview() {
    }
}

void CanvasContext::sendLoadResetHint() {
    mHintSessionWrapper.sendLoadResetHint();
}

void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
    mSyncDelayDuration = duration;
}

} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
+30 −18
Original line number Diff line number Diff line
@@ -16,10 +16,26 @@

#pragma once

#include <SkBitmap.h>
#include <SkRect.h>
#include <SkSize.h>
#include <cutils/compiler.h>
#include <utils/Functor.h>
#include <utils/Mutex.h>

#include <functional>
#include <future>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "ColorMode.h"
#include "DamageAccumulator.h"
#include "FrameInfo.h"
#include "FrameInfoVisualizer.h"
#include "FrameMetricsReporter.h"
#include "HintSessionWrapper.h"
#include "IContextFactory.h"
#include "IRenderPipeline.h"
#include "JankTracker.h"
@@ -30,21 +46,6 @@
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
#include "ColorMode.h"

#include <SkBitmap.h>
#include <SkRect.h>
#include <SkSize.h>
#include <cutils/compiler.h>
#include <utils/Functor.h>
#include <utils/Mutex.h>

#include <functional>
#include <future>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace android {
namespace uirenderer {
@@ -66,7 +67,8 @@ class Frame;
class CanvasContext : public IFrameCallback {
public:
    static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                                 IContextFactory* contextFactory);
                                 IContextFactory* contextFactory, pid_t uiThreadId,
                                 pid_t renderThreadId);
    virtual ~CanvasContext();

    /**
@@ -138,7 +140,7 @@ public:
    bool makeCurrent();
    void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
    // Returns the DequeueBufferDuration.
    std::optional<nsecs_t> draw();
    void draw();
    void destroy();

    // IFrameCallback, Choreographer-driven frame callback entry point
@@ -214,9 +216,14 @@ public:

    static CanvasContext* getActiveContext();

    void sendLoadResetHint();

    void setSyncDelayDuration(nsecs_t duration);

private:
    CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                  IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
                  IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline,
                  pid_t uiThreadId, pid_t renderThreadId);

    friend class RegisterFrameCallbackTask;
    // TODO: Replace with something better for layer & other GL object
@@ -330,6 +337,11 @@ private:

    std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
    std::function<void()> mPrepareSurfaceControlForWebviewCallback;

    HintSessionWrapper mHintSessionWrapper;
    nsecs_t mLastDequeueBufferDuration = 0;
    nsecs_t mSyncDelayDuration = 0;
    nsecs_t mIdleDuration = 0;
};

} /* namespace renderthread */
+6 −153
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

#include "DrawFrameTask.h"

#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>

@@ -28,70 +27,11 @@
#include "../RenderNode.h"
#include "CanvasContext.h"
#include "RenderThread.h"
#include "thread/CommonPool.h"
#include "utils/TimeUtils.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_sendHint)(APerformanceHintSession* session, int32_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_sendHint gAPH_sendHintFn = 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_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
    LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
                        "Failed to find required symbol APerformanceHint_sendHint!");

    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)
@@ -100,13 +40,11 @@ DrawFrameTask::DrawFrameTask()

DrawFrameTask::~DrawFrameTask() {}

void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
                               int32_t uiThreadId, int32_t renderThreadId) {
void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
                               RenderNode* targetNode) {
    mRenderThread = thread;
    mContext = context;
    mTargetNode = targetNode;
    mUiThreadId = uiThreadId;
    mRenderThreadId = renderThreadId;
}

void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -150,11 +88,11 @@ void DrawFrameTask::postAndWait() {
void DrawFrameTask::run() {
    const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
    ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
    nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued;

    mContext->setSyncDelayDuration(systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued);

    bool canUnblockUiThread;
    bool canDrawThisFrame;
    bool didDraw = false;
    {
        TreeInfo info(TreeInfo::MODE_FULL, *mContext);
        info.forceDrawFrame = mForceDrawFrame;
@@ -175,9 +113,6 @@ void DrawFrameTask::run() {
    std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
    mFrameCallback = nullptr;
    mFrameCompleteCallback = 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) {
@@ -188,18 +123,15 @@ void DrawFrameTask::run() {
    if (CC_UNLIKELY(frameCallback)) {
        context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult,
                                   frameNr = context->getFrameNumber()]() {
            auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr));
            auto frameCommitCallback = frameCallback(syncResult, frameNr);
            if (frameCommitCallback) {
                context->addFrameCommitListener(std::move(frameCommitCallback));
            }
        });
    }

    nsecs_t dequeueBufferDuration = 0;
    if (CC_LIKELY(canDrawThisFrame)) {
        std::optional<nsecs_t> drawResult = context->draw();
        didDraw = drawResult.has_value();
        dequeueBufferDuration = drawResult.value_or(0);
        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.
@@ -218,41 +150,6 @@ void DrawFrameTask::run() {
    if (!canUnblockUiThread) {
        unblockUiThread();
    }

    if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);

    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 &&
        targetWorkDuration < kSanityCheckUpperBound &&
        targetWorkDuration != mLastTargetWorkDuration) {
        mLastTargetWorkDuration = targetWorkDuration;
        mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration);
    }

    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;
}

void DrawFrameTask::sendLoadResetHint() {
    if (!(Properties::useHintManager && Properties::isDrawingEnabled())) return;
    if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
    nsecs_t now = systemTime();
    if (now - mLastFrameNotification > kResetHintTimeout) {
        mHintSessionWrapper->sendHint(SessionHint::CPU_LOAD_RESET);
    }
    mLastFrameNotification = now;
}

bool DrawFrameTask::syncFrameState(TreeInfo& info) {
@@ -305,50 +202,6 @@ 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);
    }
}

void DrawFrameTask::HintSessionWrapper::sendHint(SessionHint hint) {
    if (mHintSession && Properties::isDrawingEnabled()) {
        gAPH_sendHintFn(mHintSession, static_cast<int>(hint));
    }
}

} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
Loading