DrawFrameTask.cpp revision fe5e7b7346a54537b980796ceeca66bfdbd05561
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 "../DisplayList.h" 25#include "../RenderNode.h" 26#include "CanvasContext.h" 27#include "RenderThread.h" 28 29namespace android { 30namespace uirenderer { 31namespace renderthread { 32 33DrawFrameTask::DrawFrameTask() 34 : mRenderThread(NULL) 35 , mContext(NULL) 36 , mFrameTimeNanos(0) 37 , mRecordDurationNanos(0) 38 , mDensity(1.0f) // safe enough default 39 , mSyncResult(kSync_OK) { 40} 41 42DrawFrameTask::~DrawFrameTask() { 43} 44 45void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) { 46 mRenderThread = thread; 47 mContext = context; 48} 49 50void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) { 51 LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!"); 52 53 mLayers.push(layer); 54} 55 56void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) { 57 for (size_t i = 0; i < mLayers.size(); i++) { 58 if (mLayers[i] == layer) { 59 mLayers.removeAt(i); 60 break; 61 } 62 } 63} 64 65void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { 66 mDirty.set(left, top, right, bottom); 67} 68 69int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) { 70 LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); 71 72 mSyncResult = kSync_OK; 73 mFrameTimeNanos = frameTimeNanos; 74 mRecordDurationNanos = recordDurationNanos; 75 postAndWait(); 76 77 // Reset the single-frame data 78 mFrameTimeNanos = 0; 79 mRecordDurationNanos = 0; 80 mDirty.setEmpty(); 81 82 return mSyncResult; 83} 84 85void DrawFrameTask::postAndWait() { 86 AutoMutex _lock(mLock); 87 mRenderThread->queue(this); 88 mSignal.wait(mLock); 89} 90 91void DrawFrameTask::run() { 92 ATRACE_NAME("DrawFrame"); 93 94 mContext->profiler().setDensity(mDensity); 95 mContext->profiler().startFrame(mRecordDurationNanos); 96 97 bool canUnblockUiThread; 98 bool canDrawThisFrame; 99 { 100 TreeInfo info; 101 canUnblockUiThread = syncFrameState(info); 102 canDrawThisFrame = info.out.canDrawThisFrame; 103 } 104 105 // Grab a copy of everything we need 106 Rect dirty(mDirty); 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(&dirty); 116 } 117 118 if (!canUnblockUiThread) { 119 unblockUiThread(); 120 } 121} 122 123static void initTreeInfo(TreeInfo& info) { 124 info.prepareTextures = true; 125 info.performStagingPush = true; 126 info.evaluateAnimations = true; 127} 128 129bool DrawFrameTask::syncFrameState(TreeInfo& info) { 130 ATRACE_CALL(); 131 mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos); 132 mContext->makeCurrent(); 133 Caches::getInstance().textureCache.resetMarkInUse(); 134 initTreeInfo(info); 135 mContext->prepareDraw(&mLayers, info); 136 if (info.out.hasAnimations) { 137 // TODO: dirty calculations, for now just do a full-screen inval 138 mDirty.setEmpty(); 139 if (info.out.requiresUiRedraw) { 140 mSyncResult |= kSync_UIRedrawRequired; 141 } 142 } 143 // If prepareTextures is false, we ran out of texture cache space 144 return !info.out.hasFunctors && info.prepareTextures; 145} 146 147void DrawFrameTask::unblockUiThread() { 148 AutoMutex _lock(mLock); 149 mSignal.signal(); 150} 151 152} /* namespace renderthread */ 153} /* namespace uirenderer */ 154} /* namespace android */ 155