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.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 
     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 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 
    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 
    327 void CanvasContext::stopDrawing() {
    328     mRenderThread.removeFrameCallback(this);
    329     mAnimationContext->pauseAnimators();
    330 }
    331 
    332 void CanvasContext::notifyFramePending() {
    333     ATRACE_CALL();
    334     mRenderThread.pushBackFrameCallback(this);
    335 }
    336 
    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 }
    612 
    613 // Called by choreographer to do an RT-driven animation
    614 void CanvasContext::doFrame() {
    615 #if HWUI_NEW_OPS
    616     if (CC_UNLIKELY(mEglSurface == EGL_NO_SURFACE)) return;
    617 #else
    618     if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) return;
    619 #endif
    620     prepareAndDraw(nullptr);
    621 }
    622 
    623 void CanvasContext::prepareAndDraw(RenderNode* node) {
    624     ATRACE_CALL();
    625 
    626     nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
    627     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
    628     UiFrameInfoBuilder(frameInfo)
    629         .addFlag(FrameInfoFlags::RTAnimation)
    630         .setVsync(vsync, vsync);
    631 
    632     TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
    633     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
    634     if (info.out.canDrawThisFrame) {
    635         draw();
    636     }
    637 }
    638 
    639 void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
    640     ATRACE_CALL();
    641     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
    642     if (thread.eglManager().hasEglContext()) {
    643         mode = DrawGlInfo::kModeProcess;
    644     }
    645 
    646     thread.renderState().invokeFunctor(functor, mode, nullptr);
    647 }
    648 
    649 void CanvasContext::markLayerInUse(RenderNode* node) {
    650     if (mPrefetchedLayers.erase(node)) {
    651         node->decStrong(nullptr);
    652     }
    653 }
    654 
    655 void CanvasContext::freePrefetchedLayers(TreeObserver* observer) {
    656     if (mPrefetchedLayers.size()) {
    657         for (auto& node : mPrefetchedLayers) {
    658             ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
    659                     node->getName());
    660             node->destroyHardwareResources(observer);
    661             node->decStrong(observer);
    662         }
    663         mPrefetchedLayers.clear();
    664     }
    665 }
    666 
    667 void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
    668     ATRACE_CALL();
    669     if (!mEglManager.hasEglContext()) return;
    670 #if !HWUI_NEW_OPS
    671     if (!mCanvas) return;
    672 #endif
    673 
    674     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
    675     stopDrawing();
    676 
    677     TreeInfo info(TreeInfo::MODE_FULL, *this);
    678     info.damageAccumulator = &mDamageAccumulator;
    679     info.observer = observer;
    680 #if HWUI_NEW_OPS
    681     info.layerUpdateQueue = &mLayerUpdateQueue;
    682 #else
    683     info.renderer = mCanvas;
    684 #endif
    685     info.runAnimations = false;
    686     node->prepareTree(info);
    687     SkRect ignore;
    688     mDamageAccumulator.finish(&ignore);
    689     // Tickle the GENERIC property on node to mark it as dirty for damaging
    690     // purposes when the frame is actually drawn
    691     node->setPropertyFieldsDirty(RenderNode::GENERIC);
    692 
    693 #if HWUI_NEW_OPS
    694     static const std::vector< sp<RenderNode> > emptyNodeList;
    695     auto& caches = Caches::getInstance();
    696     FrameBuilder frameBuilder(mLayerUpdateQueue, mLightGeometry, caches);
    697     mLayerUpdateQueue.clear();
    698     BakedOpRenderer renderer(caches, mRenderThread.renderState(),
    699             mOpaque, mLightInfo);
    700     LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
    701     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
    702 #else
    703     mCanvas->markLayersAsBuildLayers();
    704     mCanvas->flushLayerUpdates();
    705 #endif
    706 
    707     node->incStrong(nullptr);
    708     mPrefetchedLayers.insert(node);
    709 }
    710 
    711 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
    712     layer->apply();
    713     return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
    714 }
    715 
    716 void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
    717     stopDrawing();
    718     if (mEglManager.hasEglContext()) {
    719         freePrefetchedLayers(observer);
    720         for (const sp<RenderNode>& node : mRenderNodes) {
    721             node->destroyHardwareResources(observer);
    722         }
    723         Caches& caches = Caches::getInstance();
    724         // Make sure to release all the textures we were owning as there won't
    725         // be another draw
    726         caches.textureCache.resetMarkInUse(this);
    727         mRenderThread.renderState().flush(Caches::FlushMode::Layers);
    728     }
    729 }
    730 
    731 void CanvasContext::trimMemory(RenderThread& thread, int level) {
    732     // No context means nothing to free
    733     if (!thread.eglManager().hasEglContext()) return;
    734 
    735     ATRACE_CALL();
    736     if (level >= TRIM_MEMORY_COMPLETE) {
    737         thread.renderState().flush(Caches::FlushMode::Full);
    738         thread.eglManager().destroy();
    739     } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
    740         thread.renderState().flush(Caches::FlushMode::Moderate);
    741     }
    742 }
    743 
    744 void CanvasContext::runWithGlContext(RenderTask* task) {
    745     LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(),
    746             "GL context not initialized!");
    747     task->run();
    748 }
    749 
    750 Layer* CanvasContext::createTextureLayer() {
    751     mEglManager.initialize();
    752     return LayerRenderer::createTextureLayer(mRenderThread.renderState());
    753 }
    754 
    755 void CanvasContext::setTextureAtlas(RenderThread& thread,
    756         const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize) {
    757     thread.eglManager().setTextureAtlas(buffer, map, mapSize);
    758 }
    759 
    760 void CanvasContext::dumpFrames(int fd) {
    761     FILE* file = fdopen(fd, "a");
    762     fprintf(file, "\n\n---PROFILEDATA---\n");
    763     for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
    764         fprintf(file, "%s", FrameInfoNames[i].c_str());
    765         fprintf(file, ",");
    766     }
    767     for (size_t i = 0; i < mFrames.size(); i++) {
    768         FrameInfo& frame = mFrames[i];
    769         if (frame[FrameInfoIndex::SyncStart] == 0) {
    770             continue;
    771         }
    772         fprintf(file, "\n");
    773         for (int i = 0; i < static_cast<int>(FrameInfoIndex::NumIndexes); i++) {
    774             fprintf(file, "%" PRId64 ",", frame[i]);
    775         }
    776     }
    777     fprintf(file, "\n---PROFILEDATA---\n\n");
    778     fflush(file);
    779 }
    780 
    781 void CanvasContext::resetFrameStats() {
    782     mFrames.clear();
    783     mRenderThread.jankTracker().reset();
    784 }
    785 
    786 void CanvasContext::serializeDisplayListTree() {
    787 #if ENABLE_RENDERNODE_SERIALIZATION
    788     using namespace google::protobuf::io;
    789     char package[128];
    790     // Check whether tracing is enabled for this process.
    791     FILE * file = fopen("/proc/self/cmdline", "r");
    792     if (file) {
    793         if (!fgets(package, 128, file)) {
    794             ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
    795             fclose(file);
    796             return;
    797         }
    798         fclose(file);
    799     } else {
    800         ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
    801                 errno);
    802         return;
    803     }
    804     char path[1024];
    805     snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package);
    806     int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH);
    807     if (fd == -1) {
    808         ALOGD("Failed to open '%s'", path);
    809         return;
    810     }
    811     proto::RenderNode tree;
    812     // TODO: Streaming writes?
    813     mRootRenderNode->copyTo(&tree);
    814     std::string data = tree.SerializeAsString();
    815     write(fd, data.c_str(), data.length());
    816     close(fd);
    817 #endif
    818 }
    819 
    820 void CanvasContext::waitOnFences() {
    821     if (mFrameFences.size()) {
    822         ATRACE_CALL();
    823         for (auto& fence : mFrameFences) {
    824             fence->getResult();
    825         }
    826         mFrameFences.clear();
    827     }
    828 }
    829 
    830 class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
    831 public:
    832     FuncTaskProcessor(Caches& caches)
    833             : TaskProcessor<bool>(&caches.tasks) {}
    834 
    835     virtual void onProcess(const sp<Task<bool> >& task) override {
    836         FuncTask* t = static_cast<FuncTask*>(task.get());
    837         t->func();
    838         task->setResult(true);
    839     }
    840 };
    841 
    842 void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
    843     if (!mFrameWorkProcessor.get()) {
    844         mFrameWorkProcessor = new FuncTaskProcessor(Caches::getInstance());
    845     }
    846     sp<FuncTask> task(new FuncTask());
    847     task->func = func;
    848     mFrameFences.push_back(task);
    849     mFrameWorkProcessor->add(task);
    850 }
    851 
    852 int64_t CanvasContext::getFrameNumber() {
    853     // mFrameNumber is reset to -1 when the surface changes or we swap buffers
    854     if (mFrameNumber == -1 && mNativeSurface.get()) {
    855         mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber());
    856     }
    857     return mFrameNumber;
    858 }
    859 
    860 } /* namespace renderthread */
    861 } /* namespace uirenderer */
    862 } /* namespace android */
    863