1 /*
2 * Copyright (c) 2021-2024 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 "pipeline/rs_render_thread.h"
17
18 #include <cstdint>
19
20 #include "rs_trace.h"
21 #include "sandbox_utils.h"
22
23 #include "animation/rs_animation_fraction.h"
24 #include "command/rs_surface_node_command.h"
25 #include "common/rs_background_thread.h"
26 #include "delegate/rs_functional_delegate.h"
27 #include "pipeline/rs_draw_cmd_list.h"
28 #include "pipeline/rs_node_map.h"
29 #include "pipeline/rs_render_node_map.h"
30 #include "pipeline/rs_render_node_gc.h"
31 #include "pipeline/rs_root_render_node.h"
32 #include "pipeline/rs_surface_buffer_callback_manager.h"
33 #include "pipeline/rs_surface_render_node.h"
34 #include "platform/common/rs_log.h"
35 #include "platform/common/rs_system_properties.h"
36 #include "property/rs_property_trace.h"
37 #include "render/rs_image_cache.h"
38 #include "render/rs_typeface_cache.h"
39 #include "render_context/shader_cache.h"
40 #include "rs_frame_report.h"
41 #include "transaction/rs_render_service_client.h"
42 #include "ui/rs_surface_extractor.h"
43 #include "ui/rs_surface_node.h"
44 #include "ui/rs_ui_director.h"
45 #ifdef RS_ENABLE_VK
46 #include "platform/ohos/backend/rs_vulkan_context.h"
47 #endif
48 #ifdef OHOS_RSS_CLIENT
49 #include "res_sched_client.h"
50 #include "res_type.h"
51 #endif
52
53 #ifdef RES_CLINET_SCHED_ENABLE
54 #include "qos.h"
55 #endif
56
57 #ifdef ROSEN_PREVIEW
58 #include "glfw_render_context.h"
59 #endif
60
61 #ifdef ROSEN_OHOS
62 #include <unistd.h>
63 #include "frame_collector.h"
64 #include "render_frame_trace.h"
65 #include "platform/ohos/overdraw/rs_overdraw_controller.h"
66 #ifdef ACCESSIBILITY_ENABLE
67 #include "accessibility_config.h"
68 #include "platform/common/rs_accessibility.h"
69 #endif
70
71 static const std::string RT_INTERVAL_NAME = "renderthread";
72 #endif
73 #if !defined(ROSEN_PREVIEW) && !defined(ROSEN_IOS)
74 #include <sys/prctl.h>
75 #endif
SystemCallSetThreadName(const std::string & name)76 static void SystemCallSetThreadName(const std::string& name)
77 {
78 #if !defined(ROSEN_PREVIEW) && !defined(ROSEN_IOS)
79
80 if (prctl(PR_SET_NAME, name.c_str()) < 0) {
81 return;
82 }
83 #endif
84 }
85
86 namespace OHOS {
87 namespace Rosen {
88 namespace {
89 static constexpr uint64_t REFRESH_PERIOD = 16666667;
90 }
91
SendFrameEvent(bool start)92 void SendFrameEvent(bool start)
93 {
94 #ifdef ROSEN_OHOS
95 FrameCollector::GetInstance().MarkFrameEvent(start ? FrameEventType::WaitVsyncStart : FrameEventType::WaitVsyncEnd);
96 #endif
97 }
98
Instance()99 RSRenderThread& RSRenderThread::Instance()
100 {
101 static RSRenderThread renderThread;
102 RSAnimationFraction::Init();
103 return renderThread;
104 }
105
RSRenderThread()106 RSRenderThread::RSRenderThread()
107 {
108 static std::function<std::shared_ptr<Drawing::Typeface> (uint64_t)> customTypefaceQueryfunc =
109 [] (uint64_t globalUniqueId) -> std::shared_ptr<Drawing::Typeface> {
110 return RSTypefaceCache::Instance().GetDrawingTypefaceCache(globalUniqueId);
111 };
112 Drawing::DrawOpItem::SetTypefaceQueryCallBack(customTypefaceQueryfunc);
113 mainFunc_ = [&]() {
114 uint64_t renderStartTimeStamp = jankDetector_->GetSysTimeNs();
115 RS_TRACE_BEGIN("RSRenderThread DrawFrame: " + std::to_string(timestamp_));
116 #ifdef ROSEN_OHOS
117 FRAME_TRACE::RenderFrameTrace::GetInstance().RenderStartFrameTrace(RT_INTERVAL_NAME);
118 #endif
119 prevTimestamp_ = timestamp_;
120 ProcessCommands();
121 ROSEN_LOGD("RSRenderThread DrawFrame(%{public}" PRIu64 ") in %{public}s",
122 prevTimestamp_, renderContext_ ? "GPU" : "CPU");
123 Animate(prevTimestamp_);
124 Render();
125 SendCommands();
126 {
127 std::lock_guard<std::mutex> lock(context_->activeNodesInRootMutex_);
128 context_->activeNodesInRoot_.clear();
129 }
130 RSRenderNodeGC::Instance().ReleaseNodeMemory();
131 ReleasePixelMapInBackgroundThread();
132 context_->pendingSyncNodes_.clear();
133 #ifdef ROSEN_OHOS
134 FRAME_TRACE::RenderFrameTrace::GetInstance().RenderEndFrameTrace(RT_INTERVAL_NAME);
135 #endif
136 jankDetector_->CalculateSkippedFrame(renderStartTimeStamp, jankDetector_->GetSysTimeNs());
137 RSTypefaceCache::Instance().HandleDelayDestroyQueue();
138 RS_TRACE_END();
139 };
140 context_ = std::make_shared<RSContext>();
141 context_->Initialize();
142 jankDetector_ = std::make_shared<RSJankDetector>();
143 #ifdef ACCESSIBILITY_ENABLE
144 RSAccessibility::GetInstance().ListenHighContrastChange([](bool newHighContrast) {
145 std::thread thread(
146 [](bool newHighContrast) {
147 auto& renderThread = RSRenderThread::Instance();
148 renderThread.SetHighContrast(newHighContrast);
149 },
150 newHighContrast);
151 thread.detach();
152 });
153 #endif
154 #ifdef ROSEN_OHOS
155 Drawing::DrawSurfaceBufferOpItem::RegisterSurfaceBufferCallback(
156 RSSurfaceBufferCallbackManager::Instance().GetSurfaceBufferOpItemCallback());
157 #endif
158 }
159
~RSRenderThread()160 RSRenderThread::~RSRenderThread()
161 {
162 Stop();
163 #ifndef NEW_RENDER_CONTEXT
164 if (renderContext_ != nullptr) {
165 ROSEN_LOGD("Destroy renderContext!!");
166 delete renderContext_;
167 renderContext_ = nullptr;
168 }
169 #endif
170 }
171
Start()172 void RSRenderThread::Start()
173 {
174 ROSEN_LOGD("RSRenderThread start.");
175 running_.store(true);
176 std::unique_lock<std::mutex> cmdLock(rtMutex_);
177 if (thread_ == nullptr) {
178 thread_ = std::make_unique<std::thread>([this] { this->RSRenderThread::RenderLoop(); });
179 }
180 }
181
ReleasePixelMapInBackgroundThread()182 void RSRenderThread::ReleasePixelMapInBackgroundThread()
183 {
184 if (!RSImageCache::Instance().CheckUniqueIdIsEmpty()) {
185 static std::function<void()> task = []() -> void { RSImageCache::Instance().ReleaseUniqueIdList(); };
186 RSBackgroundThread::Instance().PostTask(task);
187 }
188 }
189
Stop()190 void RSRenderThread::Stop()
191 {
192 running_.store(false);
193
194 if (handler_) {
195 handler_->RemoveAllEvents();
196 handler_ = nullptr;
197 }
198 receiver_ = nullptr;
199 if (runner_) {
200 runner_->Stop();
201 }
202
203 if (thread_ != nullptr && thread_->joinable()) {
204 thread_->join();
205 }
206
207 thread_ = nullptr;
208 ROSEN_LOGD("RSRenderThread stopped.");
209 }
210
RecvTransactionData(std::unique_ptr<RSTransactionData> & transactionData)211 void RSRenderThread::RecvTransactionData(std::unique_ptr<RSTransactionData>& transactionData)
212 {
213 {
214 std::unique_lock<std::mutex> cmdLock(cmdMutex_);
215 std::string str = "RecvCommands ptr:" + std::to_string(reinterpret_cast<uintptr_t>(transactionData.get()));
216 commandTimestamp_ = transactionData->GetTimestamp();
217 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, str.c_str());
218 cmds_.emplace_back(std::move(transactionData));
219 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
220 }
221 // [PLANNING]: process in next vsync (temporarily)
222 RSRenderThread::Instance().RequestNextVSync();
223 }
224
RequestNextVSync()225 void RSRenderThread::RequestNextVSync()
226 {
227 if (handler_) {
228 RS_TRACE_FUNC();
229 SendFrameEvent(true);
230 VSyncReceiver::FrameCallback fcb = {
231 .userData_ = this,
232 .callbackWithId_ = [this](uint64_t timestamp, int64_t frameCount,
233 void* arg) { this->OnVsync(timestamp, frameCount); },
234 };
235 if (receiver_ != nullptr) {
236 receiver_->RequestNextVSync(fcb);
237 } else {
238 hasSkipVsync_ = true;
239 }
240 } else {
241 hasSkipVsync_ = true;
242 }
243 }
244
GetTid()245 int32_t RSRenderThread::GetTid()
246 {
247 return tid_;
248 }
249
CreateAndInitRenderContextIfNeed()250 void RSRenderThread::CreateAndInitRenderContextIfNeed()
251 {
252 #if defined(NEW_RENDER_CONTEXT)
253 #if !defined(ROSEN_PREVIEW)
254 if (renderContext_ == nullptr) {
255 renderContext_ = RenderContextBaseFactory::CreateRenderContext();
256 drawingContext_ = std::make_shared<Rosen::DrawingContext>(renderContext_->GetRenderType());
257 RS_TRACE_NAME("Init Context");
258 renderContext_->Init(); // init egl context on RT
259 if (!cacheDir_.empty()) {
260 ShaderCache::Instance().SetFilePath(cacheDir_);
261 }
262 ROSEN_LOGD("Create and Init RenderContext");
263 }
264 #endif
265 #else
266 #if (defined(RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && !defined(ROSEN_PREVIEW)
267 if (renderContext_ == nullptr) {
268 renderContext_ = new RenderContext();
269 ROSEN_LOGD("Create RenderContext");
270 #ifdef ROSEN_OHOS
271 #ifdef RS_ENABLE_GL
272 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
273 RS_TRACE_NAME("InitializeEglContext");
274 renderContext_->InitializeEglContext(); // init egl context on RT
275 if (!cacheDir_.empty()) {
276 renderContext_->SetCacheDir(cacheDir_);
277 }
278 }
279 #endif
280 #ifdef RS_ENABLE_VK
281 if (RSSystemProperties::IsUseVulkan()) {
282 renderContext_->SetUpGpuContext(nullptr);
283 }
284 #endif
285 #endif
286 }
287 #endif
288 #endif
289 }
290
RenderLoop()291 void RSRenderThread::RenderLoop()
292 {
293 SystemCallSetThreadName("RSRenderThread");
294
295 #ifdef OHOS_RSS_CLIENT
296 std::unordered_map<std::string, std::string> payload;
297 payload["uid"] = std::to_string(getuid());
298 payload["pid"] = std::to_string(GetRealPid());
299 ResourceSchedule::ResSchedClient::GetInstance().ReportData(
300 ResourceSchedule::ResType::RES_TYPE_REPORT_RENDER_THREAD, getproctid(), payload);
301 #endif
302 #ifdef ROSEN_OHOS
303 tid_ = gettid();
304 #endif
305 CreateAndInitRenderContextIfNeed();
306 std::string name = "RSRenderThread_" + std::to_string(GetRealPid());
307 runner_ = AppExecFwk::EventRunner::Create(false);
308 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
309 auto rsClient = std::static_pointer_cast<RSRenderServiceClient>(RSIRenderClient::CreateRenderServiceClient());
310 receiver_ = rsClient->CreateVSyncReceiver(name, handler_);
311 if (receiver_ == nullptr) {
312 ROSEN_LOGE("RSRenderThread CreateVSyncReceiver Error");
313 return;
314 }
315 receiver_->Init();
316 if (hasSkipVsync_) {
317 hasSkipVsync_ = false;
318 RSRenderThread::Instance().RequestNextVSync();
319 }
320 #ifdef ROSEN_PREVIEW
321 static auto onSizeChange = [&](int width, int height) {
322 if (isRunning_) {
323 RSRenderThread::Instance().RequestNextVSync();
324 }
325 };
326 GlfwRenderContext::GetGlobal()->OnSizeChanged(onSizeChange);
327 #endif
328
329 #ifdef ROSEN_OHOS
330 FrameCollector::GetInstance().SetRepaintCallback([this]() { this->RequestNextVSync(); });
331
332 auto delegate = RSFunctionalDelegate::Create();
333 delegate->SetRepaintCallback([this]() { this->RequestNextVSync(); });
334 RSOverdrawController::GetInstance().SetDelegate(delegate);
335 #endif
336
337 #ifdef RES_CLINET_SCHED_ENABLE
338 auto ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
339 RS_LOGI("RSRenderThread: SetThreadQos retcode = %{public}d", ret);
340 #endif
341
342 if (runner_) {
343 runner_->Run();
344 }
345 }
346
OnVsync(uint64_t timestamp,int64_t frameCount)347 void RSRenderThread::OnVsync(uint64_t timestamp, int64_t frameCount)
348 {
349 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::OnVsync");
350 #ifdef ROSEN_PREVIEW
351 isRunning_ = true;
352 #endif
353 SendFrameEvent(false);
354 mValue = (mValue + 1) % 2; // 1 and 2 is Calculated parameters
355 RS_TRACE_INT("Vsync-client", mValue);
356 timestamp_ = timestamp;
357 if (activeWindowCnt_.load() > 0) {
358 mainFunc_(); // start render-loop now
359 }
360 #ifdef ROSEN_PREVIEW
361 isRunning_ = false;
362 #endif
363 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
364 }
365
UpdateWindowStatus(bool active)366 void RSRenderThread::UpdateWindowStatus(bool active)
367 {
368 if (active) {
369 activeWindowCnt_++;
370 } else {
371 activeWindowCnt_--;
372 }
373 ROSEN_LOGD("RSRenderThread UpdateWindowStatus %{public}d, cur activeWindowCnt_ %{public}d",
374 active, activeWindowCnt_.load());
375 }
376
ProcessCommands()377 void RSRenderThread::ProcessCommands()
378 {
379 // Attention: there are two situations
380 // 1. when commandTimestamp_ != 0, it means that UIDirector has called
381 // "RSRenderThread::Instance().RequestNextVSync()", which equals there are some commands form UIThread need to be
382 // executed. To make commands from UIThread sync with buffer flushed by RenderThread, we choose commandTimestamp_ as
383 // uiTimestamp_ which would be used in RenderThreadVisitor when we call flushFrame.
384 // 2. when cmds_.empty() is true or commandTimestamp_ = 0,
385 // it means that some thread except UIThread like RSRenderThread::Animate
386 // has called "RSRenderThread::Instance().RequestNextVSync()", which equals that some commands form RenderThread
387 // need to be executed. To make commands from RenderThread sync with buffer flushed by RenderThread, we choose
388 // (prevTimestamp_ - 1) as uiTimestamp_ which would be used in RenderThreadVisitor when we call flushFrame.
389
390 // The reason why prevTimestamp_ need to be minus 1 is that timestamp used in UIThread is always less than (for now)
391 // timestamp used in RenderThread. If we do not do this, when RenderThread::Animate execute flushFrame and use
392 // prevTimestamp_ as buffer timestamp which equals T0, UIDirector send messages in the same vsync period, and the
393 // commandTimestamp_ would also be T0, RenderService would execute commands from UIDirector and composite buffer
394 // which rendering is executed by RSRenderThread::Animate for they have the same timestamp. To avoid this situation,
395 // we should always use "prevTimestamp_ - 1".
396
397 std::unique_lock<std::mutex> cmdLock(cmdMutex_);
398 if (cmds_.empty()) {
399 uiTimestamp_ = prevTimestamp_ - 1;
400 return;
401 }
402 if (RsFrameReport::GetInstance().GetEnable()) {
403 RsFrameReport::GetInstance().ProcessCommandsStart();
404 }
405
406 if (commandTimestamp_ != 0) {
407 uiTimestamp_ = commandTimestamp_;
408 commandTimestamp_ = 0;
409 } else {
410 uiTimestamp_ = prevTimestamp_ - 1;
411 }
412
413 ROSEN_LOGD("RSRenderThread ProcessCommands size: %{public}lu\n", (unsigned long)cmds_.size());
414 std::vector<std::unique_ptr<RSTransactionData>> cmds;
415 std::swap(cmds, cmds_);
416 cmdLock.unlock();
417
418 // To improve overall responsiveness, we make animations start on LAST frame instead of THIS frame.
419 // If last frame is too far away (earlier than 2 vsync from now), we use currentTimestamp_ - REFRESH_PERIOD as
420 // 'virtual' last frame timestamp.
421 if (timestamp_ - lastAnimateTimestamp_ > 2 * REFRESH_PERIOD) { // 2: if last frame is earlier than 2 vsync from now
422 context_->currentTimestamp_ = timestamp_ - REFRESH_PERIOD;
423 } else {
424 context_->currentTimestamp_ = lastAnimateTimestamp_;
425 }
426 uint64_t uiEndTimeStamp = jankDetector_->GetSysTimeNs();
427 for (auto& cmdData : cmds) {
428 std::string str = "ProcessCommands ptr:" + std::to_string(reinterpret_cast<uintptr_t>(cmdData.get()));
429 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, str.c_str());
430 // only set transactionTimestamp_ in UniRender mode
431 context_->transactionTimestamp_ = RSSystemProperties::GetUniRenderEnabled() ? cmdData->GetTimestamp() : 0;
432 cmdData->Process(*context_);
433 jankDetector_->UpdateUiDrawFrameMsg(cmdData->GetTimestamp(), uiEndTimeStamp, cmdData->GetAbilityName());
434 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
435 }
436 }
437
Animate(uint64_t timestamp)438 void RSRenderThread::Animate(uint64_t timestamp)
439 {
440 RS_TRACE_FUNC();
441
442 if (RsFrameReport::GetInstance().GetEnable()) {
443 RsFrameReport::GetInstance().AnimateStart();
444 }
445
446 lastAnimateTimestamp_ = timestamp;
447
448 if (context_->animatingNodeList_.empty()) {
449 return;
450 }
451
452 bool needRequestNextVsync = false;
453 // isCalculateAnimationValue is embedded modify for stat animate frame drop
454 bool isCalculateAnimationValue = false;
455 // iterate and animate all animating nodes, remove if animation finished
456 EraseIf(context_->animatingNodeList_,
457 [timestamp, &needRequestNextVsync, &isCalculateAnimationValue](const auto& iter) -> bool {
458 auto node = iter.second.lock();
459 if (node == nullptr) {
460 ROSEN_LOGD("RSRenderThread::Animate removing expired animating node");
461 return true;
462 }
463 auto [hasRunningAnimation, nodeNeedRequestNextVsync, nodeCalculateAnimationValue] = node->Animate(timestamp);
464 if (!hasRunningAnimation) {
465 ROSEN_LOGD("RSRenderThread::Animate removing finished animating node %{public}" PRIu64, node->GetId());
466 }
467 needRequestNextVsync = needRequestNextVsync || nodeNeedRequestNextVsync;
468 isCalculateAnimationValue = isCalculateAnimationValue || nodeCalculateAnimationValue;
469 return !hasRunningAnimation;
470 });
471 if (!isCalculateAnimationValue && needRequestNextVsync) {
472 RS_TRACE_NAME("Animation running empty");
473 }
474
475 if (needRequestNextVsync) {
476 RSRenderThread::Instance().RequestNextVSync();
477 }
478 }
479
Render()480 void RSRenderThread::Render()
481 {
482 if (RSSystemProperties::GetRenderNodeTraceEnabled()) {
483 RSPropertyTrace::GetInstance().RefreshNodeTraceInfo();
484 }
485 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::Render");
486 if (RsFrameReport::GetInstance().GetEnable()) {
487 RsFrameReport::GetInstance().RenderStart(timestamp_);
488 }
489 std::unique_lock<std::mutex> lock(mutex_);
490 const auto& rootNode = context_->GetGlobalRootRenderNode();
491
492 if (rootNode == nullptr) {
493 ROSEN_LOGE("RSRenderThread::Render, rootNode is nullptr");
494 return;
495 }
496 if (visitor_ == nullptr) {
497 visitor_ = std::make_shared<RSRenderThreadVisitor>();
498 }
499 // get latest partial render status from system properties and set it to RTvisitor_
500 visitor_->SetPartialRenderStatus(RSSystemProperties::GetPartialRenderEnabled(), isRTRenderForced_);
501 rootNode->Prepare(visitor_);
502 rootNode->Process(visitor_);
503 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
504 }
505
SendCommands()506 void RSRenderThread::SendCommands()
507 {
508 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::SendCommands");
509 if (RsFrameReport::GetInstance().GetEnable()) {
510 RsFrameReport::GetInstance().SendCommandsStart();
511 }
512
513 RSUIDirector::RecvMessages();
514 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
515 }
516
Detach(NodeId id)517 void RSRenderThread::Detach(NodeId id)
518 {
519 if (auto node = context_->GetNodeMap().GetRenderNode<RSRootRenderNode>(id)) {
520 std::unique_lock<std::mutex> lock(mutex_);
521 context_->GetGlobalRootRenderNode()->RemoveChild(node);
522 }
523 }
524
PostTask(RSTaskMessage::RSTask task)525 void RSRenderThread::PostTask(RSTaskMessage::RSTask task)
526 {
527 if (handler_) {
528 handler_->PostTask(task);
529 }
530 }
531
PostSyncTask(RSTaskMessage::RSTask task)532 void RSRenderThread::PostSyncTask(RSTaskMessage::RSTask task)
533 {
534 if (handler_) {
535 handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
536 }
537 }
538
PostPreTask()539 void RSRenderThread::PostPreTask()
540 {
541 if (handler_ && preTask_) {
542 handler_->PostTask(preTask_);
543 }
544 }
545 } // namespace Rosen
546 } // namespace OHOS
547