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