xref: /aosp_15_r20/frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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