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