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