]> git.sesse.net Git - vlc/blob - modules/video_output/egl.c
Qt4: Tell the window manager to keep the fullscreen controller window on top.
[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 library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This library 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 General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, 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
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_opengl.h>
34 #include <vlc_vout_window.h>
35 #ifdef __unix__
36 # include <vlc_xlib.h>
37 #endif
38
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 *);
44
45 vlc_module_begin ()
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)
52
53     add_submodule ()
54     set_capability ("opengl es2", 50)
55     set_callbacks (OpenGLES2, Close)
56
57     add_submodule ()
58     set_capability ("opengl es", 50)
59     set_callbacks (OpenGLES, Close)
60
61 vlc_module_end ()
62
63 typedef struct vlc_gl_sys_t
64 {
65     EGLDisplay display;
66     EGLSurface surface;
67     EGLContext context;
68 } vlc_gl_sys_t;
69
70 /* OpenGL callbacks */
71 static int MakeCurrent (vlc_gl_t *);
72 static void SwapBuffers (vlc_gl_t *);
73
74 static bool CheckAPI (EGLDisplay dpy, const char *api)
75 {
76     const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
77     size_t apilen = strlen (api);
78
79     /* Cannot use strtok_r() on constant string... */
80     do
81     {
82         if (!strncmp (apis, api, apilen)
83           && (memchr (" ", apis[apilen], 2) != NULL))
84             return true;
85
86         apis = strchr (apis, ' ');
87     }
88     while (apis != NULL);
89
90     return false;
91 }
92
93 struct gl_api
94 {
95    const char name[10];
96    EGLenum    api;
97    EGLint     min_minor;
98    EGLint     render_bit;
99    EGLint     attr[3];
100 };
101
102 /**
103  * Probe EGL display availability
104  */
105 static int Open (vlc_object_t *obj, const struct gl_api *api)
106 {
107     vlc_gl_t *gl = (vlc_gl_t *)obj;
108
109 #ifdef __unix__
110     /* EGL can only use the default X11 display */
111     if (gl->surface->display.x11 != NULL)
112         return VLC_EGENERIC;
113     if (!vlc_xlib_init (obj))
114         return VLC_EGENERIC;
115 #endif
116
117     /* Initialize EGL display */
118     /* TODO: support various display types */
119     EGLDisplay dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
120     if (dpy == EGL_NO_DISPLAY)
121         return VLC_EGENERIC;
122
123     vlc_gl_sys_t *sys = malloc (sizeof (*sys));
124     if (unlikely(sys == NULL))
125         return VLC_ENOMEM;
126     gl->sys = sys;
127     sys->display = dpy;
128
129     EGLint major, minor;
130     if (eglInitialize (dpy, &major, &minor) != EGL_TRUE)
131     {
132         /* No need to call eglTerminate() in this case */
133         free (sys);
134         return VLC_EGENERIC;
135     }
136
137     if (major != 1 || minor < api->min_minor || !CheckAPI (dpy, api->name))
138         goto error;
139
140     msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION),
141              eglQueryString (dpy, EGL_VENDOR));
142     {
143         const char *ext = eglQueryString (dpy, EGL_EXTENSIONS);
144         if (*ext)
145             msg_Dbg (obj, " extensions: %s", ext);
146     }
147
148     const EGLint conf_attr[] = {
149         EGL_RED_SIZE, 5,
150         EGL_GREEN_SIZE, 5,
151         EGL_BLUE_SIZE, 5,
152         EGL_RENDERABLE_TYPE, api->render_bit,
153         EGL_NONE
154     };
155     EGLConfig cfgv[1];
156     EGLint cfgc;
157
158     if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
159      || cfgc == 0)
160         goto error;
161
162     /* Create a drawing surface */
163 #if defined (WIN32)
164     EGLNativeWindowType win = gl->surface->handle.hwnd;
165 #elif defined (__unix__)
166     EGLNativeWindowType win = gl->surface->handle.xid;
167 #endif
168
169     EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL);
170     if (surface == EGL_NO_SURFACE)
171     {
172         msg_Err (obj, "cannot create EGL window surface");
173         goto error;
174     }
175     sys->surface = surface;
176
177     if (eglBindAPI (api->api) != EGL_TRUE)
178     {
179         msg_Err (obj, "cannot bind EGL API");
180         goto error;
181     }
182
183     EGLContext ctx = eglCreateContext (dpy, cfgv[0], EGL_NO_CONTEXT,
184                                        api->attr);
185     if (ctx == EGL_NO_CONTEXT)
186     {
187         msg_Err (obj, "cannot create EGL context");
188         goto error;
189     }
190     sys->context = ctx;
191
192     /* Initialize OpenGL callbacks */
193     gl->sys = sys;
194     gl->makeCurrent = MakeCurrent;
195     gl->swap = SwapBuffers;
196     gl->lock = NULL;
197     gl->unlock = NULL;
198     return VLC_SUCCESS;
199
200 error:
201     Close (obj);
202     return VLC_EGENERIC;
203 }
204
205 static int OpenGLES2 (vlc_object_t *obj)
206 {
207     static const struct gl_api api = {
208         "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
209         { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
210     };
211     return Open (obj, &api);
212 }
213
214 static int OpenGLES (vlc_object_t *obj)
215 {
216     static const struct gl_api api = {
217         "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
218         { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
219     };
220     return Open (obj, &api);
221 }
222
223 static int OpenGL (vlc_object_t *obj)
224 {
225     static const struct gl_api api = {
226         "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
227         { EGL_NONE },
228     };
229     return Open (obj, &api);
230 }
231
232 static void Close (vlc_object_t *obj)
233 {
234     vlc_gl_t *gl = (vlc_gl_t *)obj;
235     vlc_gl_sys_t *sys = gl->sys;
236
237     eglTerminate (sys->display);
238     free (sys);
239 }
240
241 static int MakeCurrent (vlc_gl_t *gl)
242 {
243     vlc_gl_sys_t *sys = gl->sys;
244
245     if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
246                         sys->context) != EGL_TRUE)
247         return VLC_EGENERIC;
248     return VLC_SUCCESS;
249 }
250
251 static void SwapBuffers (vlc_gl_t *gl)
252 {
253     vlc_gl_sys_t *sys = gl->sys;
254
255     eglSwapBuffers (sys->display, sys->surface);
256 }