1 /*
2 * Copyright (c) 2021-2023 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 #include "pipeline/rs_uni_render_thread.h"
16
17 #include <malloc.h>
18 #include <memory>
19 #include <parameters.h>
20
21 #include "common/rs_common_def.h"
22 #include "common/rs_optional_trace.h"
23 #include "common/rs_singleton.h"
24 #include "drawable/rs_display_render_node_drawable.h"
25 #include "drawable/rs_property_drawable_utils.h"
26 #include "drawable/rs_surface_render_node_drawable.h"
27 #include "graphic_common_c.h"
28 #include "hgm_core.h"
29 #include "include/core/SkGraphics.h"
30 #include "include/gpu/GrDirectContext.h"
31 #include "static_factory.h"
32 #include "memory/rs_memory_manager.h"
33 #include "params/rs_display_render_params.h"
34 #include "params/rs_surface_render_params.h"
35 #include "pipeline/parallel_render/rs_sub_thread_manager.h"
36 #include "pipeline/round_corner_display/rs_round_corner_display_manager.h"
37 #include "pipeline/rs_hardware_thread.h"
38 #include "pipeline/rs_main_thread.h"
39 #include "pipeline/rs_render_node_gc.h"
40 #include "pipeline/rs_surface_handler.h"
41 #include "pipeline/rs_task_dispatcher.h"
42 #include "pipeline/rs_uifirst_manager.h"
43 #include "pipeline/rs_uni_render_engine.h"
44 #include "pipeline/rs_uni_render_util.h"
45 #include "pipeline/sk_resource_manager.h"
46 #include "platform/common/rs_log.h"
47 #include "platform/ohos/rs_jank_stats.h"
48 #include "platform/ohos/rs_node_stats.h"
49 #include "rs_trace.h"
50 #include "surface.h"
51 #include "sync_fence.h"
52 #include "system/rs_system_parameters.h"
53 #ifdef RES_SCHED_ENABLE
54 #include "system_ability_definition.h"
55 #include "if_system_ability_manager.h"
56 #include <iservice_registry.h>
57 #endif
58
59 #ifdef SOC_PERF_ENABLE
60 #include "socperf_client.h"
61 #endif
62
63 #include <sched.h>
64 #include "res_sched_client.h"
65 #include "res_type.h"
66
67 namespace OHOS {
68 namespace Rosen {
69 namespace {
70 constexpr const char* CLEAR_GPU_CACHE = "ClearGpuCache";
71 constexpr const char* DEFAULT_CLEAR_GPU_CACHE = "DefaultClearGpuCache";
72 constexpr const char* PURGE_CACHE_BETWEEN_FRAMES = "PurgeCacheBetweenFrames";
73 constexpr const char* SUPPRESS_GPUCACHE_BELOW_CERTAIN_RATIO = "SuppressGpuCacheBelowCertainRatio";
74 const std::string PERF_FOR_BLUR_IF_NEEDED_TASK_NAME = "PerfForBlurIfNeeded";
75 constexpr uint32_t TIME_OF_EIGHT_FRAMES = 8000;
76 constexpr uint32_t TIME_OF_THE_FRAMES = 1000;
77 constexpr uint32_t TIME_OF_DEFAULT_CLEAR_GPU_CACHE = 5000;
78 constexpr uint32_t WAIT_FOR_RELEASED_BUFFER_TIMEOUT = 3000;
79 constexpr uint32_t RELEASE_IN_HARDWARE_THREAD_TASK_NUM = 4;
80 constexpr uint64_t PERF_PERIOD_BLUR = 480000000;
81 constexpr uint64_t PERF_PERIOD_BLUR_TIMEOUT = 80000000;
82 constexpr uint64_t ONE_MEGABYTE = 1000 * 1000;
83
84 const std::map<int, int32_t> BLUR_CNT_TO_BLUR_CODE {
85 { 1, 10021 },
86 { 2, 10022 },
87 { 3, 10023 },
88 };
89
PerfRequest(int32_t perfRequestCode,bool onOffTag)90 void PerfRequest(int32_t perfRequestCode, bool onOffTag)
91 {
92 #ifdef SOC_PERF_ENABLE
93 OHOS::SOCPERF::SocPerfClient::GetInstance().PerfRequestEx(perfRequestCode, onOffTag, "");
94 RS_LOGD("RSUniRenderThread::soc perf info [%{public}d %{public}d]", perfRequestCode, onOffTag);
95 #endif
96 }
97 };
98
99 thread_local CaptureParam RSUniRenderThread::captureParam_ = {};
100
SetCaptureParam(const CaptureParam & param)101 void RSUniRenderThread::SetCaptureParam(const CaptureParam& param)
102 {
103 captureParam_ = param;
104 }
105
GetCaptureParam()106 CaptureParam& RSUniRenderThread::GetCaptureParam()
107 {
108 return captureParam_;
109 }
110
ResetCaptureParam()111 void RSUniRenderThread::ResetCaptureParam()
112 {
113 captureParam_ = {};
114 }
115
IsInCaptureProcess()116 bool RSUniRenderThread::IsInCaptureProcess()
117 {
118 return captureParam_.isSnapshot_ || captureParam_.isMirror_;
119 }
120
Instance()121 RSUniRenderThread& RSUniRenderThread::Instance()
122 {
123 static RSUniRenderThread instance;
124 return instance;
125 }
126
RSUniRenderThread()127 RSUniRenderThread::RSUniRenderThread()
128 :postImageReleaseTaskFlag_(Rosen::RSSystemProperties::GetImageReleaseUsingPostTask())
129 {}
130
~RSUniRenderThread()131 RSUniRenderThread::~RSUniRenderThread() noexcept {}
132
InitGrContext()133 void RSUniRenderThread::InitGrContext()
134 {
135 // uniRenderEngine must be inited on the same thread with requestFrame
136 uniRenderEngine_ = std::make_shared<RSUniRenderEngine>();
137 if (!uniRenderEngine_) {
138 RS_LOGE("uniRenderEngine_ is nullptr");
139 return;
140 }
141 uniRenderEngine_->Init();
142 #ifdef RS_ENABLE_VK
143 if (Drawing::SystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
144 Drawing::SystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
145 uniRenderEngine_->GetSkContext()->RegisterPostFunc([](const std::function<void()>& task) {
146 RSUniRenderThread::Instance().PostImageReleaseTask(task);
147 });
148 }
149 if (Drawing::SystemProperties::GetGpuApiType() == GpuApiType::VULKAN) {
150 if (RSSystemProperties::IsFoldScreenFlag()) {
151 vmaOptimizeFlag_ = true;
152 }
153 }
154 #endif
155 auto renderContext = uniRenderEngine_->GetRenderContext();
156 if (!renderContext) {
157 return;
158 }
159 auto grContext = renderContext->GetDrGPUContext();
160 if (!grContext) {
161 return;
162 }
163 MemoryManager::SetGpuCacheSuppressWindowSwitch(
164 grContext, RSSystemProperties::GetGpuCacheSuppressWindowEnabled());
165 MemoryManager::SetGpuMemoryAsyncReclaimerSwitch(
166 grContext, RSSystemProperties::GetGpuMemoryAsyncReclaimerEnabled(), []() {
167 const uint32_t RS_IPC_QOS_LEVEL = 7;
168 std::unordered_map<std::string, std::string> mapPayload = { { "bundleName", "render_service" },
169 { "pid", std::to_string(getpid()) }, { std::to_string(gettid()), std::to_string(RS_IPC_QOS_LEVEL) } };
170 using namespace OHOS::ResourceSchedule;
171 auto& schedClient = ResSchedClient::GetInstance();
172 schedClient.ReportData(ResType::RES_TYPE_THREAD_QOS_CHANGE, 0, mapPayload);
173 });
174 }
175
Inittcache()176 void RSUniRenderThread::Inittcache()
177 {
178 if (RSSystemParameters::GetTcacheEnabled()) {
179 // enable cache
180 mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_ENABLE);
181 }
182 }
183
Start()184 void RSUniRenderThread::Start()
185 {
186 runner_ = AppExecFwk::EventRunner::Create("RSUniRenderThread");
187 if (!runner_) {
188 RS_LOGE("RSUniRenderThread Start runner null");
189 return;
190 }
191 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
192 runner_->Run();
193 auto postTaskProxy = [](RSTaskMessage::RSTask task, const std::string& name, int64_t delayTime,
194 AppExecFwk::EventQueue::Priority priority) {
195 RSUniRenderThread::Instance().PostTask(task, name, delayTime, priority);
196 };
197 RSRenderNodeGC::Instance().SetRenderTask(postTaskProxy);
198 PostSyncTask([this] {
199 RS_LOGE("RSUniRenderThread Started ...");
200 Inittcache();
201 InitGrContext();
202 tid_ = gettid();
203 #ifdef RES_SCHED_ENABLE
204 SubScribeSystemAbility();
205 #endif
206 });
207
208 auto taskDispatchFunc = [this](const RSTaskDispatcher::RSTask& task, bool isSyncTask = false) {
209 if (isSyncTask) {
210 PostSyncTask(task);
211 } else {
212 PostTask(task);
213 }
214 };
215 RSTaskDispatcher::GetInstance().RegisterTaskDispatchFunc(tid_, taskDispatchFunc);
216
217 if (!rootNodeDrawable_) {
218 const std::shared_ptr<RSBaseRenderNode> rootNode =
219 RSMainThread::Instance()->GetContext().GetGlobalRootRenderNode();
220 if (!rootNode) {
221 RS_LOGE("rootNode is nullptr");
222 return;
223 }
224 auto ptr = DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(rootNode);
225 rootNodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(ptr);
226 }
227 }
228
GetRenderEngine() const229 std::shared_ptr<RSBaseRenderEngine> RSUniRenderThread::GetRenderEngine() const
230 {
231 return uniRenderEngine_;
232 }
233
PostTask(const std::function<void ()> & task)234 void RSUniRenderThread::PostTask(const std::function<void()>& task)
235 {
236 if (!handler_) {
237 return;
238 }
239 handler_->PostTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
240 }
241
PostRTTask(const std::function<void ()> & task)242 void RSUniRenderThread::PostRTTask(const std::function<void()>& task)
243 {
244 auto tid = gettid();
245 if (tid == tid_) {
246 task();
247 } else {
248 PostTask(task);
249 }
250 }
251
PostImageReleaseTask(const std::function<void ()> & task)252 void RSUniRenderThread::PostImageReleaseTask(const std::function<void()>& task)
253 {
254 imageReleaseCount_++;
255 if (postImageReleaseTaskFlag_) {
256 PostRTTask(task);
257 return;
258 }
259 if (tid_ == gettid()) {
260 task();
261 return;
262 }
263 std::unique_lock<std::mutex> releaseLock(imageReleaseMutex_);
264 imageReleaseTasks_.push_back(task);
265 }
266
RunImageReleaseTask()267 void RSUniRenderThread::RunImageReleaseTask()
268 {
269 if (postImageReleaseTaskFlag_) { // release using post task
270 RS_TRACE_NAME_FMT("RunImageReleaseTask using PostTask: count %d", imageReleaseCount_);
271 imageReleaseCount_ = 0;
272 return;
273 }
274 std::vector<Callback> tasks;
275 {
276 std::unique_lock<std::mutex> releaseLock(imageReleaseMutex_);
277 std::swap(imageReleaseTasks_, tasks);
278 }
279 if (tasks.empty()) {
280 return;
281 }
282 RS_TRACE_NAME_FMT("RunImageReleaseTask: count %d", imageReleaseCount_);
283 imageReleaseCount_ = 0;
284 for (auto task : tasks) {
285 task();
286 }
287 }
288
ClearResource()289 void RSUniRenderThread::ClearResource()
290 {
291 RunImageReleaseTask();
292 DrawableV2::RSRenderNodeDrawableAdapter::ClearResource();
293 }
294
PostTask(RSTaskMessage::RSTask task,const std::string & name,int64_t delayTime,AppExecFwk::EventQueue::Priority priority)295 void RSUniRenderThread::PostTask(RSTaskMessage::RSTask task, const std::string& name, int64_t delayTime,
296 AppExecFwk::EventQueue::Priority priority)
297 {
298 if (handler_) {
299 handler_->PostTask(task, name, delayTime, priority);
300 }
301 }
302
RemoveTask(const std::string & name)303 void RSUniRenderThread::RemoveTask(const std::string& name)
304 {
305 if (handler_) {
306 handler_->RemoveTask(name);
307 }
308 }
309
PostSyncTask(const std::function<void ()> & task)310 void RSUniRenderThread::PostSyncTask(const std::function<void()>& task)
311 {
312 if (!handler_) {
313 return;
314 }
315 handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
316 }
317
IsIdle() const318 bool RSUniRenderThread::IsIdle() const
319 {
320 return handler_ ? handler_->IsIdle() : false;
321 }
322
Sync(std::unique_ptr<RSRenderThreadParams> && stagingRenderThreadParams)323 void RSUniRenderThread::Sync(std::unique_ptr<RSRenderThreadParams>&& stagingRenderThreadParams)
324 {
325 RSRenderThreadParamsManager::Instance().SetRSRenderThreadParams(std::move(stagingRenderThreadParams));
326 }
327
Render()328 void RSUniRenderThread::Render()
329 {
330 if (!rootNodeDrawable_) {
331 RS_LOGE("rootNodeDrawable is nullptr");
332 }
333 if (vmaOptimizeFlag_) { // render this frame with vma cache on/off
334 std::lock_guard<std::mutex> lock(vmaCacheCountMutex_);
335 if (vmaCacheCount_ > 0) {
336 vmaCacheCount_--;
337 Drawing::StaticFactory::SetVmaCacheStatus(true);
338 } else {
339 Drawing::StaticFactory::SetVmaCacheStatus(false);
340 }
341 }
342 Drawing::Canvas canvas;
343 RSNodeStats::GetInstance().ClearNodeStats();
344 rootNodeDrawable_->OnDraw(canvas);
345 RSNodeStats::GetInstance().ReportRSNodeLimitExceeded();
346 PerfForBlurIfNeeded();
347 }
348
ReleaseSelfDrawingNodeBuffer()349 void RSUniRenderThread::ReleaseSelfDrawingNodeBuffer()
350 {
351 auto& renderThreadParams = GetRSRenderThreadParams();
352 if (!renderThreadParams) {
353 return;
354 }
355 std::vector<std::function<void()>> releaseTasks;
356 for (const auto& drawable : renderThreadParams->GetSelfDrawables()) {
357 if (UNLIKELY(!drawable)) {
358 continue;
359 }
360 auto surfaceDrawable = std::static_pointer_cast<DrawableV2::RSSurfaceRenderNodeDrawable>(drawable);
361 auto& params = surfaceDrawable->GetRenderParams();
362 if (UNLIKELY(!params)) {
363 continue;
364 }
365 auto surfaceParams = static_cast<RSSurfaceRenderParams*>(params.get());
366 if (UNLIKELY(!surfaceParams)) {
367 continue;
368 }
369 bool needRelease = !surfaceParams->GetHardwareEnabled() || !surfaceParams->GetLayerCreated();
370 if (needRelease && surfaceParams->GetLastFrameHardwareEnabled()) {
371 surfaceParams->releaseInHardwareThreadTaskNum_ = RELEASE_IN_HARDWARE_THREAD_TASK_NUM;
372 }
373 if (needRelease) {
374 auto preBuffer = params->GetPreBuffer();
375 if (preBuffer == nullptr) {
376 if (surfaceParams->releaseInHardwareThreadTaskNum_ > 0) {
377 surfaceParams->releaseInHardwareThreadTaskNum_--;
378 }
379 continue;
380 }
381 auto releaseTask = [buffer = preBuffer, consumer = surfaceDrawable->GetConsumerOnDraw(),
382 useReleaseFence = surfaceParams->GetLastFrameHardwareEnabled(),
383 acquireFence = acquireFence_]() mutable {
384 auto ret = consumer->ReleaseBuffer(buffer, useReleaseFence ?
385 RSHardwareThread::Instance().releaseFence_ : acquireFence);
386 if (ret != OHOS::SURFACE_ERROR_OK) {
387 RS_LOGD("ReleaseSelfDrawingNodeBuffer failed ret:%{public}d", ret);
388 }
389 };
390 params->SetPreBuffer(nullptr);
391 if (surfaceParams->releaseInHardwareThreadTaskNum_ > 0) {
392 releaseTasks.emplace_back(releaseTask);
393 surfaceParams->releaseInHardwareThreadTaskNum_--;
394 } else {
395 releaseTask();
396 }
397 }
398 }
399 if (releaseTasks.empty()) {
400 return;
401 }
402 auto releaseBufferTask = [releaseTasks]() {
403 for (const auto& task : releaseTasks) {
404 task();
405 }
406 };
407 auto delayTime = RSHardwareThread::Instance().delayTime_;
408 if (delayTime > 0) {
409 RSHardwareThread::Instance().PostDelayTask(releaseBufferTask, delayTime);
410 } else {
411 RSHardwareThread::Instance().PostTask(releaseBufferTask);
412 }
413 }
414
ReleaseSurface()415 void RSUniRenderThread::ReleaseSurface()
416 {
417 std::lock_guard<std::mutex> lock(mutex_);
418 while (tmpSurfaces_.size() > 0) {
419 auto tmp = tmpSurfaces_.front();
420 tmpSurfaces_.pop();
421 tmp = nullptr;
422 }
423 }
424
AddToReleaseQueue(std::shared_ptr<Drawing::Surface> && surface)425 void RSUniRenderThread::AddToReleaseQueue(std::shared_ptr<Drawing::Surface>&& surface)
426 {
427 std::lock_guard<std::mutex> lock(mutex_);
428 tmpSurfaces_.push(std::move(surface));
429 }
430
GetCurrentTimestamp() const431 uint64_t RSUniRenderThread::GetCurrentTimestamp() const
432 {
433 auto& renderThreadParams = GetRSRenderThreadParams();
434 return renderThreadParams ? renderThreadParams->GetCurrentTimestamp() : 0;
435 }
436
GetActualTimestamp() const437 int64_t RSUniRenderThread::GetActualTimestamp() const
438 {
439 auto& renderThreadParams = GetRSRenderThreadParams();
440 return renderThreadParams ? renderThreadParams->GetActualTimestamp() : 0;
441 }
442
GetVsyncId() const443 uint64_t RSUniRenderThread::GetVsyncId() const
444 {
445 auto& renderThreadParams = GetRSRenderThreadParams();
446 return renderThreadParams ? renderThreadParams->GetVsyncId() : 0;
447 }
448
GetForceRefreshFlag() const449 bool RSUniRenderThread::GetForceRefreshFlag() const
450 {
451 auto& renderThreadParams = GetRSRenderThreadParams();
452 return renderThreadParams ? renderThreadParams->GetForceRefreshFlag() : false;
453 }
454
GetPendingScreenRefreshRate() const455 uint32_t RSUniRenderThread::GetPendingScreenRefreshRate() const
456 {
457 auto& renderThreadParams = GetRSRenderThreadParams();
458 return renderThreadParams ? renderThreadParams->GetPendingScreenRefreshRate() : 0;
459 }
460
GetPendingConstraintRelativeTime() const461 uint64_t RSUniRenderThread::GetPendingConstraintRelativeTime() const
462 {
463 auto& renderThreadParams = GetRSRenderThreadParams();
464 return renderThreadParams ? renderThreadParams->GetPendingConstraintRelativeTime() : 0;
465 }
466
467 #ifdef RES_SCHED_ENABLE
SubScribeSystemAbility()468 void RSUniRenderThread::SubScribeSystemAbility()
469 {
470 RS_LOGD("%{public}s", __func__);
471 sptr<ISystemAbilityManager> systemAbilityManager =
472 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
473 if (!systemAbilityManager) {
474 RS_LOGE("%{public}s failed to get system ability manager client", __func__);
475 return;
476 }
477 std::string threadName = "RSHardwareThread";
478 std::string strUid = std::to_string(getuid());
479 std::string strPid = std::to_string(getpid());
480 std::string strTid = std::to_string(gettid());
481
482 saStatusChangeListener_ = new (std::nothrow)VSyncSystemAbilityListener(threadName, strUid, strPid, strTid);
483 int32_t ret = systemAbilityManager->SubscribeSystemAbility(RES_SCHED_SYS_ABILITY_ID, saStatusChangeListener_);
484 if (ret != ERR_OK) {
485 RS_LOGE("%{public}s subscribe system ability %{public}d failed.", __func__, RES_SCHED_SYS_ABILITY_ID);
486 saStatusChangeListener_ = nullptr;
487 }
488 }
489 #endif
WaitUntilDisplayNodeBufferReleased(DrawableV2::RSDisplayRenderNodeDrawable & displayNodeDrawable)490 bool RSUniRenderThread::WaitUntilDisplayNodeBufferReleased(
491 DrawableV2::RSDisplayRenderNodeDrawable& displayNodeDrawable)
492 {
493 std::unique_lock<std::mutex> lock(displayNodeBufferReleasedMutex_);
494 displayNodeBufferReleased_ = false; // prevent spurious wakeup of condition variable
495 if (!displayNodeDrawable.IsSurfaceCreated()) {
496 return true;
497 }
498 auto consumer = displayNodeDrawable.GetRSSurfaceHandlerOnDraw()->GetConsumer();
499 if (consumer && consumer->QueryIfBufferAvailable()) {
500 return true;
501 }
502 return displayNodeBufferReleasedCond_.wait_until(lock, std::chrono::system_clock::now() +
503 std::chrono::milliseconds(WAIT_FOR_RELEASED_BUFFER_TIMEOUT), [this]() { return displayNodeBufferReleased_; });
504 }
505
NotifyDisplayNodeBufferReleased()506 void RSUniRenderThread::NotifyDisplayNodeBufferReleased()
507 {
508 RS_TRACE_NAME("RSUniRenderThread::NotifyDisplayNodeBufferReleased");
509 std::lock_guard<std::mutex> lock(displayNodeBufferReleasedMutex_);
510 displayNodeBufferReleased_ = true;
511 displayNodeBufferReleasedCond_.notify_one();
512 }
513
PerfForBlurIfNeeded()514 void RSUniRenderThread::PerfForBlurIfNeeded()
515 {
516 if (!handler_) {
517 return;
518 }
519 handler_->RemoveTask(PERF_FOR_BLUR_IF_NEEDED_TASK_NAME);
520 static uint64_t prePerfTimestamp = 0;
521 static int preBlurCnt = 0;
522 static int cnt = 0;
523 auto params = GetRSRenderThreadParams().get();
524 if (!params) {
525 return;
526 }
527 auto threadTimestamp = params->GetCurrentTimestamp();
528
529 auto task = [this]() {
530 if (preBlurCnt == 0) {
531 return;
532 }
533 auto now = std::chrono::steady_clock::now().time_since_epoch();
534 auto timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
535 RS_OPTIONAL_TRACE_NAME_FMT("PerfForBlurIfNeeded now[%ld] timestamp[%ld] preBlurCnt[%d]",
536 now, timestamp, preBlurCnt);
537 if (static_cast<uint64_t>(timestamp) - prePerfTimestamp > PERF_PERIOD_BLUR_TIMEOUT) {
538 PerfRequest(BLUR_CNT_TO_BLUR_CODE.at(preBlurCnt), false);
539 prePerfTimestamp = 0;
540 preBlurCnt = 0;
541 }
542 };
543
544 // delay 100ms
545 handler_->PostTask(task, PERF_FOR_BLUR_IF_NEEDED_TASK_NAME, 100);
546 int blurCnt = RSPropertyDrawableUtils::GetAndResetBlurCnt();
547 // clamp blurCnt to 0~3.
548 blurCnt = std::clamp<int>(blurCnt, 0, 3);
549 cnt = (blurCnt < preBlurCnt) ? (cnt + 1) : 0;
550
551 // if blurCnt > preBlurCnt, than change perf code;
552 // if blurCnt < preBlurCnt 10 times continuously, than change perf code.
553 bool cntIsMatch = blurCnt > preBlurCnt || cnt > 10;
554 if (cntIsMatch && preBlurCnt != 0) {
555 RS_OPTIONAL_TRACE_NAME_FMT("PerfForBlurIfNeeded Perf close, preBlurCnt[%d] blurCnt[%ld]", preBlurCnt, blurCnt);
556 PerfRequest(BLUR_CNT_TO_BLUR_CODE.at(preBlurCnt), false);
557 preBlurCnt = blurCnt == 0 ? 0 : preBlurCnt;
558 }
559 if (blurCnt == 0) {
560 return;
561 }
562 if (threadTimestamp - prePerfTimestamp > PERF_PERIOD_BLUR || cntIsMatch) {
563 RS_OPTIONAL_TRACE_NAME_FMT("PerfForBlurIfNeeded PerfRequest, preBlurCnt[%d] blurCnt[%ld]", preBlurCnt, blurCnt);
564 PerfRequest(BLUR_CNT_TO_BLUR_CODE.at(blurCnt), true);
565 prePerfTimestamp = threadTimestamp;
566 preBlurCnt = blurCnt;
567 }
568 }
569
GetClearMemoryFinished() const570 bool RSUniRenderThread::GetClearMemoryFinished() const
571 {
572 std::lock_guard<std::mutex> lock(clearMemoryMutex_);
573 return clearMemoryFinished_;
574 }
575
GetClearMemDeeply() const576 bool RSUniRenderThread::GetClearMemDeeply() const
577 {
578 std::lock_guard<std::mutex> lock(clearMemoryMutex_);
579 return clearMemDeeply_;
580 }
581
SetClearMoment(ClearMemoryMoment moment)582 void RSUniRenderThread::SetClearMoment(ClearMemoryMoment moment)
583 {
584 clearMoment_ = moment;
585 }
586
GetClearMoment() const587 ClearMemoryMoment RSUniRenderThread::GetClearMoment() const
588 {
589 std::lock_guard<std::mutex> lock(clearMemoryMutex_);
590 return clearMoment_;
591 }
592
GetRefreshRate() const593 uint32_t RSUniRenderThread::GetRefreshRate() const
594 {
595 auto screenManager = CreateOrGetScreenManager();
596 if (!screenManager) {
597 RS_LOGE("RSUniRenderThread::GetRefreshRate screenManager is nullptr");
598 return 60; // The default refreshrate is 60
599 }
600 return HgmCore::Instance().GetScreenCurrentRefreshRate(screenManager->GetDefaultScreenId());
601 }
602
GetWatermarkImg()603 std::shared_ptr<Drawing::Image> RSUniRenderThread::GetWatermarkImg()
604 {
605 auto& renderThreadParams = GetRSRenderThreadParams();
606 return renderThreadParams ? renderThreadParams->GetWatermarkImg() : nullptr;
607 }
608
GetWatermarkFlag() const609 bool RSUniRenderThread::GetWatermarkFlag() const
610 {
611 auto& renderThreadParams = GetRSRenderThreadParams();
612 return renderThreadParams ? renderThreadParams->GetWatermarkFlag() : false;
613 }
614
IsCurtainScreenOn() const615 bool RSUniRenderThread::IsCurtainScreenOn() const
616 {
617 auto& renderThreadParams = GetRSRenderThreadParams();
618 return renderThreadParams ? renderThreadParams->IsCurtainScreenOn() : false;
619 }
620
FormatNumber(size_t number)621 std::string FormatNumber(size_t number)
622 {
623 constexpr uint8_t FORMATE_NUM_STEP = 3;
624 std::string strNumber = std::to_string(number);
625 int n = strNumber.length();
626 for (int i = n - FORMATE_NUM_STEP; i > 0; i -= FORMATE_NUM_STEP) {
627 strNumber.insert(i, ",");
628 }
629 return strNumber;
630 }
631
TrimMemEmptyType(Drawing::GPUContext * gpuContext)632 static void TrimMemEmptyType(Drawing::GPUContext* gpuContext)
633 {
634 gpuContext->Flush();
635 SkGraphics::PurgeAllCaches();
636 gpuContext->FreeGpuResources();
637 gpuContext->PurgeUnlockedResources(true);
638 #ifdef NEW_RENDER_CONTEXT
639 MemoryHandler::ClearShader();
640 #else
641 std::shared_ptr<RenderContext> rendercontext = std::make_shared<RenderContext>();
642 rendercontext->CleanAllShaderCache();
643 #endif
644 gpuContext->FlushAndSubmit(true);
645 }
646
TrimMemShaderType()647 static void TrimMemShaderType()
648 {
649 #ifdef NEW_RENDER_CONTEXT
650 MemoryHandler::ClearShader();
651 #else
652 std::shared_ptr<RenderContext> rendercontext = std::make_shared<RenderContext>();
653 rendercontext->CleanAllShaderCache();
654 #endif
655 }
656
TrimMemGpuLimitType(Drawing::GPUContext * gpuContext,std::string & dumpString,std::string & type,const std::string & typeGpuLimit)657 static void TrimMemGpuLimitType(Drawing::GPUContext* gpuContext, std::string& dumpString,
658 std::string& type, const std::string& typeGpuLimit)
659 {
660 size_t cacheLimit = 0;
661 int maxResources;
662 gpuContext->GetResourceCacheLimits(&maxResources, &cacheLimit);
663
664 constexpr int MAX_GPU_LIMIT_SIZE = 4000;
665 std::string strM = type.substr(typeGpuLimit.length());
666 size_t maxResourcesBytes = cacheLimit; // max 4G
667 char* end = nullptr;
668 errno = 0;
669 long long sizeM = std::strtoll(strM.c_str(), &end, 10);
670 if (end != nullptr && end != strM.c_str() && errno == 0 && *end == '\0' &&
671 sizeM > 0 && sizeM <= MAX_GPU_LIMIT_SIZE) {
672 maxResourcesBytes = sizeM * ONE_MEGABYTE;
673 }
674
675 gpuContext->SetResourceCacheLimits(maxResources, maxResourcesBytes);
676 dumpString.append("setgpulimit: " + FormatNumber(cacheLimit)
677 + "==>" + FormatNumber(maxResourcesBytes) + "\n");
678 }
679
IsColorFilterModeOn() const680 bool RSUniRenderThread::IsColorFilterModeOn() const
681 {
682 if (!uniRenderEngine_) {
683 return false;
684 }
685 ColorFilterMode colorFilterMode = uniRenderEngine_->GetColorFilterMode();
686 if (colorFilterMode == ColorFilterMode::INVERT_COLOR_DISABLE_MODE ||
687 colorFilterMode >= ColorFilterMode::DALTONIZATION_NORMAL_MODE) {
688 return false;
689 }
690 return true;
691 }
692
IsHighContrastTextModeOn() const693 bool RSUniRenderThread::IsHighContrastTextModeOn() const
694 {
695 if (!uniRenderEngine_) {
696 return false;
697 }
698 return uniRenderEngine_->IsHighContrastEnabled();
699 }
700
TrimMem(std::string & dumpString,std::string & type)701 void RSUniRenderThread::TrimMem(std::string& dumpString, std::string& type)
702 {
703 auto task = [this, &dumpString, &type] {
704 std::string typeGpuLimit = "setgpulimit";
705 if (!uniRenderEngine_) {
706 return;
707 }
708 auto renderContext = uniRenderEngine_->GetRenderContext();
709 if (!renderContext) {
710 return;
711 }
712 auto gpuContext = renderContext->GetDrGPUContext();
713 if (gpuContext == nullptr) {
714 return;
715 }
716 if (type.empty()) {
717 TrimMemEmptyType(gpuContext);
718 } else if (type == "cpu") {
719 gpuContext->Flush();
720 SkGraphics::PurgeAllCaches();
721 gpuContext->FlushAndSubmit(true);
722 } else if (type == "gpu") {
723 gpuContext->Flush();
724 gpuContext->FreeGpuResources();
725 gpuContext->FlushAndSubmit(true);
726 } else if (type == "uihidden") {
727 gpuContext->Flush();
728 gpuContext->PurgeUnlockAndSafeCacheGpuResources();
729 gpuContext->FlushAndSubmit(true);
730 } else if (type == "unlock") {
731 gpuContext->Flush();
732 gpuContext->PurgeUnlockedResources(false);
733 gpuContext->FlushAndSubmit(true);
734 } else if (type == "shader") {
735 TrimMemShaderType();
736 } else if (type == "flushcache") {
737 int ret = mallopt(M_FLUSH_THREAD_CACHE, 0);
738 dumpString.append("flushcache " + std::to_string(ret) + "\n");
739 } else if (type.substr(0, typeGpuLimit.length()) == typeGpuLimit) {
740 TrimMemGpuLimitType(gpuContext, dumpString, type, typeGpuLimit);
741 } else {
742 uint32_t pid = static_cast<uint32_t>(std::atoi(type.c_str()));
743 Drawing::GPUResourceTag tag(pid, 0, 0, 0, "TrimMem");
744 MemoryManager::ReleaseAllGpuResource(gpuContext, tag);
745 }
746 dumpString.append("trimMem: " + type + "\n");
747 };
748 PostSyncTask(task);
749 }
750
DumpMem(DfxString & log)751 void RSUniRenderThread::DumpMem(DfxString& log)
752 {
753 std::vector<std::pair<NodeId, std::string>> nodeTags;
754 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
755 nodeMap.TraverseSurfaceNodes([&nodeTags](const std::shared_ptr<RSSurfaceRenderNode> node) {
756 std::string name = node->GetName() + " " + std::to_string(node->GetId());
757 nodeTags.push_back({node->GetId(), name});
758 });
759 PostSyncTask([&log, &nodeTags, this]() {
760 if (!uniRenderEngine_) {
761 return;
762 }
763 auto renderContext = uniRenderEngine_->GetRenderContext();
764 if (!renderContext) {
765 return;
766 }
767 auto gpuContext = renderContext->GetDrGPUContext();
768 MemoryManager::DumpDrawingGpuMemory(log, gpuContext, nodeTags);
769 });
770 }
771
ClearMemoryCache(ClearMemoryMoment moment,bool deeply,pid_t pid)772 void RSUniRenderThread::ClearMemoryCache(ClearMemoryMoment moment, bool deeply, pid_t pid)
773 {
774 if (!RSSystemProperties::GetReleaseResourceEnabled()) {
775 return;
776 }
777 {
778 std::lock_guard<std::mutex> lock(clearMemoryMutex_);
779 clearMemDeeply_ = clearMemDeeply_ || deeply;
780 SetClearMoment(moment);
781 clearMemoryFinished_ = false;
782 exitedPidSet_.emplace(pid);
783 }
784 PostClearMemoryTask(moment, deeply, false);
785 }
786
DefaultClearMemoryCache()787 void RSUniRenderThread::DefaultClearMemoryCache()
788 {
789 // To clean memory when no render in 5s
790 if (!RSSystemProperties::GetReleaseResourceEnabled()) {
791 return;
792 }
793 PostClearMemoryTask(ClearMemoryMoment::DEFAULT_CLEAN, false, true);
794 }
795
PostClearMemoryTask(ClearMemoryMoment moment,bool deeply,bool isDefaultClean)796 void RSUniRenderThread::PostClearMemoryTask(ClearMemoryMoment moment, bool deeply, bool isDefaultClean)
797 {
798 auto task = [this, moment, deeply, isDefaultClean]() {
799 if (!uniRenderEngine_) {
800 return;
801 }
802 auto renderContext = uniRenderEngine_->GetRenderContext();
803 if (!renderContext) {
804 return;
805 }
806 auto grContext = renderContext->GetDrGPUContext();
807 if (UNLIKELY(!grContext)) {
808 return;
809 }
810 RS_LOGD("Clear memory cache %{public}d", moment);
811 RS_TRACE_NAME_FMT("Clear memory cache, cause the moment [%d] happen", moment);
812 std::lock_guard<std::mutex> lock(clearMemoryMutex_);
813 SKResourceManager::Instance().ReleaseResource();
814 grContext->Flush();
815 SkGraphics::PurgeAllCaches(); // clear cpu cache
816 auto pid = *(this->exitedPidSet_.begin());
817 if (this->exitedPidSet_.size() == 1 && pid == -1) { // no exited app, just clear scratch resource
818 if (deeply || this->deviceType_ != DeviceType::PHONE) {
819 MemoryManager::ReleaseUnlockAndSafeCacheGpuResource(grContext);
820 } else {
821 MemoryManager::ReleaseUnlockGpuResource(grContext);
822 }
823 } else {
824 MemoryManager::ReleaseUnlockGpuResource(grContext, this->exitedPidSet_);
825 }
826 auto screenManager_ = CreateOrGetScreenManager();
827 screenManager_->ClearFrameBufferIfNeed();
828 grContext->FlushAndSubmit(true);
829 if (this->vmaOptimizeFlag_) {
830 MemoryManager::VmaDefragment(grContext);
831 }
832 if (RSSystemProperties::GetRenderNodePurgeEnabled()) {
833 auto purgeDrawables =
834 DrawableV2::RSRenderNodeDrawableAdapter::GetDrawableVectorById(nodesNeedToBeClearMemory_);
835 for (auto& drawable : purgeDrawables) {
836 drawable->Purge();
837 }
838 }
839 nodesNeedToBeClearMemory_.clear();
840 if (!isDefaultClean) {
841 this->clearMemoryFinished_ = true;
842 } else {
843 this->isDefaultCleanTaskFinished_ = true;
844 {
845 RS_TRACE_NAME_FMT("Purge unlocked resources when clear memory");
846 grContext->PurgeUnlockedResources(false);
847 }
848 }
849 RSUifirstManager::Instance().TryReleaseTextureForIdleThread();
850 this->clearMemDeeply_ = false;
851 this->SetClearMoment(ClearMemoryMoment::NO_CLEAR);
852 };
853 if (!isDefaultClean) {
854 PostTask(task, CLEAR_GPU_CACHE,
855 (this->deviceType_ == DeviceType::PHONE ? TIME_OF_EIGHT_FRAMES : TIME_OF_THE_FRAMES) / GetRefreshRate());
856 } else {
857 PostTask(task, DEFAULT_CLEAR_GPU_CACHE, TIME_OF_DEFAULT_CLEAR_GPU_CACHE);
858 }
859 }
860
ResetClearMemoryTask(const std::unordered_map<NodeId,bool> && ids,bool isDoDirectComposition)861 void RSUniRenderThread::ResetClearMemoryTask(const std::unordered_map<NodeId, bool>&& ids, bool isDoDirectComposition)
862 {
863 for (auto [nodeId, purgeFlag] : ids) {
864 if (purgeFlag) {
865 nodesNeedToBeClearMemory_.insert(nodeId);
866 } else {
867 nodesNeedToBeClearMemory_.erase(nodeId);
868 }
869 }
870 if (!GetClearMemoryFinished()) {
871 RemoveTask(CLEAR_GPU_CACHE);
872 if (!isDoDirectComposition) {
873 ClearMemoryCache(clearMoment_, clearMemDeeply_);
874 }
875 }
876 if (!isDefaultCleanTaskFinished_) {
877 RemoveTask(DEFAULT_CLEAR_GPU_CACHE);
878 if (!isDoDirectComposition) {
879 DefaultClearMemoryCache();
880 }
881 }
882 }
883
SetDefaultClearMemoryFinished(bool isFinished)884 void RSUniRenderThread::SetDefaultClearMemoryFinished(bool isFinished)
885 {
886 isDefaultCleanTaskFinished_ = isFinished;
887 }
888
IsDefaultClearMemoryFinished()889 bool RSUniRenderThread::IsDefaultClearMemoryFinished()
890 {
891 return isDefaultCleanTaskFinished_;
892 }
893
PurgeCacheBetweenFrames()894 void RSUniRenderThread::PurgeCacheBetweenFrames()
895 {
896 if (!RSSystemProperties::GetReleaseResourceEnabled()) {
897 return;
898 }
899 RS_TRACE_NAME_FMT("MEM PurgeCacheBetweenFrames add task");
900 PostTask(
901 [this]() {
902 if (!uniRenderEngine_) {
903 return;
904 }
905 auto renderContext = uniRenderEngine_->GetRenderContext();
906 if (!renderContext) {
907 return;
908 }
909 auto grContext = renderContext->GetDrGPUContext();
910 if (!grContext) {
911 return;
912 }
913 RS_TRACE_NAME_FMT("PurgeCacheBetweenFrames");
914 std::set<int> protectedPidSet = { RSMainThread::Instance()->GetDesktopPidForRotationScene() };
915 MemoryManager::PurgeCacheBetweenFrames(grContext, true, this->exitedPidSet_, protectedPidSet);
916 RemoveTask(PURGE_CACHE_BETWEEN_FRAMES);
917 },
918 PURGE_CACHE_BETWEEN_FRAMES, 0, AppExecFwk::EventQueue::Priority::LOW);
919 }
920
FlushGpuMemoryInWaitQueueBetweenFrames()921 void RSUniRenderThread::FlushGpuMemoryInWaitQueueBetweenFrames()
922 {
923 if (!uniRenderEngine_) {
924 return;
925 }
926 auto renderContext = uniRenderEngine_->GetRenderContext();
927 if (!renderContext) {
928 return;
929 }
930 auto grContext = renderContext->GetDrGPUContext();
931 if (!grContext) {
932 return;
933 }
934 MemoryManager::FlushGpuMemoryInWaitQueue(grContext);
935 }
936
SuppressGpuCacheBelowCertainRatioBetweenFrames()937 void RSUniRenderThread::SuppressGpuCacheBelowCertainRatioBetweenFrames()
938 {
939 RemoveTask(SUPPRESS_GPUCACHE_BELOW_CERTAIN_RATIO);
940 PostTask(
941 [this]() {
942 if (!uniRenderEngine_) {
943 return;
944 }
945 auto renderContext = uniRenderEngine_->GetRenderContext();
946 if (!renderContext) {
947 return;
948 }
949 auto grContext = renderContext->GetDrGPUContext();
950 if (!grContext) {
951 return;
952 }
953 RS_TRACE_NAME_FMT("SuppressGpuCacheBelowCertainRatio");
954 MemoryManager::SuppressGpuCacheBelowCertainRatio(grContext, [this]() -> bool {
955 return this->handler_->HasPreferEvent(static_cast<int>(AppExecFwk::EventQueue::Priority::HIGH));
956 });
957 },
958 SUPPRESS_GPUCACHE_BELOW_CERTAIN_RATIO, 0, AppExecFwk::EventQueue::Priority::LOW);
959 }
960
MemoryManagementBetweenFrames()961 void RSUniRenderThread::MemoryManagementBetweenFrames()
962 {
963 if (RSSystemProperties::GetGpuMemoryAsyncReclaimerEnabled()) {
964 FlushGpuMemoryInWaitQueueBetweenFrames();
965 }
966 if (RSSystemProperties::GetGpuCacheSuppressWindowEnabled()) {
967 SuppressGpuCacheBelowCertainRatioBetweenFrames();
968 }
969 }
970
RenderServiceTreeDump(std::string & dumpString)971 void RSUniRenderThread::RenderServiceTreeDump(std::string& dumpString)
972 {
973 PostSyncTask([this, &dumpString]() {
974 if (!rootNodeDrawable_) {
975 dumpString.append("rootNode is null\n");
976 return;
977 }
978 rootNodeDrawable_->DumpDrawableTree(0, dumpString, RSMainThread::Instance()->GetContext());
979 });
980 }
981
UpdateDisplayNodeScreenId()982 void RSUniRenderThread::UpdateDisplayNodeScreenId()
983 {
984 const std::shared_ptr<RSBaseRenderNode> rootNode =
985 RSMainThread::Instance()->GetContext().GetGlobalRootRenderNode();
986 if (!rootNode) {
987 RS_LOGE("RSUniRenderThread::UpdateDisplayNodeScreenId rootNode is nullptr");
988 return;
989 }
990 auto child = rootNode->GetFirstChild();
991 if (child != nullptr && child->IsInstanceOf<RSDisplayRenderNode>()) {
992 auto displayNode = child->ReinterpretCastTo<RSDisplayRenderNode>();
993 if (displayNode) {
994 displayNodeScreenId_ = displayNode->GetScreenId();
995 }
996 }
997 }
998
GetDynamicRefreshRate() const999 uint32_t RSUniRenderThread::GetDynamicRefreshRate() const
1000 {
1001 uint32_t refreshRate = OHOS::Rosen::HgmCore::Instance().GetScreenCurrentRefreshRate(displayNodeScreenId_);
1002 if (refreshRate == 0) {
1003 RS_LOGE("RSUniRenderThread::GetDynamicRefreshRate refreshRate is invalid");
1004 return STANDARD_REFRESH_RATE;
1005 }
1006 return refreshRate;
1007 }
1008
SetAcquireFence(sptr<SyncFence> acquireFence)1009 void RSUniRenderThread::SetAcquireFence(sptr<SyncFence> acquireFence)
1010 {
1011 acquireFence_ = acquireFence;
1012 }
1013
SetVmaCacheStatus(bool flag)1014 void RSUniRenderThread::SetVmaCacheStatus(bool flag)
1015 {
1016 static constexpr int MAX_VMA_CACHE_COUNT = 600;
1017 RS_LOGD("RSUniRenderThread::SetVmaCacheStatus(): %d, %d", vmaOptimizeFlag_, flag);
1018 if (!vmaOptimizeFlag_) {
1019 return;
1020 }
1021 std::lock_guard<std::mutex> lock(vmaCacheCountMutex_);
1022 vmaCacheCount_ = flag ? MAX_VMA_CACHE_COUNT : 0;
1023 }
1024 } // namespace Rosen
1025 } // namespace OHOS
1026