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 #define ATRACE_TAG ATRACE_TAG_VIEW
     18 
     19 #include "DrawFrameTask.h"
     20 
     21 #include <utils/Log.h>
     22 #include <utils/Trace.h>
     23 
     24 #include "../DeferredLayerUpdater.h"
     25 #include "../DisplayList.h"
     26 #include "../RenderNode.h"
     27 #include "CanvasContext.h"
     28 #include "RenderThread.h"
     29 
     30 namespace android {
     31 namespace uirenderer {
     32 namespace renderthread {
     33 
     34 DrawFrameTask::DrawFrameTask()
     35         : mRenderThread(NULL)
     36         , mContext(NULL)
     37         , mFrameTimeNanos(0)
     38         , mRecordDurationNanos(0)
     39         , mDensity(1.0f) // safe enough default
     40         , mSyncResult(kSync_OK) {
     41 }
     42 
     43 DrawFrameTask::~DrawFrameTask() {
     44 }
     45 
     46 void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) {
     47     mRenderThread = thread;
     48     mContext = context;
     49 }
     50 
     51 void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
     52     LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!");
     53 
     54     for (size_t i = 0; i < mLayers.size(); i++) {
     55         if (mLayers[i].get() == layer) {
     56             return;
     57         }
     58     }
     59     mLayers.push_back(layer);
     60 }
     61 
     62 void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
     63     for (size_t i = 0; i < mLayers.size(); i++) {
     64         if (mLayers[i].get() == layer) {
     65             mLayers.erase(mLayers.begin() + i);
     66             return;
     67         }
     68     }
     69 }
     70 
     71 int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
     72     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
     73 
     74     mSyncResult = kSync_OK;
     75     mFrameTimeNanos = frameTimeNanos;
     76     mRecordDurationNanos = recordDurationNanos;
     77     postAndWait();
     78 
     79     // Reset the single-frame data
     80     mFrameTimeNanos = 0;
     81     mRecordDurationNanos = 0;
     82 
     83     return mSyncResult;
     84 }
     85 
     86 void DrawFrameTask::postAndWait() {
     87     AutoMutex _lock(mLock);
     88     mRenderThread->queue(this);
     89     mSignal.wait(mLock);
     90 }
     91 
     92 void DrawFrameTask::run() {
     93     ATRACE_NAME("DrawFrame");
     94 
     95     mContext->profiler().setDensity(mDensity);
     96     mContext->profiler().startFrame(mRecordDurationNanos);
     97 
     98     bool canUnblockUiThread;
     99     bool canDrawThisFrame;
    100     {
    101         TreeInfo info(TreeInfo::MODE_FULL, mRenderThread->renderState());
    102         canUnblockUiThread = syncFrameState(info);
    103         canDrawThisFrame = info.out.canDrawThisFrame;
    104     }
    105 
    106     // Grab a copy of everything we need
    107     CanvasContext* context = mContext;
    108 
    109     // From this point on anything in "this" is *UNSAFE TO ACCESS*
    110     if (canUnblockUiThread) {
    111         unblockUiThread();
    112     }
    113 
    114     if (CC_LIKELY(canDrawThisFrame)) {
    115         context->draw();
    116     }
    117 
    118     if (!canUnblockUiThread) {
    119         unblockUiThread();
    120     }
    121 }
    122 
    123 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
    124     ATRACE_CALL();
    125     mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
    126     mContext->makeCurrent();
    127     Caches::getInstance().textureCache.resetMarkInUse();
    128 
    129     for (size_t i = 0; i < mLayers.size(); i++) {
    130         mContext->processLayerUpdate(mLayers[i].get());
    131     }
    132     mLayers.clear();
    133     mContext->prepareTree(info);
    134 
    135     // This is after the prepareTree so that any pending operations
    136     // (RenderNode tree state, prefetched layers, etc...) will be flushed.
    137     if (CC_UNLIKELY(!mContext->hasSurface())) {
    138         mSyncResult |= kSync_LostSurfaceRewardIfFound;
    139     }
    140 
    141     if (info.out.hasAnimations) {
    142         if (info.out.requiresUiRedraw) {
    143             mSyncResult |= kSync_UIRedrawRequired;
    144         }
    145     }
    146     // If prepareTextures is false, we ran out of texture cache space
    147     return info.prepareTextures;
    148 }
    149 
    150 void DrawFrameTask::unblockUiThread() {
    151     AutoMutex _lock(mLock);
    152     mSignal.signal();
    153 }
    154 
    155 } /* namespace renderthread */
    156 } /* namespace uirenderer */
    157 } /* namespace android */
    158