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