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