1 /*
2 * Copyright (c) 2021 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 #include "render_context.h"
17
18 #include <sstream>
19 #include <string>
20
21 #include "rs_trace.h"
22 #include "window.h"
23
24 #ifdef RS_ENABLE_VK
25 #include "platform/ohos/backend/rs_vulkan_context.h"
26 #endif
27
28 #ifdef RS_ENABLE_GL
29 #include "EGL/egl.h"
30 #endif
31
32 #include "memory/rs_tag_tracker.h"
33
34 #include "render_context_log.h"
35
36 namespace OHOS {
37 namespace Rosen {
38 using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
39 constexpr const char* EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
40 constexpr const char* EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
41 constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
42 constexpr char CHARACTER_WHITESPACE = ' ';
43 constexpr const char* CHARACTER_STRING_WHITESPACE = " ";
44 constexpr const char* EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
45 constexpr const char* EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";
46
47 // use functor to call gel*KHR API
GetEGLSetDamageRegionKHRFunc()48 static PFNEGLSETDAMAGEREGIONKHRPROC GetEGLSetDamageRegionKHRFunc()
49 {
50 static auto func = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
51 return func;
52 }
53
CheckEglExtension(const char * extensions,const char * extension)54 static bool CheckEglExtension(const char* extensions, const char* extension)
55 {
56 size_t extlen = strlen(extension);
57 const char* end = extensions + strlen(extensions);
58
59 while (extensions < end) {
60 size_t n = 0;
61 /* Skip whitespaces, if any */
62 if (*extensions == CHARACTER_WHITESPACE) {
63 extensions++;
64 continue;
65 }
66
67 n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
68
69 /* Compare strings */
70 if (n == extlen && strncmp(extension, extensions, n) == 0) {
71 return true; /* Found */
72 }
73 extensions += n;
74 }
75 /* Not found */
76 return false;
77 }
78
GetPlatformEglDisplay(EGLenum platform,void * native_display,const EGLint * attrib_list)79 static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void* native_display, const EGLint* attrib_list)
80 {
81 static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;
82
83 if (!eglGetPlatformDisplayExt) {
84 const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
85 if (extensions &&
86 (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
87 CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
88 eglGetPlatformDisplayExt = reinterpret_cast<GetPlatformDisplayExt>(
89 eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT));
90 }
91 }
92
93 if (eglGetPlatformDisplayExt) {
94 return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
95 }
96
97 return eglGetDisplay(static_cast<EGLNativeDisplayType>(native_display));
98 }
99
RenderContext()100 RenderContext::RenderContext()
101 : drGPUContext_(nullptr),
102 surface_(nullptr),
103 nativeWindow_(nullptr),
104 eglDisplay_(EGL_NO_DISPLAY),
105 eglContext_(EGL_NO_CONTEXT),
106 eglSurface_(EGL_NO_SURFACE),
107 config_(nullptr),
108 mHandler_(nullptr)
109 {}
110
~RenderContext()111 RenderContext::~RenderContext()
112 {
113 if (eglDisplay_ == EGL_NO_DISPLAY) {
114 return;
115 }
116
117 eglDestroyContext(eglDisplay_, eglContext_);
118 if (pbufferSurface_ != EGL_NO_SURFACE) {
119 eglDestroySurface(eglDisplay_, pbufferSurface_);
120 }
121 eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
122 eglTerminate(eglDisplay_);
123 eglReleaseThread();
124
125 eglDisplay_ = EGL_NO_DISPLAY;
126 eglContext_ = EGL_NO_CONTEXT;
127 eglSurface_ = EGL_NO_SURFACE;
128 pbufferSurface_ = EGL_NO_SURFACE;
129 drGPUContext_ = nullptr;
130 surface_ = nullptr;
131 mHandler_ = nullptr;
132 }
133
CreatePbufferSurface()134 void RenderContext::CreatePbufferSurface()
135 {
136 const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
137
138 if ((extensions != nullptr) &&
139 (!CheckEglExtension(extensions, EGL_KHR_SURFACELESS_CONTEXT)) &&
140 (pbufferSurface_ == EGL_NO_SURFACE)) {
141 EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
142 pbufferSurface_ = eglCreatePbufferSurface(eglDisplay_, config_, attribs);
143 if (pbufferSurface_ == EGL_NO_SURFACE) {
144 LOGE("Failed to create pbuffer surface");
145 return;
146 }
147 }
148 }
149
InitializeEglContext()150 void RenderContext::InitializeEglContext()
151 {
152 if (IsEglContextReady()) {
153 return;
154 }
155
156 LOGD("Creating EGLContext!!!");
157 eglDisplay_ = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
158 if (eglDisplay_ == EGL_NO_DISPLAY) {
159 LOGW("Failed to create EGLDisplay gl errno : %{public}x", eglGetError());
160 return;
161 }
162
163 EGLint major, minor;
164 if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
165 LOGE("Failed to initialize EGLDisplay");
166 return;
167 }
168
169 if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
170 LOGE("Failed to bind OpenGL ES API");
171 return;
172 }
173
174 unsigned int ret;
175 EGLint count;
176 EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
177 EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE };
178
179 ret = eglChooseConfig(eglDisplay_, config_attribs, &config_, 1, &count);
180 if (!(ret && static_cast<unsigned int>(count) >= 1)) {
181 LOGE("Failed to eglChooseConfig");
182 return;
183 }
184
185 static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE };
186
187 eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, context_attribs);
188 if (eglContext_ == EGL_NO_CONTEXT) {
189 LOGE("Failed to create egl context %{public}x", eglGetError());
190 return;
191 }
192 CreatePbufferSurface();
193 if (!eglMakeCurrent(eglDisplay_, pbufferSurface_, pbufferSurface_, eglContext_)) {
194 LOGE("Failed to make current on surface, error is %{public}x", eglGetError());
195 return;
196 }
197
198 LOGD("Create EGL context successfully, version %{public}d.%{public}d", major, minor);
199 }
200
MakeCurrent(EGLSurface surface,EGLContext context)201 void RenderContext::MakeCurrent(EGLSurface surface, EGLContext context)
202 {
203 if (surface == EGL_NO_SURFACE) {
204 surface = pbufferSurface_;
205 }
206 if (context == EGL_NO_CONTEXT) {
207 context = eglContext_;
208 }
209 if (!eglMakeCurrent(eglDisplay_, surface, surface, context)) {
210 LOGE("Failed to make current on surface, error is %{public}x", eglGetError());
211 }
212 eglSurface_ = surface;
213 }
214
SetAndMakeCurrentShareContex(EGLContext shareContext)215 void RenderContext::SetAndMakeCurrentShareContex(EGLContext shareContext)
216 {
217 eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, shareContext);
218 eglContext_ = shareContext;
219 }
220
ShareMakeCurrent(EGLContext shareContext)221 void RenderContext::ShareMakeCurrent(EGLContext shareContext)
222 {
223 eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, shareContext);
224 }
225
ShareMakeCurrentNoSurface(EGLContext shareContext)226 void RenderContext::ShareMakeCurrentNoSurface(EGLContext shareContext)
227 {
228 eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, shareContext);
229 }
230
MakeSelfCurrent()231 void RenderContext::MakeSelfCurrent()
232 {
233 eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_);
234 }
235
CreateShareContext()236 EGLContext RenderContext::CreateShareContext()
237 {
238 std::unique_lock<std::mutex> lock(shareContextMutex_);
239 static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE};
240 auto eglShareContext = eglCreateContext(eglDisplay_, config_, eglContext_, context_attribs);
241 return eglShareContext;
242 }
243
SwapBuffers(EGLSurface surface) const244 void RenderContext::SwapBuffers(EGLSurface surface) const
245 {
246 RS_TRACE_FUNC();
247 if (!eglSwapBuffers(eglDisplay_, surface)) {
248 LOGE("Failed to SwapBuffers on surface, error is %{public}x", eglGetError());
249 } else {
250 LOGD("SwapBuffers successfully");
251 }
252 }
253
DestroyEGLSurface(EGLSurface surface)254 void RenderContext::DestroyEGLSurface(EGLSurface surface)
255 {
256 if (!eglDestroySurface(eglDisplay_, surface)) {
257 LOGE("Failed to DestroyEGLSurface surface, error is %{public}x", eglGetError());
258 }
259 }
260
CreateEGLSurface(EGLNativeWindowType eglNativeWindow)261 EGLSurface RenderContext::CreateEGLSurface(EGLNativeWindowType eglNativeWindow)
262 {
263 if (!IsEglContextReady()) {
264 LOGE("EGL context has not initialized");
265 return EGL_NO_SURFACE;
266 }
267 nativeWindow_ = eglNativeWindow;
268
269 eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
270
271 EGLSurface surface = eglCreateWindowSurface(eglDisplay_, config_, nativeWindow_, NULL);
272 if (surface == EGL_NO_SURFACE) {
273 LOGW("Failed to create eglsurface!!! %{public}x", eglGetError());
274 return EGL_NO_SURFACE;
275 }
276
277 LOGD("CreateEGLSurface");
278
279 eglSurface_ = surface;
280 return surface;
281 }
282
SetUpGpuContext(std::shared_ptr<Drawing::GPUContext> drawingContext)283 bool RenderContext::SetUpGpuContext(std::shared_ptr<Drawing::GPUContext> drawingContext)
284 {
285 if (drGPUContext_ != nullptr) {
286 LOGD("Drawing GPUContext has already created!!");
287 return true;
288 }
289 #ifdef RS_ENABLE_GL
290 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
291 mHandler_ = std::make_shared<MemoryHandler>();
292 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
293 if (isUniRenderMode_) {
294 cacheDir_ = UNIRENDER_CACHE_DIR;
295 }
296 Drawing::GPUContextOptions options;
297 options.SetIsUniRender(isUniRenderMode_);
298 if (glesVersion != nullptr) {
299 auto size = glesVersion ? strlen(glesVersion) : 0;
300 mHandler_->ConfigureContext(&options, glesVersion, size, cacheDir_, isUniRenderMode_);
301 }
302
303 auto drGPUContext = std::make_shared<Drawing::GPUContext>();
304 if (!drGPUContext->BuildFromGL(options)) {
305 LOGE("SetUpGrContext drGPUContext is null");
306 return false;
307 }
308 drGPUContext_ = std::move(drGPUContext);
309 return true;
310 }
311 #endif
312 #ifdef RS_ENABLE_VK
313 if (RSSystemProperties::IsUseVulkan()) {
314 if (drawingContext == nullptr) {
315 drawingContext = RsVulkanContext::GetSingleton(cacheDir_).CreateDrawingContext();
316 }
317 std::shared_ptr<Drawing::GPUContext> drGPUContext(drawingContext);
318 drGPUContext_ = std::move(drGPUContext);
319 return true;
320 }
321 #endif
322 return false;
323 }
324
325 #ifdef RS_ENABLE_VK
AbandonContext()326 void RenderContext::AbandonContext()
327 {
328 if (!RSSystemProperties::IsUseVulkan()) {
329 return;
330 }
331 if (drGPUContext_ == nullptr) {
332 LOGD("grContext is nullptr.");
333 return;
334 }
335 drGPUContext_->FlushAndSubmit(true);
336 drGPUContext_->PurgeUnlockAndSafeCacheGpuResources();
337 }
338 #endif
339
AcquireSurface(int width,int height)340 std::shared_ptr<Drawing::Surface> RenderContext::AcquireSurface(int width, int height)
341 {
342 if (!SetUpGpuContext(nullptr)) {
343 LOGE("GrContext is not ready!!!");
344 return nullptr;
345 }
346
347 std::shared_ptr<Drawing::ColorSpace> colorSpace = nullptr;
348
349 switch (colorSpace_) {
350 // [planning] in order to stay consistant with the colorspace used before, we disabled
351 // COLOR_GAMUT_SRGB to let the branch to default, then skColorSpace is set to nullptr
352 case GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
353 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
354 Drawing::CMSMatrixType::DCIP3);
355 break;
356 case GRAPHIC_COLOR_GAMUT_ADOBE_RGB:
357 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
358 Drawing::CMSMatrixType::ADOBE_RGB);
359 break;
360 case GRAPHIC_COLOR_GAMUT_BT2020:
361 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
362 Drawing::CMSMatrixType::REC2020);
363 break;
364 default:
365 break;
366 }
367
368 RSTagTracker tagTracker(GetSharedDrGPUContext(), RSTagTracker::TAGTYPE::TAG_ACQUIRE_SURFACE);
369
370 struct Drawing::FrameBuffer bufferInfo;
371 bufferInfo.width = width;
372 bufferInfo.height = height;
373 bufferInfo.FBOID = 0;
374 bufferInfo.Format = GL_RGBA8;
375 bufferInfo.gpuContext = drGPUContext_;
376 bufferInfo.colorSpace = colorSpace;
377 bufferInfo.colorType = Drawing::COLORTYPE_RGBA_8888;
378
379 if (pixelFormat_ == GRAPHIC_PIXEL_FMT_RGBA_1010102) {
380 bufferInfo.Format = GL_RGB10_A2;
381 bufferInfo.colorType = Drawing::COLORTYPE_RGBA_1010102;
382 }
383
384 surface_ = std::make_shared<Drawing::Surface>();
385 if (!surface_->Bind(bufferInfo)) {
386 LOGW("surface_ is nullptr");
387 surface_ = nullptr;
388 return nullptr;
389 }
390
391 LOGD("CreateCanvas successfully!!!");
392 return surface_;
393 }
394
RenderFrame()395 void RenderContext::RenderFrame()
396 {
397 RS_TRACE_FUNC();
398 // flush commands
399 if (surface_ != nullptr && surface_->GetCanvas() != nullptr) {
400 LOGD("RenderFrame: Canvas");
401 RSTagTracker tagTracker(GetSharedDrGPUContext(), RSTagTracker::TAGTYPE::TAG_RENDER_FRAME);
402 surface_->GetCanvas()->Flush();
403 } else {
404 LOGW("canvas is nullptr!!!");
405 }
406 }
407
QueryEglBufferAge()408 EGLint RenderContext::QueryEglBufferAge()
409 {
410 if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
411 LOGE("eglDisplay or eglSurface is nullptr");
412 return EGL_UNKNOWN;
413 }
414 EGLint bufferAge = EGL_UNKNOWN;
415 EGLBoolean ret = eglQuerySurface(eglDisplay_, eglSurface_, EGL_BUFFER_AGE_KHR, &bufferAge);
416 if (ret == EGL_FALSE) {
417 LOGE("eglQuerySurface is failed");
418 return EGL_UNKNOWN;
419 }
420 return bufferAge;
421 }
422
DamageFrame(int32_t left,int32_t top,int32_t width,int32_t height)423 void RenderContext::DamageFrame(int32_t left, int32_t top, int32_t width, int32_t height)
424 {
425 if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
426 LOGE("eglDisplay or eglSurface is nullptr");
427 return;
428 }
429 RS_TRACE_FUNC();
430
431 EGLint rect[4];
432 rect[0] = left;
433 rect[1] = top;
434 rect[2] = width;
435 rect[3] = height;
436
437 EGLBoolean ret = GetEGLSetDamageRegionKHRFunc()(eglDisplay_, eglSurface_, rect, 1);
438 if (ret == EGL_FALSE) {
439 LOGE("eglSetDamageRegionKHR is failed");
440 }
441 }
442
DamageFrame(const std::vector<RectI> & rects)443 void RenderContext::DamageFrame(const std::vector<RectI> &rects)
444 {
445 if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
446 LOGE("eglDisplay or eglSurface is nullptr");
447 return;
448 }
449 RS_TRACE_FUNC();
450
451 size_t size = rects.size();
452 if (size == 0) {
453 LOGD("invalid rects size");
454 return;
455 }
456
457 EGLint eglRect[size * 4]; // 4 is size of RectI.
458 int index = 0;
459 for (const RectI& rect : rects) {
460 eglRect[index * 4] = rect.left_; // 4 is size of RectI.
461 eglRect[index * 4 + 1] = rect.top_; // 4 is size of RectI.
462 eglRect[index * 4 + 2] = rect.width_; // 4 is size of RectI, 2 is the index of the width_ subscript.
463 eglRect[index * 4 + 3] = rect.height_; // 4 is size of RectI, 3 is the index of the height_ subscript.
464 index++;
465 }
466
467 EGLBoolean ret = GetEGLSetDamageRegionKHRFunc()(eglDisplay_, eglSurface_, eglRect, size);
468 if (ret == EGL_FALSE) {
469 LOGE("eglSetDamageRegionKHR is failed");
470 }
471 }
472
ClearRedundantResources()473 void RenderContext::ClearRedundantResources()
474 {
475 RS_TRACE_FUNC();
476 if (drGPUContext_ != nullptr) {
477 LOGD("grContext clear redundant resources");
478 drGPUContext_->Flush();
479 // GPU resources that haven't been used in the past 10 seconds
480 drGPUContext_->PerformDeferredCleanup(std::chrono::seconds(10));
481 }
482 }
483
ConvertColorGamutToColorSpace(GraphicColorGamut colorGamut)484 std::shared_ptr<Drawing::ColorSpace> RenderContext::ConvertColorGamutToColorSpace(GraphicColorGamut colorGamut)
485 {
486 std::shared_ptr<Drawing::ColorSpace> colorSpace = nullptr;
487 switch (colorGamut) {
488 // [planning] in order to stay consistant with the colorspace used before, we disabled
489 // GRAPHIC_COLOR_GAMUT_SRGB to let the branch to default, then skColorSpace is set to nullptr
490 case GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
491 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
492 Drawing::CMSMatrixType::DCIP3);
493 break;
494 case GRAPHIC_COLOR_GAMUT_ADOBE_RGB:
495 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
496 Drawing::CMSMatrixType::ADOBE_RGB);
497 break;
498 case GRAPHIC_COLOR_GAMUT_BT2020:
499 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
500 Drawing::CMSMatrixType::REC2020);
501 break;
502 default:
503 colorSpace = Drawing::ColorSpace::CreateSRGB();
504 break;
505 }
506
507 return colorSpace;
508 }
509
510 #if defined(RS_ENABLE_VK)
CheckShaderCacheOverSoftLimit() const511 bool RenderContext::CheckShaderCacheOverSoftLimit() const
512 {
513 auto& shaderCache = ShaderCache::Instance();
514 if (!shaderCache.IfInitialized()) {
515 LOGE("CheckShaderCacheOverSoftLimit shaderCache not Initialized");
516 return false;
517 }
518 return shaderCache.CheckShaderCacheOverSoftLimit();
519 }
520 #endif
521
522 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
GetShaderCacheSize() const523 std::string RenderContext::GetShaderCacheSize() const
524 {
525 #ifdef RS_ENABLE_VK
526 if (RSSystemProperties::IsUseVulkan()) {
527 if (RsVulkanContext::GetSingleton().GetMemoryHandler()) {
528 return RsVulkanContext::GetSingleton().GetMemoryHandler()->QuerryShader();
529 }
530 }
531 #else
532 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
533 if (mHandler_) {
534 return mHandler_->QuerryShader();
535 }
536 }
537 #endif
538 LOGD("GetShaderCacheSize no shader cache");
539 return "";
540 }
541
CleanAllShaderCache() const542 std::string RenderContext::CleanAllShaderCache() const
543 {
544 #ifdef RS_ENABLE_VK
545 if (RSSystemProperties::IsUseVulkan()) {
546 if (RsVulkanContext::GetSingleton().GetMemoryHandler()) {
547 return RsVulkanContext::GetSingleton().GetMemoryHandler()->ClearShader();
548 }
549 }
550 #else
551 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
552 if (mHandler_) {
553 return mHandler_->ClearShader();
554 }
555 }
556 #endif
557 LOGD("CleanAllShaderCache no shader cache");
558 return "";
559 }
560 #endif
561
GetInstance()562 RenderContextFactory& RenderContextFactory::GetInstance()
563 {
564 static RenderContextFactory rf;
565 return rf;
566 }
567 } // namespace Rosen
568 } // namespace OHOS
569