• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }