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