• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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