• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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