diff options
Diffstat (limited to 'libs/hwui/renderthread/CanvasContext.cpp')
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 252 |
1 files changed, 185 insertions, 67 deletions
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 667a7517a24c..81cee6103d22 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -26,6 +26,7 @@ #include <cstdlib> #include <functional> +#include <gui/TraceUtils.h> #include "../Properties.h" #include "AnimationContext.h" #include "Frame.h" @@ -39,7 +40,6 @@ #include "thread/CommonPool.h" #include "utils/GLUtils.h" #include "utils/TimeUtils.h" -#include "utils/TraceUtils.h" #define TRIM_MEMORY_COMPLETE 80 #define TRIM_MEMORY_UI_HIDDEN 20 @@ -56,6 +56,22 @@ namespace android { namespace uirenderer { namespace renderthread { +namespace { +class ScopedActiveContext { +public: + ScopedActiveContext(CanvasContext* context) { sActiveContext = context; } + + ~ScopedActiveContext() { sActiveContext = nullptr; } + + static CanvasContext* getActiveContext() { return sActiveContext; } + +private: + static CanvasContext* sActiveContext; +}; + +CanvasContext* ScopedActiveContext::sActiveContext = nullptr; +} /* namespace */ + CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { auto renderType = Properties::getRenderPipelineType(); @@ -108,7 +124,6 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode->makeRoot(); mRenderNodes.emplace_back(rootRenderNode); mProfiler.setDensity(DeviceInfo::getDensity()); - setRenderAheadDepth(Properties::defaultRenderAhead); } CanvasContext::~CanvasContext() { @@ -134,6 +149,7 @@ void CanvasContext::removeRenderNode(RenderNode* node) { void CanvasContext::destroy() { stopDrawing(); setSurface(nullptr); + setSurfaceControl(nullptr); freePrefetchedLayers(); destroyHardwareResources(); mAnimationContext->destroy(); @@ -157,14 +173,6 @@ static void setBufferCount(ANativeWindow* window) { void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) { ATRACE_CALL(); - if (mRenderAheadDepth == 0 && DeviceInfo::get()->getMaxRefreshRate() > 66.6f) { - mFixedRenderAhead = false; - mRenderAheadCapacity = 1; - } else { - mFixedRenderAhead = true; - mRenderAheadCapacity = mRenderAheadDepth; - } - if (window) { mNativeSurface = std::make_unique<ReliableSurface>(window); mNativeSurface->init(); @@ -172,11 +180,36 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) { // TODO: Fix error handling & re-shorten timeout ANativeWindow_setDequeueTimeout(window, 4000_ms); } - mNativeSurface->setExtraBufferCount(mRenderAheadCapacity); } else { mNativeSurface = nullptr; } + setupPipelineSurface(); +} + +void CanvasContext::setSurfaceControl(ASurfaceControl* surfaceControl) { + if (surfaceControl == mSurfaceControl) return; + + auto funcs = mRenderThread.getASurfaceControlFunctions(); + + if (surfaceControl == nullptr) { + setASurfaceTransactionCallback(nullptr); + setPrepareSurfaceControlForWebviewCallback(nullptr); + } + + if (mSurfaceControl != nullptr) { + funcs.unregisterListenerFunc(this, &onSurfaceStatsAvailable); + funcs.releaseFunc(mSurfaceControl); + } + mSurfaceControl = surfaceControl; + mSurfaceControlGenerationId++; + mExpectSurfaceStats = surfaceControl != nullptr; + if (mSurfaceControl != nullptr) { + funcs.acquireFunc(mSurfaceControl); + funcs.registerListenerFunc(surfaceControl, this, &onSurfaceStatsAvailable); + } +} +void CanvasContext::setupPipelineSurface() { bool hasSurface = mRenderPipeline->setSurface( mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior); @@ -187,7 +220,7 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) { mFrameNumber = -1; - if (window != nullptr && hasSurface) { + if (mNativeSurface != nullptr && hasSurface) { mHaveNewSurface = true; mSwapHistory.clear(); // Enable frame stats after the surface has been bound to the appropriate graphics API. @@ -242,9 +275,9 @@ void CanvasContext::setOpaque(bool opaque) { mOpaque = opaque; } -void CanvasContext::setWideGamut(bool wideGamut) { - ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; - mRenderPipeline->setSurfaceColorProperties(colorMode); +void CanvasContext::setColorMode(ColorMode mode) { + mRenderPipeline->setSurfaceColorProperties(mode); + setupPipelineSurface(); } bool CanvasContext::makeCurrent() { @@ -321,8 +354,8 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // just keep using the previous frame's structure instead if (!wasSkipped(mCurrentFrameInfo)) { mCurrentFrameInfo = mJankTracker.startFrame(); - mLast4FrameInfos.next().first = mCurrentFrameInfo; } + mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo); mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued; mCurrentFrameInfo->markSyncStart(); @@ -426,6 +459,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy } void CanvasContext::stopDrawing() { + cleanupResources(); mRenderThread.removeFrameCallback(this); mAnimationContext->pauseAnimators(); mGenerationID++; @@ -436,25 +470,13 @@ void CanvasContext::notifyFramePending() { mRenderThread.pushBackFrameCallback(this); } -void CanvasContext::setPresentTime() { - int64_t presentTime = NATIVE_WINDOW_TIMESTAMP_AUTO; - int renderAhead = 0; - const auto frameIntervalNanos = mRenderThread.timeLord().frameIntervalNanos(); - if (mFixedRenderAhead) { - renderAhead = std::min(mRenderAheadDepth, mRenderAheadCapacity); - } else if (frameIntervalNanos < 15_ms) { - renderAhead = std::min(1, static_cast<int>(mRenderAheadCapacity)); - } - - if (renderAhead) { - presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + - (frameIntervalNanos * (renderAhead + 1)) - DeviceInfo::get()->getAppOffset() + - (frameIntervalNanos / 2); +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; + } } - native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime); -} - -void CanvasContext::draw() { SkRect dirty; mDamageAccumulator.finish(&dirty); @@ -462,18 +484,21 @@ void CanvasContext::draw() { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); // Notify the callbacks, even if there's nothing to draw so they aren't waiting // indefinitely + waitOnFences(); for (auto& func : mFrameCompleteCallbacks) { std::invoke(func, mFrameNumber); } mFrameCompleteCallbacks.clear(); - return; + return 0; } + ScopedActiveContext activeContext(this); + mCurrentFrameInfo->set(FrameInfoIndex::FrameInterval) = + mRenderThread.timeLord().frameIntervalNanos(); + mCurrentFrameInfo->markIssueDrawCommandsStart(); Frame frame = mRenderPipeline->getFrame(); - setPresentTime(); - SkRect windowDirty = computeDirtyRect(frame, &dirty); bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, @@ -484,6 +509,17 @@ void CanvasContext::draw() { waitOnFences(); + if (mNativeSurface) { + // TODO(b/165985262): measure performance impact + const auto vsyncId = mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId); + if (vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) { + const auto inputEventId = + static_cast<int32_t>(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId)); + native_window_set_frame_timeline_info(mNativeSurface->getNativeWindow(), vsyncId, + inputEventId); + } + } + bool requireSwap = false; int error = OK; bool didSwap = @@ -536,17 +572,14 @@ void CanvasContext::draw() { } mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration; - mLast4FrameInfos[-1].second = frameCompleteNr; mHaveNewSurface = false; mFrameNumber = -1; } else { mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; - mLast4FrameInfos[-1].second = -1; } - // TODO: Use a fence for real completion? - mCurrentFrameInfo->markFrameCompleted(); + mCurrentFrameInfo->markSwapBuffersCompleted(); #if LOG_FRAMETIME_MMA float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart, @@ -570,28 +603,100 @@ void CanvasContext::draw() { mFrameCompleteCallbacks.clear(); } - mJankTracker.finishFrame(*mCurrentFrameInfo); - if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { - mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); + if (requireSwap) { + if (mExpectSurfaceStats) { + reportMetricsWithPresentTime(); + std::lock_guard lock(mLast4FrameInfosMutex); + std::pair<FrameInfo*, int64_t>& next = mLast4FrameInfos.next(); + next.first = mCurrentFrameInfo; + next.second = frameCompleteNr; + } else { + mCurrentFrameInfo->markFrameCompleted(); + mCurrentFrameInfo->set(FrameInfoIndex::GpuCompleted) + = mCurrentFrameInfo->get(FrameInfoIndex::FrameCompleted); + mJankTracker.finishFrame(*mCurrentFrameInfo, mFrameMetricsReporter); + } + } + + cleanupResources(); + mRenderThread.cacheManager().onFrameCompleted(); + return mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); +} + +void CanvasContext::cleanupResources() { + auto& tracker = mJankTracker.frames(); + auto size = tracker.size(); + auto capacity = tracker.capacity(); + if (size == capacity) { + nsecs_t nowNanos = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t frameCompleteNanos = + tracker[0].get(FrameInfoIndex::FrameCompleted); + nsecs_t frameDiffNanos = nowNanos - frameCompleteNanos; + nsecs_t cleanupMillis = ns2ms(std::max(frameDiffNanos, 10_s)); + mRenderThread.cacheManager().performDeferredCleanup(cleanupMillis); + } +} + +void CanvasContext::reportMetricsWithPresentTime() { + if (mFrameMetricsReporter == nullptr) { + return; } + if (mNativeSurface == nullptr) { + return; + } + FrameInfo* forthBehind; + int64_t frameNumber; + { // acquire lock + std::scoped_lock lock(mLast4FrameInfosMutex); + if (mLast4FrameInfos.size() != mLast4FrameInfos.capacity()) { + // Not enough frames yet + return; + } + // Surface object keeps stats for the last 8 frames. + std::tie(forthBehind, frameNumber) = mLast4FrameInfos.front(); + } // release lock + + nsecs_t presentTime = 0; + native_window_get_frame_timestamps( + mNativeSurface->getNativeWindow(), frameNumber, nullptr /*outRequestedPresentTime*/, + nullptr /*outAcquireTime*/, nullptr /*outLatchTime*/, + nullptr /*outFirstRefreshStartTime*/, nullptr /*outLastRefreshStartTime*/, + nullptr /*outGpuCompositionDoneTime*/, &presentTime, nullptr /*outDequeueReadyTime*/, + nullptr /*outReleaseTime*/); + + forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime; + mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/); +} + +void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control, + ASurfaceControlStats* stats) { - if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) { - // By looking 4 frames back, we guarantee all SF stats are available. There are at - // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames. - FrameInfo* forthBehind = mLast4FrameInfos.front().first; - int64_t composedFrameId = mLast4FrameInfos.front().second; - nsecs_t acquireTime = -1; - if (mNativeSurface) { - native_window_get_frame_timestamps(mNativeSurface->getNativeWindow(), composedFrameId, - nullptr, &acquireTime, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr); + CanvasContext* instance = static_cast<CanvasContext*>(context); + + const ASurfaceControlFunctions& functions = + instance->mRenderThread.getASurfaceControlFunctions(); + + nsecs_t gpuCompleteTime = functions.getAcquireTimeFunc(stats); + uint64_t frameNumber = functions.getFrameNumberFunc(stats); + + FrameInfo* frameInfo = nullptr; + { + std::lock_guard(instance->mLast4FrameInfosMutex); + for (size_t i = 0; i < instance->mLast4FrameInfos.size(); i++) { + if (instance->mLast4FrameInfos[i].second == frameNumber) { + frameInfo = instance->mLast4FrameInfos[i].first; + break; + } } - // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING - forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1; - mJankTracker.finishGpuDraw(*forthBehind); } - mRenderThread.cacheManager().onFrameCompleted(); + if (frameInfo != nullptr) { + frameInfo->set(FrameInfoIndex::FrameCompleted) = std::max(gpuCompleteTime, + frameInfo->get(FrameInfoIndex::SwapBuffersCompleted)); + frameInfo->set(FrameInfoIndex::GpuCompleted) = gpuCompleteTime; + std::lock_guard(instance->mFrameMetricsReporterMutex); + instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter); + } } // Called by choreographer to do an RT-driven animation @@ -617,8 +722,13 @@ void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos(); + int64_t vsyncId = mRenderThread.timeLord().lastVsyncId(); + int64_t frameDeadline = mRenderThread.timeLord().lastFrameDeadline(); + int64_t frameInterval = mRenderThread.timeLord().frameIntervalNanos(); int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; - UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync); + UiFrameInfoBuilder(frameInfo) + .addFlag(FrameInfoFlags::RTAnimation) + .setVsync(vsync, vsync, vsyncId, frameDeadline, frameInterval); TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node); @@ -745,14 +855,6 @@ bool CanvasContext::surfaceRequiresRedraw() { return width != mLastFrameWidth || height != mLastFrameHeight; } -void CanvasContext::setRenderAheadDepth(int renderAhead) { - if (renderAhead > 2 || renderAhead < 0 || mNativeSurface) { - return; - } - mFixedRenderAhead = true; - mRenderAheadDepth = static_cast<uint32_t>(renderAhead); -} - SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { // can't rely on prior content of window if viewport size changes @@ -803,6 +905,22 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { return windowDirty; } +CanvasContext* CanvasContext::getActiveContext() { + return ScopedActiveContext::getActiveContext(); +} + +bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control) { + if (!mASurfaceTransactionCallback) return false; + return std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction), + reinterpret_cast<int64_t>(control), getFrameNumber()); +} + +void CanvasContext::prepareSurfaceControlForWebview() { + if (mPrepareSurfaceControlForWebviewCallback) { + std::invoke(mPrepareSurfaceControlForWebviewCallback); + } +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ |