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 #include "rs_sub_thread.h"
18
19 #include <string>
20 #include "GLES3/gl3.h"
21 #include "include/core/SkCanvas.h"
22 #include "memory/rs_tag_tracker.h"
23 #include "rs_trace.h"
24 #include "pipeline/parallel_render/rs_sub_thread_manager.h"
25 #include "pipeline/rs_main_thread.h"
26 #include "memory/rs_memory_graphic.h"
27 #include "memory/rs_memory_manager.h"
28 #include "pipeline/rs_uni_render_util.h"
29 #include "pipeline/rs_uni_render_visitor.h"
30 #include "pipeline/rs_surface_render_node.h"
31 #ifdef RES_SCHED_ENABLE
32 #include "res_type.h"
33 #include "res_sched_client.h"
34 #endif
35
36 #ifdef RS_ENABLE_VK
37 #include "platform/ohos/backend/rs_vulkan_context.h"
38 #endif
39
40 namespace OHOS::Rosen {
41 namespace {
42 #ifdef RES_SCHED_ENABLE
43 const uint32_t RS_SUB_QOS_LEVEL = 7;
44 constexpr const char* RS_BUNDLE_NAME = "render_service";
45 #endif
46 }
~RSSubThread()47 RSSubThread::~RSSubThread()
48 {
49 RS_LOGI("~RSSubThread():%{public}d", threadIndex_);
50 PostTask([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 std::string strBundleName = RS_BUNDLE_NAME;
68 std::string strPid = std::to_string(getpid());
69 std::string strTid = std::to_string(gettid());
70 std::string strQos = std::to_string(RS_SUB_QOS_LEVEL);
71 std::unordered_map<std::string, std::string> mapPayload;
72 mapPayload["pid"] = strPid;
73 mapPayload[strTid] = strQos;
74 mapPayload["bundleName"] = strBundleName;
75 uint32_t type = OHOS::ResourceSchedule::ResType::RES_TYPE_THREAD_QOS_CHANGE;
76 int64_t value = 0;
77 OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(type, value, mapPayload);
78 #endif
79 grContext_ = CreateShareGrContext();
80 });
81 return tid;
82 }
83
PostTask(const std::function<void ()> & task,const std::string & name)84 void RSSubThread::PostTask(const std::function<void()>& task, const std::string& name)
85 {
86 if (handler_) {
87 handler_->PostImmediateTask(task, name);
88 }
89 }
90
PostSyncTask(const std::function<void ()> & task)91 void RSSubThread::PostSyncTask(const std::function<void()>& task)
92 {
93 if (handler_) {
94 handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
95 }
96 }
97
RemoveTask(const std::string & name)98 void RSSubThread::RemoveTask(const std::string& name)
99 {
100 if (handler_) {
101 handler_->RemoveTask(name);
102 }
103 }
104
DumpMem(DfxString & log)105 void RSSubThread::DumpMem(DfxString& log)
106 {
107 PostSyncTask([&log, this]() {
108 MemoryManager::DumpDrawingGpuMemory(log, grContext_.get());
109 });
110 }
111
GetAppGpuMemoryInMB()112 float RSSubThread::GetAppGpuMemoryInMB()
113 {
114 float total = 0.f;
115 PostSyncTask([&total, this]() {
116 total = MemoryManager::GetAppGpuMemoryInMB(grContext_.get());
117 });
118 return total;
119 }
120
CreateShareEglContext()121 void RSSubThread::CreateShareEglContext()
122 {
123 if (renderContext_ == nullptr) {
124 RS_LOGE("renderContext_ is nullptr");
125 return;
126 }
127 #ifdef RS_ENABLE_GL
128 if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
129 return;
130 }
131 eglShareContext_ = renderContext_->CreateShareContext();
132 if (eglShareContext_ == EGL_NO_CONTEXT) {
133 RS_LOGE("eglShareContext_ is EGL_NO_CONTEXT");
134 return;
135 }
136 if (!eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, eglShareContext_)) {
137 RS_LOGE("eglMakeCurrent failed");
138 return;
139 }
140 #endif
141 }
142
DestroyShareEglContext()143 void RSSubThread::DestroyShareEglContext()
144 {
145 #ifdef RS_ENABLE_GL
146 if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
147 return;
148 }
149 if (renderContext_ != nullptr) {
150 eglDestroyContext(renderContext_->GetEGLDisplay(), eglShareContext_);
151 eglShareContext_ = EGL_NO_CONTEXT;
152 eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
153 }
154 #endif
155 }
156
RenderCache(const std::shared_ptr<RSSuperRenderTask> & threadTask)157 void RSSubThread::RenderCache(const std::shared_ptr<RSSuperRenderTask>& threadTask)
158 {
159 if (threadTask == nullptr || threadTask->GetTaskSize() == 0) {
160 return;
161 }
162 if (grContext_ == nullptr) {
163 grContext_ = CreateShareGrContext();
164 if (grContext_ == nullptr) {
165 RS_LOGI("grContext is null");
166 return;
167 }
168 }
169 auto visitor = std::make_shared<RSUniRenderVisitor>();
170 visitor->SetSubThreadConfig(threadIndex_);
171 visitor->SetFocusedNodeId(RSMainThread::Instance()->GetFocusNodeId(),
172 RSMainThread::Instance()->GetFocusLeashWindowId());
173 auto screenManager = CreateOrGetScreenManager();
174 visitor->SetScreenInfo(screenManager->QueryScreenInfo(screenManager->GetDefaultScreenId()));
175 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
176 bool needRequestVsync = false;
177 while (threadTask->GetTaskSize() > 0) {
178 auto task = threadTask->GetNextRenderTask();
179 if (!task || (task->GetIdx() == 0)) {
180 RS_LOGE("renderTask is nullptr");
181 continue;
182 }
183 auto node = task->GetNode();
184 if (!node) {
185 RS_LOGE("surfaceNode is nullptr");
186 continue;
187 }
188 auto surfaceNodePtr = node->ReinterpretCastTo<RSSurfaceRenderNode>();
189 if (!surfaceNodePtr) {
190 RS_LOGE("RenderCache ReinterpretCastTo fail");
191 continue;
192 }
193 // flag CacheSurfaceProcessed is used for cacheCmdskippedNodes collection in rs_mainThread
194 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DOING);
195 if (RSMainThread::Instance()->GetFrameCount() != threadTask->GetFrameCount()) {
196 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::WAITING);
197 continue;
198 }
199
200 RS_TRACE_NAME_FMT("draw cache render node: [%s, %llu]", surfaceNodePtr->GetName().c_str(),
201 surfaceNodePtr->GetId());
202 if (surfaceNodePtr->GetCacheSurface(threadIndex_, true) == nullptr || surfaceNodePtr->NeedInitCacheSurface()) {
203 RSRenderNode::ClearCacheSurfaceFunc func = std::bind(&RSUniRenderUtil::ClearNodeCacheSurface,
204 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
205 surfaceNodePtr->InitCacheSurface(grContext_.get(), func, threadIndex_);
206 }
207
208 RSTagTracker nodeProcessTracker(grContext_.get(), surfaceNodePtr->GetId(),
209 RSTagTracker::TAGTYPE::TAG_SUB_THREAD);
210 bool needNotify = !surfaceNodePtr->HasCachedTexture();
211 node->Process(visitor);
212 nodeProcessTracker.SetTagEnd();
213 #ifndef USE_ROSEN_DRAWING
214 auto cacheSurface = surfaceNodePtr->GetCacheSurface(threadIndex_, true);
215 if (cacheSurface) {
216 RS_TRACE_NAME_FMT("Render cache skSurface flush and submit");
217 RSTagTracker nodeFlushTracker(grContext_.get(), surfaceNodePtr->GetId(),
218 RSTagTracker::TAGTYPE::TAG_SUB_THREAD);
219 cacheSurface->flushAndSubmit(true);
220 nodeFlushTracker.SetTagEnd();
221 }
222 #else
223 auto cacheSurface = surfaceNodePtr->GetCacheSurface(threadIndex_, true);
224 if (cacheSurface) {
225 RS_TRACE_NAME_FMT("Render cache skSurface flush and submit");
226 RSTagTracker nodeFlushTracker(grContext_.get(), surfaceNodePtr->GetId(),
227 RSTagTracker::TAGTYPE::TAG_SUB_THREAD);
228 cacheSurface->FlushAndSubmit(true);
229 nodeFlushTracker.SetTagEnd();
230 }
231 #endif
232 surfaceNodePtr->UpdateBackendTexture();
233 RSMainThread::Instance()->PostTask([]() {
234 RSMainThread::Instance()->SetIsCachedSurfaceUpdated(true);
235 });
236 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DONE);
237 surfaceNodePtr->SetCacheSurfaceNeedUpdated(true);
238 needRequestVsync = true;
239
240 if (needNotify) {
241 RSSubThreadManager::Instance()->NodeTaskNotify(node->GetId());
242 }
243 }
244 if (needRequestVsync) {
245 RSMainThread::Instance()->RequestNextVSync();
246 }
247 #endif
248 }
249
250 #ifndef USE_ROSEN_DRAWING
CreateShareGrContext()251 sk_sp<GrDirectContext> RSSubThread::CreateShareGrContext()
252 {
253 RS_TRACE_NAME("CreateShareGrContext");
254 #ifdef RS_ENABLE_GL
255 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
256 CreateShareEglContext();
257 const GrGLInterface *grGlInterface = GrGLCreateNativeInterface();
258 sk_sp<const GrGLInterface> glInterface(grGlInterface);
259 if (glInterface.get() == nullptr) {
260 RS_LOGE("CreateShareGrContext failed");
261 return nullptr;
262 }
263
264 GrContextOptions options = {};
265 options.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
266 // fix svg antialiasing bug
267 options.fGpuPathRenderers &= ~GpuPathRenderers::kAtlas;
268 options.fPreferExternalImagesOverES3 = true;
269 options.fDisableDistanceFieldPaths = true;
270
271 auto handler = std::make_shared<MemoryHandler>();
272 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
273 auto size = glesVersion ? strlen(glesVersion) : 0;
274 handler->ConfigureContext(&options, glesVersion, size);
275
276 sk_sp<GrDirectContext> grContext = GrDirectContext::MakeGL(std::move(glInterface), options);
277 if (grContext == nullptr) {
278 RS_LOGE("nullptr grContext is null");
279 return nullptr;
280 }
281 return grContext;
282 }
283 #endif
284
285 #ifdef RS_ENABLE_VK
286 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
287 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
288 sk_sp<GrDirectContext> grContext = GrDirectContext::MakeVulkan(
289 RsVulkanContext::GetSingleton().GetGrVkBackendContext());
290 if (grContext == nullptr) {
291 RS_LOGE("nullptr grContext is null");
292 return nullptr;
293 }
294 return grContext;
295 }
296 #endif
297 return nullptr;
298 }
299 #else
CreateShareGrContext()300 std::shared_ptr<Drawing::GPUContext> RSSubThread::CreateShareGrContext()
301 {
302 RS_TRACE_NAME("CreateShareGrContext");
303 #ifdef RS_ENABLE_GL
304 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
305 CreateShareEglContext();
306 auto gpuContext = std::make_shared<Drawing::GPUContext>();
307 Drawing::GPUContextOptions options;
308 auto handler = std::make_shared<MemoryHandler>();
309 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
310 auto size = glesVersion ? strlen(glesVersion) : 0;
311 handler->ConfigureContext(&options, glesVersion, size);
312
313 if (!gpuContext->BuildFromGL(options)) {
314 RS_LOGE("nullptr gpuContext is null");
315 return nullptr;
316 }
317 return gpuContext;
318 }
319 #endif
320
321 #ifdef RS_ENABLE_VK
322 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
323 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
324 auto gpuContext = std::make_shared<Drawing::GPUContext>();
325 Drawing::GPUContextOptions options;
326 auto handler = std::make_shared<MemoryHandler>();
327 std::string vulkanVersion = RsVulkanContext::GetSingleton().GetVulkanVersion();
328 auto size = vulkanVersion.size();
329 handler->ConfigureContext(&options, vulkanVersion.c_str(), size);
330 if (!gpuContext->BuildFromVK(RsVulkanContext::GetSingleton().GetGrVkBackendContext(), options)) {
331 RS_LOGE("nullptr gpuContext is null");
332 return nullptr;
333 }
334 return gpuContext;
335 }
336 #endif
337 return nullptr;
338 }
339 #endif
340
ResetGrContext()341 void RSSubThread::ResetGrContext()
342 {
343 RS_TRACE_NAME("ResetGrContext release resource");
344 if (grContext_ == nullptr) {
345 return;
346 }
347 #ifndef USE_ROSEN_DRAWING
348 grContext_->flushAndSubmit(true);
349 grContext_->freeGpuResources();
350 #else
351 grContext_->FlushAndSubmit(true);
352 grContext_->FreeGpuResources();
353 #endif
354 }
355
ReleaseSurface()356 void RSSubThread::ReleaseSurface()
357 {
358 std::lock_guard<std::mutex> lock(mutex_);
359 while (tmpSurfaces_.size() > 0) {
360 auto tmp = tmpSurfaces_.front();
361 tmpSurfaces_.pop();
362 tmp = nullptr;
363 }
364 }
365
366 #ifndef USE_ROSEN_DRAWING
AddToReleaseQueue(sk_sp<SkSurface> && surface)367 void RSSubThread::AddToReleaseQueue(sk_sp<SkSurface>&& surface)
368 #else
369 void RSSubThread::AddToReleaseQueue(std::shared_ptr<Drawing::Surface>&& surface)
370 #endif
371 {
372 std::lock_guard<std::mutex> lock(mutex_);
373 tmpSurfaces_.push(std::move(surface));
374 }
375
CountSubMem(int pid)376 MemoryGraphic RSSubThread::CountSubMem(int pid)
377 {
378 MemoryGraphic memoryGraphic;
379 PostSyncTask([&pid, &memoryGraphic, this]() {
380 memoryGraphic = MemoryManager::CountPidMemory(pid, grContext_.get());
381 });
382 return memoryGraphic;
383 }
384 }
385