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