]> git.sesse.net Git - vlc/blob - modules/video_output/egl.c
Fix some common typos.
[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 #ifdef __unix__
113     /* EGL can only use the default X11 display */
114     if (gl->surface->display.x11 != NULL)
115         return VLC_EGENERIC;
116     if (!vlc_xlib_init (obj))
117         return VLC_EGENERIC;
118 #endif
119
120     /* Initialize EGL display */
121     /* TODO: support various display types */
122     EGLDisplay dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
123     if (dpy == EGL_NO_DISPLAY)
124         return VLC_EGENERIC;
125
126     vlc_gl_sys_t *sys = malloc (sizeof (*sys));
127     if (unlikely(sys == NULL))
128         return VLC_ENOMEM;
129     gl->sys = sys;
130     sys->display = dpy;
131
132     EGLint major, minor;
133     if (eglInitialize (dpy, &major, &minor) != EGL_TRUE)
134     {
135         /* No need to call eglTerminate() in this case */
136         free (sys);
137         return VLC_EGENERIC;
138     }
139
140     if (major != 1 || minor < api->min_minor || !CheckAPI (dpy, api->name))
141         goto error;
142
143     msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION),
144              eglQueryString (dpy, EGL_VENDOR));
145     {
146         const char *ext = eglQueryString (dpy, EGL_EXTENSIONS);
147         if (*ext)
148             msg_Dbg (obj, " extensions: %s", ext);
149     }
150
151     const EGLint conf_attr[] = {
152         EGL_RED_SIZE, 5,
153         EGL_GREEN_SIZE, 5,
154         EGL_BLUE_SIZE, 5,
155         EGL_RENDERABLE_TYPE, api->render_bit,
156         EGL_NONE
157     };
158     EGLConfig cfgv[1];
159     EGLint cfgc;
160
161     if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
162      || cfgc == 0)
163         goto error;
164
165     /* Create a drawing surface */
166 #if defined (WIN32)
167     EGLNativeWindowType win = gl->surface->handle.hwnd;
168 #elif defined (__unix__)
169     EGLNativeWindowType win = gl->surface->handle.xid;
170 #endif
171
172     EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL);
173     if (surface == EGL_NO_SURFACE)
174     {
175         msg_Err (obj, "cannot create EGL window surface");
176         goto error;
177     }
178     sys->surface = surface;
179
180     if (eglBindAPI (api->api) != EGL_TRUE)
181     {
182         msg_Err (obj, "cannot bind EGL API");
183         goto error;
184     }
185
186     EGLContext ctx = eglCreateContext (dpy, cfgv[0], EGL_NO_CONTEXT,
187                                        api->attr);
188     if (ctx == EGL_NO_CONTEXT)
189     {
190         msg_Err (obj, "cannot create EGL context");
191         goto error;
192     }
193     sys->context = ctx;
194
195     /* Initialize OpenGL callbacks */
196     gl->sys = sys;
197     gl->makeCurrent = MakeCurrent;
198     gl->swap = SwapBuffers;
199     gl->getProcAddress = GetSymbol;
200     gl->lock = NULL;
201     gl->unlock = NULL;
202     return VLC_SUCCESS;
203
204 error:
205     Close (obj);
206     return VLC_EGENERIC;
207 }
208
209 static int OpenGLES2 (vlc_object_t *obj)
210 {
211     static const struct gl_api api = {
212         "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
213         { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
214     };
215     return Open (obj, &api);
216 }
217
218 static int OpenGLES (vlc_object_t *obj)
219 {
220     static const struct gl_api api = {
221         "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
222         { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
223     };
224     return Open (obj, &api);
225 }
226
227 static int OpenGL (vlc_object_t *obj)
228 {
229     static const struct gl_api api = {
230         "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
231         { EGL_NONE },
232     };
233     return Open (obj, &api);
234 }
235
236 static void Close (vlc_object_t *obj)
237 {
238     vlc_gl_t *gl = (vlc_gl_t *)obj;
239     vlc_gl_sys_t *sys = gl->sys;
240
241     eglTerminate (sys->display);
242     free (sys);
243 }
244
245 static int MakeCurrent (vlc_gl_t *gl)
246 {
247     vlc_gl_sys_t *sys = gl->sys;
248
249     if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
250                         sys->context) != EGL_TRUE)
251         return VLC_EGENERIC;
252     return VLC_SUCCESS;
253 }
254
255 static void SwapBuffers (vlc_gl_t *gl)
256 {
257     vlc_gl_sys_t *sys = gl->sys;
258
259     eglSwapBuffers (sys->display, sys->surface);
260 }
261
262 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
263 {
264     (void) gl;
265     return (void *)eglGetProcAddress (procname);
266 }