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