DrawFrameTask.cpp revision 1b54fb27ac48495ed0b33868fda5776fb49fe0f3
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 30namespace android { 31namespace uirenderer { 32namespace renderthread { 33 34DrawFrameTask::DrawFrameTask() 35 : mRenderThread(nullptr) 36 , mContext(nullptr) 37 , mSyncResult(kSync_OK) { 38} 39 40DrawFrameTask::~DrawFrameTask() { 41} 42 43void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) { 44 mRenderThread = thread; 45 mContext = context; 46} 47 48void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { 49 LOG_ALWAYS_FATAL_IF(!mContext, "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 59void 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 68int DrawFrameTask::drawFrame() { 69 LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); 70 71 mSyncResult = kSync_OK; 72 postAndWait(); 73 74 return mSyncResult; 75} 76 77void DrawFrameTask::postAndWait() { 78 AutoMutex _lock(mLock); 79 mRenderThread->queue(this); 80 mSignal.wait(mLock); 81} 82 83void DrawFrameTask::run() { 84 ATRACE_NAME("DrawFrame"); 85 86 bool canUnblockUiThread; 87 bool canDrawThisFrame; 88 { 89 TreeInfo info(TreeInfo::MODE_FULL, mRenderThread->renderState()); 90 canUnblockUiThread = syncFrameState(info); 91 canDrawThisFrame = info.out.canDrawThisFrame; 92 } 93 94 // Grab a copy of everything we need 95 CanvasContext* context = mContext; 96 97 // From this point on anything in "this" is *UNSAFE TO ACCESS* 98 if (canUnblockUiThread) { 99 unblockUiThread(); 100 } 101 102 if (CC_LIKELY(canDrawThisFrame)) { 103 context->draw(); 104 } 105 106 if (!canUnblockUiThread) { 107 unblockUiThread(); 108 } 109} 110 111bool DrawFrameTask::syncFrameState(TreeInfo& info) { 112 ATRACE_CALL(); 113 int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)]; 114 mRenderThread->timeLord().vsyncReceived(vsync); 115 mContext->makeCurrent(); 116 Caches::getInstance().textureCache.resetMarkInUse(); 117 118 for (size_t i = 0; i < mLayers.size(); i++) { 119 mContext->processLayerUpdate(mLayers[i].get()); 120 } 121 mLayers.clear(); 122 mContext->prepareTree(info, mFrameInfo); 123 124 // This is after the prepareTree so that any pending operations 125 // (RenderNode tree state, prefetched layers, etc...) will be flushed. 126 if (CC_UNLIKELY(!mContext->hasSurface())) { 127 mSyncResult |= kSync_LostSurfaceRewardIfFound; 128 } 129 130 if (info.out.hasAnimations) { 131 if (info.out.requiresUiRedraw) { 132 mSyncResult |= kSync_UIRedrawRequired; 133 } 134 } 135 // If prepareTextures is false, we ran out of texture cache space 136 return info.prepareTextures; 137} 138 139void DrawFrameTask::unblockUiThread() { 140 AutoMutex _lock(mLock); 141 mSignal.signal(); 142} 143 144} /* namespace renderthread */ 145} /* namespace uirenderer */ 146} /* namespace android */ 147