DrawFrameTask.cpp revision b7d34b64dd32e3d84bd43344c9c3d9ad098129af
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 28namespace android { 29namespace uirenderer { 30namespace renderthread { 31 32DrawFrameTask::DrawFrameTask() 33 : mRenderThread(nullptr) 34 , mContext(nullptr) 35 , mSyncResult(SyncResult::OK) { 36} 37 38DrawFrameTask::~DrawFrameTask() { 39} 40 41void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, 42 RenderNode* targetNode) { 43 mRenderThread = thread; 44 mContext = context; 45 mTargetNode = targetNode; 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(TreeObserver* observer) { 69 LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); 70 71 mSyncResult = SyncResult::OK; 72 mSyncQueued = systemTime(CLOCK_MONOTONIC); 73 mObserver = observer; 74 postAndWait(); 75 76 return mSyncResult; 77} 78 79void DrawFrameTask::postAndWait() { 80 AutoMutex _lock(mLock); 81 mRenderThread->queue(this); 82 mSignal.wait(mLock); 83} 84 85void DrawFrameTask::run() { 86 ATRACE_NAME("DrawFrame"); 87 88 bool canUnblockUiThread; 89 bool canDrawThisFrame; 90 { 91 TreeInfo info(TreeInfo::MODE_FULL, *mContext); 92 info.observer = mObserver; 93 canUnblockUiThread = syncFrameState(info); 94 canDrawThisFrame = info.out.canDrawThisFrame; 95 } 96 97 // Grab a copy of everything we need 98 CanvasContext* context = mContext; 99 100 // From this point on anything in "this" is *UNSAFE TO ACCESS* 101 if (canUnblockUiThread) { 102 unblockUiThread(); 103 } 104 105 if (CC_LIKELY(canDrawThisFrame)) { 106 context->draw(); 107 } else { 108 // wait on fences so tasks don't overlap next frame 109 context->waitOnFences(); 110 } 111 112 if (!canUnblockUiThread) { 113 unblockUiThread(); 114 } 115} 116 117bool DrawFrameTask::syncFrameState(TreeInfo& info) { 118 ATRACE_CALL(); 119 int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)]; 120 mRenderThread->timeLord().vsyncReceived(vsync); 121 bool canDraw = mContext->makeCurrent(); 122 mContext->unpinImages(); 123 124 for (size_t i = 0; i < mLayers.size(); i++) { 125 mLayers[i]->apply(); 126 } 127 mLayers.clear(); 128 mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode); 129 130 // This is after the prepareTree so that any pending operations 131 // (RenderNode tree state, prefetched layers, etc...) will be flushed. 132 if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) { 133 if (!mContext->hasSurface()) { 134 mSyncResult |= SyncResult::LostSurfaceRewardIfFound; 135 } else { 136 // If we have a surface but can't draw we must be stopped 137 mSyncResult |= SyncResult::ContextIsStopped; 138 } 139 info.out.canDrawThisFrame = false; 140 } 141 142 if (info.out.hasAnimations) { 143 if (info.out.requiresUiRedraw) { 144 mSyncResult |= SyncResult::UIRedrawRequired; 145 } 146 } 147 // If prepareTextures is false, we ran out of texture cache space 148 return info.prepareTextures; 149} 150 151void DrawFrameTask::unblockUiThread() { 152 AutoMutex _lock(mLock); 153 mSignal.signal(); 154} 155 156} /* namespace renderthread */ 157} /* namespace uirenderer */ 158} /* namespace android */ 159