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 typedef struct vlc_gl_sys_t
45 #if defined (USE_PLATFORM_X11)
50 static int MakeCurrent (vlc_gl_t *gl)
52 vlc_gl_sys_t *sys = gl->sys;
54 if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
55 sys->context) != EGL_TRUE)
60 static void ReleaseCurrent (vlc_gl_t *gl)
62 vlc_gl_sys_t *sys = gl->sys;
64 eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
68 static void SwapBuffers (vlc_gl_t *gl)
70 vlc_gl_sys_t *sys = gl->sys;
72 eglSwapBuffers (sys->display, sys->surface);
75 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
78 return (void *)eglGetProcAddress (procname);
81 static bool CheckToken(const char *haystack, const char *needle)
83 size_t len = strlen(needle);
85 while (haystack != NULL)
87 while (*haystack == ' ')
89 if (!strncmp(haystack, needle, len)
90 && (memchr(" ", haystack[len], 2) != NULL))
93 haystack = strchr(haystack, ' ');
98 static bool CheckAPI (EGLDisplay dpy, const char *api)
100 const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
101 return CheckToken(apis, api);
104 static bool CheckClientExt(const char *name)
106 const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
107 return CheckToken(exts, name);
119 #ifdef EGL_EXT_platform_base
120 static EGLDisplay GetDisplayEXT(EGLenum plat, void *dpy, const EGLint *attrs)
122 PFNEGLGETPLATFORMDISPLAYEXTPROC getDisplay =
123 (PFNEGLGETPLATFORMDISPLAYEXTPROC)
124 eglGetProcAddress("eglGetPlatformDisplayEXT");
126 assert(getDisplay != NULL);
127 return getDisplay(plat, dpy, attrs);
130 static EGLSurface CreateWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config,
131 void *window, const EGLint *attrs)
133 PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createSurface =
134 (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
135 eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
137 assert(createSurface != NULL);
138 return createSurface(dpy, config, window, attrs);
142 static EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config,
143 void *window, const EGLint *attrs)
145 EGLNativeWindowType *native = window;
147 return eglCreateWindowSurface(dpy, config, *native, attrs);
150 static void Close (vlc_object_t *obj)
152 vlc_gl_t *gl = (vlc_gl_t *)obj;
153 vlc_gl_sys_t *sys = gl->sys;
155 if (sys->display != EGL_NO_DISPLAY)
157 if (sys->surface != EGL_NO_SURFACE)
158 eglDestroySurface(sys->display, sys->surface);
159 eglTerminate(sys->display);
161 #ifdef USE_PLATFORM_X11
162 if (sys->x11 != NULL)
163 XCloseDisplay(sys->x11);
169 * Probe EGL display availability
171 static int Open (vlc_object_t *obj, const struct gl_api *api)
173 vlc_gl_t *gl = (vlc_gl_t *)obj;
174 vlc_gl_sys_t *sys = malloc(sizeof (*sys));
175 if (unlikely(sys == NULL))
179 sys->display = EGL_NO_DISPLAY;
180 sys->surface = EGL_NO_SURFACE;
182 vout_window_t *wnd = gl->surface;
183 EGLSurface (*createSurface)(EGLDisplay, EGLConfig, void *, const EGLint *)
184 = CreateWindowSurface;
187 #ifdef USE_PLATFORM_X11
190 if (wnd->type != VOUT_WINDOW_TYPE_XID || !vlc_xlib_init(obj))
193 window = &wnd->handle.xid;
194 sys->x11 = XOpenDisplay(wnd->display.x11);
195 if (sys->x11 == NULL)
200 XWindowAttributes wa;
202 if (!XGetWindowAttributes(sys->x11, wnd->handle.xid, &wa))
204 snum = XScreenNumberOfScreen(wa.screen);
206 # ifdef EGL_EXT_platform_x11
207 if (CheckClientExt("EGL_EXT_platform_x11"))
209 const EGLint attrs[] = {
210 EGL_PLATFORM_X11_SCREEN_EXT, snum,
213 sys->display = GetDisplayEXT(EGL_PLATFORM_X11_EXT, sys->x11, attrs);
214 createSurface = CreateWindowSurfaceEXT;
220 if (snum == XDefaultScreen(sys->x11))
221 sys->display = eglGetDisplay(sys->x11);
225 #elif defined (USE_PLATFORM_WIN32)
226 if (wnd->type != VOUT_WINDOW_TYPE_HWND)
229 window = &wnd->handle.hwnd;
230 # if defined (_WIN32) || defined (__VC32__) \
231 && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__)
232 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
235 #elif defined (USE_PLATFORM_ANDROID)
236 if (wnd->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
239 window = &wnd->handle.anativewindow;
240 # if defined (__ANDROID__) || defined (ANDROID)
241 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
246 if (sys->display == EGL_NO_DISPLAY)
249 /* Initialize EGL display */
251 if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
253 msg_Dbg(obj, "EGL version %s by %s",
254 eglQueryString(sys->display, EGL_VERSION),
255 eglQueryString(sys->display, EGL_VENDOR));
257 const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
259 msg_Dbg(obj, " extensions: %s", ext);
261 if (major != 1 || minor < api->min_minor
262 || !CheckAPI(sys->display, api->name))
264 msg_Err(obj, "cannot select %s API", api->name);
268 const EGLint conf_attr[] = {
272 EGL_RENDERABLE_TYPE, api->render_bit,
278 if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
281 msg_Err (obj, "cannot choose EGL configuration");
285 /* Create a drawing surface */
286 sys->surface = createSurface(sys->display, cfgv[0], window, NULL);
287 if (sys->surface == EGL_NO_SURFACE)
289 msg_Err (obj, "cannot create EGL window surface");
293 if (eglBindAPI (api->api) != EGL_TRUE)
295 msg_Err (obj, "cannot bind EGL API");
299 EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
301 if (ctx == EGL_NO_CONTEXT)
303 msg_Err (obj, "cannot create EGL context");
308 /* Initialize OpenGL callbacks */
309 gl->makeCurrent = MakeCurrent;
310 gl->releaseCurrent = ReleaseCurrent;
311 gl->swap = SwapBuffers;
312 gl->getProcAddress = GetSymbol;
322 static int OpenGLES2 (vlc_object_t *obj)
324 static const struct gl_api api = {
325 "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
326 { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
328 return Open (obj, &api);
331 static int OpenGLES (vlc_object_t *obj)
333 static const struct gl_api api = {
334 "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
335 { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
337 return Open (obj, &api);
340 static int OpenGL (vlc_object_t *obj)
342 static const struct gl_api api = {
343 "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
346 return Open (obj, &api);
350 set_shortname (N_("EGL"))
351 set_description (N_("EGL extension for OpenGL"))
352 set_category (CAT_VIDEO)
353 set_subcategory (SUBCAT_VIDEO_VOUT)
354 set_capability ("opengl", 50)
355 set_callbacks (OpenGL, Close)
359 set_capability ("opengl es2", 50)
360 set_callbacks (OpenGLES2, Close)
364 set_capability ("opengl es", 50)
365 set_callbacks (OpenGLES, Close)