1 /*
2 * Copyright (c) 2022 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_cold_start_thread.h"
17 #include "include/core/SkCanvas.h"
18 #include "include/core/SkSurface.h"
19 #include "include/core/SkImageInfo.h"
20 #ifdef RS_ENABLE_GL
21 #include <EGL/egl.h>
22 #include <GLES3/gl32.h>
23 #if defined(NEW_SKIA)
24 #include "include/gpu/GrDirectContext.h"
25 #else
26 #include "include/gpu/GrContext.h"
27 #endif
28 #endif
29 #ifdef ROSEN_OHOS
30 #include <sys/prctl.h>
31 #endif
32 #include "memory/rs_tag_tracker.h"
33 #include "pipeline/rs_draw_cmd_list.h"
34 #include "pipeline/rs_main_thread.h"
35 #include "platform/common/rs_log.h"
36 #include "rs_trace.h"
37
38 namespace OHOS {
39 namespace Rosen {
40 static const std::string THREAD_NAME = "ColdStartThread";
41 static const std::string PLAYBACK_TASK_NAME = "PlaybackTask";
42
SystemCallSetThreadName(const std::string & name)43 static void SystemCallSetThreadName(const std::string& name)
44 {
45 #ifdef ROSEN_OHOS
46 if (prctl(PR_SET_NAME, name.c_str()) < 0) {
47 return;
48 }
49 #endif
50 }
51
RSColdStartThread(std::weak_ptr<RSSurfaceRenderNode> surfaceRenderNode,NodeId surfaceNodeId)52 RSColdStartThread::RSColdStartThread(std::weak_ptr<RSSurfaceRenderNode> surfaceRenderNode, NodeId surfaceNodeId)
53 : surfaceNode_(surfaceRenderNode), surfaceNodeId_(surfaceNodeId)
54 {
55 RS_LOGD("RSColdStartThread surfaceNodeId:%" PRIu64 "", surfaceNodeId);
56 #ifdef RS_ENABLE_GL
57 thread_ = std::make_unique<std::thread>(&RSColdStartThread::Run, this, eglGetCurrentContext());
58 #else
59 thread_ = std::make_unique<std::thread>(&RSColdStartThread::Run, this);
60 #endif
61 std::unique_lock<std::mutex> lock(mutex_);
62 cv_.wait_for(lock, std::chrono::milliseconds(10), [this]() { // wait for 10ms max
63 return isRunning_.load();
64 });
65 }
66
~RSColdStartThread()67 RSColdStartThread::~RSColdStartThread()
68 {
69 RS_LOGD("~RSColdStartThread");
70 if (isRunning_.load()) {
71 Stop();
72 }
73 }
74
Stop()75 void RSColdStartThread::Stop()
76 {
77 if (!isRunning_.load() || handler_ == nullptr) {
78 return;
79 }
80 if (!handler_->IsIdle()) {
81 RS_LOGD("RSColdStartThread::Stop handler not idle, delay stop");
82 RSMainThread::Instance()->RequestNextVSync();
83 return;
84 }
85
86 RS_LOGD("RSColdStartThread::Stop");
87 RS_TRACE_NAME_FMT("RSColdStartThread::Stop");
88 isRunning_.store(false);
89 handler_->PostSyncTask([this]() {
90 RS_TRACE_NAME_FMT("RSColdStartThread abandonContext"); // abandonContext here to avoid crash
91 RS_LOGD("RSColdStartThread releaseResourcesAndAbandonContext");
92 {
93 std::lock_guard<std::mutex> lock(imageMutex_);
94 while (!images_.empty()) {
95 images_.pop();
96 }
97 }
98 #ifndef USE_ROSEN_DRAWING
99 #ifdef RS_ENABLE_GL
100 if (grContext_ != nullptr) {
101 grContext_->releaseResourcesAndAbandonContext();
102 grContext_ = nullptr;
103 }
104 #endif
105 skSurface_ = nullptr;
106 #else
107 #ifdef RS_ENABLE_GL
108 if (gpuContext_ != nullptr) {
109 RS_LOGE("[%s:%d] Drawing is not supported", __func__, __LINE__);
110 gpuContext_ = nullptr;
111 }
112 #endif
113 drSurface_ = nullptr;
114 #endif
115 #ifdef RS_ENABLE_GL
116 context_ = nullptr;
117 #endif
118 }, AppExecFwk::EventQueue::Priority::IMMEDIATE);
119
120 RS_TRACE_NAME_FMT("RSColdStartThread runner stop");
121 RS_LOGD("RSColdStartThread runner stop");
122 if (runner_ != nullptr) {
123 runner_->Stop();
124 }
125 if (thread_ != nullptr && thread_->joinable()) {
126 thread_->detach();
127 }
128 RSMainThread::Instance()->PostTask([id = surfaceNodeId_]() {
129 RS_LOGD("RSMainThread DestroyColdStartThread id:%" PRIu64 "", id);
130 RSColdStartManager::Instance().DestroyColdStartThread(id);
131 });
132 }
133
PostTask(std::function<void ()> task)134 void RSColdStartThread::PostTask(std::function<void()> task)
135 {
136 if (handler_) {
137 handler_->PostTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
138 }
139 }
140
IsIdle()141 bool RSColdStartThread::IsIdle()
142 {
143 return handler_ && handler_->IsIdle();
144 }
145
146 #ifdef RS_ENABLE_GL
Run(EGLContext context)147 void RSColdStartThread::Run(EGLContext context)
148 #else
149 void RSColdStartThread::Run()
150 #endif
151 {
152 RS_LOGD("RSColdStartThread::Run");
153 RS_TRACE_NAME_FMT("RSColdStartThread::Run");
154 SystemCallSetThreadName(THREAD_NAME);
155 #ifdef RS_ENABLE_GL
156 context_ = RSSharedContext::MakeSharedGLContext(context);
157 if (context_ != nullptr) {
158 context_->MakeCurrent();
159 }
160 #endif
161 runner_ = AppExecFwk::EventRunner::Create(false);
162 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
163 {
164 std::lock_guard<std::mutex> lock(mutex_);
165 isRunning_.store(true);
166 cv_.notify_one();
167 }
168 if (runner_ != nullptr) {
169 runner_->Run();
170 }
171 }
172
173 #ifndef USE_ROSEN_DRAWING
PostPlayBackTask(std::shared_ptr<DrawCmdList> drawCmdList,float width,float height)174 void RSColdStartThread::PostPlayBackTask(std::shared_ptr<DrawCmdList> drawCmdList, float width, float height)
175 #else
176 void RSColdStartThread::PostPlayBackTask(std::shared_ptr<Drawing::DrawCmdList> drawCmdList, float width, float height)
177 #endif
178 {
179 if (handler_ == nullptr) {
180 RS_LOGE("RSColdStartThread::PostPlayBackTask failed, handler_ is nullptr");
181 return;
182 }
183 auto task = [drawCmdList = drawCmdList, width = width, height = height, this]() {
184 #ifdef RS_ENABLE_GL
185 if (context_ == nullptr) {
186 RS_LOGE("RSColdStartThread::PostPlayBackTask context_ is nullptr");
187 return;
188 }
189 #endif
190 if (drawCmdList == nullptr) {
191 RS_LOGE("RSColdStartThread::PostPlayBackTask drawCmdList is nullptr");
192 return;
193 }
194 auto node = surfaceNode_.lock();
195 if (!node) {
196 RS_LOGE("RSColdStartThread::PostPlayBackTask surfaceNode is nullptr");
197 return;
198 }
199 #ifndef USE_ROSEN_DRAWING
200 #ifdef RS_ENABLE_GL
201 if (grContext_ == nullptr) {
202 grContext_ = context_->MakeGrContext();
203 }
204 RSTagTracker tagTracker(grContext_.get(), node->GetId(), RSTagTracker::TAGTYPE::TAG_COLD_START);
205 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
206 skSurface_ = SkSurface::MakeRenderTarget(grContext_.get(), SkBudgeted::kYes, info);
207 #else
208 skSurface_ = SkSurface::MakeRasterN32Premul(width, height);
209 #endif
210 if (skSurface_ == nullptr || skSurface_->getCanvas() == nullptr) {
211 RS_LOGE("RSColdStartThread::PostPlayBackTask make SkSurface failed");
212 return;
213 }
214
215 RS_LOGD("RSColdStartThread::PostPlayBackTask drawCmdList Playback");
216 RS_TRACE_NAME_FMT("RSColdStartThread Playback:%s", node->GetName().c_str());
217 auto canvas = skSurface_->getCanvas();
218 canvas->clear(SK_ColorTRANSPARENT);
219 drawCmdList->Playback(*canvas);
220
221 RS_TRACE_BEGIN("flush");
222 skSurface_->flush();
223 #else // USE_ROSEN_DRAWING
224 #ifdef RS_ENABLE_GL
225 if (gpuContext_ == nullptr) {
226 gpuContext_ = context_->MakeDrContext();
227 }
228 #endif
229 if (drSurface_ == nullptr || drSurface_->GetCanvas() == nullptr) {
230 RS_LOGE("RSColdStartThread::PostPlayBackTask make SkSurface failed");
231 return;
232 }
233
234 RS_LOGD("RSColdStartThread::PostPlayBackTask drawCmdList Playback");
235 RS_TRACE_NAME_FMT("RSColdStartThread Playback:%s", node->GetName().c_str());
236 auto canvas = drSurface_->GetCanvas();
237 canvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
238 drawCmdList->Playback(*canvas);
239
240 RS_TRACE_BEGIN("flush");
241 #endif // USE_ROSEN_DRAWING
242 #ifdef RS_ENABLE_GL
243 glFinish();
244 #endif
245 #ifndef USE_ROSEN_DRAWING
246 sk_sp<SkImage> image = skSurface_->makeImageSnapshot();
247 #else
248 std::shared_ptr<Drawing::Image> image = drSurface_->GetImageSnapshot();
249 #endif
250 RS_TRACE_END();
251
252 if (node->GetCachedImage() == nullptr) {
253 node->NotifyUIBufferAvailable();
254 }
255 {
256 std::lock_guard<std::mutex> lock(imageMutex_);
257 images_.push(image);
258 }
259 RSMainThread::Instance()->PostTask([this]() {
260 auto node = surfaceNode_.lock();
261 if (!node) {
262 RS_LOGE("RSColdStartThread PostSyncTask surfaceNode is nullptr");
263 return;
264 }
265 {
266 RS_LOGD("RSMainThread SetCachedImage");
267 std::lock_guard<std::mutex> lock(imageMutex_);
268 if (!images_.empty()) {
269 node->SetCachedImage(images_.back());
270 }
271 }
272 RSMainThread::Instance()->RequestNextVSync();
273 });
274 };
275 if (handler_->IsIdle()) {
276 auto node = surfaceNode_.lock();
277 RS_TRACE_NAME_FMT("PostPlayBackTask:%s", node ? node->GetName().c_str() : "nullptr");
278 handler_->PostTask(task, PLAYBACK_TASK_NAME, 0, AppExecFwk::EventQueue::Priority::IMMEDIATE);
279 }
280 }
281
Instance()282 RSColdStartManager& RSColdStartManager::Instance()
283 {
284 static RSColdStartManager instance;
285 return instance;
286 }
287
288 #ifndef USE_ROSEN_DRAWING
PostPlayBackTask(NodeId id,std::shared_ptr<DrawCmdList> drawCmdList,float width,float height)289 void RSColdStartManager::PostPlayBackTask(NodeId id, std::shared_ptr<DrawCmdList> drawCmdList,
290 float width, float height)
291 #else
292 void RSColdStartManager::PostPlayBackTask(NodeId id, std::shared_ptr<Drawing::DrawCmdList> drawCmdList,
293 float width, float height)
294 #endif
295 {
296 if (coldStartThreadMap_.count(id) != 0 && coldStartThreadMap_[id] != nullptr) {
297 coldStartThreadMap_[id]->PostPlayBackTask(drawCmdList, width, height);
298 }
299 }
300
IsColdStartThreadRunning(NodeId id)301 bool RSColdStartManager::IsColdStartThreadRunning(NodeId id)
302 {
303 return coldStartThreadMap_.count(id) != 0 && coldStartThreadMap_[id] != nullptr;
304 }
305
IsColdStartThreadIdle(NodeId id)306 bool RSColdStartManager::IsColdStartThreadIdle(NodeId id)
307 {
308 if (coldStartThreadMap_.count(id) != 0 && coldStartThreadMap_[id] != nullptr) {
309 return coldStartThreadMap_[id]->IsIdle();
310 }
311 return false;
312 }
313
StartColdStartThreadIfNeed(std::shared_ptr<RSSurfaceRenderNode> surfaceNode)314 void RSColdStartManager::StartColdStartThreadIfNeed(std::shared_ptr<RSSurfaceRenderNode> surfaceNode)
315 {
316 if (surfaceNode == nullptr) {
317 RS_LOGE("RSColdStartManager::StartColdStartThreadIfNeed surfaceNode is nullptr");
318 return;
319 }
320 auto id = surfaceNode->GetId();
321 if (coldStartThreadMap_.count(id) == 0) {
322 RS_LOGD("RSColdStartManager::StartColdStartThread id:%" PRIu64 "", id);
323 coldStartThreadMap_[id] = std::make_unique<RSColdStartThread>(surfaceNode, id);
324 }
325 }
326
StopColdStartThread(NodeId id)327 void RSColdStartManager::StopColdStartThread(NodeId id)
328 {
329 if (coldStartThreadMap_.count(id) != 0 && coldStartThreadMap_[id] != nullptr) {
330 RS_LOGD("RSColdStartManager::StopColdStartThread id:%" PRIu64 "", id);
331 coldStartThreadMap_[id]->Stop();
332 }
333 }
334
DestroyColdStartThread(NodeId id)335 void RSColdStartManager::DestroyColdStartThread(NodeId id)
336 {
337 RS_LOGD("RSColdStartManager::DestroyColdStartThread id:%" PRIu64 "", id);
338 coldStartThreadMap_.erase(id);
339 }
340
CheckColdStartMap(const RSRenderNodeMap & nodeMap)341 void RSColdStartManager::CheckColdStartMap(const RSRenderNodeMap& nodeMap)
342 {
343 for (auto& elem : coldStartThreadMap_) {
344 auto node = nodeMap.GetRenderNode<RSSurfaceRenderNode>(elem.first);
345 if (!node && elem.second) {
346 RS_LOGD("RSColdStartManager::CheckColdStartMap need stop");
347 elem.second->Stop();
348 }
349 }
350 }
351 } // namespace Rosen
352 } // namespace OHOS
353