]> git.sesse.net Git - vlc/blob - modules/video_output/egl.c
EGL: print error when configuration is not usable (refs #7634)
[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
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 static void *GetSymbol(vlc_gl_t *, const char *);
74
75 static bool CheckAPI (EGLDisplay dpy, const char *api)
76 {
77     const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
78     size_t apilen = strlen (api);
79
80     /* Cannot use strtok_r() on constant string... */
81     do
82     {
83         while (*apis == ' ')
84             apis++;
85         if (!strncmp (apis, api, apilen)
86           && (memchr (" ", apis[apilen], 2) != NULL))
87             return true;
88
89         apis = strchr (apis, ' ');
90     }
91     while (apis != NULL);
92
93     return false;
94 }
95
96 struct gl_api
97 {
98    const char name[10];
99    EGLenum    api;
100    EGLint     min_minor;
101    EGLint     render_bit;
102    EGLint     attr[3];
103 };
104
105 /**
106  * Probe EGL display availability
107  */
108 static int Open (vlc_object_t *obj, const struct gl_api *api)
109 {
110     vlc_gl_t *gl = (vlc_gl_t *)obj;
111
112     /* <EGL/eglplatform.h> defines the list and order of platforms */
113 #if defined(_WIN32) || defined(__VC32__) \
114  && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
115 # define vlc_eglGetWindow(w) ((w)->handle.hwnd)
116
117 #elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */
118 # error Symbian EGL not supported.
119
120 #elif defined(WL_EGL_PLATFORM)
121 # error Wayland EGL not supported.
122
123 #elif defined(__GBM__)
124 # error Glamor EGL not supported.
125
126 #elif defined(ANDROID)
127 # error Android EGL not supported
128
129 #elif defined(__unix__) /* X11 */
130 # define vlc_eglGetWindow(w) ((w)->handle.xid)
131     /* EGL can only use the default X11 display */
132     if (gl->surface->display.x11 != NULL)
133         return VLC_EGENERIC;
134     if (!vlc_xlib_init (obj))
135         return VLC_EGENERIC;
136
137 #else
138 # error EGL platform not recognized.
139 #endif
140
141     /* Initialize EGL display */
142     /* TODO: support various display types */
143     EGLDisplay dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
144     if (dpy == EGL_NO_DISPLAY)
145         return VLC_EGENERIC;
146
147     vlc_gl_sys_t *sys = malloc (sizeof (*sys));
148     if (unlikely(sys == NULL))
149         return VLC_ENOMEM;
150     gl->sys = sys;
151     sys->display = dpy;
152
153     EGLint major, minor;
154     if (eglInitialize (dpy, &major, &minor) != EGL_TRUE)
155     {
156         /* No need to call eglTerminate() in this case */
157         free (sys);
158         return VLC_EGENERIC;
159     }
160
161     if (major != 1 || minor < api->min_minor || !CheckAPI (dpy, api->name))
162         goto error;
163
164     msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION),
165              eglQueryString (dpy, EGL_VENDOR));
166     {
167         const char *ext = eglQueryString (dpy, EGL_EXTENSIONS);
168         if (*ext)
169             msg_Dbg (obj, " extensions: %s", ext);
170     }
171
172     const EGLint conf_attr[] = {
173         EGL_RED_SIZE, 5,
174         EGL_GREEN_SIZE, 5,
175         EGL_BLUE_SIZE, 5,
176         EGL_RENDERABLE_TYPE, api->render_bit,
177         EGL_NONE
178     };
179     EGLConfig cfgv[1];
180     EGLint cfgc;
181
182     if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
183      || cfgc == 0)
184     {
185         msg_Err (obj, "cannot choose EGL configuration");
186         goto error;
187     }
188
189     /* Create a drawing surface */
190     EGLNativeWindowType win = vlc_eglGetWindow(gl->surface);
191     EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL);
192     if (surface == EGL_NO_SURFACE)
193     {
194         msg_Err (obj, "cannot create EGL window surface");
195         goto error;
196     }
197     sys->surface = surface;
198
199     if (eglBindAPI (api->api) != EGL_TRUE)
200     {
201         msg_Err (obj, "cannot bind EGL API");
202         goto error;
203     }
204
205     EGLContext ctx = eglCreateContext (dpy, cfgv[0], EGL_NO_CONTEXT,
206                                        api->attr);
207     if (ctx == EGL_NO_CONTEXT)
208     {
209         msg_Err (obj, "cannot create EGL context");
210         goto error;
211     }
212     sys->context = ctx;
213
214     /* Initialize OpenGL callbacks */
215     gl->sys = sys;
216     gl->makeCurrent = MakeCurrent;
217     gl->swap = SwapBuffers;
218     gl->getProcAddress = GetSymbol;
219     gl->lock = NULL;
220     gl->unlock = NULL;
221     return VLC_SUCCESS;
222
223 error:
224     Close (obj);
225     return VLC_EGENERIC;
226 }
227
228 static int OpenGLES2 (vlc_object_t *obj)
229 {
230     static const struct gl_api api = {
231         "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
232         { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
233     };
234     return Open (obj, &api);
235 }
236
237 static int OpenGLES (vlc_object_t *obj)
238 {
239     static const struct gl_api api = {
240         "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
241         { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
242     };
243     return Open (obj, &api);
244 }
245
246 static int OpenGL (vlc_object_t *obj)
247 {
248     static const struct gl_api api = {
249         "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
250         { EGL_NONE },
251     };
252     return Open (obj, &api);
253 }
254
255 static void Close (vlc_object_t *obj)
256 {
257     vlc_gl_t *gl = (vlc_gl_t *)obj;
258     vlc_gl_sys_t *sys = gl->sys;
259
260     eglTerminate (sys->display);
261     free (sys);
262 }
263
264 static int MakeCurrent (vlc_gl_t *gl)
265 {
266     vlc_gl_sys_t *sys = gl->sys;
267
268     if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
269                         sys->context) != EGL_TRUE)
270         return VLC_EGENERIC;
271     return VLC_SUCCESS;
272 }
273
274 static void SwapBuffers (vlc_gl_t *gl)
275 {
276     vlc_gl_sys_t *sys = gl->sys;
277
278     eglSwapBuffers (sys->display, sys->surface);
279 }
280
281 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
282 {
283     (void) gl;
284     return (void *)eglGetProcAddress (procname);
285 }