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