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 #if defined(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 if (glesVersion != nullptr) {
298 auto size = glesVersion ? strlen(glesVersion) : 0;
299 mHandler_->ConfigureContext(&options, glesVersion, size, cacheDir_, isUniRenderMode_);
300 }
301
302 auto drGPUContext = std::make_shared<Drawing::GPUContext>();
303 if (!drGPUContext->BuildFromGL(options)) {
304 LOGE("SetUpGrContext drGPUContext is null");
305 return false;
306 }
307 drGPUContext_ = std::move(drGPUContext);
308 return true;
309 }
310 #endif
311 #ifdef RS_ENABLE_VK
312 if (RSSystemProperties::IsUseVulkan()) {
313 if (drawingContext == nullptr) {
314 drawingContext = RsVulkanContext::GetSingleton().CreateDrawingContext();
315 }
316 std::shared_ptr<Drawing::GPUContext> drGPUContext(drawingContext);
317 drGPUContext_ = std::move(drGPUContext);
318 return true;
319 }
320 #endif
321 return false;
322 }
323
324 #ifdef RS_ENABLE_VK
AbandonContext()325 void RenderContext::AbandonContext()
326 {
327 if (!RSSystemProperties::IsUseVulkan()) {
328 return;
329 }
330 if (drGPUContext_ == nullptr) {
331 LOGD("grContext is nullptr.");
332 return;
333 }
334 drGPUContext_->FlushAndSubmit(true);
335 drGPUContext_->PurgeUnlockAndSafeCacheGpuResources();
336 }
337 #endif
338
AcquireSurface(int width,int height)339 std::shared_ptr<Drawing::Surface> RenderContext::AcquireSurface(int width, int height)
340 {
341 if (!SetUpGpuContext(nullptr)) {
342 LOGE("GrContext is not ready!!!");
343 return nullptr;
344 }
345
346 std::shared_ptr<Drawing::ColorSpace> colorSpace = nullptr;
347
348 switch (colorSpace_) {
349 // [planning] in order to stay consistant with the colorspace used before, we disabled
350 // COLOR_GAMUT_SRGB to let the branch to default, then skColorSpace is set to nullptr
351 case GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
352 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
353 Drawing::CMSMatrixType::DCIP3);
354 break;
355 case GRAPHIC_COLOR_GAMUT_ADOBE_RGB:
356 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
357 Drawing::CMSMatrixType::ADOBE_RGB);
358 break;
359 case GRAPHIC_COLOR_GAMUT_BT2020:
360 colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
361 Drawing::CMSMatrixType::REC2020);
362 break;
363 default:
364 break;
365 }
366
367 RSTagTracker tagTracker(GetDrGPUContext(), RSTagTracker::TAGTYPE::TAG_ACQUIRE_SURFACE);
368
369 struct Drawing::FrameBuffer bufferInfo;
370 bufferInfo.width = width;
371 bufferInfo.height = height;
372 bufferInfo.FBOID = 0;
373 bufferInfo.Format = GL_RGBA8;
374 bufferInfo.gpuContext = drGPUContext_;
375 bufferInfo.colorSpace = colorSpace;
376 bufferInfo.colorType = Drawing::COLORTYPE_RGBA_8888;
377
378 if (pixelFormat_ == GRAPHIC_PIXEL_FMT_RGBA_1010102) {
379 bufferInfo.Format = GL_RGB10_A2;
380 bufferInfo.colorType = Drawing::COLORTYPE_RGBA_1010102;
381 }
382
383 surface_ = std::make_shared<Drawing::Surface>();
384 if (!surface_->Bind(bufferInfo)) {
385 LOGW("surface_ is nullptr");
386 surface_ = nullptr;
387 return nullptr;
388 }
389
390 LOGD("CreateCanvas successfully!!!");
391 return surface_;
392 }
393
RenderFrame()394 void RenderContext::RenderFrame()
395 {
396 RS_TRACE_FUNC();
397 // flush commands
398 if (surface_ != nullptr && surface_->GetCanvas() != nullptr) {
399 LOGD("RenderFrame: Canvas");
400 RSTagTracker tagTracker(GetDrGPUContext(), RSTagTracker::TAGTYPE::TAG_RENDER_FRAME);
401 surface_->GetCanvas()->Flush();
402 } else {
403 LOGW("canvas is nullptr!!!");
404 }
405 }
406
QueryEglBufferAge()407 EGLint RenderContext::QueryEglBufferAge()
408 {
409 if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
410 LOGE("eglDisplay or eglSurface is nullptr");
411 return EGL_UNKNOWN;
412 }
413 EGLint bufferAge = EGL_UNKNOWN;
414 EGLBoolean ret = eglQuerySurface(eglDisplay_, eglSurface_, EGL_BUFFER_AGE_KHR, &bufferAge);
415 if (ret == EGL_FALSE) {
416 LOGE("eglQuerySurface is failed");
417 return EGL_UNKNOWN;
418 }
419 return bufferAge;
420 }
421
DamageFrame(int32_t left,int32_t top,int32_t width,int32_t height)422 void RenderContext::DamageFrame(int32_t left, int32_t top, int32_t width, int32_t height)
423 {
424 if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
425 LOGE("eglDisplay or eglSurface is nullptr");
426 return;
427 }
428 RS_TRACE_FUNC();
429
430 EGLint rect[4];
431 rect[0] = left;
432 rect[1] = top;
433 rect[2] = width;
434 rect[3] = height;
435
436 EGLBoolean ret = GetEGLSetDamageRegionKHRFunc()(eglDisplay_, eglSurface_, rect, 1);
437 if (ret == EGL_FALSE) {
438 LOGE("eglSetDamageRegionKHR is failed");
439 }
440 }
441
DamageFrame(const std::vector<RectI> & rects)442 void RenderContext::DamageFrame(const std::vector<RectI> &rects)
443 {
444 if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
445 LOGE("eglDisplay or eglSurface is nullptr");
446 return;
447 }
448 RS_TRACE_FUNC();
449
450 size_t size = rects.size();
451 if (size == 0) {
452 LOGD("invalid rects size");
453 return;
454 }
455
456 EGLint eglRect[size * 4]; // 4 is size of RectI.
457 int index = 0;
458 for (const RectI& rect : rects) {
459 eglRect[index * 4] = rect.left_; // 4 is size of RectI.
460 eglRect[index * 4 + 1] = rect.top_; // 4 is size of RectI.
461 eglRect[index * 4 + 2] = rect.width_; // 4 is size of RectI, 2 is the index of the width_ subscript.
462 eglRect[index * 4 + 3] = rect.height_; // 4 is size of RectI, 3 is the index of the height_ subscript.
463 index++;
464 }
465
466 EGLBoolean ret = GetEGLSetDamageRegionKHRFunc()(eglDisplay_, eglSurface_, eglRect, size);
467 if (ret == EGL_FALSE) {
468 LOGE("eglSetDamageRegionKHR is failed");
469 }
470 }
471
ClearRedundantResources()472 void RenderContext::ClearRedundantResources()
473 {
474 RS_TRACE_FUNC();
475 if (drGPUContext_ != nullptr) {
476 LOGD("grContext clear redundant resources");
477 drGPUContext_->Flush();
478 // GPU resources that haven't been used in the past 10 seconds
479 drGPUContext_->PerformDeferredCleanup(std::chrono::seconds(10));
480 }
481 }
482
ConvertColorGamutToSkColorSpace(GraphicColorGamut colorGamut)483 sk_sp<SkColorSpace> RenderContext::ConvertColorGamutToSkColorSpace(GraphicColorGamut colorGamut)
484 {
485 sk_sp<SkColorSpace> skColorSpace = nullptr;
486 switch (colorGamut) {
487 // [planning] in order to stay consistant with the colorspace used before, we disabled
488 // GRAPHIC_COLOR_GAMUT_SRGB to let the branch to default, then skColorSpace is set to nullptr
489 case GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
490 #if defined(NEW_SKIA)
491 skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
492 #else
493 skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
494 #endif
495 break;
496 case GRAPHIC_COLOR_GAMUT_ADOBE_RGB:
497 skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB);
498 break;
499 case GRAPHIC_COLOR_GAMUT_BT2020:
500 skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kRec2020);
501 break;
502 default:
503 skColorSpace = SkColorSpace::MakeSRGB();
504 break;
505 }
506
507 return skColorSpace;
508 }
509
510 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
GetShaderCacheSize() const511 std::string RenderContext::GetShaderCacheSize() const
512 {
513 #ifdef RS_ENABLE_VK
514 if (RSSystemProperties::IsUseVulkan()) {
515 if (RsVulkanContext::GetSingleton().GetMemoryHandler()) {
516 return RsVulkanContext::GetSingleton().GetMemoryHandler()->QuerryShader();
517 }
518 }
519 #else
520 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
521 if (mHandler_) {
522 return mHandler_->QuerryShader();
523 }
524 }
525 #endif
526 LOGD("GetShaderCacheSize no shader cache");
527 return "";
528 }
529
CleanAllShaderCache() const530 std::string RenderContext::CleanAllShaderCache() const
531 {
532 #ifdef RS_ENABLE_VK
533 if (RSSystemProperties::IsUseVulkan()) {
534 if (RsVulkanContext::GetSingleton().GetMemoryHandler()) {
535 return RsVulkanContext::GetSingleton().GetMemoryHandler()->ClearShader();
536 }
537 }
538 #else
539 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
540 if (mHandler_) {
541 return mHandler_->ClearShader();
542 }
543 }
544 #endif
545 LOGD("CleanAllShaderCache no shader cache");
546 return "";
547 }
548 #endif
549
GetInstance()550 RenderContextFactory& RenderContextFactory::GetInstance()
551 {
552 static RenderContextFactory rf;
553 return rf;
554 }
555 } // namespace Rosen
556 } // namespace OHOS
557