xref: /aosp_15_r20/frameworks/base/libs/hwui/renderthread/CanvasContext.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "CanvasContext.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <apex/window.h>
20*d57664e9SAndroid Build Coastguard Worker #include <fcntl.h>
21*d57664e9SAndroid Build Coastguard Worker #include <gui/TraceUtils.h>
22*d57664e9SAndroid Build Coastguard Worker #include <strings.h>
23*d57664e9SAndroid Build Coastguard Worker #include <sys/stat.h>
24*d57664e9SAndroid Build Coastguard Worker #include <ui/Fence.h>
25*d57664e9SAndroid Build Coastguard Worker 
26*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
27*d57664e9SAndroid Build Coastguard Worker #include <cstdint>
28*d57664e9SAndroid Build Coastguard Worker #include <cstdlib>
29*d57664e9SAndroid Build Coastguard Worker #include <functional>
30*d57664e9SAndroid Build Coastguard Worker 
31*d57664e9SAndroid Build Coastguard Worker #include "../Properties.h"
32*d57664e9SAndroid Build Coastguard Worker #include "AnimationContext.h"
33*d57664e9SAndroid Build Coastguard Worker #include "Frame.h"
34*d57664e9SAndroid Build Coastguard Worker #include "LayerUpdateQueue.h"
35*d57664e9SAndroid Build Coastguard Worker #include "Properties.h"
36*d57664e9SAndroid Build Coastguard Worker #include "RenderThread.h"
37*d57664e9SAndroid Build Coastguard Worker #include "hwui/Canvas.h"
38*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaCpuPipeline.h"
39*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaGpuPipeline.h"
40*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaOpenGLPipeline.h"
41*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaVulkanPipeline.h"
42*d57664e9SAndroid Build Coastguard Worker #include "thread/CommonPool.h"
43*d57664e9SAndroid Build Coastguard Worker #include "utils/GLUtils.h"
44*d57664e9SAndroid Build Coastguard Worker #include "utils/TimeUtils.h"
45*d57664e9SAndroid Build Coastguard Worker 
46*d57664e9SAndroid Build Coastguard Worker #define LOG_FRAMETIME_MMA 0
47*d57664e9SAndroid Build Coastguard Worker 
48*d57664e9SAndroid Build Coastguard Worker #if LOG_FRAMETIME_MMA
49*d57664e9SAndroid Build Coastguard Worker static float sBenchMma = 0;
50*d57664e9SAndroid Build Coastguard Worker static int sFrameCount = 0;
51*d57664e9SAndroid Build Coastguard Worker static const float NANOS_PER_MILLIS_F = 1000000.0f;
52*d57664e9SAndroid Build Coastguard Worker #endif
53*d57664e9SAndroid Build Coastguard Worker 
54*d57664e9SAndroid Build Coastguard Worker namespace android {
55*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
56*d57664e9SAndroid Build Coastguard Worker namespace renderthread {
57*d57664e9SAndroid Build Coastguard Worker 
58*d57664e9SAndroid Build Coastguard Worker namespace {
59*d57664e9SAndroid Build Coastguard Worker class ScopedActiveContext {
60*d57664e9SAndroid Build Coastguard Worker public:
ScopedActiveContext(CanvasContext * context)61*d57664e9SAndroid Build Coastguard Worker     ScopedActiveContext(CanvasContext* context) { sActiveContext = context; }
62*d57664e9SAndroid Build Coastguard Worker 
~ScopedActiveContext()63*d57664e9SAndroid Build Coastguard Worker     ~ScopedActiveContext() { sActiveContext = nullptr; }
64*d57664e9SAndroid Build Coastguard Worker 
getActiveContext()65*d57664e9SAndroid Build Coastguard Worker     static CanvasContext* getActiveContext() { return sActiveContext; }
66*d57664e9SAndroid Build Coastguard Worker 
67*d57664e9SAndroid Build Coastguard Worker private:
68*d57664e9SAndroid Build Coastguard Worker     static CanvasContext* sActiveContext;
69*d57664e9SAndroid Build Coastguard Worker };
70*d57664e9SAndroid Build Coastguard Worker 
71*d57664e9SAndroid Build Coastguard Worker CanvasContext* ScopedActiveContext::sActiveContext = nullptr;
72*d57664e9SAndroid Build Coastguard Worker } /* namespace */
73*d57664e9SAndroid Build Coastguard Worker 
create(RenderThread & thread,bool translucent,RenderNode * rootRenderNode,IContextFactory * contextFactory,pid_t uiThreadId,pid_t renderThreadId)74*d57664e9SAndroid Build Coastguard Worker CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
75*d57664e9SAndroid Build Coastguard Worker                                      RenderNode* rootRenderNode, IContextFactory* contextFactory,
76*d57664e9SAndroid Build Coastguard Worker                                      pid_t uiThreadId, pid_t renderThreadId) {
77*d57664e9SAndroid Build Coastguard Worker     auto renderType = Properties::getRenderPipelineType();
78*d57664e9SAndroid Build Coastguard Worker 
79*d57664e9SAndroid Build Coastguard Worker     switch (renderType) {
80*d57664e9SAndroid Build Coastguard Worker         case RenderPipelineType::SkiaGL:
81*d57664e9SAndroid Build Coastguard Worker             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
82*d57664e9SAndroid Build Coastguard Worker                                      std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread),
83*d57664e9SAndroid Build Coastguard Worker                                      uiThreadId, renderThreadId);
84*d57664e9SAndroid Build Coastguard Worker         case RenderPipelineType::SkiaVulkan:
85*d57664e9SAndroid Build Coastguard Worker             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
86*d57664e9SAndroid Build Coastguard Worker                                      std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread),
87*d57664e9SAndroid Build Coastguard Worker                                      uiThreadId, renderThreadId);
88*d57664e9SAndroid Build Coastguard Worker #ifndef __ANDROID__
89*d57664e9SAndroid Build Coastguard Worker         case RenderPipelineType::SkiaCpu:
90*d57664e9SAndroid Build Coastguard Worker             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
91*d57664e9SAndroid Build Coastguard Worker                                      std::make_unique<skiapipeline::SkiaCpuPipeline>(thread),
92*d57664e9SAndroid Build Coastguard Worker                                      uiThreadId, renderThreadId);
93*d57664e9SAndroid Build Coastguard Worker #endif
94*d57664e9SAndroid Build Coastguard Worker         default:
95*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
96*d57664e9SAndroid Build Coastguard Worker             break;
97*d57664e9SAndroid Build Coastguard Worker     }
98*d57664e9SAndroid Build Coastguard Worker     return nullptr;
99*d57664e9SAndroid Build Coastguard Worker }
100*d57664e9SAndroid Build Coastguard Worker 
invokeFunctor(const RenderThread & thread,Functor * functor)101*d57664e9SAndroid Build Coastguard Worker void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) {
102*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
103*d57664e9SAndroid Build Coastguard Worker     auto renderType = Properties::getRenderPipelineType();
104*d57664e9SAndroid Build Coastguard Worker     switch (renderType) {
105*d57664e9SAndroid Build Coastguard Worker         case RenderPipelineType::SkiaGL:
106*d57664e9SAndroid Build Coastguard Worker             skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor);
107*d57664e9SAndroid Build Coastguard Worker             break;
108*d57664e9SAndroid Build Coastguard Worker         case RenderPipelineType::SkiaVulkan:
109*d57664e9SAndroid Build Coastguard Worker             skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor);
110*d57664e9SAndroid Build Coastguard Worker             break;
111*d57664e9SAndroid Build Coastguard Worker         default:
112*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
113*d57664e9SAndroid Build Coastguard Worker             break;
114*d57664e9SAndroid Build Coastguard Worker     }
115*d57664e9SAndroid Build Coastguard Worker }
116*d57664e9SAndroid Build Coastguard Worker 
prepareToDraw(const RenderThread & thread,Bitmap * bitmap)117*d57664e9SAndroid Build Coastguard Worker void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
118*d57664e9SAndroid Build Coastguard Worker     skiapipeline::SkiaGpuPipeline::prepareToDraw(thread, bitmap);
119*d57664e9SAndroid Build Coastguard Worker }
120*d57664e9SAndroid Build Coastguard Worker 
CanvasContext(RenderThread & thread,bool translucent,RenderNode * rootRenderNode,IContextFactory * contextFactory,std::unique_ptr<IRenderPipeline> renderPipeline,pid_t uiThreadId,pid_t renderThreadId)121*d57664e9SAndroid Build Coastguard Worker CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
122*d57664e9SAndroid Build Coastguard Worker                              IContextFactory* contextFactory,
123*d57664e9SAndroid Build Coastguard Worker                              std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId,
124*d57664e9SAndroid Build Coastguard Worker                              pid_t renderThreadId)
125*d57664e9SAndroid Build Coastguard Worker         : mRenderThread(thread)
126*d57664e9SAndroid Build Coastguard Worker         , mGenerationID(0)
127*d57664e9SAndroid Build Coastguard Worker         , mOpaque(!translucent)
128*d57664e9SAndroid Build Coastguard Worker         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
129*d57664e9SAndroid Build Coastguard Worker         , mJankTracker(&thread.globalProfileData())
130*d57664e9SAndroid Build Coastguard Worker         , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
131*d57664e9SAndroid Build Coastguard Worker         , mContentDrawBounds(0, 0, 0, 0)
132*d57664e9SAndroid Build Coastguard Worker         , mRenderPipeline(std::move(renderPipeline))
133*d57664e9SAndroid Build Coastguard Worker         , mHintSessionWrapper(std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId)) {
134*d57664e9SAndroid Build Coastguard Worker     mRenderThread.cacheManager().registerCanvasContext(this);
135*d57664e9SAndroid Build Coastguard Worker     mRenderThread.renderState().registerContextCallback(this);
136*d57664e9SAndroid Build Coastguard Worker     rootRenderNode->makeRoot();
137*d57664e9SAndroid Build Coastguard Worker     mRenderNodes.emplace_back(rootRenderNode);
138*d57664e9SAndroid Build Coastguard Worker     mProfiler.setDensity(DeviceInfo::getDensity());
139*d57664e9SAndroid Build Coastguard Worker }
140*d57664e9SAndroid Build Coastguard Worker 
~CanvasContext()141*d57664e9SAndroid Build Coastguard Worker CanvasContext::~CanvasContext() {
142*d57664e9SAndroid Build Coastguard Worker     destroy();
143*d57664e9SAndroid Build Coastguard Worker     for (auto& node : mRenderNodes) {
144*d57664e9SAndroid Build Coastguard Worker         node->clearRoot();
145*d57664e9SAndroid Build Coastguard Worker     }
146*d57664e9SAndroid Build Coastguard Worker     mRenderNodes.clear();
147*d57664e9SAndroid Build Coastguard Worker     mRenderThread.cacheManager().unregisterCanvasContext(this);
148*d57664e9SAndroid Build Coastguard Worker     mRenderThread.renderState().removeContextCallback(this);
149*d57664e9SAndroid Build Coastguard Worker     mHintSessionWrapper->destroy();
150*d57664e9SAndroid Build Coastguard Worker }
151*d57664e9SAndroid Build Coastguard Worker 
addRenderNode(RenderNode * node,bool placeFront)152*d57664e9SAndroid Build Coastguard Worker void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
153*d57664e9SAndroid Build Coastguard Worker     int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size());
154*d57664e9SAndroid Build Coastguard Worker     node->makeRoot();
155*d57664e9SAndroid Build Coastguard Worker     mRenderNodes.emplace(mRenderNodes.begin() + pos, node);
156*d57664e9SAndroid Build Coastguard Worker }
157*d57664e9SAndroid Build Coastguard Worker 
removeRenderNode(RenderNode * node)158*d57664e9SAndroid Build Coastguard Worker void CanvasContext::removeRenderNode(RenderNode* node) {
159*d57664e9SAndroid Build Coastguard Worker     node->clearRoot();
160*d57664e9SAndroid Build Coastguard Worker     mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
161*d57664e9SAndroid Build Coastguard Worker                        mRenderNodes.end());
162*d57664e9SAndroid Build Coastguard Worker }
163*d57664e9SAndroid Build Coastguard Worker 
destroy()164*d57664e9SAndroid Build Coastguard Worker void CanvasContext::destroy() {
165*d57664e9SAndroid Build Coastguard Worker     stopDrawing();
166*d57664e9SAndroid Build Coastguard Worker     setHardwareBuffer(nullptr);
167*d57664e9SAndroid Build Coastguard Worker     setSurface(nullptr);
168*d57664e9SAndroid Build Coastguard Worker     setSurfaceControl(nullptr);
169*d57664e9SAndroid Build Coastguard Worker     freePrefetchedLayers();
170*d57664e9SAndroid Build Coastguard Worker     destroyHardwareResources();
171*d57664e9SAndroid Build Coastguard Worker     mAnimationContext->destroy();
172*d57664e9SAndroid Build Coastguard Worker     mRenderThread.cacheManager().onContextStopped(this);
173*d57664e9SAndroid Build Coastguard Worker     mHintSessionWrapper->delayedDestroy(mRenderThread, 2_s, mHintSessionWrapper);
174*d57664e9SAndroid Build Coastguard Worker }
175*d57664e9SAndroid Build Coastguard Worker 
setBufferCount(ANativeWindow * window)176*d57664e9SAndroid Build Coastguard Worker static void setBufferCount(ANativeWindow* window) {
177*d57664e9SAndroid Build Coastguard Worker     int query_value;
178*d57664e9SAndroid Build Coastguard Worker     int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
179*d57664e9SAndroid Build Coastguard Worker     if (err != 0 || query_value < 0) {
180*d57664e9SAndroid Build Coastguard Worker         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
181*d57664e9SAndroid Build Coastguard Worker         return;
182*d57664e9SAndroid Build Coastguard Worker     }
183*d57664e9SAndroid Build Coastguard Worker     auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
184*d57664e9SAndroid Build Coastguard Worker 
185*d57664e9SAndroid Build Coastguard Worker     // We only need to set min_undequeued + 2 because the renderahead amount was already factored into the
186*d57664e9SAndroid Build Coastguard Worker     // query for min_undequeued
187*d57664e9SAndroid Build Coastguard Worker     int bufferCount = min_undequeued_buffers + 2;
188*d57664e9SAndroid Build Coastguard Worker     native_window_set_buffer_count(window, bufferCount);
189*d57664e9SAndroid Build Coastguard Worker }
190*d57664e9SAndroid Build Coastguard Worker 
setHardwareBuffer(AHardwareBuffer * buffer)191*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setHardwareBuffer(AHardwareBuffer* buffer) {
192*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
193*d57664e9SAndroid Build Coastguard Worker     if (mHardwareBuffer) {
194*d57664e9SAndroid Build Coastguard Worker         AHardwareBuffer_release(mHardwareBuffer);
195*d57664e9SAndroid Build Coastguard Worker         mHardwareBuffer = nullptr;
196*d57664e9SAndroid Build Coastguard Worker     }
197*d57664e9SAndroid Build Coastguard Worker 
198*d57664e9SAndroid Build Coastguard Worker     if (buffer) {
199*d57664e9SAndroid Build Coastguard Worker         AHardwareBuffer_acquire(buffer);
200*d57664e9SAndroid Build Coastguard Worker         mHardwareBuffer = buffer;
201*d57664e9SAndroid Build Coastguard Worker     }
202*d57664e9SAndroid Build Coastguard Worker     mRenderPipeline->setHardwareBuffer(mHardwareBuffer);
203*d57664e9SAndroid Build Coastguard Worker #endif
204*d57664e9SAndroid Build Coastguard Worker }
205*d57664e9SAndroid Build Coastguard Worker 
setSurface(ANativeWindow * window,bool enableTimeout)206*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
207*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
208*d57664e9SAndroid Build Coastguard Worker 
209*d57664e9SAndroid Build Coastguard Worker     startHintSession();
210*d57664e9SAndroid Build Coastguard Worker     if (window) {
211*d57664e9SAndroid Build Coastguard Worker         mNativeSurface = std::make_unique<ReliableSurface>(window);
212*d57664e9SAndroid Build Coastguard Worker         mNativeSurface->init();
213*d57664e9SAndroid Build Coastguard Worker         if (enableTimeout) {
214*d57664e9SAndroid Build Coastguard Worker             // TODO: Fix error handling & re-shorten timeout
215*d57664e9SAndroid Build Coastguard Worker             ANativeWindow_setDequeueTimeout(window, 4000_ms);
216*d57664e9SAndroid Build Coastguard Worker         }
217*d57664e9SAndroid Build Coastguard Worker     } else {
218*d57664e9SAndroid Build Coastguard Worker         mNativeSurface = nullptr;
219*d57664e9SAndroid Build Coastguard Worker     }
220*d57664e9SAndroid Build Coastguard Worker     setupPipelineSurface();
221*d57664e9SAndroid Build Coastguard Worker }
222*d57664e9SAndroid Build Coastguard Worker 
setSurfaceControl(ASurfaceControl * surfaceControl)223*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setSurfaceControl(ASurfaceControl* surfaceControl) {
224*d57664e9SAndroid Build Coastguard Worker     if (surfaceControl == mSurfaceControl) return;
225*d57664e9SAndroid Build Coastguard Worker 
226*d57664e9SAndroid Build Coastguard Worker     auto funcs = mRenderThread.getASurfaceControlFunctions();
227*d57664e9SAndroid Build Coastguard Worker 
228*d57664e9SAndroid Build Coastguard Worker     if (surfaceControl == nullptr) {
229*d57664e9SAndroid Build Coastguard Worker         setASurfaceTransactionCallback(nullptr);
230*d57664e9SAndroid Build Coastguard Worker         setPrepareSurfaceControlForWebviewCallback(nullptr);
231*d57664e9SAndroid Build Coastguard Worker     }
232*d57664e9SAndroid Build Coastguard Worker 
233*d57664e9SAndroid Build Coastguard Worker     if (mSurfaceControl != nullptr) {
234*d57664e9SAndroid Build Coastguard Worker         funcs.unregisterListenerFunc(this, &onSurfaceStatsAvailable);
235*d57664e9SAndroid Build Coastguard Worker         funcs.releaseFunc(mSurfaceControl);
236*d57664e9SAndroid Build Coastguard Worker     }
237*d57664e9SAndroid Build Coastguard Worker     mSurfaceControl = surfaceControl;
238*d57664e9SAndroid Build Coastguard Worker     mSurfaceControlGenerationId++;
239*d57664e9SAndroid Build Coastguard Worker     mExpectSurfaceStats = surfaceControl != nullptr;
240*d57664e9SAndroid Build Coastguard Worker     if (mExpectSurfaceStats) {
241*d57664e9SAndroid Build Coastguard Worker         funcs.acquireFunc(mSurfaceControl);
242*d57664e9SAndroid Build Coastguard Worker         funcs.registerListenerFunc(surfaceControl, mSurfaceControlGenerationId, this,
243*d57664e9SAndroid Build Coastguard Worker                                    &onSurfaceStatsAvailable);
244*d57664e9SAndroid Build Coastguard Worker     }
245*d57664e9SAndroid Build Coastguard Worker }
246*d57664e9SAndroid Build Coastguard Worker 
setupPipelineSurface()247*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setupPipelineSurface() {
248*d57664e9SAndroid Build Coastguard Worker     bool hasSurface = mRenderPipeline->setSurface(
249*d57664e9SAndroid Build Coastguard Worker             mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
250*d57664e9SAndroid Build Coastguard Worker 
251*d57664e9SAndroid Build Coastguard Worker     if (mNativeSurface && !mNativeSurface->didSetExtraBuffers()) {
252*d57664e9SAndroid Build Coastguard Worker         setBufferCount(mNativeSurface->getNativeWindow());
253*d57664e9SAndroid Build Coastguard Worker     }
254*d57664e9SAndroid Build Coastguard Worker 
255*d57664e9SAndroid Build Coastguard Worker     mFrameNumber = 0;
256*d57664e9SAndroid Build Coastguard Worker 
257*d57664e9SAndroid Build Coastguard Worker     if (mNativeSurface != nullptr && hasSurface) {
258*d57664e9SAndroid Build Coastguard Worker         mHaveNewSurface = true;
259*d57664e9SAndroid Build Coastguard Worker         mSwapHistory.clear();
260*d57664e9SAndroid Build Coastguard Worker         // Enable frame stats after the surface has been bound to the appropriate graphics API.
261*d57664e9SAndroid Build Coastguard Worker         // Order is important when new and old surfaces are the same, because old surface has
262*d57664e9SAndroid Build Coastguard Worker         // its frame stats disabled automatically.
263*d57664e9SAndroid Build Coastguard Worker         native_window_enable_frame_timestamps(mNativeSurface->getNativeWindow(), true);
264*d57664e9SAndroid Build Coastguard Worker         native_window_set_scaling_mode(mNativeSurface->getNativeWindow(),
265*d57664e9SAndroid Build Coastguard Worker                                        NATIVE_WINDOW_SCALING_MODE_FREEZE);
266*d57664e9SAndroid Build Coastguard Worker     } else {
267*d57664e9SAndroid Build Coastguard Worker         mRenderThread.removeFrameCallback(this);
268*d57664e9SAndroid Build Coastguard Worker         mGenerationID++;
269*d57664e9SAndroid Build Coastguard Worker     }
270*d57664e9SAndroid Build Coastguard Worker }
271*d57664e9SAndroid Build Coastguard Worker 
setSwapBehavior(SwapBehavior swapBehavior)272*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
273*d57664e9SAndroid Build Coastguard Worker     mSwapBehavior = swapBehavior;
274*d57664e9SAndroid Build Coastguard Worker }
275*d57664e9SAndroid Build Coastguard Worker 
pauseSurface()276*d57664e9SAndroid Build Coastguard Worker bool CanvasContext::pauseSurface() {
277*d57664e9SAndroid Build Coastguard Worker     mGenerationID++;
278*d57664e9SAndroid Build Coastguard Worker     return mRenderThread.removeFrameCallback(this);
279*d57664e9SAndroid Build Coastguard Worker }
280*d57664e9SAndroid Build Coastguard Worker 
setStopped(bool stopped)281*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setStopped(bool stopped) {
282*d57664e9SAndroid Build Coastguard Worker     if (mStopped != stopped) {
283*d57664e9SAndroid Build Coastguard Worker         mStopped = stopped;
284*d57664e9SAndroid Build Coastguard Worker         if (mStopped) {
285*d57664e9SAndroid Build Coastguard Worker             mGenerationID++;
286*d57664e9SAndroid Build Coastguard Worker             mRenderThread.removeFrameCallback(this);
287*d57664e9SAndroid Build Coastguard Worker             mRenderPipeline->onStop();
288*d57664e9SAndroid Build Coastguard Worker             mRenderThread.cacheManager().onContextStopped(this);
289*d57664e9SAndroid Build Coastguard Worker         } else if (mIsDirty && hasOutputTarget()) {
290*d57664e9SAndroid Build Coastguard Worker             mRenderThread.postFrameCallback(this);
291*d57664e9SAndroid Build Coastguard Worker         }
292*d57664e9SAndroid Build Coastguard Worker     }
293*d57664e9SAndroid Build Coastguard Worker }
294*d57664e9SAndroid Build Coastguard Worker 
allocateBuffers()295*d57664e9SAndroid Build Coastguard Worker void CanvasContext::allocateBuffers() {
296*d57664e9SAndroid Build Coastguard Worker     if (mNativeSurface && Properties::isDrawingEnabled()) {
297*d57664e9SAndroid Build Coastguard Worker         ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow());
298*d57664e9SAndroid Build Coastguard Worker     }
299*d57664e9SAndroid Build Coastguard Worker }
300*d57664e9SAndroid Build Coastguard Worker 
setLightAlpha(uint8_t ambientShadowAlpha,uint8_t spotShadowAlpha)301*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
302*d57664e9SAndroid Build Coastguard Worker     mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
303*d57664e9SAndroid Build Coastguard Worker     mLightInfo.spotShadowAlpha = spotShadowAlpha;
304*d57664e9SAndroid Build Coastguard Worker }
305*d57664e9SAndroid Build Coastguard Worker 
setLightGeometry(const Vector3 & lightCenter,float lightRadius)306*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setLightGeometry(const Vector3& lightCenter, float lightRadius) {
307*d57664e9SAndroid Build Coastguard Worker     mLightGeometry.center = lightCenter;
308*d57664e9SAndroid Build Coastguard Worker     mLightGeometry.radius = lightRadius;
309*d57664e9SAndroid Build Coastguard Worker }
310*d57664e9SAndroid Build Coastguard Worker 
setOpaque(bool opaque)311*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setOpaque(bool opaque) {
312*d57664e9SAndroid Build Coastguard Worker     mOpaque = opaque;
313*d57664e9SAndroid Build Coastguard Worker }
314*d57664e9SAndroid Build Coastguard Worker 
setColorMode(ColorMode mode)315*d57664e9SAndroid Build Coastguard Worker float CanvasContext::setColorMode(ColorMode mode) {
316*d57664e9SAndroid Build Coastguard Worker     if (mode != mColorMode) {
317*d57664e9SAndroid Build Coastguard Worker         mColorMode = mode;
318*d57664e9SAndroid Build Coastguard Worker         mRenderPipeline->setSurfaceColorProperties(mode);
319*d57664e9SAndroid Build Coastguard Worker         setupPipelineSurface();
320*d57664e9SAndroid Build Coastguard Worker     }
321*d57664e9SAndroid Build Coastguard Worker     switch (mColorMode) {
322*d57664e9SAndroid Build Coastguard Worker         case ColorMode::Hdr:
323*d57664e9SAndroid Build Coastguard Worker             return Properties::maxHdrHeadroomOn8bit;
324*d57664e9SAndroid Build Coastguard Worker         case ColorMode::Hdr10:
325*d57664e9SAndroid Build Coastguard Worker             return 10.f;
326*d57664e9SAndroid Build Coastguard Worker         default:
327*d57664e9SAndroid Build Coastguard Worker             return 1.f;
328*d57664e9SAndroid Build Coastguard Worker     }
329*d57664e9SAndroid Build Coastguard Worker }
330*d57664e9SAndroid Build Coastguard Worker 
targetSdrHdrRatio() const331*d57664e9SAndroid Build Coastguard Worker float CanvasContext::targetSdrHdrRatio() const {
332*d57664e9SAndroid Build Coastguard Worker     if (mColorMode == ColorMode::Hdr || mColorMode == ColorMode::Hdr10) {
333*d57664e9SAndroid Build Coastguard Worker         return mTargetSdrHdrRatio;
334*d57664e9SAndroid Build Coastguard Worker     } else {
335*d57664e9SAndroid Build Coastguard Worker         return 1.f;
336*d57664e9SAndroid Build Coastguard Worker     }
337*d57664e9SAndroid Build Coastguard Worker }
338*d57664e9SAndroid Build Coastguard Worker 
setTargetSdrHdrRatio(float ratio)339*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setTargetSdrHdrRatio(float ratio) {
340*d57664e9SAndroid Build Coastguard Worker     if (mTargetSdrHdrRatio == ratio) return;
341*d57664e9SAndroid Build Coastguard Worker 
342*d57664e9SAndroid Build Coastguard Worker     mTargetSdrHdrRatio = ratio;
343*d57664e9SAndroid Build Coastguard Worker     mRenderPipeline->setTargetSdrHdrRatio(ratio);
344*d57664e9SAndroid Build Coastguard Worker     // We don't actually but we need to behave as if we do. Specifically we need to ensure
345*d57664e9SAndroid Build Coastguard Worker     // all buffers in the swapchain are fully re-rendered as any partial updates to them will
346*d57664e9SAndroid Build Coastguard Worker     // result in mixed target white points which looks really bad & flickery
347*d57664e9SAndroid Build Coastguard Worker     mHaveNewSurface = true;
348*d57664e9SAndroid Build Coastguard Worker }
349*d57664e9SAndroid Build Coastguard Worker 
makeCurrent()350*d57664e9SAndroid Build Coastguard Worker bool CanvasContext::makeCurrent() {
351*d57664e9SAndroid Build Coastguard Worker     if (mStopped) return false;
352*d57664e9SAndroid Build Coastguard Worker 
353*d57664e9SAndroid Build Coastguard Worker     auto result = mRenderPipeline->makeCurrent();
354*d57664e9SAndroid Build Coastguard Worker     switch (result) {
355*d57664e9SAndroid Build Coastguard Worker         case MakeCurrentResult::AlreadyCurrent:
356*d57664e9SAndroid Build Coastguard Worker             return true;
357*d57664e9SAndroid Build Coastguard Worker         case MakeCurrentResult::Failed:
358*d57664e9SAndroid Build Coastguard Worker             mHaveNewSurface = true;
359*d57664e9SAndroid Build Coastguard Worker             setSurface(nullptr);
360*d57664e9SAndroid Build Coastguard Worker             return false;
361*d57664e9SAndroid Build Coastguard Worker         case MakeCurrentResult::Succeeded:
362*d57664e9SAndroid Build Coastguard Worker             mHaveNewSurface = true;
363*d57664e9SAndroid Build Coastguard Worker             return true;
364*d57664e9SAndroid Build Coastguard Worker         default:
365*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent",
366*d57664e9SAndroid Build Coastguard Worker                              (int32_t)result);
367*d57664e9SAndroid Build Coastguard Worker     }
368*d57664e9SAndroid Build Coastguard Worker 
369*d57664e9SAndroid Build Coastguard Worker     return true;
370*d57664e9SAndroid Build Coastguard Worker }
371*d57664e9SAndroid Build Coastguard Worker 
wasSkipped(FrameInfo * info)372*d57664e9SAndroid Build Coastguard Worker static std::optional<SkippedFrameReason> wasSkipped(FrameInfo* info) {
373*d57664e9SAndroid Build Coastguard Worker     if (info) return info->getSkippedFrameReason();
374*d57664e9SAndroid Build Coastguard Worker     return std::nullopt;
375*d57664e9SAndroid Build Coastguard Worker }
376*d57664e9SAndroid Build Coastguard Worker 
isSwapChainStuffed()377*d57664e9SAndroid Build Coastguard Worker bool CanvasContext::isSwapChainStuffed() {
378*d57664e9SAndroid Build Coastguard Worker     static const auto SLOW_THRESHOLD = 6_ms;
379*d57664e9SAndroid Build Coastguard Worker 
380*d57664e9SAndroid Build Coastguard Worker     if (mSwapHistory.size() != mSwapHistory.capacity()) {
381*d57664e9SAndroid Build Coastguard Worker         // We want at least 3 frames of history before attempting to
382*d57664e9SAndroid Build Coastguard Worker         // guess if the queue is stuffed
383*d57664e9SAndroid Build Coastguard Worker         return false;
384*d57664e9SAndroid Build Coastguard Worker     }
385*d57664e9SAndroid Build Coastguard Worker     nsecs_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
386*d57664e9SAndroid Build Coastguard Worker     auto& swapA = mSwapHistory[0];
387*d57664e9SAndroid Build Coastguard Worker 
388*d57664e9SAndroid Build Coastguard Worker     // Was there a happy queue & dequeue time? If so, don't
389*d57664e9SAndroid Build Coastguard Worker     // consider it stuffed
390*d57664e9SAndroid Build Coastguard Worker     if (swapA.dequeueDuration < SLOW_THRESHOLD && swapA.queueDuration < SLOW_THRESHOLD) {
391*d57664e9SAndroid Build Coastguard Worker         return false;
392*d57664e9SAndroid Build Coastguard Worker     }
393*d57664e9SAndroid Build Coastguard Worker 
394*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 1; i < mSwapHistory.size(); i++) {
395*d57664e9SAndroid Build Coastguard Worker         auto& swapB = mSwapHistory[i];
396*d57664e9SAndroid Build Coastguard Worker 
397*d57664e9SAndroid Build Coastguard Worker         // If there's a multi-frameInterval gap we effectively already dropped a frame,
398*d57664e9SAndroid Build Coastguard Worker         // so consider the queue healthy.
399*d57664e9SAndroid Build Coastguard Worker         if (std::abs(swapA.swapCompletedTime - swapB.swapCompletedTime) > frameInterval * 3) {
400*d57664e9SAndroid Build Coastguard Worker             return false;
401*d57664e9SAndroid Build Coastguard Worker         }
402*d57664e9SAndroid Build Coastguard Worker 
403*d57664e9SAndroid Build Coastguard Worker         // Was there a happy queue & dequeue time? If so, don't
404*d57664e9SAndroid Build Coastguard Worker         // consider it stuffed
405*d57664e9SAndroid Build Coastguard Worker         if (swapB.dequeueDuration < SLOW_THRESHOLD && swapB.queueDuration < SLOW_THRESHOLD) {
406*d57664e9SAndroid Build Coastguard Worker             return false;
407*d57664e9SAndroid Build Coastguard Worker         }
408*d57664e9SAndroid Build Coastguard Worker 
409*d57664e9SAndroid Build Coastguard Worker         swapA = swapB;
410*d57664e9SAndroid Build Coastguard Worker     }
411*d57664e9SAndroid Build Coastguard Worker 
412*d57664e9SAndroid Build Coastguard Worker     // All signs point to a stuffed swap chain
413*d57664e9SAndroid Build Coastguard Worker     ATRACE_NAME("swap chain stuffed");
414*d57664e9SAndroid Build Coastguard Worker     return true;
415*d57664e9SAndroid Build Coastguard Worker }
416*d57664e9SAndroid Build Coastguard Worker 
prepareTree(TreeInfo & info,int64_t * uiFrameInfo,int64_t syncQueued,RenderNode * target)417*d57664e9SAndroid Build Coastguard Worker void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
418*d57664e9SAndroid Build Coastguard Worker                                 RenderNode* target) {
419*d57664e9SAndroid Build Coastguard Worker     mRenderThread.removeFrameCallback(this);
420*d57664e9SAndroid Build Coastguard Worker 
421*d57664e9SAndroid Build Coastguard Worker     // Make sure we have a valid device info
422*d57664e9SAndroid Build Coastguard Worker     if (!DeviceInfo::get()->hasMaxTextureSize()) {
423*d57664e9SAndroid Build Coastguard Worker         (void)mRenderThread.requireGrContext();
424*d57664e9SAndroid Build Coastguard Worker     }
425*d57664e9SAndroid Build Coastguard Worker 
426*d57664e9SAndroid Build Coastguard Worker     // If the previous frame was dropped we don't need to hold onto it, so
427*d57664e9SAndroid Build Coastguard Worker     // just keep using the previous frame's structure instead
428*d57664e9SAndroid Build Coastguard Worker     const auto reason = wasSkipped(mCurrentFrameInfo);
429*d57664e9SAndroid Build Coastguard Worker     if (reason.has_value()) {
430*d57664e9SAndroid Build Coastguard Worker         // Use the oldest skipped frame in case we skip more than a single frame
431*d57664e9SAndroid Build Coastguard Worker         if (!mSkippedFrameInfo) {
432*d57664e9SAndroid Build Coastguard Worker             switch (*reason) {
433*d57664e9SAndroid Build Coastguard Worker                 case SkippedFrameReason::AlreadyDrawn:
434*d57664e9SAndroid Build Coastguard Worker                 case SkippedFrameReason::NoBuffer:
435*d57664e9SAndroid Build Coastguard Worker                 case SkippedFrameReason::NoOutputTarget:
436*d57664e9SAndroid Build Coastguard Worker                     mSkippedFrameInfo.emplace();
437*d57664e9SAndroid Build Coastguard Worker                     mSkippedFrameInfo->vsyncId =
438*d57664e9SAndroid Build Coastguard Worker                             mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
439*d57664e9SAndroid Build Coastguard Worker                     mSkippedFrameInfo->startTime =
440*d57664e9SAndroid Build Coastguard Worker                             mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
441*d57664e9SAndroid Build Coastguard Worker                     break;
442*d57664e9SAndroid Build Coastguard Worker                 case SkippedFrameReason::DrawingOff:
443*d57664e9SAndroid Build Coastguard Worker                 case SkippedFrameReason::ContextIsStopped:
444*d57664e9SAndroid Build Coastguard Worker                 case SkippedFrameReason::NothingToDraw:
445*d57664e9SAndroid Build Coastguard Worker                     // Do not report those as skipped frames as there was no frame expected to be
446*d57664e9SAndroid Build Coastguard Worker                     // drawn
447*d57664e9SAndroid Build Coastguard Worker                     break;
448*d57664e9SAndroid Build Coastguard Worker             }
449*d57664e9SAndroid Build Coastguard Worker         }
450*d57664e9SAndroid Build Coastguard Worker     } else {
451*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo = mJankTracker.startFrame();
452*d57664e9SAndroid Build Coastguard Worker         mSkippedFrameInfo.reset();
453*d57664e9SAndroid Build Coastguard Worker     }
454*d57664e9SAndroid Build Coastguard Worker 
455*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
456*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
457*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->markSyncStart();
458*d57664e9SAndroid Build Coastguard Worker 
459*d57664e9SAndroid Build Coastguard Worker     info.damageAccumulator = &mDamageAccumulator;
460*d57664e9SAndroid Build Coastguard Worker     info.layerUpdateQueue = &mLayerUpdateQueue;
461*d57664e9SAndroid Build Coastguard Worker     info.damageGenerationId = mDamageId++;
462*d57664e9SAndroid Build Coastguard Worker     info.out.skippedFrameReason = std::nullopt;
463*d57664e9SAndroid Build Coastguard Worker 
464*d57664e9SAndroid Build Coastguard Worker     mAnimationContext->startFrame(info.mode);
465*d57664e9SAndroid Build Coastguard Worker     for (const sp<RenderNode>& node : mRenderNodes) {
466*d57664e9SAndroid Build Coastguard Worker         // Only the primary target node will be drawn full - all other nodes would get drawn in
467*d57664e9SAndroid Build Coastguard Worker         // real time mode. In case of a window, the primary node is the window content and the other
468*d57664e9SAndroid Build Coastguard Worker         // node(s) are non client / filler nodes.
469*d57664e9SAndroid Build Coastguard Worker         info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
470*d57664e9SAndroid Build Coastguard Worker         node->prepareTree(info);
471*d57664e9SAndroid Build Coastguard Worker         GL_CHECKPOINT(MODERATE);
472*d57664e9SAndroid Build Coastguard Worker     }
473*d57664e9SAndroid Build Coastguard Worker     mAnimationContext->runRemainingAnimations(info);
474*d57664e9SAndroid Build Coastguard Worker     GL_CHECKPOINT(MODERATE);
475*d57664e9SAndroid Build Coastguard Worker 
476*d57664e9SAndroid Build Coastguard Worker     freePrefetchedLayers();
477*d57664e9SAndroid Build Coastguard Worker     GL_CHECKPOINT(MODERATE);
478*d57664e9SAndroid Build Coastguard Worker 
479*d57664e9SAndroid Build Coastguard Worker     mIsDirty = true;
480*d57664e9SAndroid Build Coastguard Worker 
481*d57664e9SAndroid Build Coastguard Worker     if (CC_UNLIKELY(!hasOutputTarget())) {
482*d57664e9SAndroid Build Coastguard Worker         info.out.skippedFrameReason = SkippedFrameReason::NoOutputTarget;
483*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->setSkippedFrameReason(*info.out.skippedFrameReason);
484*d57664e9SAndroid Build Coastguard Worker         return;
485*d57664e9SAndroid Build Coastguard Worker     }
486*d57664e9SAndroid Build Coastguard Worker 
487*d57664e9SAndroid Build Coastguard Worker     if (CC_LIKELY(mSwapHistory.size() && !info.forceDrawFrame)) {
488*d57664e9SAndroid Build Coastguard Worker         nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
489*d57664e9SAndroid Build Coastguard Worker         SwapHistory& lastSwap = mSwapHistory.back();
490*d57664e9SAndroid Build Coastguard Worker         nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
491*d57664e9SAndroid Build Coastguard Worker         // The slight fudge-factor is to deal with cases where
492*d57664e9SAndroid Build Coastguard Worker         // the vsync was estimated due to being slow handling the signal.
493*d57664e9SAndroid Build Coastguard Worker         // See the logic in TimeLord#computeFrameTimeNanos or in
494*d57664e9SAndroid Build Coastguard Worker         // Choreographer.java for details on when this happens
495*d57664e9SAndroid Build Coastguard Worker         if (vsyncDelta < 2_ms) {
496*d57664e9SAndroid Build Coastguard Worker             // Already drew for this vsync pulse, UI draw request missed
497*d57664e9SAndroid Build Coastguard Worker             // the deadline for RT animations
498*d57664e9SAndroid Build Coastguard Worker             info.out.skippedFrameReason = SkippedFrameReason::AlreadyDrawn;
499*d57664e9SAndroid Build Coastguard Worker         }
500*d57664e9SAndroid Build Coastguard Worker     } else {
501*d57664e9SAndroid Build Coastguard Worker         info.out.skippedFrameReason = std::nullopt;
502*d57664e9SAndroid Build Coastguard Worker     }
503*d57664e9SAndroid Build Coastguard Worker 
504*d57664e9SAndroid Build Coastguard Worker     // TODO: Do we need to abort out if the backdrop is added but not ready? Should that even
505*d57664e9SAndroid Build Coastguard Worker     // be an allowable combination?
506*d57664e9SAndroid Build Coastguard Worker     if (mRenderNodes.size() > 2 && !mRenderNodes[1]->isRenderable()) {
507*d57664e9SAndroid Build Coastguard Worker         info.out.skippedFrameReason = SkippedFrameReason::NothingToDraw;
508*d57664e9SAndroid Build Coastguard Worker     }
509*d57664e9SAndroid Build Coastguard Worker 
510*d57664e9SAndroid Build Coastguard Worker     if (!info.out.skippedFrameReason) {
511*d57664e9SAndroid Build Coastguard Worker         int err = mNativeSurface->reserveNext();
512*d57664e9SAndroid Build Coastguard Worker         if (err != OK) {
513*d57664e9SAndroid Build Coastguard Worker             info.out.skippedFrameReason = SkippedFrameReason::NoBuffer;
514*d57664e9SAndroid Build Coastguard Worker             mCurrentFrameInfo->setSkippedFrameReason(*info.out.skippedFrameReason);
515*d57664e9SAndroid Build Coastguard Worker             ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err));
516*d57664e9SAndroid Build Coastguard Worker             if (err != TIMED_OUT) {
517*d57664e9SAndroid Build Coastguard Worker                 // A timed out surface can still recover, but assume others are permanently dead.
518*d57664e9SAndroid Build Coastguard Worker                 setSurface(nullptr);
519*d57664e9SAndroid Build Coastguard Worker                 return;
520*d57664e9SAndroid Build Coastguard Worker             }
521*d57664e9SAndroid Build Coastguard Worker         }
522*d57664e9SAndroid Build Coastguard Worker     } else {
523*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->setSkippedFrameReason(*info.out.skippedFrameReason);
524*d57664e9SAndroid Build Coastguard Worker     }
525*d57664e9SAndroid Build Coastguard Worker 
526*d57664e9SAndroid Build Coastguard Worker     bool postedFrameCallback = false;
527*d57664e9SAndroid Build Coastguard Worker     if (info.out.hasAnimations || info.out.skippedFrameReason) {
528*d57664e9SAndroid Build Coastguard Worker         if (CC_UNLIKELY(!Properties::enableRTAnimations)) {
529*d57664e9SAndroid Build Coastguard Worker             info.out.requiresUiRedraw = true;
530*d57664e9SAndroid Build Coastguard Worker         }
531*d57664e9SAndroid Build Coastguard Worker         if (!info.out.requiresUiRedraw) {
532*d57664e9SAndroid Build Coastguard Worker             // If animationsNeedsRedraw is set don't bother posting for an RT anim
533*d57664e9SAndroid Build Coastguard Worker             // as we will just end up fighting the UI thread.
534*d57664e9SAndroid Build Coastguard Worker             mRenderThread.postFrameCallback(this);
535*d57664e9SAndroid Build Coastguard Worker             postedFrameCallback = true;
536*d57664e9SAndroid Build Coastguard Worker         }
537*d57664e9SAndroid Build Coastguard Worker     }
538*d57664e9SAndroid Build Coastguard Worker 
539*d57664e9SAndroid Build Coastguard Worker     if (!postedFrameCallback &&
540*d57664e9SAndroid Build Coastguard Worker         info.out.animatedImageDelay != TreeInfo::Out::kNoAnimatedImageDelay) {
541*d57664e9SAndroid Build Coastguard Worker         // Subtract the time of one frame so it can be displayed on time.
542*d57664e9SAndroid Build Coastguard Worker         const nsecs_t kFrameTime = mRenderThread.timeLord().frameIntervalNanos();
543*d57664e9SAndroid Build Coastguard Worker         if (info.out.animatedImageDelay <= kFrameTime) {
544*d57664e9SAndroid Build Coastguard Worker             mRenderThread.postFrameCallback(this);
545*d57664e9SAndroid Build Coastguard Worker         } else {
546*d57664e9SAndroid Build Coastguard Worker             const auto delay = info.out.animatedImageDelay - kFrameTime;
547*d57664e9SAndroid Build Coastguard Worker             int genId = mGenerationID;
548*d57664e9SAndroid Build Coastguard Worker             mRenderThread.queue().postDelayed(delay, [this, genId]() {
549*d57664e9SAndroid Build Coastguard Worker                 if (mGenerationID == genId) {
550*d57664e9SAndroid Build Coastguard Worker                     mRenderThread.postFrameCallback(this);
551*d57664e9SAndroid Build Coastguard Worker                 }
552*d57664e9SAndroid Build Coastguard Worker             });
553*d57664e9SAndroid Build Coastguard Worker         }
554*d57664e9SAndroid Build Coastguard Worker     }
555*d57664e9SAndroid Build Coastguard Worker }
556*d57664e9SAndroid Build Coastguard Worker 
stopDrawing()557*d57664e9SAndroid Build Coastguard Worker void CanvasContext::stopDrawing() {
558*d57664e9SAndroid Build Coastguard Worker     mRenderThread.removeFrameCallback(this);
559*d57664e9SAndroid Build Coastguard Worker     mAnimationContext->pauseAnimators();
560*d57664e9SAndroid Build Coastguard Worker     mGenerationID++;
561*d57664e9SAndroid Build Coastguard Worker }
562*d57664e9SAndroid Build Coastguard Worker 
notifyFramePending()563*d57664e9SAndroid Build Coastguard Worker void CanvasContext::notifyFramePending() {
564*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
565*d57664e9SAndroid Build Coastguard Worker     mRenderThread.pushBackFrameCallback(this);
566*d57664e9SAndroid Build Coastguard Worker     sendLoadResetHint();
567*d57664e9SAndroid Build Coastguard Worker }
568*d57664e9SAndroid Build Coastguard Worker 
getFrame()569*d57664e9SAndroid Build Coastguard Worker Frame CanvasContext::getFrame() {
570*d57664e9SAndroid Build Coastguard Worker     if (mHardwareBuffer != nullptr) {
571*d57664e9SAndroid Build Coastguard Worker         return {mBufferParams.getLogicalWidth(), mBufferParams.getLogicalHeight(), 0};
572*d57664e9SAndroid Build Coastguard Worker     } else {
573*d57664e9SAndroid Build Coastguard Worker         return mRenderPipeline->getFrame();
574*d57664e9SAndroid Build Coastguard Worker     }
575*d57664e9SAndroid Build Coastguard Worker }
576*d57664e9SAndroid Build Coastguard Worker 
draw(bool solelyTextureViewUpdates)577*d57664e9SAndroid Build Coastguard Worker void CanvasContext::draw(bool solelyTextureViewUpdates) {
578*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
579*d57664e9SAndroid Build Coastguard Worker     if (auto grContext = getGrContext()) {
580*d57664e9SAndroid Build Coastguard Worker         if (grContext->abandoned()) {
581*d57664e9SAndroid Build Coastguard Worker             if (grContext->isDeviceLost()) {
582*d57664e9SAndroid Build Coastguard Worker                 LOG_ALWAYS_FATAL("Lost GPU device unexpectedly");
583*d57664e9SAndroid Build Coastguard Worker                 return;
584*d57664e9SAndroid Build Coastguard Worker             }
585*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("GrContext is abandoned at start of CanvasContext::draw");
586*d57664e9SAndroid Build Coastguard Worker             return;
587*d57664e9SAndroid Build Coastguard Worker         }
588*d57664e9SAndroid Build Coastguard Worker     }
589*d57664e9SAndroid Build Coastguard Worker #endif
590*d57664e9SAndroid Build Coastguard Worker     SkRect dirty;
591*d57664e9SAndroid Build Coastguard Worker     mDamageAccumulator.finish(&dirty);
592*d57664e9SAndroid Build Coastguard Worker 
593*d57664e9SAndroid Build Coastguard Worker     // reset syncDelayDuration each time we draw
594*d57664e9SAndroid Build Coastguard Worker     nsecs_t syncDelayDuration = mSyncDelayDuration;
595*d57664e9SAndroid Build Coastguard Worker     nsecs_t idleDuration = mIdleDuration;
596*d57664e9SAndroid Build Coastguard Worker     mSyncDelayDuration = 0;
597*d57664e9SAndroid Build Coastguard Worker     mIdleDuration = 0;
598*d57664e9SAndroid Build Coastguard Worker 
599*d57664e9SAndroid Build Coastguard Worker     const auto skippedFrameReason = [&]() -> std::optional<SkippedFrameReason> {
600*d57664e9SAndroid Build Coastguard Worker         if (!Properties::isDrawingEnabled()) {
601*d57664e9SAndroid Build Coastguard Worker             return SkippedFrameReason::DrawingOff;
602*d57664e9SAndroid Build Coastguard Worker         }
603*d57664e9SAndroid Build Coastguard Worker 
604*d57664e9SAndroid Build Coastguard Worker         if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
605*d57664e9SAndroid Build Coastguard Worker             return SkippedFrameReason::NothingToDraw;
606*d57664e9SAndroid Build Coastguard Worker         }
607*d57664e9SAndroid Build Coastguard Worker 
608*d57664e9SAndroid Build Coastguard Worker         return std::nullopt;
609*d57664e9SAndroid Build Coastguard Worker     }();
610*d57664e9SAndroid Build Coastguard Worker     if (skippedFrameReason) {
611*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->setSkippedFrameReason(*skippedFrameReason);
612*d57664e9SAndroid Build Coastguard Worker 
613*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
614*d57664e9SAndroid Build Coastguard Worker         if (auto grContext = getGrContext()) {
615*d57664e9SAndroid Build Coastguard Worker             // Submit to ensure that any texture uploads complete and Skia can
616*d57664e9SAndroid Build Coastguard Worker             // free its staging buffers.
617*d57664e9SAndroid Build Coastguard Worker             grContext->flushAndSubmit();
618*d57664e9SAndroid Build Coastguard Worker         }
619*d57664e9SAndroid Build Coastguard Worker #endif
620*d57664e9SAndroid Build Coastguard Worker 
621*d57664e9SAndroid Build Coastguard Worker         // Notify the callbacks, even if there's nothing to draw so they aren't waiting
622*d57664e9SAndroid Build Coastguard Worker         // indefinitely
623*d57664e9SAndroid Build Coastguard Worker         waitOnFences();
624*d57664e9SAndroid Build Coastguard Worker         for (auto& func : mFrameCommitCallbacks) {
625*d57664e9SAndroid Build Coastguard Worker             std::invoke(func, false /* didProduceBuffer */);
626*d57664e9SAndroid Build Coastguard Worker         }
627*d57664e9SAndroid Build Coastguard Worker         mFrameCommitCallbacks.clear();
628*d57664e9SAndroid Build Coastguard Worker         return;
629*d57664e9SAndroid Build Coastguard Worker     }
630*d57664e9SAndroid Build Coastguard Worker 
631*d57664e9SAndroid Build Coastguard Worker     ScopedActiveContext activeContext(this);
632*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->set(FrameInfoIndex::FrameInterval) =
633*d57664e9SAndroid Build Coastguard Worker             mRenderThread.timeLord().frameIntervalNanos();
634*d57664e9SAndroid Build Coastguard Worker 
635*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->markIssueDrawCommandsStart();
636*d57664e9SAndroid Build Coastguard Worker 
637*d57664e9SAndroid Build Coastguard Worker     Frame frame = getFrame();
638*d57664e9SAndroid Build Coastguard Worker 
639*d57664e9SAndroid Build Coastguard Worker     SkRect windowDirty = computeDirtyRect(frame, &dirty);
640*d57664e9SAndroid Build Coastguard Worker 
641*d57664e9SAndroid Build Coastguard Worker     ATRACE_FORMAT("Drawing " RECT_STRING, SK_RECT_ARGS(dirty));
642*d57664e9SAndroid Build Coastguard Worker 
643*d57664e9SAndroid Build Coastguard Worker     IRenderPipeline::DrawResult drawResult;
644*d57664e9SAndroid Build Coastguard Worker     {
645*d57664e9SAndroid Build Coastguard Worker         // FrameInfoVisualizer accesses the frame events, which cannot be mutated mid-draw
646*d57664e9SAndroid Build Coastguard Worker         // or it can lead to memory corruption.
647*d57664e9SAndroid Build Coastguard Worker         drawResult = mRenderPipeline->draw(
648*d57664e9SAndroid Build Coastguard Worker                 frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, mContentDrawBounds,
649*d57664e9SAndroid Build Coastguard Worker                 mOpaque, mLightInfo, mRenderNodes, &(profiler()), mBufferParams, profilerLock());
650*d57664e9SAndroid Build Coastguard Worker     }
651*d57664e9SAndroid Build Coastguard Worker 
652*d57664e9SAndroid Build Coastguard Worker     uint64_t frameCompleteNr = getFrameNumber();
653*d57664e9SAndroid Build Coastguard Worker 
654*d57664e9SAndroid Build Coastguard Worker     waitOnFences();
655*d57664e9SAndroid Build Coastguard Worker 
656*d57664e9SAndroid Build Coastguard Worker     if (mNativeSurface) {
657*d57664e9SAndroid Build Coastguard Worker         // TODO(b/165985262): measure performance impact
658*d57664e9SAndroid Build Coastguard Worker         const auto vsyncId = mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
659*d57664e9SAndroid Build Coastguard Worker         if (vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) {
660*d57664e9SAndroid Build Coastguard Worker             const auto inputEventId =
661*d57664e9SAndroid Build Coastguard Worker                     static_cast<int32_t>(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId));
662*d57664e9SAndroid Build Coastguard Worker             ATRACE_FORMAT(
663*d57664e9SAndroid Build Coastguard Worker                 "frameTimelineInfo(frameNumber=%llu, vsyncId=%lld, inputEventId=0x%" PRIx32 ")",
664*d57664e9SAndroid Build Coastguard Worker                 frameCompleteNr, vsyncId, inputEventId);
665*d57664e9SAndroid Build Coastguard Worker             const ANativeWindowFrameTimelineInfo ftl = {
666*d57664e9SAndroid Build Coastguard Worker                     .frameNumber = frameCompleteNr,
667*d57664e9SAndroid Build Coastguard Worker                     .frameTimelineVsyncId = vsyncId,
668*d57664e9SAndroid Build Coastguard Worker                     .inputEventId = inputEventId,
669*d57664e9SAndroid Build Coastguard Worker                     .startTimeNanos = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime),
670*d57664e9SAndroid Build Coastguard Worker                     .useForRefreshRateSelection = solelyTextureViewUpdates,
671*d57664e9SAndroid Build Coastguard Worker                     .skippedFrameVsyncId = mSkippedFrameInfo ? mSkippedFrameInfo->vsyncId
672*d57664e9SAndroid Build Coastguard Worker                                                              : UiFrameInfoBuilder::INVALID_VSYNC_ID,
673*d57664e9SAndroid Build Coastguard Worker                     .skippedFrameStartTimeNanos =
674*d57664e9SAndroid Build Coastguard Worker                             mSkippedFrameInfo ? mSkippedFrameInfo->startTime : 0,
675*d57664e9SAndroid Build Coastguard Worker             };
676*d57664e9SAndroid Build Coastguard Worker             native_window_set_frame_timeline_info(mNativeSurface->getNativeWindow(), ftl);
677*d57664e9SAndroid Build Coastguard Worker         }
678*d57664e9SAndroid Build Coastguard Worker     }
679*d57664e9SAndroid Build Coastguard Worker 
680*d57664e9SAndroid Build Coastguard Worker     bool requireSwap = false;
681*d57664e9SAndroid Build Coastguard Worker     bool didDraw = false;
682*d57664e9SAndroid Build Coastguard Worker 
683*d57664e9SAndroid Build Coastguard Worker     int error = OK;
684*d57664e9SAndroid Build Coastguard Worker     bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult, windowDirty, mCurrentFrameInfo,
685*d57664e9SAndroid Build Coastguard Worker                                                 &requireSwap);
686*d57664e9SAndroid Build Coastguard Worker 
687*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->set(FrameInfoIndex::CommandSubmissionCompleted) = std::max(
688*d57664e9SAndroid Build Coastguard Worker             drawResult.commandSubmissionTime, mCurrentFrameInfo->get(FrameInfoIndex::SwapBuffers));
689*d57664e9SAndroid Build Coastguard Worker 
690*d57664e9SAndroid Build Coastguard Worker     mIsDirty = false;
691*d57664e9SAndroid Build Coastguard Worker 
692*d57664e9SAndroid Build Coastguard Worker     if (requireSwap) {
693*d57664e9SAndroid Build Coastguard Worker         didDraw = true;
694*d57664e9SAndroid Build Coastguard Worker         // Handle any swapchain errors
695*d57664e9SAndroid Build Coastguard Worker         error = mNativeSurface->getAndClearError();
696*d57664e9SAndroid Build Coastguard Worker         if (error == TIMED_OUT) {
697*d57664e9SAndroid Build Coastguard Worker             // Try again
698*d57664e9SAndroid Build Coastguard Worker             mRenderThread.postFrameCallback(this);
699*d57664e9SAndroid Build Coastguard Worker             // But since this frame didn't happen, we need to mark full damage in the swap
700*d57664e9SAndroid Build Coastguard Worker             // history
701*d57664e9SAndroid Build Coastguard Worker             didDraw = false;
702*d57664e9SAndroid Build Coastguard Worker 
703*d57664e9SAndroid Build Coastguard Worker         } else if (error != OK || !didSwap) {
704*d57664e9SAndroid Build Coastguard Worker             // Unknown error, abandon the surface
705*d57664e9SAndroid Build Coastguard Worker             setSurface(nullptr);
706*d57664e9SAndroid Build Coastguard Worker             didDraw = false;
707*d57664e9SAndroid Build Coastguard Worker         }
708*d57664e9SAndroid Build Coastguard Worker 
709*d57664e9SAndroid Build Coastguard Worker         SwapHistory& swap = mSwapHistory.next();
710*d57664e9SAndroid Build Coastguard Worker         if (didDraw) {
711*d57664e9SAndroid Build Coastguard Worker             swap.damage = windowDirty;
712*d57664e9SAndroid Build Coastguard Worker         } else {
713*d57664e9SAndroid Build Coastguard Worker             float max = static_cast<float>(INT_MAX);
714*d57664e9SAndroid Build Coastguard Worker             swap.damage = SkRect::MakeWH(max, max);
715*d57664e9SAndroid Build Coastguard Worker         }
716*d57664e9SAndroid Build Coastguard Worker         swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
717*d57664e9SAndroid Build Coastguard Worker         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
718*d57664e9SAndroid Build Coastguard Worker         if (didDraw) {
719*d57664e9SAndroid Build Coastguard Worker             nsecs_t dequeueStart =
720*d57664e9SAndroid Build Coastguard Worker                     ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow());
721*d57664e9SAndroid Build Coastguard Worker             if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
722*d57664e9SAndroid Build Coastguard Worker                 // Ignoring dequeue duration as it happened prior to frame render start
723*d57664e9SAndroid Build Coastguard Worker                 // and thus is not part of the frame.
724*d57664e9SAndroid Build Coastguard Worker                 swap.dequeueDuration = 0;
725*d57664e9SAndroid Build Coastguard Worker             } else {
726*d57664e9SAndroid Build Coastguard Worker                 swap.dequeueDuration =
727*d57664e9SAndroid Build Coastguard Worker                         ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow());
728*d57664e9SAndroid Build Coastguard Worker             }
729*d57664e9SAndroid Build Coastguard Worker             swap.queueDuration =
730*d57664e9SAndroid Build Coastguard Worker                     ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow());
731*d57664e9SAndroid Build Coastguard Worker         } else {
732*d57664e9SAndroid Build Coastguard Worker             swap.dequeueDuration = 0;
733*d57664e9SAndroid Build Coastguard Worker             swap.queueDuration = 0;
734*d57664e9SAndroid Build Coastguard Worker         }
735*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration;
736*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration;
737*d57664e9SAndroid Build Coastguard Worker         mHaveNewSurface = false;
738*d57664e9SAndroid Build Coastguard Worker         mFrameNumber = 0;
739*d57664e9SAndroid Build Coastguard Worker     } else {
740*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0;
741*d57664e9SAndroid Build Coastguard Worker         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0;
742*d57664e9SAndroid Build Coastguard Worker     }
743*d57664e9SAndroid Build Coastguard Worker 
744*d57664e9SAndroid Build Coastguard Worker     mCurrentFrameInfo->markSwapBuffersCompleted();
745*d57664e9SAndroid Build Coastguard Worker 
746*d57664e9SAndroid Build Coastguard Worker #if LOG_FRAMETIME_MMA
747*d57664e9SAndroid Build Coastguard Worker     float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart,
748*d57664e9SAndroid Build Coastguard Worker                                                   FrameInfoIndex::FrameCompleted) /
749*d57664e9SAndroid Build Coastguard Worker                       NANOS_PER_MILLIS_F;
750*d57664e9SAndroid Build Coastguard Worker     if (sFrameCount) {
751*d57664e9SAndroid Build Coastguard Worker         sBenchMma = ((9 * sBenchMma) + thisFrame) / 10;
752*d57664e9SAndroid Build Coastguard Worker     } else {
753*d57664e9SAndroid Build Coastguard Worker         sBenchMma = thisFrame;
754*d57664e9SAndroid Build Coastguard Worker     }
755*d57664e9SAndroid Build Coastguard Worker     if (++sFrameCount == 10) {
756*d57664e9SAndroid Build Coastguard Worker         sFrameCount = 1;
757*d57664e9SAndroid Build Coastguard Worker         ALOGD("Average frame time: %.4f", sBenchMma);
758*d57664e9SAndroid Build Coastguard Worker     }
759*d57664e9SAndroid Build Coastguard Worker #endif
760*d57664e9SAndroid Build Coastguard Worker 
761*d57664e9SAndroid Build Coastguard Worker     if (didSwap) {
762*d57664e9SAndroid Build Coastguard Worker         for (auto& func : mFrameCommitCallbacks) {
763*d57664e9SAndroid Build Coastguard Worker             std::invoke(func, true /* didProduceBuffer */);
764*d57664e9SAndroid Build Coastguard Worker         }
765*d57664e9SAndroid Build Coastguard Worker         mFrameCommitCallbacks.clear();
766*d57664e9SAndroid Build Coastguard Worker     }
767*d57664e9SAndroid Build Coastguard Worker 
768*d57664e9SAndroid Build Coastguard Worker     if (requireSwap) {
769*d57664e9SAndroid Build Coastguard Worker         if (mExpectSurfaceStats) {
770*d57664e9SAndroid Build Coastguard Worker             reportMetricsWithPresentTime();
771*d57664e9SAndroid Build Coastguard Worker             {  // acquire lock
772*d57664e9SAndroid Build Coastguard Worker                 std::lock_guard lock(mLastFrameMetricsInfosMutex);
773*d57664e9SAndroid Build Coastguard Worker                 FrameMetricsInfo& next = mLastFrameMetricsInfos.next();
774*d57664e9SAndroid Build Coastguard Worker                 next.frameInfo = mCurrentFrameInfo;
775*d57664e9SAndroid Build Coastguard Worker                 next.frameNumber = frameCompleteNr;
776*d57664e9SAndroid Build Coastguard Worker                 next.surfaceId = mSurfaceControlGenerationId;
777*d57664e9SAndroid Build Coastguard Worker             }  // release lock
778*d57664e9SAndroid Build Coastguard Worker         } else {
779*d57664e9SAndroid Build Coastguard Worker             mCurrentFrameInfo->markFrameCompleted();
780*d57664e9SAndroid Build Coastguard Worker             mCurrentFrameInfo->set(FrameInfoIndex::GpuCompleted)
781*d57664e9SAndroid Build Coastguard Worker                     = mCurrentFrameInfo->get(FrameInfoIndex::FrameCompleted);
782*d57664e9SAndroid Build Coastguard Worker             std::scoped_lock lock(mFrameInfoMutex);
783*d57664e9SAndroid Build Coastguard Worker             mJankTracker.finishFrame(*mCurrentFrameInfo, mFrameMetricsReporter, frameCompleteNr,
784*d57664e9SAndroid Build Coastguard Worker                                      mSurfaceControlGenerationId);
785*d57664e9SAndroid Build Coastguard Worker         }
786*d57664e9SAndroid Build Coastguard Worker     }
787*d57664e9SAndroid Build Coastguard Worker 
788*d57664e9SAndroid Build Coastguard Worker     int64_t intendedVsync = mCurrentFrameInfo->get(FrameInfoIndex::IntendedVsync);
789*d57664e9SAndroid Build Coastguard Worker     int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline);
790*d57664e9SAndroid Build Coastguard Worker     int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);
791*d57664e9SAndroid Build Coastguard Worker 
792*d57664e9SAndroid Build Coastguard Worker     mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync);
793*d57664e9SAndroid Build Coastguard Worker 
794*d57664e9SAndroid Build Coastguard Worker     if (didDraw) {
795*d57664e9SAndroid Build Coastguard Worker         int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
796*d57664e9SAndroid Build Coastguard Worker         int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
797*d57664e9SAndroid Build Coastguard Worker         int64_t actualDuration = frameDuration -
798*d57664e9SAndroid Build Coastguard Worker                                  (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
799*d57664e9SAndroid Build Coastguard Worker                                  dequeueBufferDuration - idleDuration;
800*d57664e9SAndroid Build Coastguard Worker         mHintSessionWrapper->reportActualWorkDuration(actualDuration);
801*d57664e9SAndroid Build Coastguard Worker         mHintSessionWrapper->setActiveFunctorThreads(
802*d57664e9SAndroid Build Coastguard Worker                 WebViewFunctorManager::instance().getRenderingThreadsForActiveFunctors());
803*d57664e9SAndroid Build Coastguard Worker     }
804*d57664e9SAndroid Build Coastguard Worker 
805*d57664e9SAndroid Build Coastguard Worker     mLastDequeueBufferDuration = dequeueBufferDuration;
806*d57664e9SAndroid Build Coastguard Worker 
807*d57664e9SAndroid Build Coastguard Worker     mRenderThread.cacheManager().onFrameCompleted();
808*d57664e9SAndroid Build Coastguard Worker     return;
809*d57664e9SAndroid Build Coastguard Worker }
810*d57664e9SAndroid Build Coastguard Worker 
reportMetricsWithPresentTime()811*d57664e9SAndroid Build Coastguard Worker void CanvasContext::reportMetricsWithPresentTime() {
812*d57664e9SAndroid Build Coastguard Worker     {  // acquire lock
813*d57664e9SAndroid Build Coastguard Worker         std::scoped_lock lock(mFrameInfoMutex);
814*d57664e9SAndroid Build Coastguard Worker         if (mFrameMetricsReporter == nullptr) {
815*d57664e9SAndroid Build Coastguard Worker             return;
816*d57664e9SAndroid Build Coastguard Worker         }
817*d57664e9SAndroid Build Coastguard Worker     }  // release lock
818*d57664e9SAndroid Build Coastguard Worker     if (mNativeSurface == nullptr) {
819*d57664e9SAndroid Build Coastguard Worker         return;
820*d57664e9SAndroid Build Coastguard Worker     }
821*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
822*d57664e9SAndroid Build Coastguard Worker     FrameInfo* forthBehind;
823*d57664e9SAndroid Build Coastguard Worker     int64_t frameNumber;
824*d57664e9SAndroid Build Coastguard Worker     int32_t surfaceControlId;
825*d57664e9SAndroid Build Coastguard Worker 
826*d57664e9SAndroid Build Coastguard Worker     {  // acquire lock
827*d57664e9SAndroid Build Coastguard Worker         std::scoped_lock lock(mLastFrameMetricsInfosMutex);
828*d57664e9SAndroid Build Coastguard Worker         if (mLastFrameMetricsInfos.size() != mLastFrameMetricsInfos.capacity()) {
829*d57664e9SAndroid Build Coastguard Worker             // Not enough frames yet
830*d57664e9SAndroid Build Coastguard Worker             return;
831*d57664e9SAndroid Build Coastguard Worker         }
832*d57664e9SAndroid Build Coastguard Worker         auto frameMetricsInfo = mLastFrameMetricsInfos.front();
833*d57664e9SAndroid Build Coastguard Worker         forthBehind = frameMetricsInfo.frameInfo;
834*d57664e9SAndroid Build Coastguard Worker         frameNumber = frameMetricsInfo.frameNumber;
835*d57664e9SAndroid Build Coastguard Worker         surfaceControlId = frameMetricsInfo.surfaceId;
836*d57664e9SAndroid Build Coastguard Worker     }  // release lock
837*d57664e9SAndroid Build Coastguard Worker 
838*d57664e9SAndroid Build Coastguard Worker     nsecs_t presentTime = 0;
839*d57664e9SAndroid Build Coastguard Worker     native_window_get_frame_timestamps(
840*d57664e9SAndroid Build Coastguard Worker             mNativeSurface->getNativeWindow(), frameNumber, nullptr /*outRequestedPresentTime*/,
841*d57664e9SAndroid Build Coastguard Worker             nullptr /*outAcquireTime*/, nullptr /*outLatchTime*/,
842*d57664e9SAndroid Build Coastguard Worker             nullptr /*outFirstRefreshStartTime*/, nullptr /*outLastRefreshStartTime*/,
843*d57664e9SAndroid Build Coastguard Worker             nullptr /*outGpuCompositionDoneTime*/, &presentTime, nullptr /*outDequeueReadyTime*/,
844*d57664e9SAndroid Build Coastguard Worker             nullptr /*outReleaseTime*/);
845*d57664e9SAndroid Build Coastguard Worker 
846*d57664e9SAndroid Build Coastguard Worker     forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime;
847*d57664e9SAndroid Build Coastguard Worker     {  // acquire lock
848*d57664e9SAndroid Build Coastguard Worker         std::scoped_lock lock(mFrameInfoMutex);
849*d57664e9SAndroid Build Coastguard Worker         if (mFrameMetricsReporter != nullptr) {
850*d57664e9SAndroid Build Coastguard Worker             mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/,
851*d57664e9SAndroid Build Coastguard Worker                                                       frameNumber, surfaceControlId);
852*d57664e9SAndroid Build Coastguard Worker         }
853*d57664e9SAndroid Build Coastguard Worker     }  // release lock
854*d57664e9SAndroid Build Coastguard Worker }
855*d57664e9SAndroid Build Coastguard Worker 
addFrameMetricsObserver(FrameMetricsObserver * observer)856*d57664e9SAndroid Build Coastguard Worker void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) {
857*d57664e9SAndroid Build Coastguard Worker     std::scoped_lock lock(mFrameInfoMutex);
858*d57664e9SAndroid Build Coastguard Worker     if (mFrameMetricsReporter.get() == nullptr) {
859*d57664e9SAndroid Build Coastguard Worker         mFrameMetricsReporter.reset(new FrameMetricsReporter());
860*d57664e9SAndroid Build Coastguard Worker     }
861*d57664e9SAndroid Build Coastguard Worker 
862*d57664e9SAndroid Build Coastguard Worker     // We want to make sure we aren't reporting frames that have already been queued by the
863*d57664e9SAndroid Build Coastguard Worker     // BufferQueueProducer on the rendner thread but are still pending the callback to report their
864*d57664e9SAndroid Build Coastguard Worker     // their frame metrics.
865*d57664e9SAndroid Build Coastguard Worker     uint64_t nextFrameNumber = getFrameNumber();
866*d57664e9SAndroid Build Coastguard Worker     observer->reportMetricsFrom(nextFrameNumber, mSurfaceControlGenerationId);
867*d57664e9SAndroid Build Coastguard Worker     mFrameMetricsReporter->addObserver(observer);
868*d57664e9SAndroid Build Coastguard Worker }
869*d57664e9SAndroid Build Coastguard Worker 
removeFrameMetricsObserver(FrameMetricsObserver * observer)870*d57664e9SAndroid Build Coastguard Worker void CanvasContext::removeFrameMetricsObserver(FrameMetricsObserver* observer) {
871*d57664e9SAndroid Build Coastguard Worker     std::scoped_lock lock(mFrameInfoMutex);
872*d57664e9SAndroid Build Coastguard Worker     if (mFrameMetricsReporter.get() != nullptr) {
873*d57664e9SAndroid Build Coastguard Worker         mFrameMetricsReporter->removeObserver(observer);
874*d57664e9SAndroid Build Coastguard Worker         if (!mFrameMetricsReporter->hasObservers()) {
875*d57664e9SAndroid Build Coastguard Worker             mFrameMetricsReporter.reset(nullptr);
876*d57664e9SAndroid Build Coastguard Worker         }
877*d57664e9SAndroid Build Coastguard Worker     }
878*d57664e9SAndroid Build Coastguard Worker }
879*d57664e9SAndroid Build Coastguard Worker 
getFrameInfoFromLastFew(uint64_t frameNumber,uint32_t surfaceControlId)880*d57664e9SAndroid Build Coastguard Worker FrameInfo* CanvasContext::getFrameInfoFromLastFew(uint64_t frameNumber, uint32_t surfaceControlId) {
881*d57664e9SAndroid Build Coastguard Worker     std::scoped_lock lock(mLastFrameMetricsInfosMutex);
882*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < mLastFrameMetricsInfos.size(); i++) {
883*d57664e9SAndroid Build Coastguard Worker         if (mLastFrameMetricsInfos[i].frameNumber == frameNumber &&
884*d57664e9SAndroid Build Coastguard Worker             mLastFrameMetricsInfos[i].surfaceId == surfaceControlId) {
885*d57664e9SAndroid Build Coastguard Worker             return mLastFrameMetricsInfos[i].frameInfo;
886*d57664e9SAndroid Build Coastguard Worker         }
887*d57664e9SAndroid Build Coastguard Worker     }
888*d57664e9SAndroid Build Coastguard Worker 
889*d57664e9SAndroid Build Coastguard Worker     return nullptr;
890*d57664e9SAndroid Build Coastguard Worker }
891*d57664e9SAndroid Build Coastguard Worker 
onSurfaceStatsAvailable(void * context,int32_t surfaceControlId,ASurfaceControlStats * stats)892*d57664e9SAndroid Build Coastguard Worker void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceControlId,
893*d57664e9SAndroid Build Coastguard Worker                                             ASurfaceControlStats* stats) {
894*d57664e9SAndroid Build Coastguard Worker     auto* instance = static_cast<CanvasContext*>(context);
895*d57664e9SAndroid Build Coastguard Worker 
896*d57664e9SAndroid Build Coastguard Worker     const ASurfaceControlFunctions& functions =
897*d57664e9SAndroid Build Coastguard Worker             instance->mRenderThread.getASurfaceControlFunctions();
898*d57664e9SAndroid Build Coastguard Worker 
899*d57664e9SAndroid Build Coastguard Worker     nsecs_t gpuCompleteTime = functions.getAcquireTimeFunc(stats);
900*d57664e9SAndroid Build Coastguard Worker     if (gpuCompleteTime == Fence::SIGNAL_TIME_PENDING) {
901*d57664e9SAndroid Build Coastguard Worker         gpuCompleteTime = -1;
902*d57664e9SAndroid Build Coastguard Worker     }
903*d57664e9SAndroid Build Coastguard Worker     uint64_t frameNumber = functions.getFrameNumberFunc(stats);
904*d57664e9SAndroid Build Coastguard Worker 
905*d57664e9SAndroid Build Coastguard Worker     FrameInfo* frameInfo = instance->getFrameInfoFromLastFew(frameNumber, surfaceControlId);
906*d57664e9SAndroid Build Coastguard Worker 
907*d57664e9SAndroid Build Coastguard Worker     if (frameInfo != nullptr) {
908*d57664e9SAndroid Build Coastguard Worker         std::scoped_lock lock(instance->mFrameInfoMutex);
909*d57664e9SAndroid Build Coastguard Worker         frameInfo->set(FrameInfoIndex::FrameCompleted) = std::max(gpuCompleteTime,
910*d57664e9SAndroid Build Coastguard Worker                 frameInfo->get(FrameInfoIndex::SwapBuffersCompleted));
911*d57664e9SAndroid Build Coastguard Worker         frameInfo->set(FrameInfoIndex::GpuCompleted) = std::max(
912*d57664e9SAndroid Build Coastguard Worker                 gpuCompleteTime, frameInfo->get(FrameInfoIndex::CommandSubmissionCompleted));
913*d57664e9SAndroid Build Coastguard Worker         instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter, frameNumber,
914*d57664e9SAndroid Build Coastguard Worker                                            surfaceControlId);
915*d57664e9SAndroid Build Coastguard Worker     }
916*d57664e9SAndroid Build Coastguard Worker }
917*d57664e9SAndroid Build Coastguard Worker 
918*d57664e9SAndroid Build Coastguard Worker // Called by choreographer to do an RT-driven animation
doFrame()919*d57664e9SAndroid Build Coastguard Worker void CanvasContext::doFrame() {
920*d57664e9SAndroid Build Coastguard Worker     if (!mRenderPipeline->isSurfaceReady()) return;
921*d57664e9SAndroid Build Coastguard Worker     mIdleDuration =
922*d57664e9SAndroid Build Coastguard Worker             systemTime(SYSTEM_TIME_MONOTONIC) - mRenderThread.timeLord().computeFrameTimeNanos();
923*d57664e9SAndroid Build Coastguard Worker     prepareAndDraw(nullptr);
924*d57664e9SAndroid Build Coastguard Worker }
925*d57664e9SAndroid Build Coastguard Worker 
getNextFrameSize() const926*d57664e9SAndroid Build Coastguard Worker SkISize CanvasContext::getNextFrameSize() const {
927*d57664e9SAndroid Build Coastguard Worker     static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX};
928*d57664e9SAndroid Build Coastguard Worker     if (mNativeSurface == nullptr) {
929*d57664e9SAndroid Build Coastguard Worker         return defaultFrameSize;
930*d57664e9SAndroid Build Coastguard Worker     }
931*d57664e9SAndroid Build Coastguard Worker     ANativeWindow* anw = mNativeSurface->getNativeWindow();
932*d57664e9SAndroid Build Coastguard Worker 
933*d57664e9SAndroid Build Coastguard Worker     SkISize size;
934*d57664e9SAndroid Build Coastguard Worker     size.fWidth = ANativeWindow_getWidth(anw);
935*d57664e9SAndroid Build Coastguard Worker     size.fHeight = ANativeWindow_getHeight(anw);
936*d57664e9SAndroid Build Coastguard Worker     mRenderThread.cacheManager().notifyNextFrameSize(size.fWidth, size.fHeight);
937*d57664e9SAndroid Build Coastguard Worker     return size;
938*d57664e9SAndroid Build Coastguard Worker }
939*d57664e9SAndroid Build Coastguard Worker 
getPixelSnapMatrix() const940*d57664e9SAndroid Build Coastguard Worker const SkM44& CanvasContext::getPixelSnapMatrix() const {
941*d57664e9SAndroid Build Coastguard Worker     return mRenderPipeline->getPixelSnapMatrix();
942*d57664e9SAndroid Build Coastguard Worker }
943*d57664e9SAndroid Build Coastguard Worker 
prepareAndDraw(RenderNode * node)944*d57664e9SAndroid Build Coastguard Worker void CanvasContext::prepareAndDraw(RenderNode* node) {
945*d57664e9SAndroid Build Coastguard Worker     int64_t vsyncId = mRenderThread.timeLord().lastVsyncId();
946*d57664e9SAndroid Build Coastguard Worker     ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
947*d57664e9SAndroid Build Coastguard Worker 
948*d57664e9SAndroid Build Coastguard Worker     nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
949*d57664e9SAndroid Build Coastguard Worker     int64_t frameDeadline = mRenderThread.timeLord().lastFrameDeadline();
950*d57664e9SAndroid Build Coastguard Worker     int64_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
951*d57664e9SAndroid Build Coastguard Worker     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
952*d57664e9SAndroid Build Coastguard Worker     UiFrameInfoBuilder(frameInfo)
953*d57664e9SAndroid Build Coastguard Worker         .addFlag(FrameInfoFlags::RTAnimation)
954*d57664e9SAndroid Build Coastguard Worker         .setVsync(vsync, vsync, vsyncId, frameDeadline, frameInterval);
955*d57664e9SAndroid Build Coastguard Worker 
956*d57664e9SAndroid Build Coastguard Worker     TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
957*d57664e9SAndroid Build Coastguard Worker     prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node);
958*d57664e9SAndroid Build Coastguard Worker     if (!info.out.skippedFrameReason) {
959*d57664e9SAndroid Build Coastguard Worker         draw(info.out.solelyTextureViewUpdates);
960*d57664e9SAndroid Build Coastguard Worker     } else {
961*d57664e9SAndroid Build Coastguard Worker         // wait on fences so tasks don't overlap next frame
962*d57664e9SAndroid Build Coastguard Worker         waitOnFences();
963*d57664e9SAndroid Build Coastguard Worker     }
964*d57664e9SAndroid Build Coastguard Worker }
965*d57664e9SAndroid Build Coastguard Worker 
markLayerInUse(RenderNode * node)966*d57664e9SAndroid Build Coastguard Worker void CanvasContext::markLayerInUse(RenderNode* node) {
967*d57664e9SAndroid Build Coastguard Worker     if (mPrefetchedLayers.erase(node)) {
968*d57664e9SAndroid Build Coastguard Worker         node->decStrong(nullptr);
969*d57664e9SAndroid Build Coastguard Worker     }
970*d57664e9SAndroid Build Coastguard Worker }
971*d57664e9SAndroid Build Coastguard Worker 
freePrefetchedLayers()972*d57664e9SAndroid Build Coastguard Worker void CanvasContext::freePrefetchedLayers() {
973*d57664e9SAndroid Build Coastguard Worker     if (mPrefetchedLayers.size()) {
974*d57664e9SAndroid Build Coastguard Worker         for (auto& node : mPrefetchedLayers) {
975*d57664e9SAndroid Build Coastguard Worker             ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
976*d57664e9SAndroid Build Coastguard Worker                   node->getName());
977*d57664e9SAndroid Build Coastguard Worker             node->destroyLayers();
978*d57664e9SAndroid Build Coastguard Worker             node->decStrong(nullptr);
979*d57664e9SAndroid Build Coastguard Worker         }
980*d57664e9SAndroid Build Coastguard Worker         mPrefetchedLayers.clear();
981*d57664e9SAndroid Build Coastguard Worker     }
982*d57664e9SAndroid Build Coastguard Worker }
983*d57664e9SAndroid Build Coastguard Worker 
buildLayer(RenderNode * node)984*d57664e9SAndroid Build Coastguard Worker void CanvasContext::buildLayer(RenderNode* node) {
985*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
986*d57664e9SAndroid Build Coastguard Worker     if (!mRenderPipeline->isContextReady()) return;
987*d57664e9SAndroid Build Coastguard Worker 
988*d57664e9SAndroid Build Coastguard Worker     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
989*d57664e9SAndroid Build Coastguard Worker     stopDrawing();
990*d57664e9SAndroid Build Coastguard Worker 
991*d57664e9SAndroid Build Coastguard Worker     ScopedActiveContext activeContext(this);
992*d57664e9SAndroid Build Coastguard Worker     TreeInfo info(TreeInfo::MODE_FULL, *this);
993*d57664e9SAndroid Build Coastguard Worker     info.damageAccumulator = &mDamageAccumulator;
994*d57664e9SAndroid Build Coastguard Worker     info.layerUpdateQueue = &mLayerUpdateQueue;
995*d57664e9SAndroid Build Coastguard Worker     info.runAnimations = false;
996*d57664e9SAndroid Build Coastguard Worker     node->prepareTree(info);
997*d57664e9SAndroid Build Coastguard Worker     SkRect ignore;
998*d57664e9SAndroid Build Coastguard Worker     mDamageAccumulator.finish(&ignore);
999*d57664e9SAndroid Build Coastguard Worker     // Tickle the GENERIC property on node to mark it as dirty for damaging
1000*d57664e9SAndroid Build Coastguard Worker     // purposes when the frame is actually drawn
1001*d57664e9SAndroid Build Coastguard Worker     node->setPropertyFieldsDirty(RenderNode::GENERIC);
1002*d57664e9SAndroid Build Coastguard Worker 
1003*d57664e9SAndroid Build Coastguard Worker     mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
1004*d57664e9SAndroid Build Coastguard Worker 
1005*d57664e9SAndroid Build Coastguard Worker     node->incStrong(nullptr);
1006*d57664e9SAndroid Build Coastguard Worker     mPrefetchedLayers.insert(node);
1007*d57664e9SAndroid Build Coastguard Worker }
1008*d57664e9SAndroid Build Coastguard Worker 
destroyHardwareResources()1009*d57664e9SAndroid Build Coastguard Worker void CanvasContext::destroyHardwareResources() {
1010*d57664e9SAndroid Build Coastguard Worker     stopDrawing();
1011*d57664e9SAndroid Build Coastguard Worker     if (mRenderPipeline->isContextReady()) {
1012*d57664e9SAndroid Build Coastguard Worker         freePrefetchedLayers();
1013*d57664e9SAndroid Build Coastguard Worker         for (const sp<RenderNode>& node : mRenderNodes) {
1014*d57664e9SAndroid Build Coastguard Worker             node->destroyHardwareResources();
1015*d57664e9SAndroid Build Coastguard Worker         }
1016*d57664e9SAndroid Build Coastguard Worker         mRenderPipeline->onDestroyHardwareResources();
1017*d57664e9SAndroid Build Coastguard Worker     }
1018*d57664e9SAndroid Build Coastguard Worker }
1019*d57664e9SAndroid Build Coastguard Worker 
onContextDestroyed()1020*d57664e9SAndroid Build Coastguard Worker void CanvasContext::onContextDestroyed() {
1021*d57664e9SAndroid Build Coastguard Worker     // We don't want to destroyHardwareResources as that will invalidate display lists which
1022*d57664e9SAndroid Build Coastguard Worker     // the client may not be expecting. Instead just purge all scratch resources
1023*d57664e9SAndroid Build Coastguard Worker     if (mRenderPipeline->isContextReady()) {
1024*d57664e9SAndroid Build Coastguard Worker         freePrefetchedLayers();
1025*d57664e9SAndroid Build Coastguard Worker         for (const sp<RenderNode>& node : mRenderNodes) {
1026*d57664e9SAndroid Build Coastguard Worker             node->destroyLayers();
1027*d57664e9SAndroid Build Coastguard Worker         }
1028*d57664e9SAndroid Build Coastguard Worker         mRenderPipeline->onDestroyHardwareResources();
1029*d57664e9SAndroid Build Coastguard Worker     }
1030*d57664e9SAndroid Build Coastguard Worker }
1031*d57664e9SAndroid Build Coastguard Worker 
createTextureLayer()1032*d57664e9SAndroid Build Coastguard Worker DeferredLayerUpdater* CanvasContext::createTextureLayer() {
1033*d57664e9SAndroid Build Coastguard Worker     return mRenderPipeline->createTextureLayer();
1034*d57664e9SAndroid Build Coastguard Worker }
1035*d57664e9SAndroid Build Coastguard Worker 
dumpFrames(int fd)1036*d57664e9SAndroid Build Coastguard Worker void CanvasContext::dumpFrames(int fd) {
1037*d57664e9SAndroid Build Coastguard Worker     mJankTracker.dumpStats(fd);
1038*d57664e9SAndroid Build Coastguard Worker     mJankTracker.dumpFrames(fd);
1039*d57664e9SAndroid Build Coastguard Worker }
1040*d57664e9SAndroid Build Coastguard Worker 
resetFrameStats()1041*d57664e9SAndroid Build Coastguard Worker void CanvasContext::resetFrameStats() {
1042*d57664e9SAndroid Build Coastguard Worker     mJankTracker.reset();
1043*d57664e9SAndroid Build Coastguard Worker }
1044*d57664e9SAndroid Build Coastguard Worker 
setName(const std::string && name)1045*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setName(const std::string&& name) {
1046*d57664e9SAndroid Build Coastguard Worker     mJankTracker.setDescription(JankTrackerType::Window, std::move(name));
1047*d57664e9SAndroid Build Coastguard Worker }
1048*d57664e9SAndroid Build Coastguard Worker 
waitOnFences()1049*d57664e9SAndroid Build Coastguard Worker void CanvasContext::waitOnFences() {
1050*d57664e9SAndroid Build Coastguard Worker     if (mFrameFences.size()) {
1051*d57664e9SAndroid Build Coastguard Worker         ATRACE_CALL();
1052*d57664e9SAndroid Build Coastguard Worker         for (auto& fence : mFrameFences) {
1053*d57664e9SAndroid Build Coastguard Worker             fence.get();
1054*d57664e9SAndroid Build Coastguard Worker         }
1055*d57664e9SAndroid Build Coastguard Worker         mFrameFences.clear();
1056*d57664e9SAndroid Build Coastguard Worker     }
1057*d57664e9SAndroid Build Coastguard Worker }
1058*d57664e9SAndroid Build Coastguard Worker 
enqueueFrameWork(std::function<void ()> && func)1059*d57664e9SAndroid Build Coastguard Worker void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
1060*d57664e9SAndroid Build Coastguard Worker     mFrameFences.push_back(CommonPool::async(std::move(func)));
1061*d57664e9SAndroid Build Coastguard Worker }
1062*d57664e9SAndroid Build Coastguard Worker 
getFrameNumber()1063*d57664e9SAndroid Build Coastguard Worker uint64_t CanvasContext::getFrameNumber() {
1064*d57664e9SAndroid Build Coastguard Worker     // mFrameNumber is reset to 0 when the surface changes or we swap buffers
1065*d57664e9SAndroid Build Coastguard Worker     if (mFrameNumber == 0 && mNativeSurface.get()) {
1066*d57664e9SAndroid Build Coastguard Worker         mFrameNumber = ANativeWindow_getNextFrameId(mNativeSurface->getNativeWindow());
1067*d57664e9SAndroid Build Coastguard Worker     }
1068*d57664e9SAndroid Build Coastguard Worker     return mFrameNumber;
1069*d57664e9SAndroid Build Coastguard Worker }
1070*d57664e9SAndroid Build Coastguard Worker 
surfaceRequiresRedraw()1071*d57664e9SAndroid Build Coastguard Worker bool CanvasContext::surfaceRequiresRedraw() {
1072*d57664e9SAndroid Build Coastguard Worker     if (!mNativeSurface) return false;
1073*d57664e9SAndroid Build Coastguard Worker     if (mHaveNewSurface) return true;
1074*d57664e9SAndroid Build Coastguard Worker 
1075*d57664e9SAndroid Build Coastguard Worker     ANativeWindow* anw = mNativeSurface->getNativeWindow();
1076*d57664e9SAndroid Build Coastguard Worker     const int width = ANativeWindow_getWidth(anw);
1077*d57664e9SAndroid Build Coastguard Worker     const int height = ANativeWindow_getHeight(anw);
1078*d57664e9SAndroid Build Coastguard Worker 
1079*d57664e9SAndroid Build Coastguard Worker     return width != mLastFrameWidth || height != mLastFrameHeight;
1080*d57664e9SAndroid Build Coastguard Worker }
1081*d57664e9SAndroid Build Coastguard Worker 
computeDirtyRect(const Frame & frame,SkRect * dirty)1082*d57664e9SAndroid Build Coastguard Worker SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
1083*d57664e9SAndroid Build Coastguard Worker     if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
1084*d57664e9SAndroid Build Coastguard Worker         // can't rely on prior content of window if viewport size changes
1085*d57664e9SAndroid Build Coastguard Worker         dirty->setEmpty();
1086*d57664e9SAndroid Build Coastguard Worker         mLastFrameWidth = frame.width();
1087*d57664e9SAndroid Build Coastguard Worker         mLastFrameHeight = frame.height();
1088*d57664e9SAndroid Build Coastguard Worker     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
1089*d57664e9SAndroid Build Coastguard Worker         // New surface needs a full draw
1090*d57664e9SAndroid Build Coastguard Worker         dirty->setEmpty();
1091*d57664e9SAndroid Build Coastguard Worker     } else {
1092*d57664e9SAndroid Build Coastguard Worker         if (!dirty->isEmpty() && !dirty->intersect(SkRect::MakeIWH(frame.width(), frame.height()))) {
1093*d57664e9SAndroid Build Coastguard Worker             ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty),
1094*d57664e9SAndroid Build Coastguard Worker                   frame.width(), frame.height());
1095*d57664e9SAndroid Build Coastguard Worker             dirty->setEmpty();
1096*d57664e9SAndroid Build Coastguard Worker         }
1097*d57664e9SAndroid Build Coastguard Worker         profiler().unionDirty(dirty);
1098*d57664e9SAndroid Build Coastguard Worker     }
1099*d57664e9SAndroid Build Coastguard Worker 
1100*d57664e9SAndroid Build Coastguard Worker     if (dirty->isEmpty()) {
1101*d57664e9SAndroid Build Coastguard Worker         dirty->setIWH(frame.width(), frame.height());
1102*d57664e9SAndroid Build Coastguard Worker         return *dirty;
1103*d57664e9SAndroid Build Coastguard Worker     }
1104*d57664e9SAndroid Build Coastguard Worker 
1105*d57664e9SAndroid Build Coastguard Worker     // At this point dirty is the area of the window to update. However,
1106*d57664e9SAndroid Build Coastguard Worker     // the area of the frame we need to repaint is potentially different, so
1107*d57664e9SAndroid Build Coastguard Worker     // stash the screen area for later
1108*d57664e9SAndroid Build Coastguard Worker     SkRect windowDirty(*dirty);
1109*d57664e9SAndroid Build Coastguard Worker 
1110*d57664e9SAndroid Build Coastguard Worker     // If the buffer age is 0 we do a full-screen repaint (handled above)
1111*d57664e9SAndroid Build Coastguard Worker     // If the buffer age is 1 the buffer contents are the same as they were
1112*d57664e9SAndroid Build Coastguard Worker     // last frame so there's nothing to union() against
1113*d57664e9SAndroid Build Coastguard Worker     // Therefore we only care about the > 1 case.
1114*d57664e9SAndroid Build Coastguard Worker     if (frame.bufferAge() > 1) {
1115*d57664e9SAndroid Build Coastguard Worker         if (frame.bufferAge() > (int)mSwapHistory.size()) {
1116*d57664e9SAndroid Build Coastguard Worker             // We don't have enough history to handle this old of a buffer
1117*d57664e9SAndroid Build Coastguard Worker             // Just do a full-draw
1118*d57664e9SAndroid Build Coastguard Worker             dirty->setIWH(frame.width(), frame.height());
1119*d57664e9SAndroid Build Coastguard Worker         } else {
1120*d57664e9SAndroid Build Coastguard Worker             // At this point we haven't yet added the latest frame
1121*d57664e9SAndroid Build Coastguard Worker             // to the damage history (happens below)
1122*d57664e9SAndroid Build Coastguard Worker             // So we need to damage
1123*d57664e9SAndroid Build Coastguard Worker             for (int i = mSwapHistory.size() - 1;
1124*d57664e9SAndroid Build Coastguard Worker                  i > ((int)mSwapHistory.size()) - frame.bufferAge(); i--) {
1125*d57664e9SAndroid Build Coastguard Worker                 dirty->join(mSwapHistory[i].damage);
1126*d57664e9SAndroid Build Coastguard Worker             }
1127*d57664e9SAndroid Build Coastguard Worker         }
1128*d57664e9SAndroid Build Coastguard Worker     }
1129*d57664e9SAndroid Build Coastguard Worker 
1130*d57664e9SAndroid Build Coastguard Worker     return windowDirty;
1131*d57664e9SAndroid Build Coastguard Worker }
1132*d57664e9SAndroid Build Coastguard Worker 
getActiveContext()1133*d57664e9SAndroid Build Coastguard Worker CanvasContext* CanvasContext::getActiveContext() {
1134*d57664e9SAndroid Build Coastguard Worker     return ScopedActiveContext::getActiveContext();
1135*d57664e9SAndroid Build Coastguard Worker }
1136*d57664e9SAndroid Build Coastguard Worker 
mergeTransaction(ASurfaceTransaction * transaction,ASurfaceControl * control)1137*d57664e9SAndroid Build Coastguard Worker bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control) {
1138*d57664e9SAndroid Build Coastguard Worker     if (!mASurfaceTransactionCallback) return false;
1139*d57664e9SAndroid Build Coastguard Worker     return std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction),
1140*d57664e9SAndroid Build Coastguard Worker                        reinterpret_cast<int64_t>(control), getFrameNumber());
1141*d57664e9SAndroid Build Coastguard Worker }
1142*d57664e9SAndroid Build Coastguard Worker 
prepareSurfaceControlForWebview()1143*d57664e9SAndroid Build Coastguard Worker void CanvasContext::prepareSurfaceControlForWebview() {
1144*d57664e9SAndroid Build Coastguard Worker     if (mPrepareSurfaceControlForWebviewCallback) {
1145*d57664e9SAndroid Build Coastguard Worker         std::invoke(mPrepareSurfaceControlForWebviewCallback);
1146*d57664e9SAndroid Build Coastguard Worker     }
1147*d57664e9SAndroid Build Coastguard Worker }
1148*d57664e9SAndroid Build Coastguard Worker 
sendLoadResetHint()1149*d57664e9SAndroid Build Coastguard Worker void CanvasContext::sendLoadResetHint() {
1150*d57664e9SAndroid Build Coastguard Worker     mHintSessionWrapper->sendLoadResetHint();
1151*d57664e9SAndroid Build Coastguard Worker }
1152*d57664e9SAndroid Build Coastguard Worker 
sendLoadIncreaseHint()1153*d57664e9SAndroid Build Coastguard Worker void CanvasContext::sendLoadIncreaseHint() {
1154*d57664e9SAndroid Build Coastguard Worker     mHintSessionWrapper->sendLoadIncreaseHint();
1155*d57664e9SAndroid Build Coastguard Worker }
1156*d57664e9SAndroid Build Coastguard Worker 
setSyncDelayDuration(nsecs_t duration)1157*d57664e9SAndroid Build Coastguard Worker void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
1158*d57664e9SAndroid Build Coastguard Worker     mSyncDelayDuration = duration;
1159*d57664e9SAndroid Build Coastguard Worker }
1160*d57664e9SAndroid Build Coastguard Worker 
startHintSession()1161*d57664e9SAndroid Build Coastguard Worker void CanvasContext::startHintSession() {
1162*d57664e9SAndroid Build Coastguard Worker     mHintSessionWrapper->init();
1163*d57664e9SAndroid Build Coastguard Worker }
1164*d57664e9SAndroid Build Coastguard Worker 
shouldDither()1165*d57664e9SAndroid Build Coastguard Worker bool CanvasContext::shouldDither() {
1166*d57664e9SAndroid Build Coastguard Worker     CanvasContext* self = getActiveContext();
1167*d57664e9SAndroid Build Coastguard Worker     if (!self) return false;
1168*d57664e9SAndroid Build Coastguard Worker     return self->mColorMode != ColorMode::Default;
1169*d57664e9SAndroid Build Coastguard Worker }
1170*d57664e9SAndroid Build Coastguard Worker 
visitAllRenderNodes(std::function<void (const RenderNode &)> func) const1171*d57664e9SAndroid Build Coastguard Worker void CanvasContext::visitAllRenderNodes(std::function<void(const RenderNode&)> func) const {
1172*d57664e9SAndroid Build Coastguard Worker     for (auto node : mRenderNodes) {
1173*d57664e9SAndroid Build Coastguard Worker         node->visit(func);
1174*d57664e9SAndroid Build Coastguard Worker     }
1175*d57664e9SAndroid Build Coastguard Worker }
1176*d57664e9SAndroid Build Coastguard Worker 
1177*d57664e9SAndroid Build Coastguard Worker } /* namespace renderthread */
1178*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
1179*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
1180