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