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