kwallet: use vlc_memstream
[vlc.git] / modules / video_output / egl.c
bloba10dd5aa3956d9ffaabd83916bcf30f45c13cc6d
1 /**
2 * @file egl.c
3 * @brief EGL OpenGL extension module
4 */
5 /*****************************************************************************
6 * Copyright © 2010-2014 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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <EGL/egl.h>
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>
38 #endif
39 #ifdef USE_PLATFORM_WAYLAND
40 # include <wayland-egl.h>
41 #endif
43 typedef struct vlc_gl_sys_t
45 EGLDisplay display;
46 EGLSurface surface;
47 EGLContext context;
48 #if defined (USE_PLATFORM_X11)
49 Display *x11;
50 #endif
51 #if defined (USE_PLATFORM_WAYLAND)
52 struct wl_egl_window *window;
53 unsigned width, height;
54 #endif
55 } vlc_gl_sys_t;
57 static int MakeCurrent (vlc_gl_t *gl)
59 vlc_gl_sys_t *sys = gl->sys;
61 if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
62 sys->context) != EGL_TRUE)
63 return VLC_EGENERIC;
64 return VLC_SUCCESS;
67 static void ReleaseCurrent (vlc_gl_t *gl)
69 vlc_gl_sys_t *sys = gl->sys;
71 eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
72 EGL_NO_CONTEXT);
75 #ifdef USE_PLATFORM_WAYLAND
76 static void Resize (vlc_gl_t *gl, unsigned width, unsigned height)
78 vlc_gl_sys_t *sys = gl->sys;
80 wl_egl_window_resize(sys->window, width, height,
81 (sys->width - width) / 2,
82 (sys->height - height) / 2);
83 sys->width = width;
84 sys->height = height;
86 #else
87 # define Resize (NULL)
88 #endif
90 static void SwapBuffers (vlc_gl_t *gl)
92 vlc_gl_sys_t *sys = gl->sys;
94 eglSwapBuffers (sys->display, sys->surface);
97 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
99 (void) gl;
100 return (void *)eglGetProcAddress (procname);
103 static bool CheckToken(const char *haystack, const char *needle)
105 size_t len = strlen(needle);
107 while (haystack != NULL)
109 while (*haystack == ' ')
110 haystack++;
111 if (!strncmp(haystack, needle, len)
112 && (memchr(" ", haystack[len], 2) != NULL))
113 return true;
115 haystack = strchr(haystack, ' ');
117 return false;
120 static bool CheckAPI (EGLDisplay dpy, const char *api)
122 const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
123 return CheckToken(apis, api);
126 static bool CheckClientExt(const char *name)
128 const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
129 return CheckToken(exts, name);
132 struct gl_api
134 const char name[10];
135 EGLenum api;
136 EGLint min_minor;
137 EGLint render_bit;
138 EGLint attr[3];
141 #ifdef EGL_EXT_platform_base
142 static EGLDisplay GetDisplayEXT(EGLenum plat, void *dpy, const EGLint *attrs)
144 PFNEGLGETPLATFORMDISPLAYEXTPROC getDisplay =
145 (PFNEGLGETPLATFORMDISPLAYEXTPROC)
146 eglGetProcAddress("eglGetPlatformDisplayEXT");
148 assert(getDisplay != NULL);
149 return getDisplay(plat, dpy, attrs);
152 static EGLSurface CreateWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config,
153 void *window, const EGLint *attrs)
155 PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createSurface =
156 (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
157 eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
159 assert(createSurface != NULL);
160 return createSurface(dpy, config, window, attrs);
162 #endif
164 static EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config,
165 void *window, const EGLint *attrs)
167 EGLNativeWindowType *native = window;
169 return eglCreateWindowSurface(dpy, config, *native, attrs);
172 static void Close (vlc_object_t *obj)
174 vlc_gl_t *gl = (vlc_gl_t *)obj;
175 vlc_gl_sys_t *sys = gl->sys;
177 if (sys->display != EGL_NO_DISPLAY)
179 if (sys->surface != EGL_NO_SURFACE)
180 eglDestroySurface(sys->display, sys->surface);
181 eglTerminate(sys->display);
183 #ifdef USE_PLATFORM_X11
184 if (sys->x11 != NULL)
185 XCloseDisplay(sys->x11);
186 #endif
187 #ifdef USE_PLATFORM_WAYLAND
188 if (sys->window != NULL)
189 wl_egl_window_destroy(sys->window);
190 #endif
191 free (sys);
195 * Probe EGL display availability
197 static int Open (vlc_object_t *obj, const struct gl_api *api)
199 vlc_gl_t *gl = (vlc_gl_t *)obj;
200 vlc_gl_sys_t *sys = malloc(sizeof (*sys));
201 if (unlikely(sys == NULL))
202 return VLC_ENOMEM;
204 gl->sys = sys;
205 sys->display = EGL_NO_DISPLAY;
206 sys->surface = EGL_NO_SURFACE;
208 vout_window_t *wnd = gl->surface;
209 EGLSurface (*createSurface)(EGLDisplay, EGLConfig, void *, const EGLint *)
210 = CreateWindowSurface;
211 void *window;
213 #ifdef USE_PLATFORM_X11
214 sys->x11 = NULL;
216 if (wnd->type != VOUT_WINDOW_TYPE_XID || !vlc_xlib_init(obj))
217 goto error;
219 window = &wnd->handle.xid;
220 sys->x11 = XOpenDisplay(wnd->display.x11);
221 if (sys->x11 == NULL)
222 goto error;
224 int snum;
226 XWindowAttributes wa;
228 if (!XGetWindowAttributes(sys->x11, wnd->handle.xid, &wa))
229 goto error;
230 snum = XScreenNumberOfScreen(wa.screen);
232 # ifdef EGL_EXT_platform_x11
233 if (CheckClientExt("EGL_EXT_platform_x11"))
235 const EGLint attrs[] = {
236 EGL_PLATFORM_X11_SCREEN_EXT, snum,
237 EGL_NONE
239 sys->display = GetDisplayEXT(EGL_PLATFORM_X11_EXT, sys->x11, attrs);
240 createSurface = CreateWindowSurfaceEXT;
242 else
243 # endif
245 # ifdef __unix__
246 if (snum == XDefaultScreen(sys->x11))
247 sys->display = eglGetDisplay(sys->x11);
248 # endif
251 #elif defined (USE_PLATFORM_WAYLAND)
252 sys->window = NULL;
254 if (wnd->type != VOUT_WINDOW_TYPE_WAYLAND)
255 goto error;
257 # ifdef EGL_EXT_platform_wayland
258 if (!CheckClientExt("EGL_EXT_platform_wayland"))
259 goto error;
261 /* Resize() should be called with the proper size before Swap() */
262 window = wl_egl_window_create(wnd->handle.wl, 1, 1);
263 if (window == NULL)
264 goto error;
265 sys->window = window;
267 sys->display = GetDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, wnd->display.wl,
268 NULL);
269 createSurface = CreateWindowSurfaceEXT;
271 # endif
273 #elif defined (USE_PLATFORM_WIN32)
274 if (wnd->type != VOUT_WINDOW_TYPE_HWND)
275 goto error;
277 window = &wnd->handle.hwnd;
278 # if defined (_WIN32) || defined (__VC32__) \
279 && !defined (__CYGWIN__) && !defined (__SCITECH_SNAP__)
280 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
281 # endif
283 #elif defined (USE_PLATFORM_ANDROID)
284 if (wnd->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
285 goto error;
287 window = &wnd->handle.anativewindow;
288 # if defined (__ANDROID__) || defined (ANDROID)
289 sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
290 # endif
292 #endif
294 if (sys->display == EGL_NO_DISPLAY)
295 goto error;
297 /* Initialize EGL display */
298 EGLint major, minor;
299 if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
300 goto error;
301 msg_Dbg(obj, "EGL version %s by %s",
302 eglQueryString(sys->display, EGL_VERSION),
303 eglQueryString(sys->display, EGL_VENDOR));
305 const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
306 if (*ext)
307 msg_Dbg(obj, " extensions: %s", ext);
309 if (major != 1 || minor < api->min_minor
310 || !CheckAPI(sys->display, api->name))
312 msg_Err(obj, "cannot select %s API", api->name);
313 goto error;
316 const EGLint conf_attr[] = {
317 EGL_RED_SIZE, 5,
318 EGL_GREEN_SIZE, 5,
319 EGL_BLUE_SIZE, 5,
320 EGL_RENDERABLE_TYPE, api->render_bit,
321 EGL_NONE
323 EGLConfig cfgv[1];
324 EGLint cfgc;
326 if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
327 || cfgc == 0)
329 msg_Err (obj, "cannot choose EGL configuration");
330 goto error;
333 /* Create a drawing surface */
334 sys->surface = createSurface(sys->display, cfgv[0], window, NULL);
335 if (sys->surface == EGL_NO_SURFACE)
337 msg_Err (obj, "cannot create EGL window surface");
338 goto error;
341 if (eglBindAPI (api->api) != EGL_TRUE)
343 msg_Err (obj, "cannot bind EGL API");
344 goto error;
347 EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
348 api->attr);
349 if (ctx == EGL_NO_CONTEXT)
351 msg_Err (obj, "cannot create EGL context");
352 goto error;
354 sys->context = ctx;
356 /* Initialize OpenGL callbacks */
357 gl->makeCurrent = MakeCurrent;
358 gl->releaseCurrent = ReleaseCurrent;
359 gl->resize = Resize;
360 gl->swap = SwapBuffers;
361 gl->getProcAddress = GetSymbol;
362 return VLC_SUCCESS;
364 error:
365 Close (obj);
366 return VLC_EGENERIC;
369 static int OpenGLES2 (vlc_object_t *obj)
371 static const struct gl_api api = {
372 "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
373 { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
375 return Open (obj, &api);
378 static int OpenGLES (vlc_object_t *obj)
380 static const struct gl_api api = {
381 "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
382 { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
384 return Open (obj, &api);
387 static int OpenGL (vlc_object_t *obj)
389 static const struct gl_api api = {
390 "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
391 { EGL_NONE },
393 return Open (obj, &api);
396 vlc_module_begin ()
397 set_shortname (N_("EGL"))
398 set_description (N_("EGL extension for OpenGL"))
399 set_category (CAT_VIDEO)
400 set_subcategory (SUBCAT_VIDEO_VOUT)
401 set_capability ("opengl", 50)
402 set_callbacks (OpenGL, Close)
403 add_shortcut ("egl")
405 add_submodule ()
406 set_capability ("opengl es2", 50)
407 set_callbacks (OpenGLES2, Close)
408 add_shortcut ("egl")
410 add_submodule ()
411 set_capability ("opengl es", 50)
412 set_callbacks (OpenGLES, Close)
413 add_shortcut ("egl")
415 vlc_module_end ()