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