• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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