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