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 <gui/TraceUtils.h>
20 #include <utils/Log.h>
21
22 #include <algorithm>
23
24 #include "../DeferredLayerUpdater.h"
25 #include "../DisplayList.h"
26 #include "../Properties.h"
27 #include "../RenderNode.h"
28 #include "CanvasContext.h"
29 #include "HardwareBufferRenderParams.h"
30 #include "RenderThread.h"
31
32 namespace android {
33 namespace uirenderer {
34 namespace renderthread {
35
DrawFrameTask()36 DrawFrameTask::DrawFrameTask()
37 : mRenderThread(nullptr)
38 , mContext(nullptr)
39 , mContentDrawBounds(0, 0, 0, 0)
40 , mSyncResult(SyncResult::OK) {}
41
~DrawFrameTask()42 DrawFrameTask::~DrawFrameTask() {}
43
setContext(RenderThread * thread,CanvasContext * context,RenderNode * targetNode)44 void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
45 RenderNode* targetNode) {
46 mRenderThread = thread;
47 mContext = context;
48 mTargetNode = targetNode;
49 }
50
pushLayerUpdate(DeferredLayerUpdater * layer)51 void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
52 LOG_ALWAYS_FATAL_IF(!mContext,
53 "Lifecycle violation, there's no context to pushLayerUpdate with!");
54
55 for (size_t i = 0; i < mLayers.size(); i++) {
56 if (mLayers[i].get() == layer) {
57 return;
58 }
59 }
60 mLayers.push_back(layer);
61 }
62
removeLayerUpdate(DeferredLayerUpdater * layer)63 void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
64 for (size_t i = 0; i < mLayers.size(); i++) {
65 if (mLayers[i].get() == layer) {
66 mLayers.erase(mLayers.begin() + i);
67 return;
68 }
69 }
70 }
71
drawFrame()72 int DrawFrameTask::drawFrame() {
73 LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
74
75 mSyncResult = SyncResult::OK;
76 mSyncQueued = systemTime(SYSTEM_TIME_MONOTONIC);
77 postAndWait();
78
79 return mSyncResult;
80 }
81
postAndWait()82 void DrawFrameTask::postAndWait() {
83 ATRACE_CALL();
84 AutoMutex _lock(mLock);
85 mRenderThread->queue().post([this]() { run(); });
86 mSignal.wait(mLock);
87 }
88
run()89 void DrawFrameTask::run() {
90 const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
91 ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
92
93 mContext->setSyncDelayDuration(systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued);
94 mContext->setTargetSdrHdrRatio(mRenderSdrHdrRatio);
95
96 auto hardwareBufferParams = mHardwareBufferParams;
97 mContext->setHardwareBufferRenderParams(hardwareBufferParams);
98 IRenderPipeline* pipeline = mContext->getRenderPipeline();
99 bool canUnblockUiThread;
100 bool canDrawThisFrame;
101 bool solelyTextureViewUpdates;
102 {
103 TreeInfo info(TreeInfo::MODE_FULL, *mContext);
104 info.forceDrawFrame = mForceDrawFrame;
105 mForceDrawFrame = false;
106 canUnblockUiThread = syncFrameState(info);
107 canDrawThisFrame = !info.out.skippedFrameReason.has_value();
108 solelyTextureViewUpdates = info.out.solelyTextureViewUpdates;
109
110 if (mFrameCommitCallback) {
111 mContext->addFrameCommitListener(std::move(mFrameCommitCallback));
112 mFrameCommitCallback = nullptr;
113 }
114 }
115
116 // Grab a copy of everything we need
117 CanvasContext* context = mContext;
118 std::function<std::function<void(bool)>(int32_t, int64_t)> frameCallback =
119 std::move(mFrameCallback);
120 std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
121 mFrameCallback = nullptr;
122 mFrameCompleteCallback = nullptr;
123
124 // From this point on anything in "this" is *UNSAFE TO ACCESS*
125 if (canUnblockUiThread) {
126 unblockUiThread();
127 }
128
129 // Even if we aren't drawing this vsync pulse the next frame number will still be accurate
130 if (CC_UNLIKELY(frameCallback)) {
131 context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult,
132 frameNr = context->getFrameNumber()]() {
133 auto frameCommitCallback = frameCallback(syncResult, frameNr);
134 if (frameCommitCallback) {
135 context->addFrameCommitListener(std::move(frameCommitCallback));
136 }
137 });
138 }
139
140 if (CC_LIKELY(canDrawThisFrame)) {
141 context->draw(solelyTextureViewUpdates);
142 } else {
143 #ifdef __ANDROID__
144 // Do a flush in case syncFrameState performed any texture uploads. Since we skipped
145 // the draw() call, those uploads (or deletes) will end up sitting in the queue.
146 // Do them now
147 if (GrDirectContext* grContext = mRenderThread->getGrContext()) {
148 grContext->flushAndSubmit();
149 }
150 #endif
151 // wait on fences so tasks don't overlap next frame
152 context->waitOnFences();
153 }
154
155 if (CC_UNLIKELY(frameCompleteCallback)) {
156 std::invoke(frameCompleteCallback);
157 }
158
159 if (!canUnblockUiThread) {
160 unblockUiThread();
161 }
162
163 if (pipeline->hasHardwareBuffer()) {
164 auto fence = pipeline->flush();
165 hardwareBufferParams.invokeRenderCallback(std::move(fence), 0);
166 }
167 }
168
syncFrameState(TreeInfo & info)169 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
170 ATRACE_CALL();
171 int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
172 int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
173 int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
174 int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
175 int64_t frameInterval = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameInterval)];
176 mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId, frameDeadline,
177 frameInterval);
178 bool canDraw = mContext->makeCurrent();
179 mContext->unpinImages();
180
181 #ifdef __ANDROID__
182 for (size_t i = 0; i < mLayers.size(); i++) {
183 if (mLayers[i]) {
184 mLayers[i]->apply();
185 }
186 }
187 #endif
188
189 mLayers.clear();
190 mContext->setContentDrawBounds(mContentDrawBounds);
191 mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
192
193 // This is after the prepareTree so that any pending operations
194 // (RenderNode tree state, prefetched layers, etc...) will be flushed.
195 bool hasTarget = mContext->hasOutputTarget();
196 if (CC_UNLIKELY(!hasTarget || !canDraw)) {
197 if (!hasTarget) {
198 mSyncResult |= SyncResult::LostSurfaceRewardIfFound;
199 info.out.skippedFrameReason = SkippedFrameReason::NoOutputTarget;
200 } else {
201 // If we have a surface but can't draw we must be stopped
202 mSyncResult |= SyncResult::ContextIsStopped;
203 info.out.skippedFrameReason = SkippedFrameReason::ContextIsStopped;
204 }
205 }
206
207 if (info.out.hasAnimations) {
208 if (info.out.requiresUiRedraw) {
209 mSyncResult |= SyncResult::UIRedrawRequired;
210 }
211 }
212 if (info.out.skippedFrameReason) {
213 mSyncResult |= SyncResult::FrameDropped;
214 }
215 // If prepareTextures is false, we ran out of texture cache space
216 return info.prepareTextures;
217 }
218
unblockUiThread()219 void DrawFrameTask::unblockUiThread() {
220 AutoMutex _lock(mLock);
221 mSignal.signal();
222 }
223
224 } /* namespace renderthread */
225 } /* namespace uirenderer */
226 } /* namespace android */
227