• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <GpuMemoryTracker.h>
18 #include "CanvasContext.h"
19 
20 #include "AnimationContext.h"
21 #include "Caches.h"
22 #include "DeferredLayerUpdater.h"
23 #include "EglManager.h"
24 #include "LayerUpdateQueue.h"
25 #include "LayerRenderer.h"
26 #include "OpenGLRenderer.h"
27 #include "Properties.h"
28 #include "RenderThread.h"
29 #include "hwui/Canvas.h"
30 #include "renderstate/RenderState.h"
31 #include "renderstate/Stencil.h"
32 #include "protos/hwui.pb.h"
33 #include "utils/GLUtils.h"
34 #include "utils/TimeUtils.h"
35 
36 #include <cutils/properties.h>
37 #include <google/protobuf/io/zero_copy_stream_impl.h>
38 #include <private/hwui/DrawGlInfo.h>
39 #include <strings.h>
40 
41 #include <algorithm>
42 #include <fcntl.h>
43 #include <sys/stat.h>
44 
45 #include <cstdlib>
46 
47 #define TRIM_MEMORY_COMPLETE 80
48 #define TRIM_MEMORY_UI_HIDDEN 20
49 
50 #define ENABLE_RENDERNODE_SERIALIZATION false
51 
52 #define LOG_FRAMETIME_MMA 0
53 
54 #if LOG_FRAMETIME_MMA
55 static float sBenchMma = 0;
56 static int sFrameCount = 0;
57 static const float NANOS_PER_MILLIS_F = 1000000.0f;
58 #endif
59 
60 namespace android {
61 namespace uirenderer {
62 namespace renderthread {
63 
CanvasContext(RenderThread & thread,bool translucent,RenderNode * rootRenderNode,IContextFactory * contextFactory)64 CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
65         RenderNode* rootRenderNode, IContextFactory* contextFactory)
66         : mRenderThread(thread)
67         , mEglManager(thread.eglManager())
68         , mOpaque(!translucent)
69         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
70         , mJankTracker(thread.mainDisplayInfo())
71         , mProfiler(mFrames)
72         , mContentDrawBounds(0, 0, 0, 0) {
73     mRenderNodes.emplace_back(rootRenderNode);
74     mRenderThread.renderState().registerCanvasContext(this);
75     mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
76 }
77 
~CanvasContext()78 CanvasContext::~CanvasContext() {
79     destroy(nullptr);
80     mRenderThread.renderState().unregisterCanvasContext(this);
81 }
82 
destroy(TreeObserver * observer)83 void CanvasContext::destroy(TreeObserver* observer) {
84     stopDrawing();
85     setSurface(nullptr);
86     freePrefetchedLayers(observer);
87     destroyHardwareResources(observer);
88     mAnimationContext->destroy();
89 #if !HWUI_NEW_OPS
90     if (mCanvas) {
91         delete mCanvas;
92         mCanvas = nullptr;
93     }
94 #endif
95 }
96 
setSurface(Surface * surface)97 void CanvasContext::setSurface(Surface* surface) {
98     ATRACE_CALL();
99 
100     mNativeSurface = surface;
101 
102     if (mEglSurface != EGL_NO_SURFACE) {
103         mEglManager.destroySurface(mEglSurface);
104         mEglSurface = EGL_NO_SURFACE;
105     }
106 
107     if (surface) {
108         mEglSurface = mEglManager.createSurface(surface);
109     }
110 
111     mFrameNumber = -1;
112 
113     if (mEglSurface != EGL_NO_SURFACE) {
114         const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer);
115         mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
116         mHaveNewSurface = true;
117         mSwapHistory.clear();
118     } else {
119         mRenderThread.removeFrameCallback(this);
120     }
121 }
122 
setSwapBehavior(SwapBehavior swapBehavior)123 void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
124     mSwapBehavior = swapBehavior;
125 }
126 
initialize(Surface * surface)127 void CanvasContext::initialize(Surface* surface) {
128     setSurface(surface);
129 #if !HWUI_NEW_OPS
130     if (mCanvas) return;
131     mCanvas = new OpenGLRenderer(mRenderThread.renderState());
132     mCanvas->initProperties();
133 #endif
134 }
135 
updateSurface(Surface * surface)136 void CanvasContext::updateSurface(Surface* surface) {
137     setSurface(surface);
138 }
139 
pauseSurface(Surface * surface)140 bool CanvasContext::pauseSurface(Surface* surface) {
141     return mRenderThread.removeFrameCallback(this);
142 }
143 
setStopped(bool stopped)144 void CanvasContext::setStopped(bool stopped) {
145     if (mStopped != stopped) {
146         mStopped = stopped;
147         if (mStopped) {
148             mRenderThread.removeFrameCallback(this);
149             if (mEglManager.isCurrent(mEglSurface)) {
150                 mEglManager.makeCurrent(EGL_NO_SURFACE);
151             }
152         } else if (mIsDirty && hasSurface()) {
153             mRenderThread.postFrameCallback(this);
154         }
155     }
156 }
157 
158 // TODO: don't pass viewport size, it's automatic via EGL
setup(int width,int height,float lightRadius,uint8_t ambientShadowAlpha,uint8_t spotShadowAlpha)159 void CanvasContext::setup(int width, int height, float lightRadius,
160         uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
161 #if HWUI_NEW_OPS
162     mLightGeometry.radius = lightRadius;
163     mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
164     mLightInfo.spotShadowAlpha = spotShadowAlpha;
165 #else
166     if (!mCanvas) return;
167     mCanvas->initLight(lightRadius, ambientShadowAlpha, spotShadowAlpha);
168 #endif
169 }
170 
setLightCenter(const Vector3 & lightCenter)171 void CanvasContext::setLightCenter(const Vector3& lightCenter) {
172 #if HWUI_NEW_OPS
173     mLightGeometry.center = lightCenter;
174 #else
175     if (!mCanvas) return;
176     mCanvas->setLightCenter(lightCenter);
177 #endif
178 }
179 
setOpaque(bool opaque)180 void CanvasContext::setOpaque(bool opaque) {
181     mOpaque = opaque;
182 }
183 
makeCurrent()184 bool CanvasContext::makeCurrent() {
185     if (mStopped) return false;
186 
187     // TODO: Figure out why this workaround is needed, see b/13913604
188     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
189     EGLint error = 0;
190     mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error);
191     if (error) {
192         setSurface(nullptr);
193     }
194     return !error;
195 }
196 
wasSkipped(FrameInfo * info)197 static bool wasSkipped(FrameInfo* info) {
198     return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
199 }
200 
isSwapChainStuffed()201 bool CanvasContext::isSwapChainStuffed() {
202     static const auto SLOW_THRESHOLD = 6_ms;
203 
204     if (mSwapHistory.size() != mSwapHistory.capacity()) {
205         // We want at least 3 frames of history before attempting to
206         // guess if the queue is stuffed
207         return false;
208     }
209     nsecs_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
210     auto& swapA = mSwapHistory[0];
211 
212     // Was there a happy queue & dequeue time? If so, don't
213     // consider it stuffed
214     if (swapA.dequeueDuration < SLOW_THRESHOLD
215             && swapA.queueDuration < SLOW_THRESHOLD) {
216         return false;
217     }
218 
219     for (size_t i = 1; i < mSwapHistory.size(); i++) {
220         auto& swapB = mSwapHistory[i];
221 
222         // If there's a multi-frameInterval gap we effectively already dropped a frame,
223         // so consider the queue healthy.
224         if (swapA.swapCompletedTime - swapB.swapCompletedTime > frameInterval * 3) {
225             return false;
226         }
227 
228         // Was there a happy queue & dequeue time? If so, don't
229         // consider it stuffed
230         if (swapB.dequeueDuration < SLOW_THRESHOLD
231                 && swapB.queueDuration < SLOW_THRESHOLD) {
232             return false;
233         }
234 
235         swapA = swapB;
236     }
237 
238     // All signs point to a stuffed swap chain
239     ATRACE_NAME("swap chain stuffed");
240     return true;
241 }
242 
prepareTree(TreeInfo & info,int64_t * uiFrameInfo,int64_t syncQueued,RenderNode * target)243 void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
244         int64_t syncQueued, RenderNode* target) {
245     mRenderThread.removeFrameCallback(this);
246 
247     // If the previous frame was dropped we don't need to hold onto it, so
248     // just keep using the previous frame's structure instead
249     if (!wasSkipped(mCurrentFrameInfo)) {
250         mCurrentFrameInfo = &mFrames.next();
251     }
252     mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
253     mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
254     mCurrentFrameInfo->markSyncStart();
255 
256     info.damageAccumulator = &mDamageAccumulator;
257 #if HWUI_NEW_OPS
258     info.layerUpdateQueue = &mLayerUpdateQueue;
259 #else
260     info.renderer = mCanvas;
261 #endif
262 
263     mAnimationContext->startFrame(info.mode);
264     for (const sp<RenderNode>& node : mRenderNodes) {
265         // Only the primary target node will be drawn full - all other nodes would get drawn in
266         // real time mode. In case of a window, the primary node is the window content and the other
267         // node(s) are non client / filler nodes.
268         info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
269         node->prepareTree(info);
270         GL_CHECKPOINT(MODERATE);
271     }
272     mAnimationContext->runRemainingAnimations(info);
273     GL_CHECKPOINT(MODERATE);
274 
275     freePrefetchedLayers(info.observer);
276     GL_CHECKPOINT(MODERATE);
277 
278     mIsDirty = true;
279 
280     if (CC_UNLIKELY(!mNativeSurface.get())) {
281         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
282         info.out.canDrawThisFrame = false;
283         return;
284     }
285 
286     if (CC_LIKELY(mSwapHistory.size())) {
287         nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
288         SwapHistory& lastSwap = mSwapHistory.back();
289         nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
290         // The slight fudge-factor is to deal with cases where
291         // the vsync was estimated due to being slow handling the signal.
292         // See the logic in TimeLord#computeFrameTimeNanos or in
293         // Choreographer.java for details on when this happens
294         if (vsyncDelta < 2_ms) {
295             // Already drew for this vsync pulse, UI draw request missed
296             // the deadline for RT animations
297             info.out.canDrawThisFrame = false;
298         } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3
299                 || (latestVsync - mLastDropVsync) < 500_ms) {
300             // It's been several frame intervals, assume the buffer queue is fine
301             // or the last drop was too recent
302             info.out.canDrawThisFrame = true;
303         } else {
304             info.out.canDrawThisFrame = !isSwapChainStuffed();
305             if (!info.out.canDrawThisFrame) {
306                 // dropping frame
307                 mLastDropVsync = mRenderThread.timeLord().latestVsync();
308             }
309         }
310     } else {
311         info.out.canDrawThisFrame = true;
312     }
313 
314     if (!info.out.canDrawThisFrame) {
315         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
316     }
317 
318     if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
319         if (!info.out.requiresUiRedraw) {
320             // If animationsNeedsRedraw is set don't bother posting for an RT anim
321             // as we will just end up fighting the UI thread.
322             mRenderThread.postFrameCallback(this);
323         }
324     }
325 }
326 
stopDrawing()327 void CanvasContext::stopDrawing() {
328     mRenderThread.removeFrameCallback(this);
329     mAnimationContext->pauseAnimators();
330 }
331 
notifyFramePending()332 void CanvasContext::notifyFramePending() {
333     ATRACE_CALL();
334     mRenderThread.pushBackFrameCallback(this);
335 }
336 
draw()337 void CanvasContext::draw() {
338 #if !HWUI_NEW_OPS
339     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
340             "drawRenderNode called on a context with no canvas or surface!");
341 #endif
342 
343     SkRect dirty;
344     mDamageAccumulator.finish(&dirty);
345 
346     // TODO: Re-enable after figuring out cause of b/22592975
347 //    if (dirty.isEmpty() && Properties::skipEmptyFrames) {
348 //        mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
349 //        return;
350 //    }
351 
352     mCurrentFrameInfo->markIssueDrawCommandsStart();
353 
354     Frame frame = mEglManager.beginFrame(mEglSurface);
355 
356     if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
357         // can't rely on prior content of window if viewport size changes
358         dirty.setEmpty();
359         mLastFrameWidth = frame.width();
360         mLastFrameHeight = frame.height();
361     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
362         // New surface needs a full draw
363         dirty.setEmpty();
364     } else {
365         if (!dirty.isEmpty() && !dirty.intersect(0, 0, frame.width(), frame.height())) {
366             ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
367                     SK_RECT_ARGS(dirty), frame.width(), frame.height());
368             dirty.setEmpty();
369         }
370         profiler().unionDirty(&dirty);
371     }
372 
373     if (dirty.isEmpty()) {
374         dirty.set(0, 0, frame.width(), frame.height());
375     }
376 
377     // At this point dirty is the area of the screen to update. However,
378     // the area of the frame we need to repaint is potentially different, so
379     // stash the screen area for later
380     SkRect screenDirty(dirty);
381 
382     // If the buffer age is 0 we do a full-screen repaint (handled above)
383     // If the buffer age is 1 the buffer contents are the same as they were
384     // last frame so there's nothing to union() against
385     // Therefore we only care about the > 1 case.
386     if (frame.bufferAge() > 1) {
387         if (frame.bufferAge() > (int) mSwapHistory.size()) {
388             // We don't have enough history to handle this old of a buffer
389             // Just do a full-draw
390             dirty.set(0, 0, frame.width(), frame.height());
391         } else {
392             // At this point we haven't yet added the latest frame
393             // to the damage history (happens below)
394             // So we need to damage
395             for (int i = mSwapHistory.size() - 1;
396                     i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
397                 dirty.join(mSwapHistory[i].damage);
398             }
399         }
400     }
401 
402     mEglManager.damageFrame(frame, dirty);
403 
404 #if HWUI_NEW_OPS
405     auto& caches = Caches::getInstance();
406     FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), mLightGeometry, caches);
407 
408     frameBuilder.deferLayers(mLayerUpdateQueue);
409     mLayerUpdateQueue.clear();
410 
411     frameBuilder.deferRenderNodeScene(mRenderNodes, mContentDrawBounds);
412 
413     BakedOpRenderer renderer(caches, mRenderThread.renderState(),
414             mOpaque, mLightInfo);
415     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
416     profiler().draw(&renderer);
417     bool drew = renderer.didDraw();
418 
419     // post frame cleanup
420     caches.clearGarbage();
421     caches.pathCache.trim();
422     caches.tessellationCache.trim();
423 
424 #if DEBUG_MEMORY_USAGE
425     mCaches.dumpMemoryUsage();
426 #else
427     if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
428         caches.dumpMemoryUsage();
429     }
430 #endif
431 
432 #else
433     mCanvas->prepareDirty(frame.width(), frame.height(),
434             dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
435 
436     Rect outBounds;
437     // It there are multiple render nodes, they are laid out as follows:
438     // #0 - backdrop (content + caption)
439     // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
440     // #2 - additional overlay nodes
441     // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
442     // resizing however it might become partially visible. The following render loop will crop the
443     // backdrop against the content and draw the remaining part of it. It will then draw the content
444     // cropped to the backdrop (since that indicates a shrinking of the window).
445     //
446     // Additional nodes will be drawn on top with no particular clipping semantics.
447 
448     // The bounds of the backdrop against which the content should be clipped.
449     Rect backdropBounds = mContentDrawBounds;
450     // Usually the contents bounds should be mContentDrawBounds - however - we will
451     // move it towards the fixed edge to give it a more stable appearance (for the moment).
452     Rect contentBounds;
453     // If there is no content bounds we ignore the layering as stated above and start with 2.
454     int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() == 1) ? 2 : 0;
455     // Draw all render nodes. Note that
456     for (const sp<RenderNode>& node : mRenderNodes) {
457         if (layer == 0) { // Backdrop.
458             // Draw the backdrop clipped to the inverse content bounds, but assume that the content
459             // was moved to the upper left corner.
460             const RenderProperties& properties = node->properties();
461             Rect targetBounds(properties.getLeft(), properties.getTop(),
462                               properties.getRight(), properties.getBottom());
463             // Move the content bounds towards the fixed corner of the backdrop.
464             const int x = targetBounds.left;
465             const int y = targetBounds.top;
466             contentBounds.set(x, y, x + mContentDrawBounds.getWidth(),
467                                     y + mContentDrawBounds.getHeight());
468             // Remember the intersection of the target bounds and the intersection bounds against
469             // which we have to crop the content.
470             backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
471             backdropBounds.doIntersect(targetBounds);
472             // Check if we have to draw something on the left side ...
473             if (targetBounds.left < contentBounds.left) {
474                 mCanvas->save(SaveFlags::Clip);
475                 if (mCanvas->clipRect(targetBounds.left, targetBounds.top,
476                                       contentBounds.left, targetBounds.bottom,
477                                       SkRegion::kIntersect_Op)) {
478                     mCanvas->drawRenderNode(node.get(), outBounds);
479                 }
480                 // Reduce the target area by the area we have just painted.
481                 targetBounds.left = std::min(contentBounds.left, targetBounds.right);
482                 mCanvas->restore();
483             }
484             // ... or on the right side ...
485             if (targetBounds.right > contentBounds.right &&
486                 !targetBounds.isEmpty()) {
487                 mCanvas->save(SaveFlags::Clip);
488                 if (mCanvas->clipRect(contentBounds.right, targetBounds.top,
489                                       targetBounds.right, targetBounds.bottom,
490                                       SkRegion::kIntersect_Op)) {
491                     mCanvas->drawRenderNode(node.get(), outBounds);
492                 }
493                 // Reduce the target area by the area we have just painted.
494                 targetBounds.right = std::max(targetBounds.left, contentBounds.right);
495                 mCanvas->restore();
496             }
497             // ... or at the top ...
498             if (targetBounds.top < contentBounds.top &&
499                 !targetBounds.isEmpty()) {
500                 mCanvas->save(SaveFlags::Clip);
501                 if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right,
502                                       contentBounds.top,
503                                       SkRegion::kIntersect_Op)) {
504                     mCanvas->drawRenderNode(node.get(), outBounds);
505                 }
506                 // Reduce the target area by the area we have just painted.
507                 targetBounds.top = std::min(contentBounds.top, targetBounds.bottom);
508                 mCanvas->restore();
509             }
510             // ... or at the bottom.
511             if (targetBounds.bottom > contentBounds.bottom &&
512                 !targetBounds.isEmpty()) {
513                 mCanvas->save(SaveFlags::Clip);
514                 if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right,
515                                       targetBounds.bottom, SkRegion::kIntersect_Op)) {
516                     mCanvas->drawRenderNode(node.get(), outBounds);
517                 }
518                 mCanvas->restore();
519             }
520         } else if (layer == 1) { // Content
521             // It gets cropped against the bounds of the backdrop to stay inside.
522             mCanvas->save(SaveFlags::MatrixClip);
523 
524             // We shift and clip the content to match its final location in the window.
525             const float left = mContentDrawBounds.left;
526             const float top = mContentDrawBounds.top;
527             const float dx = backdropBounds.left - left;
528             const float dy = backdropBounds.top - top;
529             const float width = backdropBounds.getWidth();
530             const float height = backdropBounds.getHeight();
531 
532             mCanvas->translate(dx, dy);
533             if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) {
534                 mCanvas->drawRenderNode(node.get(), outBounds);
535             }
536             mCanvas->restore();
537         } else { // draw the rest on top at will!
538             mCanvas->drawRenderNode(node.get(), outBounds);
539         }
540         layer++;
541     }
542 
543     profiler().draw(mCanvas);
544 
545     bool drew = mCanvas->finish();
546 #endif
547 
548     waitOnFences();
549 
550     GL_CHECKPOINT(LOW);
551 
552     // Even if we decided to cancel the frame, from the perspective of jank
553     // metrics the frame was swapped at this point
554     mCurrentFrameInfo->markSwapBuffers();
555     mIsDirty = false;
556 
557     if (drew || mEglManager.damageRequiresSwap()) {
558         if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
559             setSurface(nullptr);
560         }
561         SwapHistory& swap = mSwapHistory.next();
562         swap.damage = screenDirty;
563         swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC);
564         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
565         if (mNativeSurface.get()) {
566             int durationUs;
567             mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
568             swap.dequeueDuration = us2ns(durationUs);
569             mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
570             swap.queueDuration = us2ns(durationUs);
571         } else {
572             swap.dequeueDuration = 0;
573             swap.queueDuration = 0;
574         }
575         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
576                 = swap.dequeueDuration;
577         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
578                 = swap.queueDuration;
579         mHaveNewSurface = false;
580         mFrameNumber = -1;
581     } else {
582         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0;
583         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0;
584     }
585 
586     // TODO: Use a fence for real completion?
587     mCurrentFrameInfo->markFrameCompleted();
588 
589 #if LOG_FRAMETIME_MMA
590     float thisFrame = mCurrentFrameInfo->duration(
591             FrameInfoIndex::IssueDrawCommandsStart,
592             FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F;
593     if (sFrameCount) {
594         sBenchMma = ((9 * sBenchMma) + thisFrame) / 10;
595     } else {
596         sBenchMma = thisFrame;
597     }
598     if (++sFrameCount == 10) {
599         sFrameCount = 1;
600         ALOGD("Average frame time: %.4f", sBenchMma);
601     }
602 #endif
603 
604     mJankTracker.addFrame(*mCurrentFrameInfo);
605     mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
606     if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) {
607         mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data());
608     }
609 
610     GpuMemoryTracker::onFrameCompleted();
611 #ifdef BUGREPORT_FONT_CACHE_USAGE
612     caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
613 #endif
614 
615 }
616 
617 // Called by choreographer to do an RT-driven animation
doFrame()618 void CanvasContext::doFrame() {
619 #if HWUI_NEW_OPS
620     if (CC_UNLIKELY(mEglSurface == EGL_NO_SURFACE)) return;
621 #else
622     if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) return;
623 #endif
624     prepareAndDraw(nullptr);
625 }
626 
prepareAndDraw(RenderNode * node)627 void CanvasContext::prepareAndDraw(RenderNode* node) {
628     ATRACE_CALL();
629 
630     nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
631     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
632     UiFrameInfoBuilder(frameInfo)
633         .addFlag(FrameInfoFlags::RTAnimation)
634         .setVsync(vsync, vsync);
635 
636     TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
637     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
638     if (info.out.canDrawThisFrame) {
639         draw();
640     } else {
641         // wait on fences so tasks don't overlap next frame
642         waitOnFences();
643     }
644 }
645 
invokeFunctor(RenderThread & thread,Functor * functor)646 void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
647     ATRACE_CALL();
648     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
649     if (thread.eglManager().hasEglContext()) {
650         mode = DrawGlInfo::kModeProcess;
651     }
652 
653     thread.renderState().invokeFunctor(functor, mode, nullptr);
654 }
655 
markLayerInUse(RenderNode * node)656 void CanvasContext::markLayerInUse(RenderNode* node) {
657     if (mPrefetchedLayers.erase(node)) {
658         node->decStrong(nullptr);
659     }
660 }
661 
freePrefetchedLayers(TreeObserver * observer)662 void CanvasContext::freePrefetchedLayers(TreeObserver* observer) {
663     if (mPrefetchedLayers.size()) {
664         for (auto& node : mPrefetchedLayers) {
665             ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
666                     node->getName());
667             node->destroyHardwareResources(observer);
668             node->decStrong(observer);
669         }
670         mPrefetchedLayers.clear();
671     }
672 }
673 
buildLayer(RenderNode * node,TreeObserver * observer)674 void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
675     ATRACE_CALL();
676     if (!mEglManager.hasEglContext()) return;
677 #if !HWUI_NEW_OPS
678     if (!mCanvas) return;
679 #endif
680 
681     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
682     stopDrawing();
683 
684     TreeInfo info(TreeInfo::MODE_FULL, *this);
685     info.damageAccumulator = &mDamageAccumulator;
686     info.observer = observer;
687 #if HWUI_NEW_OPS
688     info.layerUpdateQueue = &mLayerUpdateQueue;
689 #else
690     info.renderer = mCanvas;
691 #endif
692     info.runAnimations = false;
693     node->prepareTree(info);
694     SkRect ignore;
695     mDamageAccumulator.finish(&ignore);
696     // Tickle the GENERIC property on node to mark it as dirty for damaging
697     // purposes when the frame is actually drawn
698     node->setPropertyFieldsDirty(RenderNode::GENERIC);
699 
700 #if HWUI_NEW_OPS
701     static const std::vector< sp<RenderNode> > emptyNodeList;
702     auto& caches = Caches::getInstance();
703     FrameBuilder frameBuilder(mLayerUpdateQueue, mLightGeometry, caches);
704     mLayerUpdateQueue.clear();
705     BakedOpRenderer renderer(caches, mRenderThread.renderState(),
706             mOpaque, mLightInfo);
707     LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
708     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
709 #else
710     mCanvas->markLayersAsBuildLayers();
711     mCanvas->flushLayerUpdates();
712 #endif
713 
714     node->incStrong(nullptr);
715     mPrefetchedLayers.insert(node);
716 }
717 
copyLayerInto(DeferredLayerUpdater * layer,SkBitmap * bitmap)718 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
719     layer->apply();
720     return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
721 }
722 
destroyHardwareResources(TreeObserver * observer)723 void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
724     stopDrawing();
725     if (mEglManager.hasEglContext()) {
726         freePrefetchedLayers(observer);
727         for (const sp<RenderNode>& node : mRenderNodes) {
728             node->destroyHardwareResources(observer);
729         }
730         Caches& caches = Caches::getInstance();
731         // Make sure to release all the textures we were owning as there won't
732         // be another draw
733         caches.textureCache.resetMarkInUse(this);
734         mRenderThread.renderState().flush(Caches::FlushMode::Layers);
735     }
736 }
737 
trimMemory(RenderThread & thread,int level)738 void CanvasContext::trimMemory(RenderThread& thread, int level) {
739     // No context means nothing to free
740     if (!thread.eglManager().hasEglContext()) return;
741 
742     ATRACE_CALL();
743     if (level >= TRIM_MEMORY_COMPLETE) {
744         thread.renderState().flush(Caches::FlushMode::Full);
745         thread.eglManager().destroy();
746     } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
747         thread.renderState().flush(Caches::FlushMode::Moderate);
748     }
749 }
750 
runWithGlContext(RenderTask * task)751 void CanvasContext::runWithGlContext(RenderTask* task) {
752     LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(),
753             "GL context not initialized!");
754     task->run();
755 }
756 
createTextureLayer()757 Layer* CanvasContext::createTextureLayer() {
758     mEglManager.initialize();
759     return LayerRenderer::createTextureLayer(mRenderThread.renderState());
760 }
761 
setTextureAtlas(RenderThread & thread,const sp<GraphicBuffer> & buffer,int64_t * map,size_t mapSize)762 void CanvasContext::setTextureAtlas(RenderThread& thread,
763         const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize) {
764     thread.eglManager().setTextureAtlas(buffer, map, mapSize);
765 }
766 
dumpFrames(int fd)767 void CanvasContext::dumpFrames(int fd) {
768     FILE* file = fdopen(fd, "a");
769     fprintf(file, "\n\n---PROFILEDATA---\n");
770     for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
771         fprintf(file, "%s", FrameInfoNames[i].c_str());
772         fprintf(file, ",");
773     }
774     for (size_t i = 0; i < mFrames.size(); i++) {
775         FrameInfo& frame = mFrames[i];
776         if (frame[FrameInfoIndex::SyncStart] == 0) {
777             continue;
778         }
779         fprintf(file, "\n");
780         for (int i = 0; i < static_cast<int>(FrameInfoIndex::NumIndexes); i++) {
781             fprintf(file, "%" PRId64 ",", frame[i]);
782         }
783     }
784     fprintf(file, "\n---PROFILEDATA---\n\n");
785     fflush(file);
786 }
787 
resetFrameStats()788 void CanvasContext::resetFrameStats() {
789     mFrames.clear();
790     mRenderThread.jankTracker().reset();
791 }
792 
serializeDisplayListTree()793 void CanvasContext::serializeDisplayListTree() {
794 #if ENABLE_RENDERNODE_SERIALIZATION
795     using namespace google::protobuf::io;
796     char package[128];
797     // Check whether tracing is enabled for this process.
798     FILE * file = fopen("/proc/self/cmdline", "r");
799     if (file) {
800         if (!fgets(package, 128, file)) {
801             ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
802             fclose(file);
803             return;
804         }
805         fclose(file);
806     } else {
807         ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
808                 errno);
809         return;
810     }
811     char path[1024];
812     snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package);
813     int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH);
814     if (fd == -1) {
815         ALOGD("Failed to open '%s'", path);
816         return;
817     }
818     proto::RenderNode tree;
819     // TODO: Streaming writes?
820     mRootRenderNode->copyTo(&tree);
821     std::string data = tree.SerializeAsString();
822     write(fd, data.c_str(), data.length());
823     close(fd);
824 #endif
825 }
826 
waitOnFences()827 void CanvasContext::waitOnFences() {
828     if (mFrameFences.size()) {
829         ATRACE_CALL();
830         for (auto& fence : mFrameFences) {
831             fence->getResult();
832         }
833         mFrameFences.clear();
834     }
835 }
836 
837 class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
838 public:
FuncTaskProcessor(Caches & caches)839     FuncTaskProcessor(Caches& caches)
840             : TaskProcessor<bool>(&caches.tasks) {}
841 
onProcess(const sp<Task<bool>> & task)842     virtual void onProcess(const sp<Task<bool> >& task) override {
843         FuncTask* t = static_cast<FuncTask*>(task.get());
844         t->func();
845         task->setResult(true);
846     }
847 };
848 
enqueueFrameWork(std::function<void ()> && func)849 void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
850     if (!mFrameWorkProcessor.get()) {
851         mFrameWorkProcessor = new FuncTaskProcessor(Caches::getInstance());
852     }
853     sp<FuncTask> task(new FuncTask());
854     task->func = func;
855     mFrameFences.push_back(task);
856     mFrameWorkProcessor->add(task);
857 }
858 
getFrameNumber()859 int64_t CanvasContext::getFrameNumber() {
860     // mFrameNumber is reset to -1 when the surface changes or we swap buffers
861     if (mFrameNumber == -1 && mNativeSurface.get()) {
862         mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber());
863     }
864     return mFrameNumber;
865 }
866 
867 } /* namespace renderthread */
868 } /* namespace uirenderer */
869 } /* namespace android */
870