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 "DrawFrameTask.h"
     18 
     19 #include <utils/Log.h>
     20 #include <utils/Trace.h>
     21 
     22 #include "../DeferredLayerUpdater.h"
     23 #include "../DisplayList.h"
     24 #include "../RenderNode.h"
     25 #include "CanvasContext.h"
     26 #include "RenderThread.h"
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 namespace renderthread {
     31 
     32 DrawFrameTask::DrawFrameTask()
     33         : mRenderThread(nullptr)
     34         , mContext(nullptr)
     35         , mContentDrawBounds(0, 0, 0, 0)
     36         , mSyncResult(SyncResult::OK) {}
     37 
     38 DrawFrameTask::~DrawFrameTask() {}
     39 
     40 void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
     41                                RenderNode* targetNode) {
     42     mRenderThread = thread;
     43     mContext = context;
     44     mTargetNode = targetNode;
     45 }
     46 
     47 void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
     48     LOG_ALWAYS_FATAL_IF(!mContext,
     49                         "Lifecycle violation, there's no context to pushLayerUpdate with!");
     50 
     51     for (size_t i = 0; i < mLayers.size(); i++) {
     52         if (mLayers[i].get() == layer) {
     53             return;
     54         }
     55     }
     56     mLayers.push_back(layer);
     57 }
     58 
     59 void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
     60     for (size_t i = 0; i < mLayers.size(); i++) {
     61         if (mLayers[i].get() == layer) {
     62             mLayers.erase(mLayers.begin() + i);
     63             return;
     64         }
     65     }
     66 }
     67 
     68 int DrawFrameTask::drawFrame() {
     69     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
     70 
     71     mSyncResult = SyncResult::OK;
     72     mSyncQueued = systemTime(CLOCK_MONOTONIC);
     73     postAndWait();
     74 
     75     return mSyncResult;
     76 }
     77 
     78 void DrawFrameTask::postAndWait() {
     79     AutoMutex _lock(mLock);
     80     mRenderThread->queue().post([this]() { run(); });
     81     mSignal.wait(mLock);
     82 }
     83 
     84 void DrawFrameTask::run() {
     85     ATRACE_NAME("DrawFrame");
     86 
     87     bool canUnblockUiThread;
     88     bool canDrawThisFrame;
     89     {
     90         TreeInfo info(TreeInfo::MODE_FULL, *mContext);
     91         canUnblockUiThread = syncFrameState(info);
     92         canDrawThisFrame = info.out.canDrawThisFrame;
     93 
     94         if (mFrameCompleteCallback) {
     95             mContext->addFrameCompleteListener(std::move(mFrameCompleteCallback));
     96             mFrameCompleteCallback = nullptr;
     97         }
     98     }
     99 
    100     // Grab a copy of everything we need
    101     CanvasContext* context = mContext;
    102     std::function<void(int64_t)> callback = std::move(mFrameCallback);
    103     mFrameCallback = nullptr;
    104 
    105     // From this point on anything in "this" is *UNSAFE TO ACCESS*
    106     if (canUnblockUiThread) {
    107         unblockUiThread();
    108     }
    109 
    110     // Even if we aren't drawing this vsync pulse the next frame number will still be accurate
    111     if (CC_UNLIKELY(callback)) {
    112         context->enqueueFrameWork(
    113                 [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
    114     }
    115 
    116     if (CC_LIKELY(canDrawThisFrame)) {
    117         context->draw();
    118     } else {
    119         // wait on fences so tasks don't overlap next frame
    120         context->waitOnFences();
    121     }
    122 
    123     if (!canUnblockUiThread) {
    124         unblockUiThread();
    125     }
    126 }
    127 
    128 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
    129     ATRACE_CALL();
    130     int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
    131     mRenderThread->timeLord().vsyncReceived(vsync);
    132     bool canDraw = mContext->makeCurrent();
    133     mContext->unpinImages();
    134 
    135     for (size_t i = 0; i < mLayers.size(); i++) {
    136         mLayers[i]->apply();
    137     }
    138     mLayers.clear();
    139     mContext->setContentDrawBounds(mContentDrawBounds);
    140     mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
    141 
    142     // This is after the prepareTree so that any pending operations
    143     // (RenderNode tree state, prefetched layers, etc...) will be flushed.
    144     if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) {
    145         if (!mContext->hasSurface()) {
    146             mSyncResult |= SyncResult::LostSurfaceRewardIfFound;
    147         } else {
    148             // If we have a surface but can't draw we must be stopped
    149             mSyncResult |= SyncResult::ContextIsStopped;
    150         }
    151         info.out.canDrawThisFrame = false;
    152     }
    153 
    154     if (info.out.hasAnimations) {
    155         if (info.out.requiresUiRedraw) {
    156             mSyncResult |= SyncResult::UIRedrawRequired;
    157         }
    158     }
    159     if (!info.out.canDrawThisFrame) {
    160         mSyncResult |= SyncResult::FrameDropped;
    161     }
    162     // If prepareTextures is false, we ran out of texture cache space
    163     return info.prepareTextures;
    164 }
    165 
    166 void DrawFrameTask::unblockUiThread() {
    167     AutoMutex _lock(mLock);
    168     mSignal.signal();
    169 }
    170 
    171 } /* namespace renderthread */
    172 } /* namespace uirenderer */
    173 } /* namespace android */
    174