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