1 /*
2 * Copyright (c) 2023 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 "rs_sub_thread_manager.h"
17 #include <chrono>
18 #include "rs_trace.h"
19
20 #include "common/rs_singleton.h"
21 #include "common/rs_optional_trace.h"
22 #include "feature/uifirst/rs_uifirst_manager.h"
23 #include "pipeline/main_thread/rs_main_thread.h"
24 #include "pipeline/rs_task_dispatcher.h"
25 #include "memory/rs_memory_manager.h"
26
27 namespace OHOS::Rosen {
28 static constexpr uint32_t SUB_THREAD_NUM = 3;
29 static constexpr uint32_t SUB_VIDEO_THREAD_TASKS_NUM_MAX = 2;
30 static constexpr uint32_t WAIT_NODE_TASK_TIMEOUT = 5 * 1000; // 5s
31 constexpr const char* RELEASE_RESOURCE = "releaseResource";
32 constexpr const char* RELEASE_TEXTURE = "releaseTexture";
33
Instance()34 RSSubThreadManager* RSSubThreadManager::Instance()
35 {
36 static RSSubThreadManager instance;
37 return &instance;
38 }
39
Start(RenderContext * context)40 void RSSubThreadManager::Start(RenderContext *context)
41 {
42 if (!threadList_.empty()) {
43 return;
44 }
45 if (context) {
46 for (uint32_t i = 0; i < SUB_THREAD_NUM; ++i) {
47 auto curThread = std::make_shared<RSSubThread>(context, i);
48 auto tid = curThread->Start();
49 threadIndexMap_.emplace(tid, i);
50 reThreadIndexMap_.emplace(i, tid);
51 threadList_.push_back(curThread);
52 auto taskDispatchFunc = [i](const RSTaskDispatcher::RSTask& task, bool isSyncTask = false) {
53 RSSubThreadManager::Instance()->PostTask(task, i, isSyncTask);
54 };
55 RSTaskDispatcher::GetInstance().RegisterTaskDispatchFunc(tid, taskDispatchFunc);
56 }
57 }
58 }
59
PostTask(const std::function<void ()> & task,uint32_t threadIndex,bool isSyncTask)60 void RSSubThreadManager::PostTask(const std::function<void()>& task, uint32_t threadIndex, bool isSyncTask)
61 {
62 if (threadIndex >= threadList_.size()) {
63 RS_LOGE("taskIndex geq thread num");
64 return;
65 }
66 if (isSyncTask) {
67 threadList_[threadIndex]->PostSyncTask(task);
68 } else {
69 threadList_[threadIndex]->PostTask(task);
70 }
71 }
72
DumpMem(DfxString & log)73 void RSSubThreadManager::DumpMem(DfxString& log)
74 {
75 if (threadList_.empty()) {
76 return;
77 }
78 for (auto subThread : threadList_) {
79 if (!subThread) {
80 continue;
81 }
82 subThread->DumpMem(log);
83 }
84 }
85
GetGrContextFromSubThread(pid_t tid)86 std::shared_ptr<Drawing::GPUContext> RSSubThreadManager::GetGrContextFromSubThread(pid_t tid)
87 {
88 auto iter = threadIndexMap_.find(tid);
89 if (iter == threadIndexMap_.end()) {
90 return nullptr;
91 }
92 auto index = iter->second;
93 if ((index >= 0) && (index < SUB_THREAD_NUM)) {
94 return threadList_[index]->GetGrContext();
95 }
96 return nullptr;
97 }
98
GetAppGpuMemoryInMB()99 float RSSubThreadManager::GetAppGpuMemoryInMB()
100 {
101 if (threadList_.empty()) {
102 return 0.f;
103 }
104 float total = 0.f;
105 for (auto& subThread : threadList_) {
106 if (!subThread) {
107 continue;
108 }
109 total += subThread->GetAppGpuMemoryInMB();
110 }
111 return total;
112 }
113
WaitNodeTask(uint64_t nodeId)114 void RSSubThreadManager::WaitNodeTask(uint64_t nodeId)
115 {
116 RS_TRACE_NAME_FMT("RSSubThreadManager::WaitNodeTask for node %" PRIu64, nodeId);
117 std::unique_lock<std::mutex> lock(parallelRenderMutex_);
118 cvParallelRender_.wait_for(lock, std::chrono::milliseconds(WAIT_NODE_TASK_TIMEOUT), [&]() {
119 return !nodeTaskState_[nodeId];
120 });
121 }
122
NodeTaskNotify(uint64_t nodeId)123 void RSSubThreadManager::NodeTaskNotify(uint64_t nodeId)
124 {
125 {
126 std::unique_lock<std::mutex> lock(parallelRenderMutex_);
127 nodeTaskState_[nodeId] = 0;
128 }
129 cvParallelRender_.notify_one();
130 }
131
ResetSubThreadGrContext()132 void RSSubThreadManager::ResetSubThreadGrContext()
133 {
134 if (threadList_.empty()) {
135 return;
136 }
137 if (!needResetContext_) {
138 ReleaseTexture();
139 return;
140 }
141 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
142 auto subThread = threadList_[i];
143 subThread->PostTask(
144 [subThread]() { subThread->ResetGrContext(); },
145 RELEASE_RESOURCE);
146 }
147 needResetContext_ = false;
148 needCancelTask_ = true;
149 }
150
CancelReleaseResourceTask()151 void RSSubThreadManager::CancelReleaseResourceTask()
152 {
153 if (!needCancelTask_) {
154 return;
155 }
156 if (threadList_.empty()) {
157 return;
158 }
159 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
160 auto subThread = threadList_[i];
161 subThread->RemoveTask(RELEASE_RESOURCE);
162 }
163 needCancelTask_ = false;
164 }
165
ReleaseTexture()166 void RSSubThreadManager::ReleaseTexture()
167 {
168 if (threadList_.empty()) {
169 return;
170 }
171 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
172 auto subThread = threadList_[i];
173 subThread->PostTask(
174 [subThread]() {
175 subThread->ThreadSafetyReleaseTexture();
176 },
177 RELEASE_TEXTURE);
178 }
179 needCancelReleaseTextureTask_ = true;
180 }
181
TryReleaseTextureForIdleThread()182 void RSSubThreadManager::TryReleaseTextureForIdleThread()
183 {
184 if (threadList_.empty()) {
185 return;
186 }
187
188 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
189 auto subThread = threadList_[i];
190 if (subThread->GetDoingCacheProcessNum() != 0) {
191 continue;
192 }
193 subThread->PostTask([subThread]() { subThread->ThreadSafetyReleaseTexture(); }, RELEASE_TEXTURE);
194 }
195 needCancelReleaseTextureTask_ = true;
196 }
197
CancelReleaseTextureTask()198 void RSSubThreadManager::CancelReleaseTextureTask()
199 {
200 if (!needCancelReleaseTextureTask_) {
201 return;
202 }
203 if (threadList_.empty()) {
204 return;
205 }
206 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
207 auto subThread = threadList_[i];
208 subThread->RemoveTask(RELEASE_TEXTURE);
209 }
210 needCancelReleaseTextureTask_ = false;
211 }
212
ForceReleaseResource()213 void RSSubThreadManager::ForceReleaseResource()
214 {
215 needResetContext_ = true;
216 }
217
ReleaseSurface(uint32_t threadIndex) const218 void RSSubThreadManager::ReleaseSurface(uint32_t threadIndex) const
219 {
220 if (threadList_.size() <= threadIndex) {
221 return;
222 }
223 auto subThread = threadList_[threadIndex];
224 subThread->PostTask([subThread]() {
225 subThread->ReleaseSurface();
226 });
227 }
228
AddToReleaseQueue(std::shared_ptr<Drawing::Surface> && surface,uint32_t threadIndex)229 void RSSubThreadManager::AddToReleaseQueue(std::shared_ptr<Drawing::Surface>&& surface, uint32_t threadIndex)
230 {
231 if (threadList_.size() <= threadIndex) {
232 return;
233 }
234 threadList_[threadIndex]->AddToReleaseQueue(std::move(surface));
235 }
236
CountSubMem(int pid)237 std::vector<MemoryGraphic> RSSubThreadManager::CountSubMem(int pid)
238 {
239 std::vector<MemoryGraphic> memsContainer;
240 if (threadList_.empty()) {
241 return memsContainer;
242 }
243
244 for (auto& subThread : threadList_) {
245 if (!subThread) {
246 MemoryGraphic memoryGraphic;
247 memsContainer.push_back(memoryGraphic);
248 continue;
249 }
250 memsContainer.push_back(subThread->CountSubMem(pid));
251 }
252 return memsContainer;
253 }
254
GetReThreadIndexMap() const255 std::unordered_map<uint32_t, pid_t> RSSubThreadManager::GetReThreadIndexMap() const
256 {
257 return reThreadIndexMap_;
258 }
259
ScheduleRenderNodeDrawable(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)260 void RSSubThreadManager::ScheduleRenderNodeDrawable(
261 std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
262 {
263 if (UNLIKELY(!nodeDrawable)) {
264 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable nodeDrawable nullptr");
265 return;
266 }
267 const auto& param = nodeDrawable->GetRenderParams();
268 if (UNLIKELY(!param)) {
269 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable param nullptr");
270 return;
271 }
272
273 const auto& rtUniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
274 // rtUniParam will not be updated before UnblockMainThread
275 if (UNLIKELY(!rtUniParam)) {
276 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable renderThread param nullptr");
277 return;
278 }
279
280 auto minDoingCacheProcessNum = threadList_[defaultThreadIndex_]->GetDoingCacheProcessNum();
281 minLoadThreadIndex_ = defaultThreadIndex_;
282 unsigned int loadDefaultIndex = 0;
283 if (RSUifirstManager::Instance().GetUiFirstType() == UiFirstCcmType::MULTI) {
284 loadDefaultIndex = 1;
285 }
286 for (unsigned int j = loadDefaultIndex; j < SUB_THREAD_NUM; j++) {
287 if (j == defaultThreadIndex_) {
288 continue;
289 }
290 if (minDoingCacheProcessNum > threadList_[j]->GetDoingCacheProcessNum()) {
291 minDoingCacheProcessNum = threadList_[j]->GetDoingCacheProcessNum();
292 minLoadThreadIndex_ = j;
293 }
294 }
295 auto nowIdx = minLoadThreadIndex_;
296 if (threadIndexMap_.count(nodeDrawable->GetLastFrameUsedThreadIndex()) != 0) {
297 nowIdx = threadIndexMap_[nodeDrawable->GetLastFrameUsedThreadIndex()];
298 } else {
299 defaultThreadIndex_++;
300 if (defaultThreadIndex_ >= SUB_THREAD_NUM) {
301 defaultThreadIndex_ = loadDefaultIndex;
302 }
303 }
304 if (RSUifirstManager::Instance().GetUiFirstType() == UiFirstCcmType::MULTI) {
305 auto surfaceParams = static_cast<RSSurfaceRenderParams*>(nodeDrawable->GetRenderParams().get());
306 if (surfaceParams && surfaceParams->GetPreSubHighPriorityType() &&
307 threadList_[0]->GetDoingCacheProcessNum() < SUB_VIDEO_THREAD_TASKS_NUM_MAX) {
308 nowIdx = 0;
309 }
310 }
311
312 auto subThread = threadList_[nowIdx];
313 auto tid = reThreadIndexMap_[nowIdx];
314 {
315 std::unique_lock<std::mutex> lock(parallelRenderMutex_);
316 nodeTaskState_[param->GetId()] = 1;
317 }
318 auto submittedFrameCount = RSUniRenderThread::Instance().GetFrameCount();
319 subThread->DoingCacheProcessNumInc();
320 nodeDrawable->SetCacheSurfaceProcessedStatus(CacheProcessStatus::WAITING);
321 subThread->PostTask([subThread, nodeDrawable, tid, submittedFrameCount,
322 uniParam = new RSRenderThreadParams(*rtUniParam)]() mutable {
323 if (UNLIKELY(!uniParam)) {
324 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable subThread param is nullptr");
325 return;
326 }
327
328 // The destructor of GPUCompositonCacheGuard, a memory release check will be performed
329 RSMainThread::GPUCompositonCacheGuard guard;
330 std::unique_ptr<RSRenderThreadParams> uniParamUnique(uniParam);
331 /* Task run in SubThread, the uniParamUnique which is copyed from uniRenderThread will sync to SubTread */
332 RSRenderThreadParamsManager::Instance().SetRSRenderThreadParams(std::move(uniParamUnique));
333 nodeDrawable->SetLastFrameUsedThreadIndex(tid);
334 nodeDrawable->SetTaskFrameCount(submittedFrameCount);
335 subThread->DrawableCache(nodeDrawable);
336 RSRenderThreadParamsManager::Instance().SetRSRenderThreadParams(nullptr);
337 });
338 needResetContext_ = true;
339 }
340
ScheduleReleaseCacheSurfaceOnly(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)341 void RSSubThreadManager::ScheduleReleaseCacheSurfaceOnly(
342 std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
343 {
344 if (!nodeDrawable) {
345 return;
346 }
347 auto& param = nodeDrawable->GetRenderParams();
348 if (!param) {
349 return;
350 }
351 auto bindThreadIdx = nodeDrawable->GetLastFrameUsedThreadIndex();
352 if (!threadIndexMap_.count(bindThreadIdx)) {
353 RS_LOGE("RSSubThreadManager::ScheduleReleaseCacheSurface invalid thread idx");
354 return;
355 }
356 auto nowIdx = threadIndexMap_[bindThreadIdx];
357
358 auto subThread = threadList_[nowIdx];
359 subThread->PostTask([subThread, nodeDrawable]() { subThread->ReleaseCacheSurfaceOnly(nodeDrawable); });
360 }
361 } // namespace OHOS::Rosen
362