DrawFrameTask.cpp revision a5dda645da738da7b4ae15e28fa7d93d3b04b94f
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 , 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::addLayer(DeferredLayerUpdater* layer) { 49 LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!"); 50 51 mLayers.push(layer); 52} 53 54void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) { 55 for (size_t i = 0; i < mLayers.size(); i++) { 56 if (mLayers[i] == layer) { 57 mLayers.removeAt(i); 58 break; 59 } 60 } 61} 62 63void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { 64 mDirty.set(left, top, right, bottom); 65} 66 67int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) { 68 LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); 69 70 mSyncResult = kSync_OK; 71 mFrameTimeNanos = frameTimeNanos; 72 postAndWait(); 73 74 // Reset the single-frame data 75 mFrameTimeNanos = 0; 76 mDirty.setEmpty(); 77 78 return mSyncResult; 79} 80 81void DrawFrameTask::postAndWait() { 82 AutoMutex _lock(mLock); 83 mRenderThread->queue(this); 84 mSignal.wait(mLock); 85} 86 87void DrawFrameTask::run() { 88 ATRACE_NAME("DrawFrame"); 89 90 bool canUnblockUiThread; 91 bool canDrawThisFrame; 92 { 93 TreeInfo info; 94 canUnblockUiThread = syncFrameState(info); 95 canDrawThisFrame = info.out.canDrawThisFrame; 96 } 97 98 // Grab a copy of everything we need 99 Rect dirty(mDirty); 100 CanvasContext* context = mContext; 101 102 // From this point on anything in "this" is *UNSAFE TO ACCESS* 103 if (canUnblockUiThread) { 104 unblockUiThread(); 105 } 106 107 if (CC_LIKELY(canDrawThisFrame)) { 108 context->draw(&dirty); 109 } 110 111 if (!canUnblockUiThread) { 112 unblockUiThread(); 113 } 114} 115 116static void initTreeInfo(TreeInfo& info) { 117 info.prepareTextures = true; 118 info.performStagingPush = true; 119 info.evaluateAnimations = true; 120} 121 122bool DrawFrameTask::syncFrameState(TreeInfo& info) { 123 ATRACE_CALL(); 124 mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos); 125 mContext->makeCurrent(); 126 Caches::getInstance().textureCache.resetMarkInUse(); 127 initTreeInfo(info); 128 mContext->prepareDraw(&mLayers, info); 129 if (info.out.hasAnimations) { 130 // TODO: dirty calculations, for now just do a full-screen inval 131 mDirty.setEmpty(); 132 if (info.out.requiresUiRedraw) { 133 mSyncResult |= kSync_UIRedrawRequired; 134 } 135 } 136 // If prepareTextures is false, we ran out of texture cache space 137 return !info.out.hasFunctors && info.prepareTextures; 138} 139 140void DrawFrameTask::unblockUiThread() { 141 AutoMutex _lock(mLock); 142 mSignal.signal(); 143} 144 145} /* namespace renderthread */ 146} /* namespace uirenderer */ 147} /* namespace android */ 148