3 * @brief EGL OpenGL extension module
5 /*****************************************************************************
6 * Copyright © 2010-2014 Rémi Denis-Courmont
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
30 #include <EGL/eglext.h>
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_opengl.h>
35 #include <vlc_vout_window.h>
36 #ifdef USE_PLATFORM_X11
37 # include <vlc_xlib.h>
39 #ifdef USE_PLATFORM_WAYLAND
40 # include <wayland-egl.h>
43 typedef struct vlc_gl_sys_t
48 #if defined (USE_PLATFORM_X11)
51 #if defined (USE_PLATFORM_WAYLAND)
52 struct wl_egl_window
*window
;
53 unsigned width
, height
;
57 static int MakeCurrent (vlc_gl_t
*gl
)
59 vlc_gl_sys_t
*sys
= gl
->sys
;
61 if (eglMakeCurrent (sys
->display
, sys
->surface
, sys
->surface
,
62 sys
->context
) != EGL_TRUE
)
67 static void ReleaseCurrent (vlc_gl_t
*gl
)
69 vlc_gl_sys_t
*sys
= gl
->sys
;
71 eglMakeCurrent (sys
->display
, EGL_NO_SURFACE
, EGL_NO_SURFACE
,
75 #ifdef USE_PLATFORM_WAYLAND
76 static void Resize (vlc_gl_t
*gl
, unsigned width
, unsigned height
)
78 vlc_gl_sys_t
*sys
= gl
->sys
;
80 wl_egl_window_resize(sys
->window
, width
, height
,
81 (sys
->width
- width
) / 2,
82 (sys
->height
- height
) / 2);
87 # define Resize (NULL)
90 static void SwapBuffers (vlc_gl_t
*gl
)
92 vlc_gl_sys_t
*sys
= gl
->sys
;
94 eglSwapBuffers (sys
->display
, sys
->surface
);
97 static void *GetSymbol(vlc_gl_t
*gl
, const char *procname
)
100 return (void *)eglGetProcAddress (procname
);
103 static bool CheckToken(const char *haystack
, const char *needle
)
105 size_t len
= strlen(needle
);
107 while (haystack
!= NULL
)
109 while (*haystack
== ' ')
111 if (!strncmp(haystack
, needle
, len
)
112 && (memchr(" ", haystack
[len
], 2) != NULL
))
115 haystack
= strchr(haystack
, ' ');
120 static bool CheckAPI (EGLDisplay dpy
, const char *api
)
122 const char *apis
= eglQueryString (dpy
, EGL_CLIENT_APIS
);
123 return CheckToken(apis
, api
);
126 static bool CheckClientExt(const char *name
)
128 const char *exts
= eglQueryString(EGL_NO_DISPLAY
, EGL_EXTENSIONS
);
129 return CheckToken(exts
, name
);
141 #ifdef EGL_EXT_platform_base
142 static EGLDisplay
GetDisplayEXT(EGLenum plat
, void *dpy
, const EGLint
*attrs
)
144 PFNEGLGETPLATFORMDISPLAYEXTPROC getDisplay
=
145 (PFNEGLGETPLATFORMDISPLAYEXTPROC
)
146 eglGetProcAddress("eglGetPlatformDisplayEXT");
148 assert(getDisplay
!= NULL
);
149 return getDisplay(plat
, dpy
, attrs
);
152 static EGLSurface
CreateWindowSurfaceEXT(EGLDisplay dpy
, EGLConfig config
,
153 void *window
, const EGLint
*attrs
)
155 PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createSurface
=
156 (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC
)
157 eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
159 assert(createSurface
!= NULL
);
160 return createSurface(dpy
, config
, window
, attrs
);
164 static EGLSurface
CreateWindowSurface(EGLDisplay dpy
, EGLConfig config
,
165 void *window
, const EGLint
*attrs
)
167 EGLNativeWindowType
*native
= window
;
169 return eglCreateWindowSurface(dpy
, config
, *native
, attrs
);
172 static void Close (vlc_object_t
*obj
)
174 vlc_gl_t
*gl
= (vlc_gl_t
*)obj
;
175 vlc_gl_sys_t
*sys
= gl
->sys
;
177 if (sys
->display
!= EGL_NO_DISPLAY
)
179 if (sys
->surface
!= EGL_NO_SURFACE
)
180 eglDestroySurface(sys
->display
, sys
->surface
);
181 eglTerminate(sys
->display
);
183 #ifdef USE_PLATFORM_X11
184 if (sys
->x11
!= NULL
)
185 XCloseDisplay(sys
->x11
);
187 #ifdef USE_PLATFORM_WAYLAND
188 if (sys
->window
!= NULL
)
189 wl_egl_window_destroy(sys
->window
);
195 * Probe EGL display availability
197 static int Open (vlc_object_t
*obj
, const struct gl_api
*api
)
199 vlc_gl_t
*gl
= (vlc_gl_t
*)obj
;
200 vlc_gl_sys_t
*sys
= malloc(sizeof (*sys
));
201 if (unlikely(sys
== NULL
))
205 sys
->display
= EGL_NO_DISPLAY
;
206 sys
->surface
= EGL_NO_SURFACE
;
208 vout_window_t
*wnd
= gl
->surface
;
209 EGLSurface (*createSurface
)(EGLDisplay
, EGLConfig
, void *, const EGLint
*)
210 = CreateWindowSurface
;
213 #ifdef USE_PLATFORM_X11
216 if (wnd
->type
!= VOUT_WINDOW_TYPE_XID
|| !vlc_xlib_init(obj
))
219 window
= &wnd
->handle
.xid
;
220 sys
->x11
= XOpenDisplay(wnd
->display
.x11
);
221 if (sys
->x11
== NULL
)
226 XWindowAttributes wa
;
228 if (!XGetWindowAttributes(sys
->x11
, wnd
->handle
.xid
, &wa
))
230 snum
= XScreenNumberOfScreen(wa
.screen
);
232 # ifdef EGL_EXT_platform_x11
233 if (CheckClientExt("EGL_EXT_platform_x11"))
235 const EGLint attrs
[] = {
236 EGL_PLATFORM_X11_SCREEN_EXT
, snum
,
239 sys
->display
= GetDisplayEXT(EGL_PLATFORM_X11_EXT
, sys
->x11
, attrs
);
240 createSurface
= CreateWindowSurfaceEXT
;
246 if (snum
== XDefaultScreen(sys
->x11
))
247 sys
->display
= eglGetDisplay(sys
->x11
);
251 #elif defined (USE_PLATFORM_WAYLAND)
254 if (wnd
->type
!= VOUT_WINDOW_TYPE_WAYLAND
)
257 # ifdef EGL_EXT_platform_wayland
258 if (!CheckClientExt("EGL_EXT_platform_wayland"))
261 /* Resize() should be called with the proper size before Swap() */
262 window
= wl_egl_window_create(wnd
->handle
.wl
, 1, 1);
265 sys
->window
= window
;
267 sys
->display
= GetDisplayEXT(EGL_PLATFORM_WAYLAND_EXT
, wnd
->display
.wl
,
269 createSurface
= CreateWindowSurfaceEXT
;
273 #elif defined (USE_PLATFORM_WIN32)
274 if (wnd
->type
!= VOUT_WINDOW_TYPE_HWND
)
277 window
= &wnd
->handle
.hwnd
;
278 # if defined (_WIN32) || defined (__VC32__) \
279 && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__)
280 sys
->display
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
283 #elif defined (USE_PLATFORM_ANDROID)
284 if (wnd
->type
!= VOUT_WINDOW_TYPE_ANDROID_NATIVE
)
287 window
= &wnd
->handle
.anativewindow
;
288 # if defined (__ANDROID__) || defined (ANDROID)
289 sys
->display
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
294 if (sys
->display
== EGL_NO_DISPLAY
)
297 /* Initialize EGL display */
299 if (eglInitialize(sys
->display
, &major
, &minor
) != EGL_TRUE
)
301 msg_Dbg(obj
, "EGL version %s by %s",
302 eglQueryString(sys
->display
, EGL_VERSION
),
303 eglQueryString(sys
->display
, EGL_VENDOR
));
305 const char *ext
= eglQueryString(sys
->display
, EGL_EXTENSIONS
);
307 msg_Dbg(obj
, " extensions: %s", ext
);
309 if (major
!= 1 || minor
< api
->min_minor
310 || !CheckAPI(sys
->display
, api
->name
))
312 msg_Err(obj
, "cannot select %s API", api
->name
);
316 const EGLint conf_attr
[] = {
320 EGL_RENDERABLE_TYPE
, api
->render_bit
,
326 if (eglChooseConfig(sys
->display
, conf_attr
, cfgv
, 1, &cfgc
) != EGL_TRUE
329 msg_Err (obj
, "cannot choose EGL configuration");
333 /* Create a drawing surface */
334 sys
->surface
= createSurface(sys
->display
, cfgv
[0], window
, NULL
);
335 if (sys
->surface
== EGL_NO_SURFACE
)
337 msg_Err (obj
, "cannot create EGL window surface");
341 if (eglBindAPI (api
->api
) != EGL_TRUE
)
343 msg_Err (obj
, "cannot bind EGL API");
347 EGLContext ctx
= eglCreateContext(sys
->display
, cfgv
[0], EGL_NO_CONTEXT
,
349 if (ctx
== EGL_NO_CONTEXT
)
351 msg_Err (obj
, "cannot create EGL context");
356 /* Initialize OpenGL callbacks */
357 gl
->makeCurrent
= MakeCurrent
;
358 gl
->releaseCurrent
= ReleaseCurrent
;
360 gl
->swap
= SwapBuffers
;
361 gl
->getProcAddress
= GetSymbol
;
369 static int OpenGLES2 (vlc_object_t
*obj
)
371 static const struct gl_api api
= {
372 "OpenGL_ES", EGL_OPENGL_ES_API
, 3, EGL_OPENGL_ES2_BIT
,
373 { EGL_CONTEXT_CLIENT_VERSION
, 2, EGL_NONE
},
375 return Open (obj
, &api
);
378 static int OpenGLES (vlc_object_t
*obj
)
380 static const struct gl_api api
= {
381 "OpenGL_ES", EGL_OPENGL_ES_API
, 0, EGL_OPENGL_ES_BIT
,
382 { EGL_CONTEXT_CLIENT_VERSION
, 1, EGL_NONE
},
384 return Open (obj
, &api
);
387 static int OpenGL (vlc_object_t
*obj
)
389 static const struct gl_api api
= {
390 "OpenGL", EGL_OPENGL_API
, 4, EGL_OPENGL_BIT
,
393 return Open (obj
, &api
);
397 set_shortname (N_("EGL"))
398 set_description (N_("EGL extension for OpenGL"))
399 set_category (CAT_VIDEO
)
400 set_subcategory (SUBCAT_VIDEO_VOUT
)
401 set_capability ("opengl", 50)
402 set_callbacks (OpenGL
, Close
)
406 set_capability ("opengl es2", 50)
407 set_callbacks (OpenGLES2
, Close
)
411 set_capability ("opengl es", 50)
412 set_callbacks (OpenGLES
, Close
)