DrawFrameTask.cpp revision d72e0a339b54af0c4e731513bbad120dff694723
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(NULL) 36 , mContext(NULL) 37 , mFrameTimeNanos(0) 38 , mRecordDurationNanos(0) 39 , mDensity(1.0f) // safe enough default 40 , mSyncResult(kSync_OK) { 41} 42 43DrawFrameTask::~DrawFrameTask() { 44} 45 46void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) { 47 mRenderThread = thread; 48 mContext = context; 49} 50 51void 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 62void 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 71void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { 72 mDirty.set(left, top, right, bottom); 73} 74 75int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) { 76 LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); 77 78 mSyncResult = kSync_OK; 79 mFrameTimeNanos = frameTimeNanos; 80 mRecordDurationNanos = recordDurationNanos; 81 postAndWait(); 82 83 // Reset the single-frame data 84 mFrameTimeNanos = 0; 85 mRecordDurationNanos = 0; 86 mDirty.setEmpty(); 87 88 return mSyncResult; 89} 90 91void DrawFrameTask::postAndWait() { 92 AutoMutex _lock(mLock); 93 mRenderThread->queue(this); 94 mSignal.wait(mLock); 95} 96 97void DrawFrameTask::run() { 98 ATRACE_NAME("DrawFrame"); 99 100 mContext->profiler().setDensity(mDensity); 101 mContext->profiler().startFrame(mRecordDurationNanos); 102 103 bool canUnblockUiThread; 104 bool canDrawThisFrame; 105 { 106 TreeInfo info; 107 canUnblockUiThread = syncFrameState(info); 108 canDrawThisFrame = info.out.canDrawThisFrame; 109 } 110 111 // Grab a copy of everything we need 112 Rect dirty(mDirty); 113 CanvasContext* context = mContext; 114 115 // From this point on anything in "this" is *UNSAFE TO ACCESS* 116 if (canUnblockUiThread) { 117 unblockUiThread(); 118 } 119 120 if (CC_LIKELY(canDrawThisFrame)) { 121 context->draw(&dirty); 122 } 123 124 if (!canUnblockUiThread) { 125 unblockUiThread(); 126 } 127} 128 129static void initTreeInfo(TreeInfo& info) { 130 info.prepareTextures = true; 131 info.performStagingPush = true; 132 info.evaluateAnimations = true; 133} 134 135bool DrawFrameTask::syncFrameState(TreeInfo& info) { 136 ATRACE_CALL(); 137 mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos); 138 mContext->makeCurrent(); 139 Caches::getInstance().textureCache.resetMarkInUse(); 140 initTreeInfo(info); 141 142 for (size_t i = 0; i < mLayers.size(); i++) { 143 mContext->processLayerUpdate(mLayers[i].get(), info); 144 } 145 mLayers.clear(); 146 if (info.out.hasAnimations) { 147 // TODO: Uh... crap? 148 } 149 mContext->prepareTree(info); 150 151 if (info.out.hasAnimations) { 152 // TODO: dirty calculations, for now just do a full-screen inval 153 mDirty.setEmpty(); 154 if (info.out.requiresUiRedraw) { 155 mSyncResult |= kSync_UIRedrawRequired; 156 } 157 } 158 // If prepareTextures is false, we ran out of texture cache space 159 return !info.out.hasFunctors && info.prepareTextures; 160} 161 162void DrawFrameTask::unblockUiThread() { 163 AutoMutex _lock(mLock); 164 mSignal.signal(); 165} 166 167} /* namespace renderthread */ 168} /* namespace uirenderer */ 169} /* namespace android */ 170