• 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 
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