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