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 "GLES3/gl3.h"
25 #include "include/core/SkCanvas.h"
26
27 #include "memory/rs_memory_manager.h"
28 #include "memory/rs_tag_tracker.h"
29 #include "pipeline/parallel_render/rs_sub_thread_manager.h"
30 #include "pipeline/rs_main_thread.h"
31 #include "pipeline/rs_surface_render_node.h"
32 #include "pipeline/rs_uifirst_manager.h"
33 #include "pipeline/rs_uni_render_thread.h"
34 #include "pipeline/rs_uni_render_util.h"
35 #include "pipeline/rs_uni_render_visitor.h"
36 #include "rs_trace.h"
37
38 #ifdef RES_SCHED_ENABLE
39 #include "qos.h"
40 #endif
41
42 namespace OHOS::Rosen {
~RSSubThread()43 RSSubThread::~RSSubThread()
44 {
45 RS_LOGI("~RSSubThread():%{public}d", threadIndex_);
46 PostSyncTask([this]() {
47 DestroyShareEglContext();
48 });
49 }
50
Start()51 pid_t RSSubThread::Start()
52 {
53 RS_LOGI("RSSubThread::Start():%{public}d", threadIndex_);
54 std::string name = "RSSubThread" + std::to_string(threadIndex_);
55 runner_ = AppExecFwk::EventRunner::Create(name);
56 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
57 pid_t tid;
58 PostSyncTask([&tid]() {
59 tid = gettid();
60 });
61 PostTask([this]() {
62 #ifdef RES_SCHED_ENABLE
63 auto ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
64 RS_LOGI("RSSubThread%{public}d: SetThreadQos retcode = %{public}d", threadIndex_, ret);
65 #endif
66 grContext_ = CreateShareGrContext();
67 if (grContext_ == nullptr) {
68 return;
69 }
70 grContext_->RegisterPostFunc([this](const std::function<void()>& task) {
71 PostTask(task);
72 });
73 });
74 return tid;
75 }
76
PostTask(const std::function<void ()> & task,const std::string & name)77 void RSSubThread::PostTask(const std::function<void()>& task, const std::string& name)
78 {
79 if (handler_) {
80 handler_->PostImmediateTask(task, name);
81 }
82 }
83
PostSyncTask(const std::function<void ()> & task)84 void RSSubThread::PostSyncTask(const std::function<void()>& task)
85 {
86 if (handler_) {
87 handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
88 }
89 }
90
RemoveTask(const std::string & name)91 void RSSubThread::RemoveTask(const std::string& name)
92 {
93 if (handler_) {
94 handler_->RemoveTask(name);
95 }
96 }
97
DumpMem(DfxString & log)98 void RSSubThread::DumpMem(DfxString& log)
99 {
100 std::vector<std::pair<NodeId, std::string>> nodeTags;
101 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
102 nodeMap.TraverseSurfaceNodes([&nodeTags](const std::shared_ptr<RSSurfaceRenderNode> node) {
103 if (node == nullptr) {
104 return;
105 }
106 std::string name = node->GetName() + " " + std::to_string(node->GetId());
107 nodeTags.push_back({node->GetId(), name});
108 });
109 PostSyncTask([&log, &nodeTags, this]() {
110 MemoryManager::DumpDrawingGpuMemory(log, grContext_.get(), nodeTags);
111 });
112 }
113
GetAppGpuMemoryInMB()114 float RSSubThread::GetAppGpuMemoryInMB()
115 {
116 float total = 0.f;
117 PostSyncTask([&total, this]() {
118 total = MemoryManager::GetAppGpuMemoryInMB(grContext_.get());
119 });
120 return total;
121 }
122
CreateShareEglContext()123 void RSSubThread::CreateShareEglContext()
124 {
125 if (renderContext_ == nullptr) {
126 RS_LOGE("renderContext_ is nullptr");
127 return;
128 }
129 #ifdef RS_ENABLE_GL
130 if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
131 return;
132 }
133 eglShareContext_ = renderContext_->CreateShareContext();
134 if (eglShareContext_ == EGL_NO_CONTEXT) {
135 RS_LOGE("eglShareContext_ is EGL_NO_CONTEXT");
136 return;
137 }
138 if (!eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, eglShareContext_)) {
139 RS_LOGE("eglMakeCurrent failed");
140 return;
141 }
142 #endif
143 }
144
DestroyShareEglContext()145 void RSSubThread::DestroyShareEglContext()
146 {
147 #ifdef RS_ENABLE_GL
148 if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
149 return;
150 }
151 if (renderContext_ != nullptr) {
152 eglDestroyContext(renderContext_->GetEGLDisplay(), eglShareContext_);
153 eglShareContext_ = EGL_NO_CONTEXT;
154 eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
155 }
156 #endif
157 }
158
RenderCache(const std::shared_ptr<RSSuperRenderTask> & threadTask)159 void RSSubThread::RenderCache(const std::shared_ptr<RSSuperRenderTask>& threadTask)
160 {
161 RS_TRACE_NAME("RSSubThread::RenderCache");
162 if (threadTask == nullptr) {
163 RS_LOGE("RSSubThread::RenderCache threadTask is nullptr");
164 return;
165 }
166 if (threadTask->GetTaskSize() == 0) {
167 RS_LOGE("RSSubThread::RenderCache no task");
168 return;
169 }
170 if (grContext_ == nullptr) {
171 grContext_ = CreateShareGrContext();
172 if (grContext_ == nullptr) {
173 return;
174 }
175 }
176 auto visitor = std::make_shared<RSUniRenderVisitor>();
177 visitor->SetSubThreadConfig(threadIndex_);
178 visitor->SetFocusedNodeId(RSMainThread::Instance()->GetFocusNodeId(),
179 RSMainThread::Instance()->GetFocusLeashWindowId());
180 auto screenManager = CreateOrGetScreenManager();
181 if (!screenManager) {
182 RS_LOGE("RSSubThread::RenderCache screenManager is nullptr");
183 return;
184 }
185 visitor->SetScreenInfo(screenManager->QueryScreenInfo(screenManager->GetDefaultScreenId()));
186 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
187 bool needRequestVsync = false;
188 while (threadTask->GetTaskSize() > 0) {
189 auto task = threadTask->GetNextRenderTask();
190 if (!task || (task->GetIdx() == 0)) {
191 continue;
192 }
193 auto nodeDrawable = task->GetNode();
194 if (!nodeDrawable) {
195 continue;
196 }
197 auto surfaceNodePtr = std::static_pointer_cast<RSSurfaceRenderNode>(nodeDrawable);
198 if (!surfaceNodePtr) {
199 continue;
200 }
201 // flag CacheSurfaceProcessed is used for cacheCmdskippedNodes collection in rs_mainThread
202 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DOING);
203 if (RSMainThread::Instance()->GetFrameCount() != threadTask->GetFrameCount()) {
204 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::WAITING);
205 continue;
206 }
207
208 RS_TRACE_NAME_FMT("draw cache render nodeDrawable: [%s, %llu]", surfaceNodePtr->GetName().c_str(),
209 surfaceNodePtr->GetId());
210 if (surfaceNodePtr->GetCacheSurface(threadIndex_, true) == nullptr || surfaceNodePtr->NeedInitCacheSurface()) {
211 RSRenderNode::ClearCacheSurfaceFunc func = &RSUniRenderUtil::ClearNodeCacheSurface;
212 surfaceNodePtr->InitCacheSurface(grContext_.get(), func, threadIndex_);
213 }
214
215 RSTagTracker nodeProcessTracker(grContext_.get(), surfaceNodePtr->GetId(),
216 RSTagTracker::TAGTYPE::TAG_SUB_THREAD, surfaceNodePtr->GetName());
217 bool needNotify = !surfaceNodePtr->HasCachedTexture();
218 nodeDrawable->Process(visitor);
219 nodeProcessTracker.SetTagEnd();
220 auto cacheSurface = surfaceNodePtr->GetCacheSurface(threadIndex_, true);
221 if (cacheSurface) {
222 RS_TRACE_NAME_FMT("Rendercache skSurface flush and submit");
223 RSTagTracker nodeFlushTracker(grContext_.get(), surfaceNodePtr->GetId(),
224 RSTagTracker::TAGTYPE::TAG_SUB_THREAD, surfaceNodePtr->GetName());
225 cacheSurface->FlushAndSubmit(true);
226 nodeFlushTracker.SetTagEnd();
227 }
228 surfaceNodePtr->UpdateBackendTexture();
229 RSMainThread::Instance()->PostTask([]() {
230 RSMainThread::Instance()->SetIsCachedSurfaceUpdated(true);
231 });
232 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DONE);
233 surfaceNodePtr->SetCacheSurfaceNeedUpdated(true);
234 needRequestVsync = true;
235
236 if (needNotify) {
237 RSSubThreadManager::Instance()->NodeTaskNotify(nodeDrawable->GetId());
238 }
239 }
240 if (needRequestVsync) {
241 RSMainThread::Instance()->RequestNextVSync();
242 }
243 #endif
244 }
245
DrawableCache(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)246 void RSSubThread::DrawableCache(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
247 {
248 if (grContext_ == nullptr) {
249 grContext_ = CreateShareGrContext();
250 if (grContext_ == nullptr) {
251 RS_LOGE("RSSubThread::RenderCache DrawableCache grContext is null");
252 return;
253 }
254 }
255 if (!nodeDrawable) {
256 return;
257 }
258
259 NodeId nodeId = nodeDrawable->GetId();
260 nodeDrawable->SetSubThreadSkip(false);
261
262 RS_TRACE_NAME_FMT("RSSubThread::DrawableCache [%s]", nodeDrawable->GetName().c_str());
263 RSTagTracker tagTracker(grContext_.get(), nodeId, RSTagTracker::TAGTYPE::TAG_SUB_THREAD, nodeDrawable->GetName());
264
265 auto surfaceParams = static_cast<RSSurfaceRenderParams*>(nodeDrawable->GetRenderParams().get());
266 if (UNLIKELY(!surfaceParams)) {
267 return;
268 }
269 // set cur firstlevel node in subThread
270 RSUiFirstProcessStateCheckerHelper stateCheckerHelper(
271 surfaceParams->GetFirstLevelNodeId(), surfaceParams->GetUifirstRootNodeId(), surfaceParams->GetId());
272 nodeDrawable->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DOING);
273 if (nodeDrawable->HasCachedTexture() &&
274 nodeDrawable->GetTaskFrameCount() != RSUniRenderThread::Instance().GetFrameCount()) {
275 RS_TRACE_NAME_FMT("subthread skip node id %llu", nodeId);
276 nodeDrawable->SetCacheSurfaceProcessedStatus(CacheProcessStatus::SKIPPED);
277 nodeDrawable->SetSubThreadSkip(true);
278 doingCacheProcessNum_--;
279 return;
280 }
281 if (nodeDrawable->UseDmaBuffer()) {
282 DrawableCacheWithDma(nodeDrawable);
283 } else {
284 DrawableCacheWithSkImage(nodeDrawable);
285 }
286
287 RSMainThread::Instance()->PostTask([]() {
288 RSMainThread::Instance()->SetIsCachedSurfaceUpdated(true);
289 });
290
291 nodeDrawable->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DONE);
292 nodeDrawable->SetCacheSurfaceNeedUpdated(true);
293
294 RSSubThreadManager::Instance()->NodeTaskNotify(nodeId);
295
296 RSMainThread::Instance()->RequestNextVSync("subthread");
297
298 // mark nodedrawable can release
299 RSUifirstManager::Instance().AddProcessDoneNode(nodeId);
300 doingCacheProcessNum_--;
301 }
302
CreateShareGrContext()303 std::shared_ptr<Drawing::GPUContext> RSSubThread::CreateShareGrContext()
304 {
305 RS_TRACE_NAME("CreateShareGrContext");
306 #ifdef RS_ENABLE_GL
307 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
308 CreateShareEglContext();
309 auto gpuContext = std::make_shared<Drawing::GPUContext>();
310 Drawing::GPUContextOptions options;
311 auto handler = std::make_shared<MemoryHandler>();
312 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
313 auto size = glesVersion ? strlen(glesVersion) : 0;
314 handler->ConfigureContext(&options, glesVersion, size);
315
316 if (!gpuContext->BuildFromGL(options)) {
317 RS_LOGE("nullptr gpuContext is null");
318 return nullptr;
319 }
320 return gpuContext;
321 }
322 #endif
323
324 #ifdef RS_ENABLE_VK
325 if (RSSystemProperties::IsUseVulkan()) {
326 auto gpuContext = std::make_shared<Drawing::GPUContext>();
327 Drawing::GPUContextOptions options;
328 auto handler = std::make_shared<MemoryHandler>();
329 std::string vulkanVersion = RsVulkanContext::GetSingleton().GetVulkanVersion();
330 auto size = vulkanVersion.size();
331 handler->ConfigureContext(&options, vulkanVersion.c_str(), size);
332 bool useHBackendContext = false;
333 if (RSSystemProperties::GetVkQueueDividedEnable()) {
334 useHBackendContext = RSMainThread::Instance()->GetDeviceType() == DeviceType::PC;
335 }
336 if (!gpuContext->BuildFromVK(RsVulkanContext::GetSingleton().GetGrVkBackendContext(useHBackendContext),
337 options)) {
338 RS_LOGE("nullptr gpuContext is null");
339 return nullptr;
340 }
341 MemoryManager::SetGpuMemoryLimit(gpuContext.get());
342 return gpuContext;
343 }
344 #endif
345 return nullptr;
346 }
347
DrawableCacheWithSkImage(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)348 void RSSubThread::DrawableCacheWithSkImage(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
349 {
350 if (!nodeDrawable) {
351 RS_LOGE("RSSubThread::DrawableCacheWithSkImage nodeDrawable is nullptr");
352 return;
353 }
354 auto cacheSurface = nodeDrawable->GetCacheSurface(threadIndex_, true);
355 if (!cacheSurface || nodeDrawable->NeedInitCacheSurface()) {
356 DrawableV2::RSSurfaceRenderNodeDrawable::ClearCacheSurfaceFunc func = &RSUniRenderUtil::ClearNodeCacheSurface;
357 nodeDrawable->InitCacheSurface(grContext_.get(), func, threadIndex_, nodeDrawable->GetHDRPresent());
358 cacheSurface = nodeDrawable->GetCacheSurface(threadIndex_, true);
359 }
360
361 if (!cacheSurface) {
362 RS_LOGE("RSSubThread::DrawableCacheWithSkImage cacheSurface is nullptr");
363 return;
364 }
365
366 auto rscanvas = std::make_shared<RSPaintFilterCanvas>(cacheSurface.get());
367 if (rscanvas == nullptr) {
368 RS_LOGE("RSSubThread::DrawableCacheWithSkImage canvas is nullptr");
369 return;
370 }
371 SetHighContrastIfEnabled(*rscanvas);
372 rscanvas->SetIsParallelCanvas(true);
373 rscanvas->SetDisableFilterCache(true);
374 rscanvas->SetParallelThreadIdx(threadIndex_);
375 rscanvas->SetScreenId(nodeDrawable->GetScreenId());
376 rscanvas->SetTargetColorGamut(nodeDrawable->GetTargetColorGamut());
377 rscanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
378 nodeDrawable->SubDraw(*rscanvas);
379 bool optFenceWait = RSMainThread::Instance()->GetDeviceType() == DeviceType::PC ? false : true;
380 RSUniRenderUtil::OptimizedFlushAndSubmit(cacheSurface, grContext_.get(), optFenceWait);
381 nodeDrawable->UpdateBackendTexture();
382
383 // uifirst_debug dump img, run following commands to grant permissions before dump, otherwise dump maybe fail:
384 // 1. hdc shell mount -o rw,remount /
385 // 2. hdc shell setenforce 0 # close selinux temporarily
386 // 3. hdc shell chmod 0777 /data
387 RSBaseRenderUtil::WriteCacheImageRenderNodeToPng(cacheSurface, nodeDrawable->GetName());
388 }
389
DrawableCacheWithDma(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)390 void RSSubThread::DrawableCacheWithDma(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
391 {
392 RS_TRACE_NAME("DrawableCacheWithDma");
393 if (!nodeDrawable) {
394 RS_LOGE("RSSubThread::DrawableCache nodeDrawable is nullptr");
395 return;
396 }
397 if (!nodeDrawable->IsSurfaceCreated()) {
398 nodeDrawable->CreateSurface();
399 }
400 auto renderFrame = nodeDrawable->RequestFrame(renderContext_, grContext_);
401 if (!renderFrame) {
402 RS_LOGE("RSSubThread::DrawableCache renderFrame is nullptr");
403 return;
404 }
405 auto drSurface = renderFrame->GetFrame()->GetSurface();
406 if (!drSurface) {
407 RS_LOGE("RSSubThread::DrawableCache DrawingSurface is null");
408 return;
409 }
410 auto rsCanvas = std::make_shared<RSPaintFilterCanvas>(drSurface.get());
411 if (rsCanvas == nullptr) {
412 RS_LOGE("RSSubThread::DrawableCache canvas is nullptr");
413 return;
414 }
415 SetHighContrastIfEnabled(*rsCanvas);
416 rsCanvas->SetIsParallelCanvas(true);
417 rsCanvas->SetDisableFilterCache(true);
418 rsCanvas->SetParallelThreadIdx(threadIndex_);
419 rsCanvas->SetScreenId(nodeDrawable->GetScreenId());
420 rsCanvas->SetTargetColorGamut(nodeDrawable->GetTargetColorGamut());
421 nodeDrawable->ClipRoundRect(*rsCanvas);
422 rsCanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
423
424 nodeDrawable->SubDraw(*rsCanvas);
425 RS_TRACE_BEGIN("FlushFrame");
426 bool optFenceWait = RSMainThread::Instance()->GetDeviceType() == DeviceType::PC ? false : true;
427 RSUniRenderUtil::OptimizedFlushAndSubmit(drSurface, grContext_.get(), optFenceWait);
428 renderFrame->Flush();
429 RS_TRACE_END();
430 // uifirst_debug dump img, run following commands to grant permissions before dump, otherwise dump maybe fail:
431 // 1. hdc shell mount -o rw,remount /
432 // 2. hdc shell setenforce 0 # close selinux temporarily
433 // 3. hdc shell chmod 0777 /data
434 RSBaseRenderUtil::WriteCacheImageRenderNodeToPng(drSurface, nodeDrawable->GetName());
435 }
436
ResetGrContext()437 void RSSubThread::ResetGrContext()
438 {
439 RS_TRACE_NAME_FMT("subthread ResetGrContext release resource");
440 if (grContext_ == nullptr) {
441 return;
442 }
443 grContext_->FlushAndSubmit(true);
444 grContext_->FreeGpuResources();
445 }
446
ThreadSafetyReleaseTexture()447 void RSSubThread::ThreadSafetyReleaseTexture()
448 {
449 if (grContext_ == nullptr) {
450 return;
451 }
452 grContext_->FreeGpuResources();
453 }
454
ReleaseSurface()455 void RSSubThread::ReleaseSurface()
456 {
457 std::lock_guard<std::mutex> lock(mutex_);
458 while (tmpSurfaces_.size() > 0) {
459 auto tmp = tmpSurfaces_.front();
460 tmpSurfaces_.pop();
461 tmp = nullptr;
462 }
463 }
464
AddToReleaseQueue(std::shared_ptr<Drawing::Surface> && surface)465 void RSSubThread::AddToReleaseQueue(std::shared_ptr<Drawing::Surface>&& surface)
466 {
467 std::lock_guard<std::mutex> lock(mutex_);
468 tmpSurfaces_.push(std::move(surface));
469 }
470
ReleaseCacheSurfaceOnly(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)471 void RSSubThread::ReleaseCacheSurfaceOnly(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
472 {
473 if (!nodeDrawable) {
474 return;
475 }
476 const auto& param = nodeDrawable->GetRenderParams();
477 if (!param) {
478 return;
479 }
480 nodeDrawable->ClearCacheSurfaceOnly();
481 }
482
SetHighContrastIfEnabled(RSPaintFilterCanvas & canvas)483 void RSSubThread::SetHighContrastIfEnabled(RSPaintFilterCanvas& canvas)
484 {
485 auto renderEngine = RSUniRenderThread::Instance().GetRenderEngine();
486 if (renderEngine) {
487 canvas.SetHighContrast(renderEngine->IsHighContrastEnabled());
488 }
489 }
490 }
491