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