• 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 #define EGL_EGLEXT_PROTOTYPES
17 
18 #include "rs_sub_thread.h"
19 
20 #include <string>
21 
22 #include "drawable/rs_render_node_drawable.h"
23 #include "drawable/rs_surface_render_node_drawable.h"
24 #include "feature/uifirst/rs_sub_thread_manager.h"
25 #include "feature/uifirst/rs_uifirst_manager.h"
26 #include "GLES3/gl3.h"
27 #include "include/core/SkCanvas.h"
28 
29 #include "memory/rs_memory_graphic.h"
30 #include "memory/rs_memory_manager.h"
31 #include "memory/rs_tag_tracker.h"
32 #include "pipeline/render_thread/rs_uni_render_thread.h"
33 #include "pipeline/render_thread/rs_uni_render_util.h"
34 #include "pipeline/main_thread/rs_main_thread.h"
35 #include "pipeline/rs_surface_render_node.h"
36 #include "pipeline/main_thread/rs_uni_render_visitor.h"
37 #include "rs_trace.h"
38 
39 #ifdef RES_SCHED_ENABLE
40 #include "qos.h"
41 #endif
42 
43 #undef LOG_TAG
44 #define LOG_TAG "RSSubThread"
45 
46 namespace OHOS::Rosen {
~RSSubThread()47 RSSubThread::~RSSubThread()
48 {
49     RS_LOGI("~RSSubThread():%{public}d", threadIndex_);
50     PostSyncTask([this]() {
51         DestroyShareEglContext();
52     });
53 }
54 
Start()55 pid_t RSSubThread::Start()
56 {
57     RS_LOGI("RSSubThread::Start():%{public}d", threadIndex_);
58     std::string name = "RSSubThread" + std::to_string(threadIndex_);
59     runner_ = AppExecFwk::EventRunner::Create(name);
60     handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
61     pid_t tid;
62     PostSyncTask([&tid]() {
63         tid = gettid();
64     });
65     PostTask([this]() {
66 #ifdef RES_SCHED_ENABLE
67         auto ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
68         RS_LOGI("RSSubThread%{public}d: SetThreadQos retcode = %{public}d", threadIndex_, ret);
69 #endif
70         grContext_ = CreateShareGrContext();
71         if (grContext_ == nullptr) {
72             return;
73         }
74         grContext_->RegisterPostFunc([this](const std::function<void()>& task) {
75             PostTask(task);
76         });
77     });
78     return tid;
79 }
80 
PostTask(const std::function<void ()> & task,const std::string & name)81 void RSSubThread::PostTask(const std::function<void()>& task, const std::string& name)
82 {
83     if (handler_) {
84         handler_->PostImmediateTask(task, name);
85     }
86 }
87 
PostSyncTask(const std::function<void ()> & task)88 void RSSubThread::PostSyncTask(const std::function<void()>& task)
89 {
90     if (handler_) {
91         handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
92     }
93 }
94 
RemoveTask(const std::string & name)95 void RSSubThread::RemoveTask(const std::string& name)
96 {
97     if (handler_) {
98         handler_->RemoveTask(name);
99     }
100 }
101 
DumpMem(DfxString & log)102 void RSSubThread::DumpMem(DfxString& log)
103 {
104     std::vector<std::pair<NodeId, std::string>> nodeTags;
105     const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
106     nodeMap.TraverseSurfaceNodes([&nodeTags](const std::shared_ptr<RSSurfaceRenderNode> node) {
107         if (node == nullptr) {
108             return;
109         }
110         std::string name = node->GetName() + " " + std::to_string(node->GetId());
111         nodeTags.push_back({node->GetId(), name});
112     });
113     PostSyncTask([&log, &nodeTags, this]() {
114         MemoryManager::DumpDrawingGpuMemory(log, grContext_.get(), nodeTags);
115     });
116 }
117 
GetAppGpuMemoryInMB()118 float RSSubThread::GetAppGpuMemoryInMB()
119 {
120     float total = 0.f;
121     PostSyncTask([&total, this]() {
122         total = MemoryManager::GetAppGpuMemoryInMB(grContext_.get());
123     });
124     return total;
125 }
126 
CreateShareEglContext()127 void RSSubThread::CreateShareEglContext()
128 {
129     if (renderContext_ == nullptr) {
130         RS_LOGE("renderContext_ is nullptr");
131         return;
132     }
133 #ifdef RS_ENABLE_GL
134     if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
135         return;
136     }
137     eglShareContext_ = renderContext_->CreateShareContext();
138     if (eglShareContext_ == EGL_NO_CONTEXT) {
139         RS_LOGE("eglShareContext_ is EGL_NO_CONTEXT");
140         return;
141     }
142     if (!eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, eglShareContext_)) {
143         RS_LOGE("eglMakeCurrent failed");
144         return;
145     }
146 #endif
147 }
148 
DestroyShareEglContext()149 void RSSubThread::DestroyShareEglContext()
150 {
151 #ifdef RS_ENABLE_GL
152     if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
153         return;
154     }
155     if (renderContext_ != nullptr) {
156         eglDestroyContext(renderContext_->GetEGLDisplay(), eglShareContext_);
157         eglShareContext_ = EGL_NO_CONTEXT;
158         eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
159     }
160 #endif
161 }
162 
GetSubAppNodeId(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable,RSSurfaceRenderParams * surfaceParams)163 NodeId RSSubThread::GetSubAppNodeId(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable,
164     RSSurfaceRenderParams* surfaceParams)
165 {
166     NodeId tagNodeId = nodeDrawable->GetId();
167     for (const auto& subDrawable : nodeDrawable->GetDrawableVectorById(surfaceParams->GetAllSubSurfaceNodeIds())) {
168         if (UNLIKELY(!subDrawable)) {
169             continue;
170         }
171         auto subSurfaceParams = static_cast<RSSurfaceRenderParams*>(subDrawable->GetRenderParams().get());
172         if (UNLIKELY(!subSurfaceParams)) {
173             continue;
174         }
175         if (subSurfaceParams->IsAppWindow()) {
176             tagNodeId = subDrawable->GetId();
177             break;
178         }
179     }
180     return tagNodeId;
181 }
182 
CheckValid(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)183 bool RSSubThread::CheckValid(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
184 {
185     if (grContext_ == nullptr) {
186         grContext_ = CreateShareGrContext();
187         if (grContext_ == nullptr) {
188             RS_LOGE("RSSubThread::RenderCache DrawableCache grContext is null");
189             return false;
190         }
191     }
192     if (!nodeDrawable) {
193         return false;
194     }
195     return true;
196 }
197 
DrawableCache(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)198 void RSSubThread::DrawableCache(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
199 {
200     if (!CheckValid(nodeDrawable)) {
201         return;
202     }
203 
204     NodeId nodeId = nodeDrawable->GetId();
205     auto& rsSubThreadCache = nodeDrawable->GetRsSubThreadCache();
206     rsSubThreadCache.SetSubThreadSkip(false);
207 
208     RS_TRACE_NAME_FMT("RSSubThread::DrawableCache [%s] id:[%" PRIu64 "]", nodeDrawable->GetName().c_str(), nodeId);
209 
210     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(nodeDrawable->GetRenderParams().get());
211     if (UNLIKELY(!surfaceParams)) {
212         return;
213     }
214 
215     RSTagTracker tagTracker(grContext_, GetSubAppNodeId(nodeDrawable, surfaceParams),
216             RSTagTracker::TAGTYPE::TAG_SUB_THREAD, nodeDrawable->GetName());
217     // set cur firstlevel node in subThread
218     RSUiFirstProcessStateCheckerHelper stateCheckerHelper(
219         surfaceParams->GetFirstLevelNodeId(), surfaceParams->GetUifirstRootNodeId(), surfaceParams->GetId());
220     rsSubThreadCache.SetCacheSurfaceProcessedStatus(CacheProcessStatus::DOING);
221     if (rsSubThreadCache.HasCachedTexture() &&
222         rsSubThreadCache.GetTaskFrameCount() != RSUniRenderThread::Instance().GetFrameCount()) {
223         RS_TRACE_NAME_FMT("subthread skip id:%llu", nodeId);
224         RS_LOGI("uifirst subthread skip id:%{public}" PRIu64 " name:%{public}s postFrame:%{public}" PRIu64
225             " curFrame:%{public}" PRIu64, nodeId, nodeDrawable->GetName().c_str(), rsSubThreadCache.GetTaskFrameCount(),
226             RSUniRenderThread::Instance().GetFrameCount());
227         rsSubThreadCache.SetCacheSurfaceProcessedStatus(CacheProcessStatus::SKIPPED);
228         rsSubThreadCache.SetSubThreadSkip(true);
229         rsSubThreadCache.ProcessSurfaceSkipCount();
230         doingCacheProcessNum_--;
231         RSSubThreadManager::Instance()->NodeTaskNotify(nodeId);
232         RSUifirstManager::Instance().AddProcessSkippedNode(nodeId);
233         RSMainThread::Instance()->RequestNextVSync("subthreadSkipped");
234         return;
235     }
236     DrawableCacheWithSkImage(nodeDrawable);
237 
238     RSMainThread::Instance()->PostTask([]() {
239         RSMainThread::Instance()->SetIsCachedSurfaceUpdated(true);
240     });
241 
242     rsSubThreadCache.SetCacheSurfaceProcessedStatus(CacheProcessStatus::DONE);
243     rsSubThreadCache.SetCacheSurfaceNeedUpdated(true);
244     rsSubThreadCache.ResetSurfaceSkipCount();
245 
246     RSSubThreadManager::Instance()->NodeTaskNotify(nodeId);
247 
248     RSMainThread::Instance()->RequestNextVSync("subthreadDone");
249 
250     // mark nodedrawable can release
251     RSUifirstManager::Instance().AddProcessDoneNode(nodeId);
252     doingCacheProcessNum_--;
253     UpdateGpuMemoryStatistics();
254 }
255 
CreateShareGrContext()256 std::shared_ptr<Drawing::GPUContext> RSSubThread::CreateShareGrContext()
257 {
258     RS_TRACE_NAME("CreateShareGrContext");
259 #ifdef RS_ENABLE_GL
260     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
261         CreateShareEglContext();
262         auto gpuContext = std::make_shared<Drawing::GPUContext>();
263         Drawing::GPUContextOptions options;
264         auto handler = std::make_shared<MemoryHandler>();
265         auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
266         auto size = glesVersion ? strlen(glesVersion) : 0;
267         handler->ConfigureContext(&options, glesVersion, size);
268 
269         if (!gpuContext->BuildFromGL(options)) {
270             RS_LOGE("nullptr gpuContext is null");
271             return nullptr;
272         }
273         return gpuContext;
274     }
275 #endif
276 
277 #ifdef RS_ENABLE_VK
278     if (RSSystemProperties::IsUseVulkan()) {
279         auto gpuContext = std::make_shared<Drawing::GPUContext>();
280         Drawing::GPUContextOptions options;
281         auto handler = std::make_shared<MemoryHandler>();
282         std::string vulkanVersion = RsVulkanContext::GetSingleton().GetVulkanVersion();
283         auto size = vulkanVersion.size();
284         handler->ConfigureContext(&options, vulkanVersion.c_str(), size);
285         if (!gpuContext->BuildFromVK(RsVulkanContext::GetSingleton().GetGrVkBackendContext(), options)) {
286             RS_LOGE("nullptr gpuContext is null");
287             return nullptr;
288         }
289         MemoryManager::SetGpuMemoryLimit(gpuContext.get());
290         return gpuContext;
291     }
292 #endif
293     return nullptr;
294 }
295 
DrawableCacheWithSkImage(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)296 void RSSubThread::DrawableCacheWithSkImage(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
297 {
298     if (!nodeDrawable) {
299         RS_LOGE("RSSubThread::DrawableCacheWithSkImage nodeDrawable is nullptr");
300         return;
301     }
302     auto& rsSubThreadCache = nodeDrawable->GetRsSubThreadCache();
303     auto cacheSurface = rsSubThreadCache.GetCacheSurface(threadIndex_);
304     bool isHdrSurface = false;
305     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(nodeDrawable->GetRenderParams().get());
306     if (surfaceParams != nullptr) {
307         isHdrSurface = surfaceParams->GetHDRPresent();
308     }
309     bool isScRGBEnable = RSSystemParameters::IsNeedScRGBForP3(rsSubThreadCache.GetTargetColorGamut()) &&
310         RSUifirstManager::Instance().GetUiFirstSwitch();
311     bool isNeedFP16 = isHdrSurface || isScRGBEnable;
312     bool bufferFormatNeedUpdate = rsSubThreadCache.BufferFormatNeedUpdate(cacheSurface, isNeedFP16);
313     if (!cacheSurface || rsSubThreadCache.NeedInitCacheSurface(surfaceParams) || bufferFormatNeedUpdate) {
314         DrawableV2::RsSubThreadCache::ClearCacheSurfaceFunc func = &RSUniRenderUtil::ClearNodeCacheSurface;
315         rsSubThreadCache.InitCacheSurface(grContext_.get(), nodeDrawable, func, threadIndex_, isNeedFP16);
316         cacheSurface = rsSubThreadCache.GetCacheSurface(threadIndex_);
317     }
318 
319     if (!cacheSurface) {
320         RS_LOGE("RSSubThread::DrawableCacheWithSkImage cacheSurface is nullptr");
321         return;
322     }
323 
324     auto rscanvas = std::make_shared<RSPaintFilterCanvas>(cacheSurface.get());
325     if (rscanvas == nullptr) {
326         RS_LOGE("RSSubThread::DrawableCacheWithSkImage canvas is nullptr");
327         return;
328     }
329     SetHighContrastIfEnabled(*rscanvas);
330     rscanvas->SetIsParallelCanvas(true);
331     rscanvas->SetDisableFilterCache(true);
332     rscanvas->SetParallelThreadIdx(threadIndex_);
333     rscanvas->SetScreenId(rsSubThreadCache.GetScreenId());
334     rscanvas->SetTargetColorGamut(rsSubThreadCache.GetTargetColorGamut());
335     rscanvas->SetHdrOn(rsSubThreadCache.GetHDRPresent());
336     rscanvas->SetIsDrawingCache(true);
337     rscanvas->Save();
338     rsSubThreadCache.SubDraw(nodeDrawable.get(), *rscanvas);
339     rscanvas->Restore();
340     bool optFenceWait = (RSUifirstManager::Instance().GetUiFirstType() == UiFirstCcmType::MULTI &&
341         !rsSubThreadCache.IsHighPostPriority()) ? false : true;
342     RSUniRenderUtil::OptimizedFlushAndSubmit(cacheSurface, grContext_.get(), optFenceWait);
343     rsSubThreadCache.UpdateCacheSurfaceInfo(nodeDrawable);
344     rsSubThreadCache.UpdateBackendTexture();
345     rsSubThreadCache.SetCacheBehindWindowData(rscanvas->GetCacheBehindWindowData());
346 
347     // uifirst_debug dump img, run following commands to grant permissions before dump, otherwise dump maybe fail:
348     // 1. hdc shell mount -o rw,remount /
349     // 2. hdc shell setenforce 0 # close selinux temporarily
350     // 3. hdc shell chmod 0777 /data
351     RSBaseRenderUtil::WriteCacheImageRenderNodeToPng(cacheSurface, nodeDrawable->GetName());
352 }
353 
ResetGrContext()354 void RSSubThread::ResetGrContext()
355 {
356     RS_TRACE_NAME_FMT("subthread ResetGrContext release resource");
357     if (grContext_ == nullptr) {
358         return;
359     }
360     grContext_->FlushAndSubmit(true);
361     grContext_->FreeGpuResources();
362     UpdateGpuMemoryStatistics();
363 }
364 
ThreadSafetyReleaseTexture()365 void RSSubThread::ThreadSafetyReleaseTexture()
366 {
367     if (grContext_ == nullptr) {
368         return;
369     }
370     grContext_->FreeGpuResources();
371     UpdateGpuMemoryStatistics();
372 }
373 
ReleaseSurface()374 void RSSubThread::ReleaseSurface()
375 {
376     std::lock_guard<std::mutex> lock(mutex_);
377     while (tmpSurfaces_.size() > 0) {
378         auto tmp = tmpSurfaces_.front();
379         tmpSurfaces_.pop();
380         tmp = nullptr;
381     }
382     UpdateGpuMemoryStatistics();
383 }
384 
AddToReleaseQueue(std::shared_ptr<Drawing::Surface> && surface)385 void RSSubThread::AddToReleaseQueue(std::shared_ptr<Drawing::Surface>&& surface)
386 {
387     std::lock_guard<std::mutex> lock(mutex_);
388     tmpSurfaces_.push(std::move(surface));
389 }
390 
CountSubMem(int pid)391 MemoryGraphic RSSubThread::CountSubMem(int pid)
392 {
393     MemoryGraphic memoryGraphic;
394     PostSyncTask([&pid, &memoryGraphic, this]() {
395         memoryGraphic = MemoryManager::CountPidMemory(pid, grContext_.get());
396     });
397     return memoryGraphic;
398 }
399 
ReleaseCacheSurfaceOnly(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)400 void RSSubThread::ReleaseCacheSurfaceOnly(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
401 {
402     if (!nodeDrawable) {
403         return;
404     }
405     const auto& param = nodeDrawable->GetRenderParams();
406     if (!param) {
407         return;
408     }
409     NodeId nodeId = nodeDrawable->GetId();
410     RS_TRACE_NAME_FMT("ReleaseCacheSurfaceOnly id:" PRIu64, nodeId);
411     RS_LOGI("ReleaseCacheSurfaceOnly id:%{public}" PRIu64, nodeId);
412     nodeDrawable->GetRsSubThreadCache().ClearCacheSurfaceOnly();
413     UpdateGpuMemoryStatistics();
414 }
415 
SetHighContrastIfEnabled(RSPaintFilterCanvas & canvas)416 void RSSubThread::SetHighContrastIfEnabled(RSPaintFilterCanvas& canvas)
417 {
418     auto renderEngine = RSUniRenderThread::Instance().GetRenderEngine();
419     if (renderEngine) {
420         canvas.SetHighContrast(renderEngine->IsHighContrastEnabled());
421     }
422 }
423 
UpdateGpuMemoryStatistics()424 void RSSubThread::UpdateGpuMemoryStatistics()
425 {
426     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
427         return;
428     }
429     if (grContext_ == nullptr) {
430         return;
431     }
432     std::unordered_map<pid_t, size_t> gpuMemOfPid;
433     grContext_->GetUpdatedMemoryMap(gpuMemOfPid);
434     std::lock_guard<std::mutex> lock(memMutex_);
435     for (auto& [pid, size] : gpuMemOfPid) {
436         gpuMemoryOfPid_[pid] = size;
437     }
438 }
439 }
440