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 "egl_manager.h"
17
18 #include <fcntl.h>
19 #include <scoped_bytrace.h>
20 #include <mutex>
21 #include <unistd.h>
22
23 #include "buffer_log.h"
24
25 namespace OHOS {
26 namespace {
27 constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
28 constexpr char CHARACTER_WHITESPACE = ' ';
29 constexpr const char *CHARACTER_STRING_WHITESPACE = " ";
30 constexpr const char *EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
31 constexpr const char *EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
32 constexpr const char *EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
33 constexpr const char *EGL_EXT_IMAGE_DMA_BUF_IMPORT = "EGL_EXT_image_dma_buf_import";
34 constexpr const char *EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";
35 constexpr const char *EGL_KHR_NO_CONFIG_CONTEXT = "EGL_KHR_no_config_context";
36 constexpr const char *EGL_CREATE_IMAGE_KHR = "eglCreateImageKHR";
37 constexpr const char *EGL_DESTROY_IMAGE_KHR = "eglDestroyImageKHR";
38 constexpr const char *EGL_IMAGE_TARGET_TEXTURE2DOES = "glEGLImageTargetTexture2DOES";
39 constexpr const char *EGL_KHR_FENCE_SYNC = "EGL_KHR_fence_sync";
40 constexpr const char *EGL_CREATE_SYNC_KHR = "eglCreateSyncKHR";
41 constexpr const char *EGL_DESTROY_SYNC_KHR = "eglDestroySyncKHR";
42 constexpr const char *EGL_CLIENT_WAIT_SYNC_KHR = "eglClientWaitSyncKHR";
43 constexpr const char *EGL_DUP_NATIVE_FENCE_FD_ANDROID = "eglDupNativeFenceFDANDROID";
44 constexpr const char *EGL_KHR_WAIT_SYNC = "EGL_KHR_wait_sync";
45 constexpr const char *EGL_WAIT_SYNC_KHR = "eglWaitSyncKHR";
46 constexpr const char *GL_OES_EGL_IMAGE = "GL_OES_EGL_image";
47 } // namespace
48
EglManager()49 EglManager::EglManager()
50 {
51 BLOGD("EglManager");
52 }
53
~EglManager()54 EglManager::~EglManager()
55 {
56 BLOGD("~EglManager");
57 Deinit();
58 }
59
GetInstance()60 sptr<EglManager> EglManager::GetInstance()
61 {
62 if (instance_ == nullptr) {
63 static std::mutex mutex;
64 std::lock_guard<std::mutex> lock(mutex);
65 if (instance_ == nullptr) {
66 instance_ = new EglManager();
67 }
68 }
69 return instance_;
70 }
71
IsInit() const72 bool EglManager::IsInit() const
73 {
74 return initFlag_;
75 }
76
Init(EGLContext context)77 GSError EglManager::Init(EGLContext context)
78 {
79 ScopedBytrace eGLManagerInit("EGLManagerInit");
80 if (initFlag_) {
81 BLOGW("already init, eglMakeCurrent");
82 eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_);
83 return GSERROR_OK;
84 }
85
86 if (GbmInit() != GSERROR_OK) {
87 BLOGE("GbmInit failed.");
88 return GSERROR_INTERNEL;
89 }
90
91 if (EglInit(context) != GSERROR_OK) {
92 BLOGE("EglInit failed.");
93 return GSERROR_INTERNEL;
94 }
95
96 initFlag_ = true;
97 return GSERROR_OK;
98 }
99
GbmInit()100 GSError EglManager::GbmInit()
101 {
102 device_ = EGL_DEFAULT_DISPLAY;
103 return GSERROR_OK;
104 }
105
106 namespace {
CheckEglExtension(const char * extensions,const char * extension)107 static bool CheckEglExtension(const char *extensions, const char *extension)
108 {
109 size_t extlen = strlen(extension);
110 const char *end = extensions + strlen(extensions);
111
112 while (extensions < end) {
113 size_t n = 0;
114
115 /* Skip whitespaces, if any */
116 if (*extensions == CHARACTER_WHITESPACE) {
117 extensions++;
118 continue;
119 }
120
121 n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
122 /* Compare strings */
123 if (n == extlen && strncmp(extension, extensions, n) == 0) {
124 return true; /* Found */
125 }
126 extensions += n;
127 }
128 /* Not found */
129 return false;
130 }
131
GetPlatformEglDisplay(EGLenum platform,EGLDisplay native_display,const EGLint * attrib_list)132 static EGLDisplay GetPlatformEglDisplay(EGLenum platform, EGLDisplay native_display, const EGLint *attrib_list)
133 {
134 static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;
135
136 if (!eglGetPlatformDisplayExt) {
137 const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
138 if (extensions &&
139 (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
140 CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
141 eglGetPlatformDisplayExt =
142 (GetPlatformDisplayExt)eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT);
143 }
144 }
145
146 if (eglGetPlatformDisplayExt) {
147 return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
148 }
149 return eglGetDisplay((EGLNativeDisplayType) native_display);
150 }
151 }
152
EglCheckExt()153 GSError EglManager::EglCheckExt()
154 {
155 const char *eglExtensions = eglQueryString(display_, EGL_EXTENSIONS);
156 if (eglExtensions == nullptr) {
157 BLOGE("param is nullptr.");
158 return GSERROR_INTERNEL;
159 }
160
161 if (!CheckEglExtension(eglExtensions, EGL_EXT_IMAGE_DMA_BUF_IMPORT)) {
162 BLOGE("EGL_EXT_image_dma_buf_import not supported");
163 return GSERROR_INTERNEL;
164 }
165
166 if (!CheckEglExtension(eglExtensions, EGL_KHR_SURFACELESS_CONTEXT)) {
167 BLOGE("EGL_KHR_surfaceless_context not supported");
168 return GSERROR_INTERNEL;
169 }
170
171 if (CheckEglExtension(eglExtensions, EGL_KHR_NO_CONFIG_CONTEXT)) {
172 conf_ = EGL_NO_CONFIG_KHR;
173 } else {
174 BLOGW("EGL_KHR_no_config_context not supported");
175 EGLint count;
176 EGLint config_attribs[] = {
177 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
178 EGL_RED_SIZE, 1,
179 EGL_GREEN_SIZE, 1,
180 EGL_BLUE_SIZE, 1,
181 EGL_ALPHA_SIZE, 1,
182 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
183 EGL_NONE
184 };
185 EGLBoolean ret = eglChooseConfig(display_, config_attribs, &conf_, 1, &count);
186 if (!(ret && count >= 1)) {
187 BLOGE("Failed to eglChooseConfig");
188 return GSERROR_INTERNEL;
189 }
190 }
191 return GSERROR_OK;
192 }
193
EglFuncInit()194 GSError EglManager::EglFuncInit()
195 {
196 const char *eglExtensions = eglQueryString(display_, EGL_EXTENSIONS);
197 if (eglExtensions == nullptr) {
198 BLOGE("param is nullptr.");
199 return GSERROR_INTERNEL;
200 }
201
202 createImage_ = (EglCreateImageFunc)eglGetProcAddress(EGL_CREATE_IMAGE_KHR);
203 if (createImage_ == nullptr) {
204 BLOGE("param is nullptr.");
205 return GSERROR_INTERNEL;
206 }
207
208 destroyImage_ = (EglDestroyImageFunc)eglGetProcAddress(EGL_DESTROY_IMAGE_KHR);
209 if (destroyImage_ == nullptr) {
210 BLOGE("param is nullptr.");
211 return GSERROR_INTERNEL;
212 }
213
214 imageTargetTexture2d_ = (EglImageTargetTexture2DFunc)eglGetProcAddress(EGL_IMAGE_TARGET_TEXTURE2DOES);
215 if (imageTargetTexture2d_ == nullptr) {
216 BLOGE("param is nullptr.");
217 return GSERROR_INTERNEL;
218 }
219
220 if (CheckEglExtension(eglExtensions, EGL_KHR_FENCE_SYNC)) {
221 createSync_ = (EglCreateSyncFunc)eglGetProcAddress(EGL_CREATE_SYNC_KHR);
222 if (createSync_ == nullptr) {
223 BLOGE("param is nullptr.");
224 return GSERROR_INTERNEL;
225 }
226
227 destroySync_ = (EglDestroySyncFunc)eglGetProcAddress(EGL_DESTROY_SYNC_KHR);
228 if (destroySync_ == nullptr) {
229 BLOGE("param is nullptr.");
230 return GSERROR_INTERNEL;
231 }
232
233 clientWaitSync_ = (EglClientWaitSyncFunc)eglGetProcAddress(EGL_CLIENT_WAIT_SYNC_KHR);
234 if (clientWaitSync_ == nullptr) {
235 BLOGE("param is nullptr.");
236 return GSERROR_INTERNEL;
237 }
238
239 dupNativeFenceFd_ = (EglDupNativeFenceFdFunc)eglGetProcAddress(EGL_DUP_NATIVE_FENCE_FD_ANDROID);
240 if (dupNativeFenceFd_ == nullptr) {
241 BLOGE("param is nullptr.");
242 return GSERROR_INTERNEL;
243 }
244 }
245
246 if (CheckEglExtension(eglExtensions, EGL_KHR_WAIT_SYNC)) {
247 waitSync_ = (EglWaitSyncFunc)eglGetProcAddress(EGL_WAIT_SYNC_KHR);
248 if (waitSync_ == nullptr) {
249 BLOGE("param is nullptr.");
250 return GSERROR_INTERNEL;
251 }
252 }
253 return GSERROR_OK;
254 }
255
EglInit(EGLContext ctx)256 GSError EglManager::EglInit(EGLContext ctx)
257 {
258 ScopedBytrace func(__func__);
259 display_ = GetPlatformEglDisplay(EGL_PLATFORM_GBM_KHR, device_, NULL);
260 if (display_ == EGL_NO_DISPLAY) {
261 BLOGE("Failed to create EGLDisplay");
262 return GSERROR_INTERNEL;
263 }
264
265 EGLint major, minor;
266 if (eglInitialize(display_, &major, &minor) == EGL_FALSE) {
267 BLOGE("Failed to initialize EGLDisplay");
268 return GSERROR_INTERNEL;
269 }
270
271 if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
272 BLOGE("Failed to bind OpenGL ES API");
273 return GSERROR_INTERNEL;
274 }
275
276 if (EglCheckExt() != GSERROR_OK) {
277 BLOGE("EglCheckExt failed");
278 return GSERROR_INTERNEL;
279 }
280
281 static const EGLint context_attribs[] = {
282 EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM,
283 EGL_NONE
284 };
285
286 if (ctx == EGL_NO_CONTEXT) {
287 context_ = eglCreateContext(display_, conf_, EGL_NO_CONTEXT, context_attribs);
288 if (context_ == EGL_NO_CONTEXT) {
289 BLOGE("Failed to create EGLContext");
290 return GSERROR_INTERNEL;
291 }
292 ctxReleaseFlg_ = true;
293 } else {
294 context_ = ctx;
295 }
296
297 eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_);
298
299 const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
300 if (glExtensions == nullptr) {
301 BLOGE("param is nullptr.");
302 return GSERROR_INTERNEL;
303 }
304
305 if (!CheckEglExtension(glExtensions, GL_OES_EGL_IMAGE)) {
306 BLOGE("GL_OES_EGL_image not supported");
307 return GSERROR_INTERNEL;
308 }
309
310 if (EglFuncInit() != GSERROR_OK) {
311 BLOGE("EglFuncInit failed");
312 return GSERROR_INTERNEL;
313 }
314
315 return GSERROR_OK;
316 }
317
Deinit()318 void EglManager::Deinit()
319 {
320 initFlag_ = false;
321
322 if (drmFd_ >= 0) {
323 close(drmFd_);
324 }
325
326 if (context_ != EGL_NO_CONTEXT && ctxReleaseFlg_) {
327 eglDestroyContext(display_, context_);
328 }
329
330 if (display_ != EGL_NO_DISPLAY) {
331 eglTerminate(display_);
332 }
333 }
334
GetEGLDisplay() const335 EGLDisplay EglManager::GetEGLDisplay() const
336 {
337 if (!initFlag_) {
338 BLOGE("EglManager is not init.");
339 return EGL_NO_DISPLAY;
340 }
341 return display_;
342 }
343
GetEGLContext() const344 EGLContext EglManager::GetEGLContext() const
345 {
346 if (!initFlag_) {
347 BLOGE("EglManager is not init.");
348 return EGL_NO_CONTEXT;
349 }
350 return context_;
351 }
352
EglCreateImage(EGLContext ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attribList)353 EGLImageKHR EglManager::EglCreateImage(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attribList)
354 {
355 if (!initFlag_) {
356 BLOGE("EglManager is not init.");
357 return EGL_NO_IMAGE;
358 }
359 return createImage_(display_, ctx, target, buffer, attribList);
360 }
361
EglCreateImage(EGLenum target,EGLClientBuffer buffer,const EGLint * attribList)362 EGLImageKHR EglManager::EglCreateImage(EGLenum target, EGLClientBuffer buffer, const EGLint *attribList)
363 {
364 if (!initFlag_) {
365 BLOGE("EglManager is not init.");
366 return EGL_NO_IMAGE;
367 }
368 return createImage_(display_, context_, target, buffer, attribList);
369 }
370
EglDestroyImage(EGLImageKHR image)371 EGLBoolean EglManager::EglDestroyImage(EGLImageKHR image)
372 {
373 if (!initFlag_) {
374 BLOGE("EglManager is not init.");
375 return EGL_FALSE;
376 }
377 return destroyImage_(display_, image);
378 }
379
EglImageTargetTexture2D(GLenum target,GLeglImageOES image)380 void EglManager::EglImageTargetTexture2D(GLenum target, GLeglImageOES image)
381 {
382 if (!initFlag_) {
383 BLOGE("EglManager is not init.");
384 return;
385 }
386 return imageTargetTexture2d_(target, image);
387 }
388
EglCreateSync(EGLenum type,const EGLint * attribList)389 EGLSyncKHR EglManager::EglCreateSync(EGLenum type, const EGLint *attribList)
390 {
391 if (createSync_ == nullptr) {
392 BLOGE("param is nullptr.");
393 return EGL_NO_SYNC_KHR;
394 }
395 return createSync_(display_, type, attribList);
396 }
397
EglWaitSync(EGLSyncKHR sync,EGLint flags)398 EGLint EglManager::EglWaitSync(EGLSyncKHR sync, EGLint flags)
399 {
400 if (waitSync_ == nullptr) {
401 BLOGE("param is nullptr.");
402 return EGL_FALSE;
403 }
404 return waitSync_(display_, sync, flags);
405 }
406
EglClientWaitSync(EGLSyncKHR sync,EGLint flags,EGLTimeKHR timeout)407 EGLint EglManager::EglClientWaitSync(EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
408 {
409 if (clientWaitSync_ == nullptr) {
410 BLOGE("param is nullptr.");
411 return EGL_FALSE;
412 }
413 return clientWaitSync_(display_, sync, flags, timeout);
414 }
415
EglDestroySync(EGLSyncKHR sync)416 EGLBoolean EglManager::EglDestroySync(EGLSyncKHR sync)
417 {
418 if (destroySync_ == nullptr) {
419 BLOGE("param is nullptr.");
420 return EGL_FALSE;
421 }
422 return destroySync_(display_, sync);
423 }
424
EglDupNativeFenceFd(EGLSyncKHR sync)425 EGLint EglManager::EglDupNativeFenceFd(EGLSyncKHR sync)
426 {
427 if (dupNativeFenceFd_ == nullptr) {
428 BLOGE("param is nullptr.");
429 return EGL_DONT_CARE;
430 }
431 return dupNativeFenceFd_(display_, sync);
432 }
433
EglMakeCurrent()434 EGLBoolean EglManager::EglMakeCurrent()
435 {
436 if (!initFlag_) {
437 BLOGE("EglManager is not init.");
438 return EGL_FALSE;
439 }
440 return eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_);
441 }
442
EglMakeCurrent(EGLSurface draw,EGLSurface read)443 EGLBoolean EglManager::EglMakeCurrent(EGLSurface draw, EGLSurface read)
444 {
445 if (!initFlag_) {
446 BLOGE("EglManager is not init.");
447 return EGL_FALSE;
448 }
449 return eglMakeCurrent(display_, draw, read, context_);
450 }
451
EglMakeCurrent(EGLSurface draw,EGLSurface read,EGLContext ctx)452 EGLBoolean EglManager::EglMakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx)
453 {
454 if (!initFlag_) {
455 BLOGE("EglManager is not init.");
456 return EGL_FALSE;
457 }
458 return eglMakeCurrent(display_, draw, read, ctx);
459 }
460 } // namespace OHOS
461