• 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_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