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