• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <ctime>
19 
20 #include "base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include/hisysevent.h"
21 
22 #include "pipeline/rs_frame_report.h"
23 #include "pipeline/rs_render_node_map.h"
24 #include "pipeline/rs_root_render_node.h"
25 #include "platform/common/rs_log.h"
26 #include "rs_trace.h"
27 #include "ui/rs_ui_director.h"
28 #ifdef ROSEN_OHOS
29 #include <sys/prctl.h>
30 #include <unistd.h>
31 
32 #include "platform/ohos/rs_render_service_connect_hub.h"
33 #endif
34 #ifdef USE_FLUTTER_TEXTURE
35 #include "pipeline/rs_texture_render_node.h"
36 #endif
37 
SystemCallSetThreadName(const std::string & name)38 static void SystemCallSetThreadName(const std::string& name)
39 {
40 #ifdef ROSEN_OHOS
41     if (prctl(PR_SET_NAME, name.c_str()) < 0) {
42         return;
43     }
44 #endif
45 }
46 
47 namespace {
DrawEventReport(float frameLength)48 void DrawEventReport(float frameLength)
49 {
50     int32_t pid = getpid();
51     uint32_t uid = getuid();
52     std::string domain = "GRAPHIC";
53     std::string stringId = "NO_DRAW";
54     std::string processName = "RS_THREAD";
55     std::string msg = "It took " + std::to_string(frameLength * 1000) + "ms to draw."; // 1s = 1000ms
56 
57     OHOS::HiviewDFX::HiSysEvent::Write(domain, stringId,
58         OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
59         "PID", pid,
60         "UID", uid,
61         "PROCESS_NAME", processName,
62         "MSG", msg);
63 }
64 }
65 
66 namespace OHOS {
67 namespace Rosen {
Instance()68 RSRenderThread& RSRenderThread::Instance()
69 {
70     static RSRenderThread renderThread;
71     return renderThread;
72 }
73 
RSRenderThread()74 RSRenderThread::RSRenderThread()
75 {
76 #ifdef ACE_ENABLE_GL
77     renderContext_ = new RenderContext();
78     ROSEN_LOGD("Create RenderContext, its pointer is %p", renderContext_);
79 #endif
80     mainFunc_ = [&]() {
81         clock_t startTime = clock();
82         ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::DrawFrame");
83         {
84             prevTimestamp_ = timestamp_;
85             ProcessCommands();
86         }
87 
88         ROSEN_LOGD("RSRenderThread DrawFrame(%llu) in %s", prevTimestamp_, renderContext_ ? "GPU" : "CPU");
89         Animate(prevTimestamp_);
90         Render();
91         RS_ASYNC_TRACE_BEGIN("waiting GPU running", 1111); // 1111 means async trace code for gpu
92         SendCommands();
93         auto transactionProxy = RSTransactionProxy::GetInstance();
94         if (transactionProxy != nullptr) {
95             transactionProxy->FlushImplicitTransactionFromRT();
96         }
97         ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
98         clock_t endTime = clock();
99         float drawTime = endTime - startTime;
100         // Due to the calibration problem, there is a larger error on the windows.
101         if (drawTime > CLOCKS_PER_SEC * 6) { // The drawing timeout reaches 6 seconds.
102             drawTime = static_cast<float>(drawTime) / CLOCKS_PER_SEC;
103             DrawEventReport(drawTime);
104             ROSEN_LOGD("RSRenderThread DrawFrame took %fs.", drawTime);
105         }
106     };
107 }
108 
~RSRenderThread()109 RSRenderThread::~RSRenderThread()
110 {
111     Stop();
112 
113     if (renderContext_ != nullptr) {
114         ROSEN_LOGD("Destory renderContext!!");
115         delete renderContext_;
116         renderContext_ = nullptr;
117     }
118 }
119 
Start()120 void RSRenderThread::Start()
121 {
122     ROSEN_LOGD("RSRenderThread start.");
123     running_.store(true);
124     if (thread_ == nullptr) {
125         thread_ = std::make_unique<std::thread>(&RSRenderThread::RenderLoop, this);
126     }
127 
128 #ifdef ROSEN_OHOS
129     RSRenderServiceConnectHub::SetOnConnectCallback(
130         [weakThis = wptr<RSRenderThread>(this)](sptr<RSIRenderServiceConnection>& conn) {
131             sptr<IApplicationRenderThread> renderThreadSptr = weakThis.promote();
132             if (renderThreadSptr == nullptr) {
133                 return;
134             }
135             conn->RegisterApplicationRenderThread(getpid(), renderThreadSptr);
136         });
137 #endif
138 }
139 
Stop()140 void RSRenderThread::Stop()
141 {
142     running_.store(false);
143     WakeUp();
144 
145     if (thread_ != nullptr && thread_->joinable()) {
146         thread_->join();
147     }
148 
149     thread_ = nullptr;
150     ROSEN_LOGD("RSRenderThread stopped.");
151 }
152 
WakeUp()153 void RSRenderThread::WakeUp()
154 {
155     if (rendererLooper_ != nullptr) {
156         rendererLooper_->WakeUp();
157     }
158 }
159 
RecvTransactionData(std::unique_ptr<RSTransactionData> & transactionData)160 void RSRenderThread::RecvTransactionData(std::unique_ptr<RSTransactionData>& transactionData)
161 {
162     {
163         std::unique_lock<std::mutex> cmdLock(cmdMutex_);
164         cmds_.emplace_back(std::move(transactionData));
165     }
166     // [PLANNING]: process in next vsync (temporarily)
167     RSRenderThread::Instance().RequestNextVSync();
168 }
169 
RequestNextVSync()170 void RSRenderThread::RequestNextVSync()
171 {
172     RS_TRACE_FUNC();
173     if (vsyncClient_ != nullptr) {
174         vsyncClient_->RequestNextVsync();
175     }
176 }
177 
GetTid()178 int32_t RSRenderThread::GetTid()
179 {
180     return tid_;
181 }
182 
RenderLoop()183 void RSRenderThread::RenderLoop()
184 {
185     SystemCallSetThreadName("RSRenderThread");
186     rendererLooper_ = RSThreadLooper::Create();
187     threadHandler_ = RSThreadHandler::Create();
188 
189 #ifdef ROSEN_OHOS
190     tid_ = gettid();
191     vsyncClient_ = RSVsyncClient::Create();
192     if (vsyncClient_) {
193         vsyncClient_->SetVsyncCallback(std::bind(&RSRenderThread::OnVsync, this, std::placeholders::_1));
194     }
195 #endif
196 #ifdef ACE_ENABLE_GL
197     renderContext_->InitializeEglContext(); // init egl context on RT
198 #endif
199 
200     while (running_.load()) {
201         if (rendererLooper_ == nullptr) {
202             break;
203         }
204         {
205             if (preTask_ != nullptr) {
206                 threadHandler_->PostTask(preTask_);
207                 preTask_ = nullptr;
208             }
209         }
210         if (running_.load()) {
211             rendererLooper_->ProcessAllMessages(-1);
212         }
213     }
214 
215     StopTimer();
216     vsyncClient_ = nullptr;
217     rendererLooper_ = nullptr;
218     threadHandler_ = nullptr;
219 }
220 
OnVsync(uint64_t timestamp)221 void RSRenderThread::OnVsync(uint64_t timestamp)
222 {
223     ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::OnVsync");
224     mValue = (mValue + 1) % 2; // 1 and 2 is Calculated parameters
225     RS_TRACE_INT("Vsync-client", mValue);
226     timestamp_ = timestamp;
227     if (activeWindowCnt_.load() > 0) {
228         StartTimer(0); // start render-loop now
229     }
230     ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
231 }
232 
UpdateWindowStatus(bool active)233 void RSRenderThread::UpdateWindowStatus(bool active)
234 {
235     if (active) {
236         activeWindowCnt_++;
237     } else {
238         activeWindowCnt_--;
239     }
240     ROSEN_LOGD("RSRenderThread UpdateWindowStatus %d, cur activeWindowCnt_ %d", active, activeWindowCnt_.load());
241 }
242 
StartTimer(uint64_t interval)243 void RSRenderThread::StartTimer(uint64_t interval)
244 {
245     if (threadHandler_ != nullptr) {
246         if (timeHandle_ == nullptr) {
247             timeHandle_ = RSThreadHandler::StaticCreateTask(mainFunc_);
248         }
249         threadHandler_->PostTaskDelay(timeHandle_, interval);
250     }
251 }
252 
StopTimer()253 void RSRenderThread::StopTimer()
254 {
255     ROSEN_LOGD("RSRenderThread StopTimer.");
256     if (threadHandler_ != nullptr) {
257         if (timeHandle_ != nullptr) {
258             threadHandler_->CancelTask(timeHandle_);
259         }
260     }
261 }
262 
ProcessCommands()263 void RSRenderThread::ProcessCommands()
264 {
265     std::unique_lock<std::mutex> cmdLock(cmdMutex_);
266     if (cmds_.empty()) {
267         return;
268     }
269     if (RsFrameReport::GetInstance().GetEnable()) {
270         RsFrameReport::GetInstance().ProcessCommandsStart();
271     }
272 
273     ROSEN_LOGD("RSRenderThread ProcessCommands size: %lu\n", cmds_.size());
274     std::vector<std::unique_ptr<RSTransactionData>> cmds;
275     std::swap(cmds, cmds_);
276     cmdLock.unlock();
277 
278     ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "ProcessCommands");
279     for (auto& cmdData : cmds) {
280         cmdData->Process(context_);
281     }
282     ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
283 }
284 
Animate(uint64_t timestamp)285 void RSRenderThread::Animate(uint64_t timestamp)
286 {
287     RS_TRACE_FUNC();
288 
289     if (RsFrameReport::GetInstance().GetEnable()) {
290         RsFrameReport::GetInstance().AnimateStart();
291     }
292 
293     if (context_.animatingNodeList_.empty()) {
294         return;
295     }
296 
297     // iterate and animate all animating nodes, remove if animation finished
298     std::__libcpp_erase_if_container(context_.animatingNodeList_, [timestamp](const auto& iter) -> bool {
299         auto node = iter.second.lock();
300         if (node == nullptr) {
301             ROSEN_LOGD("RSRenderThread::Animate removing expired animating node");
302             return true;
303         }
304         bool animationFinished = !node->Animate(timestamp);
305         if (animationFinished) {
306             ROSEN_LOGD("RSRenderThread::Animate removing finished animating node %llu", node->GetId());
307         }
308         return animationFinished;
309     });
310 
311     RSRenderThread::Instance().RequestNextVSync();
312 }
313 
Render()314 void RSRenderThread::Render()
315 {
316     ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::Render");
317     if (RsFrameReport::GetInstance().GetEnable()) {
318         RsFrameReport::GetInstance().RenderStart();
319     }
320     std::unique_lock<std::mutex> lock(mutex_);
321     const auto& rootNode = context_.GetGlobalRootRenderNode();
322     if (rootNode == nullptr) {
323         ROSEN_LOGE("RSRenderThread::Render, rootNode is nullptr");
324         return;
325     }
326     if (visitor_ == nullptr) {
327         visitor_ = std::make_shared<RSRenderThreadVisitor>();
328     }
329     rootNode->Prepare(visitor_);
330     rootNode->Process(visitor_);
331     ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
332 }
333 
SendCommands()334 void RSRenderThread::SendCommands()
335 {
336     ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::SendCommands");
337     if (RsFrameReport::GetInstance().GetEnable()) {
338         RsFrameReport::GetInstance().SendCommandsStart();
339     }
340 
341     RSUIDirector::RecvMessages();
342     ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
343 }
344 
OnTransaction(std::shared_ptr<RSTransactionData> transactionData)345 void RSRenderThread::OnTransaction(std::shared_ptr<RSTransactionData> transactionData)
346 {
347     ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::OnTransaction");
348     RSUIDirector::RecvMessages(transactionData);
349     ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
350 }
351 
Detach(NodeId id)352 void RSRenderThread::Detach(NodeId id)
353 {
354     if (auto node = context_.GetNodeMap().GetRenderNode<RSRootRenderNode>(id)) {
355         std::unique_lock<std::mutex> lock(mutex_);
356         context_.GetGlobalRootRenderNode()->RemoveChild(node);
357     }
358 }
359 
PostTask(RSTaskMessage::RSTask task)360 void RSRenderThread::PostTask(RSTaskMessage::RSTask task)
361 {
362     if (threadHandler_) {
363         auto taskHandle = threadHandler_->CreateTask(task);
364         threadHandler_->PostTask(taskHandle, 0);
365     }
366 }
367 } // namespace Rosen
368 } // namespace OHOS
369