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_manager.h"
27 #include "pipeline/rs_uni_render_util.h"
28 #include "pipeline/rs_uni_render_visitor.h"
29 #include "pipeline/rs_surface_render_node.h"
30 #ifdef RES_SCHED_ENABLE
31 #include "res_type.h"
32 #include "res_sched_client.h"
33 #endif
34
35 namespace OHOS::Rosen {
36 namespace {
37 #ifdef RES_SCHED_ENABLE
38 const uint32_t RS_SUB_QOS_LEVEL = 7;
39 constexpr const char* RS_BUNDLE_NAME = "render_service";
40 #endif
41 }
~RSSubThread()42 RSSubThread::~RSSubThread()
43 {
44 RS_LOGI("~RSSubThread():%d", threadIndex_);
45 PostTask([this]() {
46 DestroyShareEglContext();
47 });
48 }
49
Start()50 void RSSubThread::Start()
51 {
52 RS_LOGI("RSSubThread::Start():%d", threadIndex_);
53 std::string name = "RSSubThread" + std::to_string(threadIndex_);
54 runner_ = AppExecFwk::EventRunner::Create(name);
55 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
56 PostTask([this]() {
57 #ifdef RES_SCHED_ENABLE
58 std::string strBundleName = RS_BUNDLE_NAME;
59 std::string strPid = std::to_string(getpid());
60 std::string strTid = std::to_string(gettid());
61 std::string strQos = std::to_string(RS_SUB_QOS_LEVEL);
62 std::unordered_map<std::string, std::string> mapPayload;
63 mapPayload["pid"] = strPid;
64 mapPayload[strTid] = strQos;
65 mapPayload["bundleName"] = strBundleName;
66 uint32_t type = OHOS::ResourceSchedule::ResType::RES_TYPE_THREAD_QOS_CHANGE;
67 int64_t value = 0;
68 OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(type, value, mapPayload);
69 #endif
70 grContext_ = CreateShareGrContext();
71 });
72 }
73
PostTask(const std::function<void ()> & task)74 void RSSubThread::PostTask(const std::function<void()>& task)
75 {
76 if (handler_) {
77 handler_->PostTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
78 }
79 }
80
PostSyncTask(const std::function<void ()> & task)81 void RSSubThread::PostSyncTask(const std::function<void()>& task)
82 {
83 if (handler_) {
84 handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
85 }
86 }
87
DumpMem(DfxString & log)88 void RSSubThread::DumpMem(DfxString& log)
89 {
90 PostSyncTask([&log, this]() {
91 MemoryManager::DumpDrawingGpuMemory(log, grContext_.get());
92 });
93 }
94
CreateShareEglContext()95 void RSSubThread::CreateShareEglContext()
96 {
97 #ifdef RS_ENABLE_GL
98 if (renderContext_ == nullptr) {
99 RS_LOGE("renderContext_ is nullptr");
100 return;
101 }
102 eglShareContext_ = renderContext_->CreateShareContext();
103 if (eglShareContext_ == EGL_NO_CONTEXT) {
104 RS_LOGE("eglShareContext_ is EGL_NO_CONTEXT");
105 return;
106 }
107 if (!eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, eglShareContext_)) {
108 RS_LOGE("eglMakeCurrent failed");
109 return;
110 }
111 #endif
112 }
113
DestroyShareEglContext()114 void RSSubThread::DestroyShareEglContext()
115 {
116 #ifdef RS_ENABLE_GL
117 if (renderContext_ != nullptr) {
118 eglDestroyContext(renderContext_->GetEGLDisplay(), eglShareContext_);
119 eglShareContext_ = EGL_NO_CONTEXT;
120 eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
121 }
122 #endif
123 }
124
RenderCache(const std::shared_ptr<RSSuperRenderTask> & threadTask)125 void RSSubThread::RenderCache(const std::shared_ptr<RSSuperRenderTask>& threadTask)
126 {
127 if (threadTask == nullptr) {
128 return;
129 }
130 if (grContext_ == nullptr) {
131 grContext_ = CreateShareGrContext();
132 if (grContext_ == nullptr) {
133 RS_LOGI("grContext is null");
134 return;
135 }
136 }
137 auto visitor = std::make_shared<RSUniRenderVisitor>();
138 visitor->SetSubThreadConfig(threadIndex_);
139 #ifdef RS_ENABLE_GL
140 while (threadTask->GetTaskSize() > 0) {
141 auto task = threadTask->GetNextRenderTask();
142 if (!task || (task->GetIdx() == 0)) {
143 RS_LOGE("renderTask is nullptr");
144 continue;
145 }
146 auto node = task->GetNode();
147 if (!node) {
148 RS_LOGE("surfaceNode is nullptr");
149 continue;
150 }
151 auto surfaceNodePtr = node->ReinterpretCastTo<RSSurfaceRenderNode>();
152 if (!surfaceNodePtr) {
153 RS_LOGE("RenderCache ReinterpretCastTo fail");
154 continue;
155 }
156 // flag CacheSurfaceProcessed is used for cacheCmdskippedNodes collection in rs_mainThread
157 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DOING);
158
159 if (RSMainThread::Instance()->GetFrameCount() != threadTask->GetFrameCount()) {
160 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::WAITING);
161 continue;
162 }
163
164 RS_TRACE_NAME_FMT("draw cache render node: [%s, %llu]", surfaceNodePtr->GetName().c_str(),
165 surfaceNodePtr->GetId());
166 if (surfaceNodePtr->NeedInitCacheSurface() || surfaceNodePtr->GetCacheSurface(threadIndex_, true) == nullptr) {
167 RSRenderNode::ClearCacheSurfaceFunc func = std::bind(&RSUniRenderUtil::ClearNodeCacheSurface,
168 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
169 surfaceNodePtr->InitCacheSurface(grContext_.get(), func, threadIndex_);
170 }
171 #ifndef USE_ROSEN_DRAWING
172 RSTagTracker nodeProcessTracker(grContext_.get(), surfaceNodePtr->GetId(),
173 RSTagTracker::TAGTYPE::TAG_SUB_THREAD);
174 #endif
175 bool needNotify = !surfaceNodePtr->HasCachedTexture();
176 node->Process(visitor);
177 #ifndef USE_ROSEN_DRAWING
178 nodeProcessTracker.SetTagEnd();
179 #ifndef NEW_SKIA
180 auto skCanvas = surfaceNodePtr->GetCacheSurface(threadIndex_, true) ?
181 surfaceNodePtr->GetCacheSurface(threadIndex_, true)->getCanvas() : nullptr;
182 if (skCanvas) {
183 RS_TRACE_NAME_FMT("render cache flush, %s", surfaceNodePtr->GetName().c_str());
184 skCanvas->flush();
185 } else {
186 RS_LOGE("skCanvas is nullptr, flush failed");
187 }
188 #else
189 if (surfaceNodePtr && surfaceNodePtr->GetCacheSurface(threadIndex_, true)) {
190 RS_TRACE_NAME_FMT("Render cache skSurface flush and submit");
191 RSTagTracker nodeFlushTracker(grContext_.get(), surfaceNodePtr->GetId(),
192 RSTagTracker::TAGTYPE::TAG_SUB_THREAD);
193 surfaceNodePtr->GetCacheSurface(threadIndex_, true)->flushAndSubmit(true);
194 nodeFlushTracker.SetTagEnd();
195 }
196 #endif
197 #else
198 auto canvas = surfaceNodePtr->GetCacheSurface(threadIndex_, true) ?
199 surfaceNodePtr->GetCacheSurface(threadIndex_, true)->GetCanvas() : nullptr;
200 if (canvas) {
201 RS_TRACE_NAME_FMT("render cache flush, %s", surfaceNodePtr->GetName().c_str());
202 canvas->Flush();
203 } else {
204 RS_LOGE("skCanvas is nullptr, flush failed");
205 }
206 #endif
207 surfaceNodePtr->UpdateBackendTexture();
208 surfaceNodePtr->SetCacheSurfaceProcessedStatus(CacheProcessStatus::DONE);
209 surfaceNodePtr->SetCacheSurfaceNeedUpdated(true);
210
211 if (needNotify) {
212 RSSubThreadManager::Instance()->NodeTaskNotify(node->GetId());
213 }
214 }
215 eglCreateSyncKHR(renderContext_->GetEGLDisplay(), EGL_SYNC_FENCE_KHR, nullptr);
216 #endif
217 }
218
219 #ifndef USE_ROSEN_DRAWING
220 #ifdef NEW_SKIA
CreateShareGrContext()221 sk_sp<GrDirectContext> RSSubThread::CreateShareGrContext()
222 #else
223 sk_sp<GrContext> RSSubThread::CreateShareGrContext()
224 #endif
225 {
226 RS_TRACE_NAME("CreateShareGrContext");
227 CreateShareEglContext();
228 const GrGLInterface *grGlInterface = GrGLCreateNativeInterface();
229 sk_sp<const GrGLInterface> glInterface(grGlInterface);
230 if (glInterface.get() == nullptr) {
231 RS_LOGE("CreateShareGrContext failed");
232 return nullptr;
233 }
234
235 GrContextOptions options = {};
236 options.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
237 options.fPreferExternalImagesOverES3 = true;
238 options.fDisableDistanceFieldPaths = true;
239
240 auto handler = std::make_shared<MemoryHandler>();
241 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
242 auto size = glesVersion ? strlen(glesVersion) : 0;
243 /* /data/service/el0/render_service is shader cache dir*/
244 handler->ConfigureContext(&options, glesVersion, size, "/data/service/el0/render_service", true);
245
246 #ifdef NEW_SKIA
247 sk_sp<GrDirectContext> grContext = GrDirectContext::MakeGL(std::move(glInterface), options);
248 #else
249 sk_sp<GrContext> grContext = GrContext::MakeGL(std::move(glInterface), options);
250 #endif
251 if (grContext == nullptr) {
252 RS_LOGE("nullptr grContext is null");
253 return nullptr;
254 }
255 return grContext;
256 }
257 #else
CreateShareGrContext()258 std::shared_ptr<Drawing::GPUContext> RSSubThread::CreateShareGrContext()
259 {
260 RS_TRACE_NAME("CreateShareGrContext");
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 /* /data/service/el0/render_service is shader cache dir*/
268 handler->ConfigureContext(&options, glesVersion, size, "/data/service/el0/render_service", true);
269
270 if (!gpuContext->BuildFromGL(options)) {
271 RS_LOGE("nullptr gpuContext is null");
272 return nullptr;
273 }
274 return gpuContext;
275 }
276 #endif
277
ResetGrContext()278 void RSSubThread::ResetGrContext()
279 {
280 RS_TRACE_NAME("ResetGrContext release resource");
281 if (grContext_ == nullptr) {
282 return;
283 }
284 #ifndef USE_ROSEN_DRAWING
285 grContext_->purgeUnlockedResources(false);
286 #endif
287 }
288 }