3 * @brief EGL OpenGL extension module
5 /*****************************************************************************
6 * Copyright © 2010-2011 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>
40 /* Plugin callbacks */
41 static int OpenGLES2 (vlc_object_t *);
42 static int OpenGLES (vlc_object_t *);
43 static int OpenGL (vlc_object_t *);
44 static void Close (vlc_object_t *);
47 set_shortname (N_("EGL"))
48 set_description (N_("EGL extension for OpenGL"))
49 set_category (CAT_VIDEO)
50 set_subcategory (SUBCAT_VIDEO_VOUT)
51 set_capability ("opengl", 50)
52 set_callbacks (OpenGL, Close)
56 set_capability ("opengl es2", 50)
57 set_callbacks (OpenGLES2, Close)
61 set_capability ("opengl es", 50)
62 set_callbacks (OpenGLES, Close)
67 typedef struct vlc_gl_sys_t
72 #if defined (USE_PLATFORM_X11)
77 /* OpenGL callbacks */
78 static int MakeCurrent (vlc_gl_t *);
79 static void ReleaseCurrent (vlc_gl_t *);
80 static void SwapBuffers (vlc_gl_t *);
81 static void *GetSymbol(vlc_gl_t *, const char *);
83 static bool CheckToken(const char *haystack, const char *needle)
85 size_t len = strlen(needle);
87 while (haystack != NULL)
89 while (*haystack == ' ')
91 if (!strncmp(haystack, needle, len)
92 && (memchr(" ", haystack[len], 2) != NULL))
95 haystack = strchr(haystack, ' ');
100 static bool CheckAPI (EGLDisplay dpy, const char *api)
102 const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
103 return CheckToken(apis, api);
106 static bool CheckClientExt(const char *name)
108 const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
109 return CheckToken(exts, name);
121 /* See http://www.khronos.org/registry/egl/api/EGL/eglplatform.h *
122 * for list and order of default EGL platforms. */
123 #if defined (_WIN32) || defined (__VC32__) \
124 && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__) /* Win32 and WinCE */
125 # define USE_DEFAULT_PLATFORM USE_PLATFORM_WIN32
126 #elif defined (__WINSCW__) || defined (__SYMBIAN32__) /* Symbian */
127 # define USE_DEFAULT_PLATFORM USE_PLATFORM_SYMBIAN
128 #elif defined (__ANDROID__) || defined (ANDROID)
129 # define USE_DEFAULT_PLATFORM USE_PLATFORM_ANDROID
130 #elif defined (__unix__) /* X11 (tentative) */
131 # define USE_DEFAULT_PLATFORM USE_PLATFORM_X11
135 * Probe EGL display availability
137 static int Open (vlc_object_t *obj, const struct gl_api *api)
139 vlc_gl_t *gl = (vlc_gl_t *)obj;
140 vout_window_t *wnd = gl->surface;
143 EGLNativeWindowType native;
145 #ifdef EGL_EXT_platform_base
146 PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createSurface = NULL;
149 vlc_gl_sys_t *sys = malloc(sizeof (*sys));
150 if (unlikely(sys == NULL))
154 sys->display = EGL_NO_DISPLAY;
155 sys->surface = EGL_NO_SURFACE;
157 #ifdef USE_PLATFORM_X11
160 if (wnd->type != VOUT_WINDOW_TYPE_XID || !vlc_xlib_init(obj))
163 sys->x11 = XOpenDisplay(wnd->display.x11);
164 if (sys->x11 == NULL)
169 XWindowAttributes wa;
171 if (!XGetWindowAttributes(sys->x11, wnd->handle.xid, &wa))
173 snum = XScreenNumberOfScreen(wa.screen);
175 # ifdef EGL_EXT_platform_x11
176 if (CheckClientExt("EGL_EXT_platform_x11"))
178 PFNEGLGETPLATFORMDISPLAYEXTPROC getDisplay;
179 const EGLint attrs[] = {
180 EGL_PLATFORM_X11_SCREEN_EXT, snum,
184 getDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
185 eglGetProcAddress("eglGetPlatformDisplayEXT");
186 createSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
187 eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
188 sys->display = getDisplay(EGL_PLATFORM_X11_EXT, sys->x11, attrs);
189 window.ext_platform = &wnd->handle.xid;
194 # if USE_DEFAULT_PLATFORM
195 if (snum == XDefaultScreen(sys->x11))
197 sys->display = eglGetDisplay(sys->x11);
198 window.native = wnd->handle.xid;
203 #elif defined (USE_PLATFORM_WIN32)
204 if (wnd->type != VOUT_WINDOW_TYPE_HWND)
207 # if USE_DEFAULT_PLATFORM
208 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
209 window.native = wnd->handle.hwnd;
212 #elif defined (USE_PLATFORM_ANDROID)
213 if (wnd->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
216 # if USE_DEFAULT_PLATFORM
217 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
218 window.native = wnd->handle.anativewindow;
223 if (sys->display == EGL_NO_DISPLAY)
226 /* Initialize EGL display */
228 if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
230 msg_Dbg(obj, "EGL version %s by %s",
231 eglQueryString(sys->display, EGL_VERSION),
232 eglQueryString(sys->display, EGL_VENDOR));
234 const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
236 msg_Dbg(obj, " extensions: %s", ext);
238 if (major != 1 || minor < api->min_minor
239 || !CheckAPI(sys->display, api->name))
241 msg_Err(obj, "cannot select %s API", api->name);
245 const EGLint conf_attr[] = {
249 EGL_RENDERABLE_TYPE, api->render_bit,
255 if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
258 msg_Err (obj, "cannot choose EGL configuration");
262 /* Create a drawing surface */
263 #ifdef EGL_EXT_platform_base
264 if (createSurface != NULL)
265 sys->surface = createSurface(sys->display, cfgv[0],
266 window.ext_platform, NULL);
269 sys->surface = eglCreateWindowSurface(sys->display, cfgv[0],
270 window.native, NULL);
272 if (sys->surface == EGL_NO_SURFACE)
274 msg_Err (obj, "cannot create EGL window surface");
278 if (eglBindAPI (api->api) != EGL_TRUE)
280 msg_Err (obj, "cannot bind EGL API");
284 EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
286 if (ctx == EGL_NO_CONTEXT)
288 msg_Err (obj, "cannot create EGL context");
293 /* Initialize OpenGL callbacks */
294 gl->makeCurrent = MakeCurrent;
295 gl->releaseCurrent = ReleaseCurrent;
296 gl->swap = SwapBuffers;
297 gl->getProcAddress = GetSymbol;
307 static int OpenGLES2 (vlc_object_t *obj)
309 static const struct gl_api api = {
310 "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
311 { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
313 return Open (obj, &api);
316 static int OpenGLES (vlc_object_t *obj)
318 static const struct gl_api api = {
319 "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
320 { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
322 return Open (obj, &api);
325 static int OpenGL (vlc_object_t *obj)
327 static const struct gl_api api = {
328 "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
331 return Open (obj, &api);
334 static void Close (vlc_object_t *obj)
336 vlc_gl_t *gl = (vlc_gl_t *)obj;
337 vlc_gl_sys_t *sys = gl->sys;
339 if (sys->display != EGL_NO_DISPLAY)
341 if (sys->surface != EGL_NO_SURFACE)
342 eglDestroySurface(sys->display, sys->surface);
343 eglTerminate(sys->display);
345 #ifdef USE_PLATFORM_X11
346 if (sys->x11 != NULL)
347 XCloseDisplay(sys->x11);
352 static int MakeCurrent (vlc_gl_t *gl)
354 vlc_gl_sys_t *sys = gl->sys;
356 if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
357 sys->context) != EGL_TRUE)
362 static void ReleaseCurrent (vlc_gl_t *gl)
364 vlc_gl_sys_t *sys = gl->sys;
366 eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
370 static void SwapBuffers (vlc_gl_t *gl)
372 vlc_gl_sys_t *sys = gl->sys;
374 eglSwapBuffers (sys->display, sys->surface);
377 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
380 return (void *)eglGetProcAddress (procname);