1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CanvasContext.h"
18 
19 #include <apex/window.h>
20 #include <fcntl.h>
21 #include <strings.h>
22 #include <sys/stat.h>
23 
24 #include <algorithm>
25 #include <cstdint>
26 #include <cstdlib>
27 #include <functional>
28 
29 #include "../Properties.h"
30 #include "AnimationContext.h"
31 #include "Frame.h"
32 #include "LayerUpdateQueue.h"
33 #include "Properties.h"
34 #include "RenderThread.h"
35 #include "hwui/Canvas.h"
36 #include "pipeline/skia/SkiaOpenGLPipeline.h"
37 #include "pipeline/skia/SkiaPipeline.h"
38 #include "pipeline/skia/SkiaVulkanPipeline.h"
39 #include "thread/CommonPool.h"
40 #include "utils/GLUtils.h"
41 #include "utils/TimeUtils.h"
42 #include "utils/TraceUtils.h"
43 
44 #define TRIM_MEMORY_COMPLETE 80
45 #define TRIM_MEMORY_UI_HIDDEN 20
46 
47 #define LOG_FRAMETIME_MMA 0
48 
49 #if LOG_FRAMETIME_MMA
50 static float sBenchMma = 0;
51 static int sFrameCount = 0;
52 static const float NANOS_PER_MILLIS_F = 1000000.0f;
53 #endif
54 
55 namespace android {
56 namespace uirenderer {
57 namespace renderthread {
58 
create(RenderThread & thread,bool translucent,RenderNode * rootRenderNode,IContextFactory * contextFactory)59 CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
60                                      RenderNode* rootRenderNode, IContextFactory* contextFactory) {
61     auto renderType = Properties::getRenderPipelineType();
62 
63     switch (renderType) {
64         case RenderPipelineType::SkiaGL:
65             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
66                                      std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
67         case RenderPipelineType::SkiaVulkan:
68             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
69                                      std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
70         default:
71             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
72             break;
73     }
74     return nullptr;
75 }
76 
invokeFunctor(const RenderThread & thread,Functor * functor)77 void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) {
78     ATRACE_CALL();
79     auto renderType = Properties::getRenderPipelineType();
80     switch (renderType) {
81         case RenderPipelineType::SkiaGL:
82             skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor);
83             break;
84         case RenderPipelineType::SkiaVulkan:
85             skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor);
86             break;
87         default:
88             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
89             break;
90     }
91 }
92 
prepareToDraw(const RenderThread & thread,Bitmap * bitmap)93 void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
94     skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap);
95 }
96 
CanvasContext(RenderThread & thread,bool translucent,RenderNode * rootRenderNode,IContextFactory * contextFactory,std::unique_ptr<IRenderPipeline> renderPipeline)97 CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
98                              IContextFactory* contextFactory,
99                              std::unique_ptr<IRenderPipeline> renderPipeline)
100         : mRenderThread(thread)
101         , mGenerationID(0)
102         , mOpaque(!translucent)
103         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
104         , mJankTracker(&thread.globalProfileData())
105         , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
106         , mContentDrawBounds(0, 0, 0, 0)
107         , mRenderPipeline(std::move(renderPipeline)) {
108     rootRenderNode->makeRoot();
109     mRenderNodes.emplace_back(rootRenderNode);
110     mProfiler.setDensity(DeviceInfo::getDensity());
111     setRenderAheadDepth(Properties::defaultRenderAhead);
112 }
113 
~CanvasContext()114 CanvasContext::~CanvasContext() {
115     destroy();
116     for (auto& node : mRenderNodes) {
117         node->clearRoot();
118     }
119     mRenderNodes.clear();
120 }
121 
addRenderNode(RenderNode * node,bool placeFront)122 void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
123     int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size());
124     node->makeRoot();
125     mRenderNodes.emplace(mRenderNodes.begin() + pos, node);
126 }
127 
removeRenderNode(RenderNode * node)128 void CanvasContext::removeRenderNode(RenderNode* node) {
129     node->clearRoot();
130     mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
131                        mRenderNodes.end());
132 }
133 
destroy()134 void CanvasContext::destroy() {
135     stopDrawing();
136     setSurface(nullptr);
137     freePrefetchedLayers();
138     destroyHardwareResources();
139     mAnimationContext->destroy();
140 }
141 
setBufferCount(ANativeWindow * window,uint32_t extraBuffers)142 static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) {
143     int query_value;
144     int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
145     if (err != 0 || query_value < 0) {
146         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
147         return;
148     }
149     auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
150 
151     int bufferCount = min_undequeued_buffers + 2 + extraBuffers;
152     native_window_set_buffer_count(window, bufferCount);
153 }
154 
setSurface(ANativeWindow * window,bool enableTimeout)155 void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
156     ATRACE_CALL();
157 
158     if (mRenderAheadDepth == 0 && DeviceInfo::get()->getMaxRefreshRate() > 66.6f) {
159         mFixedRenderAhead = false;
160         mRenderAheadCapacity = 1;
161     } else {
162         mFixedRenderAhead = true;
163         mRenderAheadCapacity = mRenderAheadDepth;
164     }
165 
166     if (window) {
167         mNativeSurface = std::make_unique<ReliableSurface>(window);
168         mNativeSurface->init();
169         if (enableTimeout) {
170             // TODO: Fix error handling & re-shorten timeout
171             ANativeWindow_setDequeueTimeout(window, 4000_ms);
172         }
173         mNativeSurface->setExtraBufferCount(mRenderAheadCapacity);
174     } else {
175         mNativeSurface = nullptr;
176     }
177 
178     bool hasSurface = mRenderPipeline->setSurface(
179             mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
180 
181     if (mNativeSurface && !mNativeSurface->didSetExtraBuffers()) {
182         setBufferCount(mNativeSurface->getNativeWindow(), mRenderAheadCapacity);
183     }
184 
185     mFrameNumber = -1;
186 
187     if (window != nullptr && hasSurface) {
188         mHaveNewSurface = true;
189         mSwapHistory.clear();
190         // Enable frame stats after the surface has been bound to the appropriate graphics API.
191         // Order is important when new and old surfaces are the same, because old surface has
192         // its frame stats disabled automatically.
193         native_window_enable_frame_timestamps(mNativeSurface->getNativeWindow(), true);
194     } else {
195         mRenderThread.removeFrameCallback(this);
196         mGenerationID++;
197     }
198 }
199 
setSwapBehavior(SwapBehavior swapBehavior)200 void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
201     mSwapBehavior = swapBehavior;
202 }
203 
pauseSurface()204 bool CanvasContext::pauseSurface() {
205     mGenerationID++;
206     return mRenderThread.removeFrameCallback(this);
207 }
208 
setStopped(bool stopped)209 void CanvasContext::setStopped(bool stopped) {
210     if (mStopped != stopped) {
211         mStopped = stopped;
212         if (mStopped) {
213             mGenerationID++;
214             mRenderThread.removeFrameCallback(this);
215             mRenderPipeline->onStop();
216         } else if (mIsDirty && hasSurface()) {
217             mRenderThread.postFrameCallback(this);
218         }
219     }
220 }
221 
allocateBuffers()222 void CanvasContext::allocateBuffers() {
223     if (mNativeSurface) {
224         ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow());
225     }
226 }
227 
setLightAlpha(uint8_t ambientShadowAlpha,uint8_t spotShadowAlpha)228 void CanvasContext::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
229     mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
230     mLightInfo.spotShadowAlpha = spotShadowAlpha;
231 }
232 
setLightGeometry(const Vector3 & lightCenter,float lightRadius)233 void CanvasContext::setLightGeometry(const Vector3& lightCenter, float lightRadius) {
234     mLightGeometry.center = lightCenter;
235     mLightGeometry.radius = lightRadius;
236 }
237 
setOpaque(bool opaque)238 void CanvasContext::setOpaque(bool opaque) {
239     mOpaque = opaque;
240 }
241 
setWideGamut(bool wideGamut)242 void CanvasContext::setWideGamut(bool wideGamut) {
243     ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
244     mRenderPipeline->setSurfaceColorProperties(colorMode);
245 }
246 
makeCurrent()247 bool CanvasContext::makeCurrent() {
248     if (mStopped) return false;
249 
250     auto result = mRenderPipeline->makeCurrent();
251     switch (result) {
252         case MakeCurrentResult::AlreadyCurrent:
253             return true;
254         case MakeCurrentResult::Failed:
255             mHaveNewSurface = true;
256             setSurface(nullptr);
257             return false;
258         case MakeCurrentResult::Succeeded:
259             mHaveNewSurface = true;
260             return true;
261         default:
262             LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent",
263                              (int32_t)result);
264     }
265 
266     return true;
267 }
268 
wasSkipped(FrameInfo * info)269 static bool wasSkipped(FrameInfo* info) {
270     return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
271 }
272 
isSwapChainStuffed()273 bool CanvasContext::isSwapChainStuffed() {
274     static const auto SLOW_THRESHOLD = 6_ms;
275 
276     if (mSwapHistory.size() != mSwapHistory.capacity()) {
277         // We want at least 3 frames of history before attempting to
278         // guess if the queue is stuffed
279         return false;
280     }
281     nsecs_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
282     auto& swapA = mSwapHistory[0];
283 
284     // Was there a happy queue & dequeue time? If so, don't
285     // consider it stuffed
286     if (swapA.dequeueDuration < SLOW_THRESHOLD && swapA.queueDuration < SLOW_THRESHOLD) {
287         return false;
288     }
289 
290     for (size_t i = 1; i < mSwapHistory.size(); i++) {
291         auto& swapB = mSwapHistory[i];
292 
293         // If there's a multi-frameInterval gap we effectively already dropped a frame,
294         // so consider the queue healthy.
295         if (std::abs(swapA.swapCompletedTime - swapB.swapCompletedTime) > frameInterval * 3) {
296             return false;
297         }
298 
299         // Was there a happy queue & dequeue time? If so, don't
300         // consider it stuffed
301         if (swapB.dequeueDuration < SLOW_THRESHOLD && swapB.queueDuration < SLOW_THRESHOLD) {
302             return false;
303         }
304 
305         swapA = swapB;
306     }
307 
308     // All signs point to a stuffed swap chain
309     ATRACE_NAME("swap chain stuffed");
310     return true;
311 }
312 
prepareTree(TreeInfo & info,int64_t * uiFrameInfo,int64_t syncQueued,RenderNode * target)313 void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
314                                 RenderNode* target) {
315     mRenderThread.removeFrameCallback(this);
316 
317     // If the previous frame was dropped we don't need to hold onto it, so
318     // just keep using the previous frame's structure instead
319     if (!wasSkipped(mCurrentFrameInfo)) {
320         mCurrentFrameInfo = mJankTracker.startFrame();
321         mLast4FrameInfos.next().first = mCurrentFrameInfo;
322     }
323     mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
324     mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
325     mCurrentFrameInfo->markSyncStart();
326 
327     info.damageAccumulator = &mDamageAccumulator;
328     info.layerUpdateQueue = &mLayerUpdateQueue;
329     info.damageGenerationId = mDamageId++;
330     info.out.canDrawThisFrame = true;
331 
332     mAnimationContext->startFrame(info.mode);
333     for (const sp<RenderNode>& node : mRenderNodes) {
334         // Only the primary target node will be drawn full - all other nodes would get drawn in
335         // real time mode. In case of a window, the primary node is the window content and the other
336         // node(s) are non client / filler nodes.
337         info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
338         node->prepareTree(info);
339         GL_CHECKPOINT(MODERATE);
340     }
341     mAnimationContext->runRemainingAnimations(info);
342     GL_CHECKPOINT(MODERATE);
343 
344     freePrefetchedLayers();
345     GL_CHECKPOINT(MODERATE);
346 
347     mIsDirty = true;
348 
349     if (CC_UNLIKELY(!hasSurface())) {
350         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
351         info.out.canDrawThisFrame = false;
352         return;
353     }
354 
355     if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
356         nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
357         SwapHistory& lastSwap = mSwapHistory.back();
358         nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
359         // The slight fudge-factor is to deal with cases where
360         // the vsync was estimated due to being slow handling the signal.
361         // See the logic in TimeLord#computeFrameTimeNanos or in
362         // Choreographer.java for details on when this happens
363         if (vsyncDelta < 2_ms) {
364             // Already drew for this vsync pulse, UI draw request missed
365             // the deadline for RT animations
366             info.out.canDrawThisFrame = false;
367         }
368     } else {
369         info.out.canDrawThisFrame = true;
370     }
371 
372     // TODO: Do we need to abort out if the backdrop is added but not ready? Should that even
373     // be an allowable combination?
374     if (mRenderNodes.size() > 2 && !mRenderNodes[1]->isRenderable()) {
375         info.out.canDrawThisFrame = false;
376     }
377 
378     if (info.out.canDrawThisFrame) {
379         int err = mNativeSurface->reserveNext();
380         if (err != OK) {
381             mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
382             info.out.canDrawThisFrame = false;
383             ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err));
384             if (err != TIMED_OUT) {
385                 // A timed out surface can still recover, but assume others are permanently dead.
386                 setSurface(nullptr);
387                 return;
388             }
389         }
390     } else {
391         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
392     }
393 
394     bool postedFrameCallback = false;
395     if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
396         if (CC_UNLIKELY(!Properties::enableRTAnimations)) {
397             info.out.requiresUiRedraw = true;
398         }
399         if (!info.out.requiresUiRedraw) {
400             // If animationsNeedsRedraw is set don't bother posting for an RT anim
401             // as we will just end up fighting the UI thread.
402             mRenderThread.postFrameCallback(this);
403             postedFrameCallback = true;
404         }
405     }
406 
407     if (!postedFrameCallback &&
408         info.out.animatedImageDelay != TreeInfo::Out::kNoAnimatedImageDelay) {
409         // Subtract the time of one frame so it can be displayed on time.
410         const nsecs_t kFrameTime = mRenderThread.timeLord().frameIntervalNanos();
411         if (info.out.animatedImageDelay <= kFrameTime) {
412             mRenderThread.postFrameCallback(this);
413         } else {
414             const auto delay = info.out.animatedImageDelay - kFrameTime;
415             int genId = mGenerationID;
416             mRenderThread.queue().postDelayed(delay, [this, genId]() {
417                 if (mGenerationID == genId) {
418                     mRenderThread.postFrameCallback(this);
419                 }
420             });
421         }
422     }
423 }
424 
stopDrawing()425 void CanvasContext::stopDrawing() {
426     mRenderThread.removeFrameCallback(this);
427     mAnimationContext->pauseAnimators();
428     mGenerationID++;
429 }
430 
notifyFramePending()431 void CanvasContext::notifyFramePending() {
432     ATRACE_CALL();
433     mRenderThread.pushBackFrameCallback(this);
434 }
435 
setPresentTime()436 void CanvasContext::setPresentTime() {
437     int64_t presentTime = NATIVE_WINDOW_TIMESTAMP_AUTO;
438     int renderAhead = 0;
439     const auto frameIntervalNanos = mRenderThread.timeLord().frameIntervalNanos();
440     if (mFixedRenderAhead) {
441         renderAhead = std::min(mRenderAheadDepth, mRenderAheadCapacity);
442     } else if (frameIntervalNanos < 15_ms) {
443         renderAhead = std::min(1, static_cast<int>(mRenderAheadCapacity));
444     }
445 
446     if (renderAhead) {
447         presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
448                 (frameIntervalNanos * (renderAhead + 1)) - DeviceInfo::get()->getAppOffset() +
449                 (frameIntervalNanos / 2);
450     }
451     native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime);
452 }
453 
draw()454 void CanvasContext::draw() {
455     SkRect dirty;
456     mDamageAccumulator.finish(&dirty);
457 
458     if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
459         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
460         // Notify the callbacks, even if there's nothing to draw so they aren't waiting
461         // indefinitely
462         for (auto& func : mFrameCompleteCallbacks) {
463             std::invoke(func, mFrameNumber);
464         }
465         mFrameCompleteCallbacks.clear();
466         return;
467     }
468 
469     mCurrentFrameInfo->markIssueDrawCommandsStart();
470 
471     Frame frame = mRenderPipeline->getFrame();
472     setPresentTime();
473 
474     SkRect windowDirty = computeDirtyRect(frame, &dirty);
475 
476     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
477                                       mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
478                                       &(profiler()));
479 
480     int64_t frameCompleteNr = getFrameNumber();
481 
482     waitOnFences();
483 
484     bool requireSwap = false;
485     int error = OK;
486     bool didSwap =
487             mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
488 
489     mIsDirty = false;
490 
491     if (requireSwap) {
492         bool didDraw = true;
493         // Handle any swapchain errors
494         error = mNativeSurface->getAndClearError();
495         if (error == TIMED_OUT) {
496             // Try again
497             mRenderThread.postFrameCallback(this);
498             // But since this frame didn't happen, we need to mark full damage in the swap
499             // history
500             didDraw = false;
501 
502         } else if (error != OK || !didSwap) {
503             // Unknown error, abandon the surface
504             setSurface(nullptr);
505             didDraw = false;
506         }
507 
508         SwapHistory& swap = mSwapHistory.next();
509         if (didDraw) {
510             swap.damage = windowDirty;
511         } else {
512             float max = static_cast<float>(INT_MAX);
513             swap.damage = SkRect::MakeWH(max, max);
514         }
515         swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
516         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
517         if (didDraw) {
518             nsecs_t dequeueStart =
519                     ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow());
520             if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
521                 // Ignoring dequeue duration as it happened prior to frame render start
522                 // and thus is not part of the frame.
523                 swap.dequeueDuration = 0;
524             } else {
525                 swap.dequeueDuration =
526                         ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow());
527             }
528             swap.queueDuration =
529                     ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow());
530         } else {
531             swap.dequeueDuration = 0;
532             swap.queueDuration = 0;
533         }
534         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration;
535         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration;
536         mLast4FrameInfos[-1].second = frameCompleteNr;
537         mHaveNewSurface = false;
538         mFrameNumber = -1;
539     } else {
540         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0;
541         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0;
542         mLast4FrameInfos[-1].second = -1;
543     }
544 
545     // TODO: Use a fence for real completion?
546     mCurrentFrameInfo->markFrameCompleted();
547 
548 #if LOG_FRAMETIME_MMA
549     float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart,
550                                                   FrameInfoIndex::FrameCompleted) /
551                       NANOS_PER_MILLIS_F;
552     if (sFrameCount) {
553         sBenchMma = ((9 * sBenchMma) + thisFrame) / 10;
554     } else {
555         sBenchMma = thisFrame;
556     }
557     if (++sFrameCount == 10) {
558         sFrameCount = 1;
559         ALOGD("Average frame time: %.4f", sBenchMma);
560     }
561 #endif
562 
563     if (didSwap) {
564         for (auto& func : mFrameCompleteCallbacks) {
565             std::invoke(func, frameCompleteNr);
566         }
567         mFrameCompleteCallbacks.clear();
568     }
569 
570     mJankTracker.finishFrame(*mCurrentFrameInfo);
571     if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) {
572         mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data());
573     }
574 
575     if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) {
576         // By looking 4 frames back, we guarantee all SF stats are available. There are at
577         // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames.
578         FrameInfo* forthBehind = mLast4FrameInfos.front().first;
579         int64_t composedFrameId = mLast4FrameInfos.front().second;
580         nsecs_t acquireTime = -1;
581         if (mNativeSurface) {
582             native_window_get_frame_timestamps(mNativeSurface->getNativeWindow(), composedFrameId,
583                                                nullptr, &acquireTime, nullptr, nullptr, nullptr,
584                                                nullptr, nullptr, nullptr, nullptr);
585         }
586         // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING
587         forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1;
588         mJankTracker.finishGpuDraw(*forthBehind);
589     }
590 
591     mRenderThread.cacheManager().onFrameCompleted();
592 }
593 
594 // Called by choreographer to do an RT-driven animation
doFrame()595 void CanvasContext::doFrame() {
596     if (!mRenderPipeline->isSurfaceReady()) return;
597     prepareAndDraw(nullptr);
598 }
599 
getNextFrameSize() const600 SkISize CanvasContext::getNextFrameSize() const {
601     static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX};
602     if (mNativeSurface == nullptr) {
603         return defaultFrameSize;
604     }
605     ANativeWindow* anw = mNativeSurface->getNativeWindow();
606 
607     SkISize size;
608     size.fWidth = ANativeWindow_getWidth(anw);
609     size.fHeight = ANativeWindow_getHeight(anw);
610     return size;
611 }
612 
prepareAndDraw(RenderNode * node)613 void CanvasContext::prepareAndDraw(RenderNode* node) {
614     ATRACE_CALL();
615 
616     nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
617     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
618     UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync);
619 
620     TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
621     prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node);
622     if (info.out.canDrawThisFrame) {
623         draw();
624     } else {
625         // wait on fences so tasks don't overlap next frame
626         waitOnFences();
627     }
628 }
629 
markLayerInUse(RenderNode * node)630 void CanvasContext::markLayerInUse(RenderNode* node) {
631     if (mPrefetchedLayers.erase(node)) {
632         node->decStrong(nullptr);
633     }
634 }
635 
freePrefetchedLayers()636 void CanvasContext::freePrefetchedLayers() {
637     if (mPrefetchedLayers.size()) {
638         for (auto& node : mPrefetchedLayers) {
639             ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
640                   node->getName());
641             node->destroyLayers();
642             node->decStrong(nullptr);
643         }
644         mPrefetchedLayers.clear();
645     }
646 }
647 
buildLayer(RenderNode * node)648 void CanvasContext::buildLayer(RenderNode* node) {
649     ATRACE_CALL();
650     if (!mRenderPipeline->isContextReady()) return;
651 
652     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
653     stopDrawing();
654 
655     TreeInfo info(TreeInfo::MODE_FULL, *this);
656     info.damageAccumulator = &mDamageAccumulator;
657     info.layerUpdateQueue = &mLayerUpdateQueue;
658     info.runAnimations = false;
659     node->prepareTree(info);
660     SkRect ignore;
661     mDamageAccumulator.finish(&ignore);
662     // Tickle the GENERIC property on node to mark it as dirty for damaging
663     // purposes when the frame is actually drawn
664     node->setPropertyFieldsDirty(RenderNode::GENERIC);
665 
666     mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
667 
668     node->incStrong(nullptr);
669     mPrefetchedLayers.insert(node);
670 }
671 
destroyHardwareResources()672 void CanvasContext::destroyHardwareResources() {
673     stopDrawing();
674     if (mRenderPipeline->isContextReady()) {
675         freePrefetchedLayers();
676         for (const sp<RenderNode>& node : mRenderNodes) {
677             node->destroyHardwareResources();
678         }
679         mRenderPipeline->onDestroyHardwareResources();
680     }
681 }
682 
trimMemory(RenderThread & thread,int level)683 void CanvasContext::trimMemory(RenderThread& thread, int level) {
684     ATRACE_CALL();
685     if (!thread.getGrContext()) return;
686     ATRACE_CALL();
687     if (level >= TRIM_MEMORY_COMPLETE) {
688         thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
689         thread.destroyRenderingContext();
690     } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
691         thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
692     }
693 }
694 
createTextureLayer()695 DeferredLayerUpdater* CanvasContext::createTextureLayer() {
696     return mRenderPipeline->createTextureLayer();
697 }
698 
dumpFrames(int fd)699 void CanvasContext::dumpFrames(int fd) {
700     mJankTracker.dumpStats(fd);
701     mJankTracker.dumpFrames(fd);
702 }
703 
resetFrameStats()704 void CanvasContext::resetFrameStats() {
705     mJankTracker.reset();
706 }
707 
setName(const std::string && name)708 void CanvasContext::setName(const std::string&& name) {
709     mJankTracker.setDescription(JankTrackerType::Window, std::move(name));
710 }
711 
waitOnFences()712 void CanvasContext::waitOnFences() {
713     if (mFrameFences.size()) {
714         ATRACE_CALL();
715         for (auto& fence : mFrameFences) {
716             fence.get();
717         }
718         mFrameFences.clear();
719     }
720 }
721 
enqueueFrameWork(std::function<void ()> && func)722 void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
723     mFrameFences.push_back(CommonPool::async(std::move(func)));
724 }
725 
getFrameNumber()726 int64_t CanvasContext::getFrameNumber() {
727     // mFrameNumber is reset to -1 when the surface changes or we swap buffers
728     if (mFrameNumber == -1 && mNativeSurface.get()) {
729         mFrameNumber = ANativeWindow_getNextFrameId(mNativeSurface->getNativeWindow());
730     }
731     return mFrameNumber;
732 }
733 
surfaceRequiresRedraw()734 bool CanvasContext::surfaceRequiresRedraw() {
735     if (!mNativeSurface) return false;
736     if (mHaveNewSurface) return true;
737 
738     ANativeWindow* anw = mNativeSurface->getNativeWindow();
739     const int width = ANativeWindow_getWidth(anw);
740     const int height = ANativeWindow_getHeight(anw);
741 
742     return width != mLastFrameWidth || height != mLastFrameHeight;
743 }
744 
setRenderAheadDepth(int renderAhead)745 void CanvasContext::setRenderAheadDepth(int renderAhead) {
746     if (renderAhead > 2 || renderAhead < 0 || mNativeSurface) {
747         return;
748     }
749     mFixedRenderAhead = true;
750     mRenderAheadDepth = static_cast<uint32_t>(renderAhead);
751 }
752 
computeDirtyRect(const Frame & frame,SkRect * dirty)753 SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
754     if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
755         // can't rely on prior content of window if viewport size changes
756         dirty->setEmpty();
757         mLastFrameWidth = frame.width();
758         mLastFrameHeight = frame.height();
759     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
760         // New surface needs a full draw
761         dirty->setEmpty();
762     } else {
763         if (!dirty->isEmpty() && !dirty->intersect(SkRect::MakeIWH(frame.width(), frame.height()))) {
764             ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty),
765                   frame.width(), frame.height());
766             dirty->setEmpty();
767         }
768         profiler().unionDirty(dirty);
769     }
770 
771     if (dirty->isEmpty()) {
772         dirty->setIWH(frame.width(), frame.height());
773     }
774 
775     // At this point dirty is the area of the window to update. However,
776     // the area of the frame we need to repaint is potentially different, so
777     // stash the screen area for later
778     SkRect windowDirty(*dirty);
779 
780     // If the buffer age is 0 we do a full-screen repaint (handled above)
781     // If the buffer age is 1 the buffer contents are the same as they were
782     // last frame so there's nothing to union() against
783     // Therefore we only care about the > 1 case.
784     if (frame.bufferAge() > 1) {
785         if (frame.bufferAge() > (int)mSwapHistory.size()) {
786             // We don't have enough history to handle this old of a buffer
787             // Just do a full-draw
788             dirty->setIWH(frame.width(), frame.height());
789         } else {
790             // At this point we haven't yet added the latest frame
791             // to the damage history (happens below)
792             // So we need to damage
793             for (int i = mSwapHistory.size() - 1;
794                  i > ((int)mSwapHistory.size()) - frame.bufferAge(); i--) {
795                 dirty->join(mSwapHistory[i].damage);
796             }
797         }
798     }
799 
800     return windowDirty;
801 }
802 
803 } /* namespace renderthread */
804 } /* namespace uirenderer */
805 } /* namespace android */
806