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