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