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 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_opengl.h>
34 #include <vlc_vout_window.h>
35 #ifdef USE_PLATFORM_X11
36 # include <vlc_xlib.h>
39 /* Plugin callbacks */
40 static int OpenGLES2 (vlc_object_t *);
41 static int OpenGLES (vlc_object_t *);
42 static int OpenGL (vlc_object_t *);
43 static void Close (vlc_object_t *);
46 set_shortname (N_("EGL"))
47 set_description (N_("EGL extension for OpenGL"))
48 set_category (CAT_VIDEO)
49 set_subcategory (SUBCAT_VIDEO_VOUT)
50 set_capability ("opengl", 50)
51 set_callbacks (OpenGL, Close)
55 set_capability ("opengl es2", 50)
56 set_callbacks (OpenGLES2, Close)
60 set_capability ("opengl es", 50)
61 set_callbacks (OpenGLES, Close)
66 typedef struct vlc_gl_sys_t
71 #if defined (USE_PLATFORM_X11)
76 /* OpenGL callbacks */
77 static int MakeCurrent (vlc_gl_t *);
78 static void ReleaseCurrent (vlc_gl_t *);
79 static void SwapBuffers (vlc_gl_t *);
80 static void *GetSymbol(vlc_gl_t *, const char *);
82 static bool CheckToken(const char *haystack, const char *needle)
84 size_t len = strlen(needle);
86 while (haystack != NULL)
88 while (*haystack == ' ')
90 if (!strncmp(haystack, needle, len)
91 && (memchr(" ", haystack[len], 2) != NULL))
94 haystack = strchr(haystack, ' ');
99 static bool CheckAPI (EGLDisplay dpy, const char *api)
101 const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
102 return CheckToken(apis, api);
105 static bool CheckClientExt(const char *name)
107 const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
108 return CheckToken(exts, name);
120 /* See http://www.khronos.org/registry/egl/api/EGL/eglplatform.h *
121 * for list and order of default EGL platforms. */
122 #if defined (_WIN32) || defined (__VC32__) \
123 && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__) /* Win32 and WinCE */
125 #elif defined (__WINSCW__) || defined (__SYMBIAN32__) /* Symbian */
126 # error Symbian EGL not supported.
127 #elif defined (__ANDROID__) || defined (ANDROID)
128 # error Android EGL not supported.
129 #elif defined (__unix__) /* X11 (tentative) */
132 # error EGL platform not recognized.
136 * Probe EGL display availability
138 static int Open (vlc_object_t *obj, const struct gl_api *api)
140 vlc_gl_t *gl = (vlc_gl_t *)obj;
141 vout_window_t *wnd = gl->surface;
142 EGLNativeWindowType window;
144 vlc_gl_sys_t *sys = malloc(sizeof (*sys));
145 if (unlikely(sys == NULL))
149 sys->display = EGL_NO_DISPLAY;
151 #ifdef USE_PLATFORM_X11
154 if (wnd->type != VOUT_WINDOW_TYPE_XID || !vlc_xlib_init(obj))
157 sys->x11 = XOpenDisplay(wnd->display.x11);
158 if (sys->x11 == NULL)
163 XWindowAttributes wa;
165 if (!XGetWindowAttributes(sys->x11, wnd->handle.xid, &wa))
167 snum = XScreenNumberOfScreen(wa.screen);
169 if (snum == XDefaultScreen(sys->x11))
171 sys->display = eglGetDisplay(sys->x11);
172 window = wnd->handle.xid;
175 #elif defined (USE_PLATFORM_WIN32)
176 if (wnd->type != VOUT_WINDOW_TYPE_HWND)
179 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
180 window = wnd->handle.hwnd;
184 if (sys->display == EGL_NO_DISPLAY)
187 /* Initialize EGL display */
189 if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
191 msg_Dbg(obj, "EGL version %s by %s",
192 eglQueryString(sys->display, EGL_VERSION),
193 eglQueryString(sys->display, EGL_VENDOR));
195 const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
197 msg_Dbg(obj, " extensions: %s", ext);
199 if (major != 1 || minor < api->min_minor
200 || !CheckAPI(sys->display, api->name))
202 msg_Err(obj, "cannot select %s API", api->name);
206 const EGLint conf_attr[] = {
210 EGL_RENDERABLE_TYPE, api->render_bit,
216 if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
219 msg_Err (obj, "cannot choose EGL configuration");
223 /* Create a drawing surface */
224 sys->surface = eglCreateWindowSurface(sys->display, cfgv[0], window, NULL);
225 if (sys->surface == EGL_NO_SURFACE)
227 msg_Err (obj, "cannot create EGL window surface");
231 if (eglBindAPI (api->api) != EGL_TRUE)
233 msg_Err (obj, "cannot bind EGL API");
237 EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
239 if (ctx == EGL_NO_CONTEXT)
241 msg_Err (obj, "cannot create EGL context");
246 /* Initialize OpenGL callbacks */
247 gl->makeCurrent = MakeCurrent;
248 gl->releaseCurrent = ReleaseCurrent;
249 gl->swap = SwapBuffers;
250 gl->getProcAddress = GetSymbol;
260 static int OpenGLES2 (vlc_object_t *obj)
262 static const struct gl_api api = {
263 "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
264 { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
266 return Open (obj, &api);
269 static int OpenGLES (vlc_object_t *obj)
271 static const struct gl_api api = {
272 "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
273 { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
275 return Open (obj, &api);
278 static int OpenGL (vlc_object_t *obj)
280 static const struct gl_api api = {
281 "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
284 return Open (obj, &api);
287 static void Close (vlc_object_t *obj)
289 vlc_gl_t *gl = (vlc_gl_t *)obj;
290 vlc_gl_sys_t *sys = gl->sys;
292 if (sys->display != EGL_NO_DISPLAY)
293 eglTerminate(sys->display);
294 #ifdef USE_PLATFORM_X11
295 if (sys->x11 != NULL)
296 XCloseDisplay(sys->x11);
301 static int MakeCurrent (vlc_gl_t *gl)
303 vlc_gl_sys_t *sys = gl->sys;
305 if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
306 sys->context) != EGL_TRUE)
311 static void ReleaseCurrent (vlc_gl_t *gl)
313 vlc_gl_sys_t *sys = gl->sys;
315 eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
319 static void SwapBuffers (vlc_gl_t *gl)
321 vlc_gl_sys_t *sys = gl->sys;
323 eglSwapBuffers (sys->display, sys->surface);
326 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
329 return (void *)eglGetProcAddress (procname);