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)