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