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