]> git.sesse.net Git - vlc/blob - modules/video_output/egl.c
MMAL: check that the vout is not windowed
[vlc] / modules / video_output / egl.c
1 /**
2  * @file egl.c
3  * @brief EGL OpenGL extension module
4  */
5 /*****************************************************************************
6  * Copyright © 2010-2011 Rémi Denis-Courmont
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <EGL/egl.h>
30 #include <EGL/eglext.h>
31
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>
38 #endif
39
40 typedef struct vlc_gl_sys_t
41 {
42     EGLDisplay display;
43     EGLSurface surface;
44     EGLContext context;
45 #if defined (USE_PLATFORM_X11)
46     Display *x11;
47 #endif
48 } vlc_gl_sys_t;
49
50 static int MakeCurrent (vlc_gl_t *gl)
51 {
52     vlc_gl_sys_t *sys = gl->sys;
53
54     if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
55                         sys->context) != EGL_TRUE)
56         return VLC_EGENERIC;
57     return VLC_SUCCESS;
58 }
59
60 static void ReleaseCurrent (vlc_gl_t *gl)
61 {
62     vlc_gl_sys_t *sys = gl->sys;
63
64     eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
65                     EGL_NO_CONTEXT);
66 }
67
68 static void SwapBuffers (vlc_gl_t *gl)
69 {
70     vlc_gl_sys_t *sys = gl->sys;
71
72     eglSwapBuffers (sys->display, sys->surface);
73 }
74
75 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
76 {
77     (void) gl;
78     return (void *)eglGetProcAddress (procname);
79 }
80
81 static bool CheckToken(const char *haystack, const char *needle)
82 {
83     size_t len = strlen(needle);
84
85     while (haystack != NULL)
86     {
87         while (*haystack == ' ')
88             haystack++;
89         if (!strncmp(haystack, needle, len)
90          && (memchr(" ", haystack[len], 2) != NULL))
91             return true;
92
93         haystack = strchr(haystack, ' ');
94     }
95     return false;
96 }
97
98 static bool CheckAPI (EGLDisplay dpy, const char *api)
99 {
100     const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
101     return CheckToken(apis, api);
102 }
103
104 static bool CheckClientExt(const char *name)
105 {
106     const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
107     return CheckToken(exts, name);
108 }
109
110 struct gl_api
111 {
112    const char name[10];
113    EGLenum    api;
114    EGLint     min_minor;
115    EGLint     render_bit;
116    EGLint     attr[3];
117 };
118
119 #ifdef EGL_EXT_platform_base
120 static EGLDisplay GetDisplayEXT(EGLenum plat, void *dpy, const EGLint *attrs)
121 {
122     PFNEGLGETPLATFORMDISPLAYEXTPROC getDisplay =
123         (PFNEGLGETPLATFORMDISPLAYEXTPROC)
124         eglGetProcAddress("eglGetPlatformDisplayEXT");
125
126     assert(getDisplay != NULL);
127     return getDisplay(plat, dpy, attrs);
128 }
129
130 static EGLSurface CreateWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config,
131                                          void *window, const EGLint *attrs)
132 {
133     PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createSurface =
134         (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
135         eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
136
137     assert(createSurface != NULL);
138     return createSurface(dpy, config, window, attrs);
139 }
140 #endif
141
142 static EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config,
143                                       void *window, const EGLint *attrs)
144 {
145     EGLNativeWindowType *native = window;
146
147     return eglCreateWindowSurface(dpy, config, *native, attrs);
148 }
149
150 static void Close (vlc_object_t *obj)
151 {
152     vlc_gl_t *gl = (vlc_gl_t *)obj;
153     vlc_gl_sys_t *sys = gl->sys;
154
155     if (sys->display != EGL_NO_DISPLAY)
156     {
157         if (sys->surface != EGL_NO_SURFACE)
158             eglDestroySurface(sys->display, sys->surface);
159         eglTerminate(sys->display);
160     }
161 #ifdef USE_PLATFORM_X11
162     if (sys->x11 != NULL)
163         XCloseDisplay(sys->x11);
164 #endif
165     free (sys);
166 }
167
168 /**
169  * Probe EGL display availability
170  */
171 static int Open (vlc_object_t *obj, const struct gl_api *api)
172 {
173     vlc_gl_t *gl = (vlc_gl_t *)obj;
174     vlc_gl_sys_t *sys = malloc(sizeof (*sys));
175     if (unlikely(sys == NULL))
176         return VLC_ENOMEM;
177
178     gl->sys = sys;
179     sys->display = EGL_NO_DISPLAY;
180     sys->surface = EGL_NO_SURFACE;
181
182     vout_window_t *wnd = gl->surface;
183     EGLSurface (*createSurface)(EGLDisplay, EGLConfig, void *, const EGLint *)
184         = CreateWindowSurface;
185     void *window;
186
187 #ifdef USE_PLATFORM_X11
188     sys->x11 = NULL;
189
190     if (wnd->type != VOUT_WINDOW_TYPE_XID || !vlc_xlib_init(obj))
191         goto error;
192
193     window = &wnd->handle.xid;
194     sys->x11 = XOpenDisplay(wnd->display.x11);
195     if (sys->x11 == NULL)
196         goto error;
197
198     int snum;
199     {
200         XWindowAttributes wa;
201
202         if (!XGetWindowAttributes(sys->x11, wnd->handle.xid, &wa))
203             goto error;
204         snum = XScreenNumberOfScreen(wa.screen);
205     }
206 # ifdef EGL_EXT_platform_x11
207     if (CheckClientExt("EGL_EXT_platform_x11"))
208     {
209         const EGLint attrs[] = {
210             EGL_PLATFORM_X11_SCREEN_EXT, snum,
211             EGL_NONE
212         };
213         sys->display = GetDisplayEXT(EGL_PLATFORM_X11_EXT, sys->x11, attrs);
214         createSurface = CreateWindowSurfaceEXT;
215     }
216     else
217 # endif
218     {
219 # ifdef __unix__
220         if (snum == XDefaultScreen(sys->x11))
221             sys->display = eglGetDisplay(sys->x11);
222     }
223 # endif
224
225 #elif defined (USE_PLATFORM_WIN32)
226     if (wnd->type != VOUT_WINDOW_TYPE_HWND)
227         goto error;
228
229     window = &wnd->handle.hwnd;
230 # if defined (_WIN32) || defined (__VC32__) \
231   && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__)
232     sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
233 # endif
234
235 #elif defined (USE_PLATFORM_ANDROID)
236     if (wnd->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
237         goto error;
238
239     window = &wnd->handle.anativewindow;
240 # if defined (__ANDROID__) || defined (ANDROID)
241     sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
242 # endif
243
244 #endif
245
246     if (sys->display == EGL_NO_DISPLAY)
247         goto error;
248
249     /* Initialize EGL display */
250     EGLint major, minor;
251     if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
252         goto error;
253     msg_Dbg(obj, "EGL version %s by %s",
254             eglQueryString(sys->display, EGL_VERSION),
255             eglQueryString(sys->display, EGL_VENDOR));
256
257     const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
258     if (*ext)
259         msg_Dbg(obj, " extensions: %s", ext);
260
261     if (major != 1 || minor < api->min_minor
262      || !CheckAPI(sys->display, api->name))
263     {
264         msg_Err(obj, "cannot select %s API", api->name);
265         goto error;
266     }
267
268     const EGLint conf_attr[] = {
269         EGL_RED_SIZE, 5,
270         EGL_GREEN_SIZE, 5,
271         EGL_BLUE_SIZE, 5,
272         EGL_RENDERABLE_TYPE, api->render_bit,
273         EGL_NONE
274     };
275     EGLConfig cfgv[1];
276     EGLint cfgc;
277
278     if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
279      || cfgc == 0)
280     {
281         msg_Err (obj, "cannot choose EGL configuration");
282         goto error;
283     }
284
285     /* Create a drawing surface */
286     sys->surface = createSurface(sys->display, cfgv[0], window, NULL);
287     if (sys->surface == EGL_NO_SURFACE)
288     {
289         msg_Err (obj, "cannot create EGL window surface");
290         goto error;
291     }
292
293     if (eglBindAPI (api->api) != EGL_TRUE)
294     {
295         msg_Err (obj, "cannot bind EGL API");
296         goto error;
297     }
298
299     EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
300                                       api->attr);
301     if (ctx == EGL_NO_CONTEXT)
302     {
303         msg_Err (obj, "cannot create EGL context");
304         goto error;
305     }
306     sys->context = ctx;
307
308     /* Initialize OpenGL callbacks */
309     gl->makeCurrent = MakeCurrent;
310     gl->releaseCurrent = ReleaseCurrent;
311     gl->swap = SwapBuffers;
312     gl->getProcAddress = GetSymbol;
313     gl->lock = NULL;
314     gl->unlock = NULL;
315     return VLC_SUCCESS;
316
317 error:
318     Close (obj);
319     return VLC_EGENERIC;
320 }
321
322 static int OpenGLES2 (vlc_object_t *obj)
323 {
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 },
327     };
328     return Open (obj, &api);
329 }
330
331 static int OpenGLES (vlc_object_t *obj)
332 {
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 },
336     };
337     return Open (obj, &api);
338 }
339
340 static int OpenGL (vlc_object_t *obj)
341 {
342     static const struct gl_api api = {
343         "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
344         { EGL_NONE },
345     };
346     return Open (obj, &api);
347 }
348
349 vlc_module_begin ()
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)
356     add_shortcut ("egl")
357
358     add_submodule ()
359     set_capability ("opengl es2", 50)
360     set_callbacks (OpenGLES2, Close)
361     add_shortcut ("egl")
362
363     add_submodule ()
364     set_capability ("opengl es", 50)
365     set_callbacks (OpenGLES, Close)
366     add_shortcut ("egl")
367
368 vlc_module_end ()