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