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 "pipeline/rs_main_thread.h"
23 #include "pipeline/rs_task_dispatcher.h"
24 #include "memory/rs_memory_manager.h"
25
26 namespace OHOS::Rosen {
27 static constexpr uint32_t SUB_THREAD_NUM = 3;
28 static constexpr uint32_t WAIT_NODE_TASK_TIMEOUT = 5 * 1000; // 5s
29 constexpr const char* RELEASE_RESOURCE = "releaseResource";
30 constexpr const char* RELEASE_TEXTURE = "releaseTexture";
31
Instance()32 RSSubThreadManager* RSSubThreadManager::Instance()
33 {
34 static RSSubThreadManager instance;
35 return &instance;
36 }
37
Start(RenderContext * context)38 void RSSubThreadManager::Start(RenderContext *context)
39 {
40 if (!threadList_.empty()) {
41 return;
42 }
43 if (context) {
44 for (uint32_t i = 0; i < SUB_THREAD_NUM; ++i) {
45 auto curThread = std::make_shared<RSSubThread>(context, i);
46 auto tid = curThread->Start();
47 threadIndexMap_.emplace(tid, i);
48 reThreadIndexMap_.emplace(i, tid);
49 threadList_.push_back(curThread);
50 auto taskDispatchFunc = [i](const RSTaskDispatcher::RSTask& task, bool isSyncTask = false) {
51 RSSubThreadManager::Instance()->PostTask(task, i, isSyncTask);
52 };
53 RSTaskDispatcher::GetInstance().RegisterTaskDispatchFunc(tid, taskDispatchFunc);
54 }
55 }
56 }
57
PostTask(const std::function<void ()> & task,uint32_t threadIndex,bool isSyncTask)58 void RSSubThreadManager::PostTask(const std::function<void()>& task, uint32_t threadIndex, bool isSyncTask)
59 {
60 if (threadIndex >= threadList_.size()) {
61 RS_LOGE("taskIndex geq thread num");
62 return;
63 }
64 if (isSyncTask) {
65 threadList_[threadIndex]->PostSyncTask(task);
66 } else {
67 threadList_[threadIndex]->PostTask(task);
68 }
69 }
70
DumpMem(DfxString & log)71 void RSSubThreadManager::DumpMem(DfxString& log)
72 {
73 if (threadList_.empty()) {
74 return;
75 }
76 for (auto subThread : threadList_) {
77 if (!subThread) {
78 continue;
79 }
80 subThread->DumpMem(log);
81 }
82 }
83
GetGrContextFromSubThread(pid_t tid)84 std::shared_ptr<Drawing::GPUContext> RSSubThreadManager::GetGrContextFromSubThread(pid_t tid)
85 {
86 auto iter = threadIndexMap_.find(tid);
87 if (iter == threadIndexMap_.end()) {
88 return nullptr;
89 }
90 auto index = iter->second;
91 if ((index >= 0) && (index < SUB_THREAD_NUM)) {
92 return threadList_[index]->GetGrContext();
93 }
94 return nullptr;
95 }
96
GetAppGpuMemoryInMB()97 float RSSubThreadManager::GetAppGpuMemoryInMB()
98 {
99 if (threadList_.empty()) {
100 return 0.f;
101 }
102 float total = 0.f;
103 for (auto& subThread : threadList_) {
104 if (!subThread) {
105 continue;
106 }
107 total += subThread->GetAppGpuMemoryInMB();
108 }
109 return total;
110 }
111
SubmitSubThreadTask(const std::shared_ptr<RSDisplayRenderNode> & node,const std::list<std::shared_ptr<RSSurfaceRenderNode>> & subThreadNodes)112 void RSSubThreadManager::SubmitSubThreadTask(const std::shared_ptr<RSDisplayRenderNode>& node,
113 const std::list<std::shared_ptr<RSSurfaceRenderNode>>& subThreadNodes)
114 {
115 RS_TRACE_NAME("RSSubThreadManager::SubmitSubThreadTask");
116 bool ifNeedRequestNextVsync = false;
117
118 if (node == nullptr) {
119 ROSEN_LOGE("RSSubThreadManager::SubmitSubThreadTask display node is null");
120 return;
121 }
122 if (subThreadNodes.empty()) {
123 return;
124 }
125 CancelReleaseTextureTask();
126 CancelReleaseResourceTask();
127 std::vector<std::unique_ptr<RSRenderTask>> renderTaskList;
128 auto cacheSkippedNodeMap = RSMainThread::Instance()->GetCacheCmdSkippedNodes();
129 for (const auto& child : subThreadNodes) {
130 if (!child) {
131 ROSEN_LOGE("RSSubThreadManager::SubmitSubThreadTask !child");
132 continue;
133 }
134 if (!child->ShouldPaint()) {
135 RS_OPTIONAL_TRACE_NAME_FMT("SubmitTask skip node: [%s, %llu]", child->GetName().c_str(), child->GetId());
136 ROSEN_LOGE("RSSubThreadManager::SubmitSubThreadTask child->ShouldPaint()");
137 continue;
138 }
139 if (!child->GetNeedSubmitSubThread()) {
140 RS_OPTIONAL_TRACE_NAME_FMT("subThreadNodes : static skip %s", child->GetName().c_str());
141 ROSEN_LOGE("RSSubThreadManager::SubmitSubThreadTask !child->GetNeedSubmitSubThread()");
142 continue;
143 }
144 if (cacheSkippedNodeMap.count(child->GetId()) != 0 && child->HasCachedTexture()) {
145 RS_OPTIONAL_TRACE_NAME_FMT("SubmitTask cacheCmdSkippedNode: [%s, %llu]",
146 child->GetName().c_str(), child->GetId());
147 ROSEN_LOGE("RSSubThreadManager::SubmitSubThreadTask "
148 "cacheSkippedNodeMap.count(child->GetId()) != 0 && child->HasCachedTexture()");
149 continue;
150 }
151 nodeTaskState_[child->GetId()] = 1;
152 if (child->GetCacheSurfaceProcessedStatus() != CacheProcessStatus::DOING) {
153 child->SetCacheSurfaceProcessedStatus(CacheProcessStatus::WAITING);
154 }
155 renderTaskList.push_back(std::make_unique<RSRenderTask>(*child, RSRenderTask::RenderNodeStage::CACHE));
156 }
157 if (renderTaskList.size()) {
158 ifNeedRequestNextVsync = true;
159 }
160
161 std::vector<std::shared_ptr<RSSuperRenderTask>> superRenderTaskList;
162 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
163 superRenderTaskList.emplace_back(std::make_shared<RSSuperRenderTask>(node,
164 RSMainThread::Instance()->GetFrameCount()));
165 }
166
167 for (auto& renderTask : renderTaskList) {
168 auto renderNode = renderTask->GetNode();
169 auto surfaceNode = renderNode->ReinterpretCastTo<RSSurfaceRenderNode>();
170 if (surfaceNode == nullptr) {
171 ROSEN_LOGE("RSSubThreadManager::SubmitSubThreadTask surfaceNode is null");
172 continue;
173 }
174 auto threadIndex = surfaceNode->GetSubmittedSubThreadIndex();
175 if (threadIndex != INT_MAX && superRenderTaskList[threadIndex]) {
176 RS_OPTIONAL_TRACE_NAME("node:[ " + surfaceNode->GetName() + ", " + std::to_string(surfaceNode->GetId()) +
177 ", " + std::to_string(threadIndex) + " ]; ");
178 superRenderTaskList[threadIndex]->AddTask(std::move(renderTask));
179 } else {
180 if (superRenderTaskList[minLoadThreadIndex_]) {
181 RS_OPTIONAL_TRACE_NAME("node:[ " + surfaceNode->GetName() +
182 ", " + std::to_string(surfaceNode->GetId()) +
183 ", " + std::to_string(minLoadThreadIndex_) + " ]; ");
184 superRenderTaskList[minLoadThreadIndex_]->AddTask(std::move(renderTask));
185 surfaceNode->SetSubmittedSubThreadIndex(minLoadThreadIndex_);
186 }
187 }
188 uint32_t minLoadThreadIndex = 0;
189 auto minNodesNum = superRenderTaskList[0]->GetTaskSize();
190 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
191 auto num = superRenderTaskList[i]->GetTaskSize();
192 if (num < minNodesNum) {
193 minNodesNum = num;
194 minLoadThreadIndex = i;
195 }
196 }
197 minLoadThreadIndex_ = minLoadThreadIndex;
198 }
199
200 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
201 auto subThread = threadList_[i];
202 subThread->PostTask([subThread, renderTask = superRenderTaskList[i]]() {
203 subThread->RenderCache(renderTask);
204 });
205 }
206 needResetContext_ = true;
207 if (ifNeedRequestNextVsync) {
208 RSMainThread::Instance()->SetIsCachedSurfaceUpdated(true);
209 RSMainThread::Instance()->RequestNextVSync();
210 }
211 }
212
WaitNodeTask(uint64_t nodeId)213 void RSSubThreadManager::WaitNodeTask(uint64_t nodeId)
214 {
215 RS_TRACE_NAME_FMT("SSubThreadManager::WaitNodeTask for node %d", nodeId);
216 std::unique_lock<std::mutex> lock(parallelRenderMutex_);
217 cvParallelRender_.wait_for(lock, std::chrono::milliseconds(WAIT_NODE_TASK_TIMEOUT), [&]() {
218 return !nodeTaskState_[nodeId];
219 });
220 }
221
NodeTaskNotify(uint64_t nodeId)222 void RSSubThreadManager::NodeTaskNotify(uint64_t nodeId)
223 {
224 {
225 std::unique_lock<std::mutex> lock(parallelRenderMutex_);
226 nodeTaskState_[nodeId] = 0;
227 }
228 cvParallelRender_.notify_one();
229 }
230
ResetSubThreadGrContext()231 void RSSubThreadManager::ResetSubThreadGrContext()
232 {
233 if (threadList_.empty()) {
234 return;
235 }
236 if (!needResetContext_) {
237 ReleaseTexture();
238 return;
239 }
240 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
241 auto subThread = threadList_[i];
242 subThread->PostTask(
243 [subThread]() { subThread->ResetGrContext(); },
244 RELEASE_RESOURCE);
245 }
246 needResetContext_ = false;
247 needCancelTask_ = true;
248 }
249
CancelReleaseResourceTask()250 void RSSubThreadManager::CancelReleaseResourceTask()
251 {
252 if (!needCancelTask_) {
253 return;
254 }
255 if (threadList_.empty()) {
256 return;
257 }
258 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
259 auto subThread = threadList_[i];
260 subThread->RemoveTask(RELEASE_RESOURCE);
261 }
262 needCancelTask_ = false;
263 }
264
ReleaseTexture()265 void RSSubThreadManager::ReleaseTexture()
266 {
267 if (threadList_.empty()) {
268 return;
269 }
270 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
271 auto subThread = threadList_[i];
272 subThread->PostTask(
273 [subThread]() {
274 subThread->ThreadSafetyReleaseTexture();
275 },
276 RELEASE_TEXTURE);
277 }
278 needCancelReleaseTextureTask_ = true;
279 }
280
TryReleaseTextureForIdleThread()281 void RSSubThreadManager::TryReleaseTextureForIdleThread()
282 {
283 if (threadList_.empty()) {
284 return;
285 }
286
287 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
288 auto subThread = threadList_[i];
289 if (subThread->GetDoingCacheProcessNum() != 0) {
290 continue;
291 }
292 subThread->PostTask([subThread]() { subThread->ThreadSafetyReleaseTexture(); }, RELEASE_TEXTURE);
293 }
294 needCancelReleaseTextureTask_ = true;
295 }
296
CancelReleaseTextureTask()297 void RSSubThreadManager::CancelReleaseTextureTask()
298 {
299 if (!needCancelReleaseTextureTask_) {
300 return;
301 }
302 if (threadList_.empty()) {
303 return;
304 }
305 for (uint32_t i = 0; i < SUB_THREAD_NUM; i++) {
306 auto subThread = threadList_[i];
307 subThread->RemoveTask(RELEASE_TEXTURE);
308 }
309 needCancelReleaseTextureTask_ = false;
310 }
311
ForceReleaseResource()312 void RSSubThreadManager::ForceReleaseResource()
313 {
314 needResetContext_ = true;
315 }
316
ReleaseSurface(uint32_t threadIndex) const317 void RSSubThreadManager::ReleaseSurface(uint32_t threadIndex) const
318 {
319 if (threadList_.size() <= threadIndex) {
320 return;
321 }
322 auto subThread = threadList_[threadIndex];
323 subThread->PostTask([subThread]() {
324 subThread->ReleaseSurface();
325 });
326 }
327
AddToReleaseQueue(std::shared_ptr<Drawing::Surface> && surface,uint32_t threadIndex)328 void RSSubThreadManager::AddToReleaseQueue(std::shared_ptr<Drawing::Surface>&& surface, uint32_t threadIndex)
329 {
330 if (threadList_.size() <= threadIndex) {
331 return;
332 }
333 threadList_[threadIndex]->AddToReleaseQueue(std::move(surface));
334 }
335
GetReThreadIndexMap() const336 std::unordered_map<uint32_t, pid_t> RSSubThreadManager::GetReThreadIndexMap() const
337 {
338 return reThreadIndexMap_;
339 }
340
ScheduleRenderNodeDrawable(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)341 void RSSubThreadManager::ScheduleRenderNodeDrawable(
342 std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
343 {
344 if (UNLIKELY(!nodeDrawable)) {
345 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable nodeDrawable nullptr");
346 return;
347 }
348 const auto& param = nodeDrawable->GetRenderParams();
349 if (UNLIKELY(!param)) {
350 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable param nullptr");
351 return;
352 }
353
354 const auto& rtUniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
355 // rtUniParam will not be updated before UnblockMainThread
356 if (UNLIKELY(!rtUniParam)) {
357 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable renderThread param nullptr");
358 return;
359 }
360
361 auto minDoingCacheProcessNum = threadList_[defaultThreadIndex_]->GetDoingCacheProcessNum();
362 minLoadThreadIndex_ = defaultThreadIndex_;
363 for (unsigned int j = 0; j < SUB_THREAD_NUM; j++) {
364 if (j == defaultThreadIndex_) {
365 continue;
366 }
367 if (minDoingCacheProcessNum > threadList_[j]->GetDoingCacheProcessNum()) {
368 minDoingCacheProcessNum = threadList_[j]->GetDoingCacheProcessNum();
369 minLoadThreadIndex_ = j;
370 }
371 }
372 auto nowIdx = minLoadThreadIndex_;
373 if (threadIndexMap_.count(nodeDrawable->GetLastFrameUsedThreadIndex()) != 0) {
374 nowIdx = threadIndexMap_[nodeDrawable->GetLastFrameUsedThreadIndex()];
375 } else {
376 defaultThreadIndex_++;
377 if (defaultThreadIndex_ >= SUB_THREAD_NUM) {
378 defaultThreadIndex_ = 0;
379 }
380 }
381
382 auto subThread = threadList_[nowIdx];
383 auto tid = reThreadIndexMap_[nowIdx];
384 nodeTaskState_[param->GetId()] = 1;
385 auto submittedFrameCount = RSUniRenderThread::Instance().GetFrameCount();
386 subThread->DoingCacheProcessNumInc();
387 nodeDrawable->SetCacheSurfaceProcessedStatus(CacheProcessStatus::WAITING);
388
389 subThread->PostTask([subThread, nodeDrawable, tid, submittedFrameCount,
390 uniParam = new RSRenderThreadParams(*rtUniParam)]() mutable {
391 if (UNLIKELY(!uniParam)) {
392 RS_LOGE("RSSubThreadManager::ScheduleRenderNodeDrawable subThread param is nullptr");
393 return;
394 }
395 std::unique_ptr<RSRenderThreadParams> uniParamUnique(uniParam);
396 /* Task run in SubThread, the uniParamUnique which is copyed from uniRenderThread will sync to SubTread */
397 RSRenderThreadParamsManager::Instance().SetRSRenderThreadParams(std::move(uniParamUnique));
398 nodeDrawable->SetLastFrameUsedThreadIndex(tid);
399 nodeDrawable->SetTaskFrameCount(submittedFrameCount);
400 subThread->DrawableCache(nodeDrawable);
401 RSRenderThreadParamsManager::Instance().SetRSRenderThreadParams(nullptr);
402 });
403 needResetContext_ = true;
404 }
405
ScheduleReleaseCacheSurfaceOnly(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)406 void RSSubThreadManager::ScheduleReleaseCacheSurfaceOnly(
407 std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
408 {
409 if (!nodeDrawable) {
410 return;
411 }
412 auto& param = nodeDrawable->GetRenderParams();
413 if (!param) {
414 return;
415 }
416 auto bindThreadIdx = nodeDrawable->GetLastFrameUsedThreadIndex();
417 if (!threadIndexMap_.count(bindThreadIdx)) {
418 RS_LOGE("RSSubThreadManager::ScheduleReleaseCacheSurface invalid thread idx");
419 return;
420 }
421 auto nowIdx = threadIndexMap_[bindThreadIdx];
422
423 auto subThread = threadList_[nowIdx];
424 subThread->PostTask([subThread, nodeDrawable]() { subThread->ReleaseCacheSurfaceOnly(nodeDrawable); });
425 }
426 } // namespace OHOS::Rosen
427