1 /*
2 * Copyright (c) 2022-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "rs_draw_frame.h"
17
18 #include <hitrace_meter.h>
19 #include <parameters.h>
20
21 #include "rs_trace.h"
22
23 #include "drawable/rs_canvas_drawing_render_node_drawable.h"
24 #include "feature/hetero_hdr/rs_hdr_manager.h"
25 #include "feature/hpae/rs_hpae_manager.h"
26 #include "feature/uifirst/rs_uifirst_manager.h"
27 #include "gfx/performance/rs_perfmonitor_reporter.h"
28 #include "memory/rs_memory_manager.h"
29 #include "pipeline/main_thread/rs_main_thread.h"
30 #include "pipeline/rs_render_node_gc.h"
31 #include "render/rs_filter_cache_manager.h"
32 #include "render/rs_high_performance_visual_engine.h"
33 #include "rs_frame_report.h"
34 #include "rs_uni_render_thread.h"
35
36 #include "rs_profiler.h"
37 #ifdef SUBTREE_PARALLEL_ENABLE
38 #include "rs_parallel_manager.h"
39 #endif
40
41 namespace OHOS {
42 namespace Rosen {
43
44 namespace {
45 constexpr int RENDER_TIMEOUT = 2500; // 2500ms: render timeout threshold
46 constexpr int RENDER_TIMEOUT_ABORT = 12; // 12: render 12 consecutive frames are too long
47 }
RSDrawFrame()48 RSDrawFrame::RSDrawFrame()
49 : unirenderInstance_(RSUniRenderThread::Instance()), rsParallelType_(RSSystemParameters::GetRsParallelType())
50 {}
51
~RSDrawFrame()52 RSDrawFrame::~RSDrawFrame() noexcept {}
53
SetRenderThreadParams(std::unique_ptr<RSRenderThreadParams> & stagingRenderThreadParams)54 void RSDrawFrame::SetRenderThreadParams(std::unique_ptr<RSRenderThreadParams>& stagingRenderThreadParams)
55 {
56 stagingRenderThreadParams_ = std::move(stagingRenderThreadParams);
57 }
58
59 bool RSDrawFrame::debugTraceEnabled_ =
60 std::atoi((OHOS::system::GetParameter("persist.sys.graphic.openDebugTrace", "0")).c_str()) != 0;
61
SetEarlyZEnabled(Drawing::GPUContext * gpuContext)62 void RSDrawFrame::SetEarlyZEnabled(Drawing::GPUContext* gpuContext)
63 {
64 if (UNLIKELY(gpuContext == nullptr)) {
65 RS_LOGE("RSDrawFrame::SetEarlyZEnabled gpuContext is nullptr!");
66 return;
67 }
68 bool isFlushEarlyZFlag = RSJankStats::GetInstance().GetFlushEarlyZ();
69 if (isFlushEarlyZFlag) {
70 bool earlyZEnableFlag = RSJankStats::GetInstance().GetEarlyZEnableFlag();
71 gpuContext->SetEarlyZEnabled(earlyZEnableFlag);
72 }
73 }
74
RenderFrame()75 void RSDrawFrame::RenderFrame()
76 {
77 HitracePerfScoped perfTrace(RSDrawFrame::debugTraceEnabled_, HITRACE_TAG_GRAPHIC_AGP, "OnRenderFramePerfCount");
78 RS_TRACE_NAME_FMT("RenderFrame");
79 StartCheck();
80 // The destructor of GPUCompositonCacheGuard, a memory release check will be performed
81 RSMainThread::GPUCompositonCacheGuard guard;
82 RsFrameReport::GetInstance().UniRenderStart();
83 RSJankStatsRenderFrameHelper::GetInstance().JankStatsStart();
84 unirenderInstance_.IncreaseFrameCount();
85 RSUifirstManager::Instance().ProcessSubDoneNode();
86 Sync();
87 RSJankStatsRenderFrameHelper::GetInstance().JankStatsAfterSync(unirenderInstance_.GetRSRenderThreadParams(),
88 RSBaseRenderUtil::GetAccumulatedBufferCount());
89 unirenderInstance_.UpdateScreenNodeScreenId();
90 RSMainThread::Instance()->ProcessUiCaptureTasks();
91 RSHdrManager::Instance().PostHdrSubTasks();
92 RSUifirstManager::Instance().PostUifistSubTasks();
93 UnblockMainThread();
94 RsFrameReport::GetInstance().CheckUnblockMainThreadPoint();
95 Render();
96 ReleaseSpecialDrawingNodeBuffer();
97 NotifyClearGpuCache();
98 RSMainThread::Instance()->CallbackDrawContextStatusToWMS(true);
99 RSRenderNodeGC::Instance().ReleaseDrawableMemory();
100 if (RSSystemProperties::GetPurgeBetweenFramesEnabled()) {
101 unirenderInstance_.PurgeCacheBetweenFrames();
102 }
103 unirenderInstance_.MemoryManagementBetweenFrames();
104 unirenderInstance_.PurgeShaderCacheAfterAnimate();
105 MemoryManager::MemoryOverCheck(unirenderInstance_.GetRenderEngine()->GetRenderContext()->GetDrGPUContext());
106 RSJankStatsRenderFrameHelper::GetInstance().JankStatsEnd(unirenderInstance_.GetDynamicRefreshRate());
107 SetEarlyZEnabled(unirenderInstance_.GetRenderEngine()->GetRenderContext()->GetDrGPUContext());
108 RSPerfMonitorReporter::GetInstance().ReportAtRsFrameEnd();
109 RsFrameReport::GetInstance().UniRenderEnd();
110 EndCheck();
111 }
112
StartCheck()113 void RSDrawFrame::StartCheck()
114 {
115 timer_ = std::make_shared<RSTimer>("RenderFrame", RENDER_TIMEOUT);
116 }
117
EndCheck()118 void RSDrawFrame::EndCheck()
119 {
120 exceptionCheck_.pid_ = getpid();
121 exceptionCheck_.uid_ = getuid();
122 exceptionCheck_.processName_ = "/system/bin/render_service";
123 exceptionCheck_.exceptionPoint_ = "render_pipeline_timeout";
124
125 if (timer_->GetDuration() >= RENDER_TIMEOUT) {
126 if (++longFrameCount_ == 6) { // 6: render 6 consecutive frames are too long
127 RS_LOGE("Render Six consecutive frames are too long.");
128 exceptionCheck_.exceptionCnt_ = longFrameCount_;
129 exceptionCheck_.exceptionMoment_ = timer_->GetSeconds();
130 exceptionCheck_.UploadRenderExceptionData();
131 }
132 } else {
133 longFrameCount_ = 0;
134 }
135 if (longFrameCount_ == RENDER_TIMEOUT_ABORT) {
136 exceptionCheck_.exceptionCnt_ = longFrameCount_;
137 exceptionCheck_.exceptionMoment_ = timer_->GetSeconds();
138 exceptionCheck_.UploadRenderExceptionData();
139 RS_LOGE("RSDrawFrame::EndCheck PID:%{public}d, UID:%{public}u, PROCESS_NAME:%{public}s, \
140 EXCEPTION_CNT:%{public}d, EXCEPTION_TIME:%{public}" PRId64", EXCEPTION_POINT:%{public}s",
141 getpid(), getuid(), exceptionCheck_.processName_.c_str(), longFrameCount_,
142 exceptionCheck_.exceptionMoment_, exceptionCheck_.exceptionPoint_.c_str());
143 }
144 }
145
NotifyClearGpuCache()146 void RSDrawFrame::NotifyClearGpuCache()
147 {
148 if (RSFilterCacheManager::GetFilterInvalid()) {
149 unirenderInstance_.ClearMemoryCache(ClearMemoryMoment::FILTER_INVALID, true);
150 RSFilterCacheManager::SetFilterInvalid(false);
151 }
152 }
153
ReleaseSpecialDrawingNodeBuffer()154 void RSDrawFrame::ReleaseSpecialDrawingNodeBuffer()
155 {
156 unirenderInstance_.ReleaseSelfDrawingNodeBuffer();
157 unirenderInstance_.ReleaseSurfaceBufferOpItemBuffer();
158 }
159
PostAndWait()160 void RSDrawFrame::PostAndWait()
161 {
162 RS_TRACE_NAME_FMT("PostAndWait, parallel type %d", static_cast<int>(rsParallelType_));
163 RsFrameReport& fr = RsFrameReport::GetInstance();
164 if (fr.GetEnable()) {
165 fr.SendCommandsStart();
166 fr.RenderEnd();
167 }
168
169 uint32_t renderFrameNumber = RS_PROFILER_GET_FRAME_NUMBER();
170 switch (rsParallelType_) {
171 case RsParallelType::RS_PARALLEL_TYPE_SYNC: { // wait until render finish in render thread
172 unirenderInstance_.PostSyncTask([this, renderFrameNumber]() {
173 unirenderInstance_.SetMainLooping(true);
174 RS_PROFILER_ON_PARALLEL_RENDER_BEGIN();
175 RenderFrame();
176 unirenderInstance_.ClearResource();
177 RS_PROFILER_ON_PARALLEL_RENDER_END(renderFrameNumber);
178 unirenderInstance_.SetMainLooping(false);
179 });
180 break;
181 }
182 case RsParallelType::RS_PARALLEL_TYPE_SINGLE_THREAD: { // render in main thread
183 RenderFrame();
184 unirenderInstance_.ClearResource();
185 break;
186 }
187 case RsParallelType::RS_PARALLEL_TYPE_ASYNC: // wait until sync finish in render thread
188 default: {
189 std::unique_lock<std::mutex> frameLock(frameMutex_);
190 canUnblockMainThread = false;
191 unirenderInstance_.PostTask([this, renderFrameNumber]() {
192 unirenderInstance_.SetMainLooping(true);
193 RS_PROFILER_ON_PARALLEL_RENDER_BEGIN();
194 RSMainThread::Instance()->GetRSVsyncRateReduceManager().FrameDurationBegin();
195 RenderFrame();
196 unirenderInstance_.ClearResource();
197 RSMainThread::Instance()->GetRSVsyncRateReduceManager().FrameDurationEnd();
198 RS_PROFILER_ON_PARALLEL_RENDER_END(renderFrameNumber);
199 unirenderInstance_.SetMainLooping(false);
200 });
201
202 frameCV_.wait(frameLock, [this] { return canUnblockMainThread; });
203 }
204 }
205 }
206
PostDirectCompositionJankStats(const JankDurationParams & rsParams,bool optimizeLoad)207 void RSDrawFrame::PostDirectCompositionJankStats(const JankDurationParams& rsParams, bool optimizeLoad)
208 {
209 RS_TRACE_NAME_FMT("PostDirectCompositionJankStats, parallel type %d", static_cast<int>(rsParallelType_));
210 switch (rsParallelType_) {
211 case RsParallelType::RS_PARALLEL_TYPE_SYNC: // wait until render finish in render thread
212 case RsParallelType::RS_PARALLEL_TYPE_SINGLE_THREAD: // render in main thread
213 case RsParallelType::RS_PARALLEL_TYPE_ASYNC: // wait until sync finish in render thread
214 default: {
215 bool isReportTaskDelayed = unirenderInstance_.IsMainLooping();
216 if (optimizeLoad) { // judge whether we should post task to unirender thread when we need to optimize load
217 auto postTaskHandler = [this](const std::function<void()>& task) {
218 unirenderInstance_.PostTask(task);
219 };
220 RSJankStats::GetInstance().HandleDirectComposition(rsParams, isReportTaskDelayed, postTaskHandler);
221 } else { // directly post task to unirender thread when we do not need to optimize load
222 auto task = [rsParams, isReportTaskDelayed]() -> void {
223 RSJankStats::GetInstance().HandleDirectComposition(rsParams, isReportTaskDelayed);
224 };
225 unirenderInstance_.PostTask(task);
226 }
227 }
228 }
229 }
230
CheckCanvasSkipSync(std::shared_ptr<RSRenderNode> node)231 bool RSDrawFrame::CheckCanvasSkipSync(std::shared_ptr<RSRenderNode> node)
232 {
233 if (node->GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE) {
234 auto nodeDrawable =
235 std::static_pointer_cast<DrawableV2::RSCanvasDrawingRenderNodeDrawable>(node->GetRenderDrawable());
236 if (nodeDrawable == nullptr) {
237 return true;
238 }
239 if (nodeDrawable->IsNeedDraw() && nodeDrawable->GetDrawSkipType() == DrawableV2::DrawSkipType::NONE) {
240 stagingSyncCanvasDrawingNodes_.emplace(node->GetId(), node);
241 return false;
242 }
243 }
244 return true;
245 }
246
Sync()247 void RSDrawFrame::Sync()
248 {
249 RS_TRACE_NAME_FMT("Sync");
250 RSMainThread::Instance()->GetContext().GetGlobalRootRenderNode()->Sync();
251 bool isHdrOn = false;
252 if (stagingRenderThreadParams_ && stagingRenderThreadParams_->HasDisplayHdrOn()) {
253 isHdrOn = true;
254 }
255 #if defined(ROSEN_OHOS) && defined(ENABLE_HPAE_BLUR)
256 RSHpaeManager::GetInstance().OnSync(isHdrOn);
257 #endif
258
259 auto& pendingSyncNodes = RSMainThread::Instance()->GetContext().pendingSyncNodes_;
260 for (auto [id, weakPtr] : stagingSyncCanvasDrawingNodes_) {
261 pendingSyncNodes.emplace(id, weakPtr);
262 }
263 stagingSyncCanvasDrawingNodes_.clear();
264 for (auto& [id, weakPtr] : pendingSyncNodes) {
265 if (auto node = weakPtr.lock()) {
266 if (!CheckCanvasSkipSync(node)) {
267 node->SkipSync();
268 continue;
269 }
270 if (!RSUifirstManager::Instance().CollectSkipSyncNode(node)) {
271 node->Sync();
272 } else {
273 node->SkipSync();
274 }
275 }
276 }
277 pendingSyncNodes.clear();
278 HveFilter::GetHveFilter().ClearSurfaceNodeInfo();
279
280 unirenderInstance_.Sync(std::move(stagingRenderThreadParams_));
281 #ifdef SUBTREE_PARALLEL_ENABLE
282 RSParallelManager::Singleton().Sync();
283 #endif
284 }
285
UnblockMainThread()286 void RSDrawFrame::UnblockMainThread()
287 {
288 RS_TRACE_NAME_FMT("UnlockMainThread");
289 std::unique_lock<std::mutex> frameLock(frameMutex_);
290 if (!canUnblockMainThread) {
291 canUnblockMainThread = true;
292 frameCV_.notify_all();
293 }
294 }
295
Render()296 void RSDrawFrame::Render()
297 {
298 RS_TRACE_NAME_FMT("Render vsyncId: %" PRIu64 "", unirenderInstance_.GetVsyncId());
299 unirenderInstance_.Render();
300 }
301 } // namespace Rosen
302 } // namespace OHOS
303