3 * @brief EGL video output module
5 /*****************************************************************************
6 * Copyright © 2010-2011 Rémi Denis-Courmont
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.
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.
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 ****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_vout_display.h>
34 #include <vlc_opengl.h>
37 # include <vlc_xlib.h>
41 # define VLC_API_NAME "OpenGL_ES"
42 # define VLC_API EGL_OPENGL_ES_API
43 # if USE_OPENGL_ES == 2
44 # define VLC_RENDERABLE_BIT EGL_OPENGL_ES2_BIT
46 # define VLC_RENDERABLE_BIT EGL_OPENGL_ES_BIT
49 # define VLC_API_NAME "OpenGL"
50 # define VLC_API EGL_OPENGL_API
51 # define VLC_RENDERABLE_BIT EGL_OPENGL_BIT
58 /* Plugin callbacks */
59 static int Open (vlc_object_t *);
60 static void Close (vlc_object_t *);
63 set_shortname (N_("EGL"))
64 set_description (N_("EGL video output"))
65 set_category (CAT_VIDEO)
66 set_subcategory (SUBCAT_VIDEO_VOUT)
67 set_capability ("vout display", 0)
68 set_callbacks (Open, Close)
71 struct vout_display_sys_t
77 vout_display_opengl_t vgl;
80 vout_window_t *window;
83 /* Display callbacks */
84 static picture_pool_t *Pool (vout_display_t *, unsigned);
85 static void PictureRender (vout_display_t *, picture_t *, subpicture_t *);
86 static void PictureDisplay (vout_display_t *, picture_t *, subpicture_t *);
87 static int Control (vout_display_t *, int, va_list);
88 /* OpenGL callbacks */
89 static void SwapBuffers (vlc_gl_t *gl);
91 static bool CheckAPI (EGLDisplay dpy, const char *api)
93 const char *apis = eglQueryString (dpy, EGL_CLIENT_APIS);
94 size_t apilen = strlen (api);
96 /* Cannot use strtok_r() on constant string... */
99 if (!strncmp (apis, api, apilen)
100 && (memchr (" ", apis[apilen], 2) != NULL))
103 apis = strchr (apis, ' ');
105 while (apis != NULL);
110 static vout_window_t *MakeWindow (vout_display_t *vd, EGLNativeWindowType *id)
112 vout_window_cfg_t wnd_cfg;
114 memset (&wnd_cfg, 0, sizeof (wnd_cfg));
116 wnd_cfg.type = VOUT_WINDOW_TYPE_HWND;
117 #elif defined (__unix__)
118 wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
120 # error Unknown native window type!
122 wnd_cfg.x = var_InheritInteger (vd, "video-x");
123 wnd_cfg.y = var_InheritInteger (vd, "video-y");
124 wnd_cfg.width = vd->cfg->display.width;
125 wnd_cfg.height = vd->cfg->display.height;
127 vout_window_t *wnd = vout_display_NewWindow (vd, &wnd_cfg);
130 *id = wnd->handle.hwnd;
131 #elif defined (__unix__)
132 *id = wnd->handle.xid;
135 msg_Err (vd, "parent window not available");
140 * Probe EGL display availability
142 static int Open (vlc_object_t *obj)
145 if (!vlc_xlib_init (obj))
148 vout_display_t *vd = (vout_display_t *)obj;
150 /* Initialize EGL display */
151 /* TODO: support various display types */
152 EGLDisplay dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
153 if (dpy == EGL_NO_DISPLAY)
156 vout_display_sys_t *sys = malloc (sizeof (*sys));
157 if (unlikely(sys == NULL))
165 /* XXX Explicit hack!
166 * Mesa EGL plugins (as of version 7.8.2) are not properly linked to
167 * libEGL.so even though they import some of its symbols. This is
168 * typically not a problem. Unfortunately, LibVLC loads plugins as
169 * RTLD_LOCAL so that they do not pollute the namespace. Then the
170 * libEGL symbols are not visible to EGL plugins, and the run-time
171 * linker exits the whole process. */
172 if (dlopen ("libEGL.so", RTLD_GLOBAL|RTLD_NOW) == NULL)
173 msg_Warn (gl, "libEGL cannot be loaded. Process might crash.");
174 if (dlopen ("libGL.so", RTLD_GLOBAL|RTLD_NOW) == NULL)
175 msg_Warn (gl, "libGL cannot be loaded. Process might crash.");
179 if (eglInitialize (dpy, &major, &minor) != EGL_TRUE)
181 /* No need to call eglTerminate() in this case */
188 #if USE_OPENGL_ES == 2
189 if (minor < 3) /* Well well, this wouldn't compile with 1.2 anyway */
191 #elif USE_OPENGL_ES == 0
196 if (!CheckAPI (dpy, VLC_API_NAME))
199 msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION),
200 eglQueryString (dpy, EGL_VENDOR));
202 const char *ext = eglQueryString (dpy, EGL_EXTENSIONS);
204 msg_Dbg (obj, " extensions: %s", ext);
207 static const EGLint conf_attr[] = {
211 EGL_RENDERABLE_TYPE, VLC_RENDERABLE_BIT,
217 if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
221 /* Create a drawing surface */
222 EGLNativeWindowType win;
223 sys->window = MakeWindow (vd, &win);
224 if (sys->window == NULL)
227 EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL);
228 if (surface == EGL_NO_SURFACE)
230 msg_Err (obj, "cannot create EGL window surface");
233 sys->surface = surface;
235 if (eglBindAPI (VLC_API) != EGL_TRUE)
237 msg_Err (obj, "cannot bind EGL API");
241 static const EGLint ctx_attr[] = {
243 EGL_CONTEXT_CLIENT_VERSION, USE_OPENGL_ES,
248 EGLContext ctx = eglCreateContext (dpy, cfgv[0], EGL_NO_CONTEXT,
250 if (ctx == EGL_NO_CONTEXT)
252 msg_Err (obj, "cannot create EGL context");
256 if (eglMakeCurrent (dpy, surface, surface, ctx) != EGL_TRUE)
259 /* Initialize OpenGL callbacks */
261 sys->gl.unlock = NULL;
262 sys->gl.swap = SwapBuffers;
265 if (vout_display_opengl_Init (&sys->vgl, &vd->fmt, &sys->gl))
268 /* Initialize video display */
269 vd->info.has_pictures_invalid = false;
270 vd->info.has_event_thread = false;
272 vd->prepare = PictureRender;
273 vd->display = PictureDisplay;
274 vd->control = Control;
279 vout_display_DeleteWindow (vd, sys->window);
288 * Destrisconnect from the X server.
290 static void Close (vlc_object_t *obj)
292 vout_display_t *vd = (vout_display_t *)obj;
293 vout_display_sys_t *sys = vd->sys;
294 EGLDisplay dpy = sys->display;
296 if (sys->gl.sys != NULL)
297 vout_display_opengl_Clean (&sys->vgl);
299 vout_display_DeleteWindow (vd, sys->window);
303 static void SwapBuffers (vlc_gl_t *gl)
305 vout_display_sys_t *sys = gl->sys;
307 eglSwapBuffers (sys->display, sys->surface);
311 * Return a direct buffer
313 static picture_pool_t *Pool (vout_display_t *vd, unsigned count)
315 vout_display_sys_t *sys = vd->sys;
318 sys->pool = vout_display_opengl_GetPool (&sys->vgl);
323 static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
325 vout_display_sys_t *sys = vd->sys;
327 vout_display_opengl_Prepare (&sys->vgl, pic);
331 static void PictureDisplay (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
333 vout_display_sys_t *sys = vd->sys;
335 vout_display_opengl_Display (&sys->vgl, &vd->source);
336 picture_Release (pic);
340 static int Control (vout_display_t *vd, int query, va_list ap)
342 vout_display_sys_t *sys = vd->sys;
346 case VOUT_DISPLAY_HIDE_MOUSE:
347 case VOUT_DISPLAY_RESET_PICTURES: // not needed?
350 case VOUT_DISPLAY_CHANGE_FULLSCREEN:
352 const vout_display_cfg_t *cfg =
353 va_arg (ap, const vout_display_cfg_t *);
355 return vout_window_SetFullScreen (sys->window, cfg->is_fullscreen);
358 case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
360 unsigned state = va_arg (ap, unsigned);
362 return vout_window_SetState (sys->window, state);
365 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
366 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
367 case VOUT_DISPLAY_CHANGE_ZOOM:
369 const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *);
370 const video_format_t *src = &vd->source;
372 if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
376 force = va_arg (ap, int);
378 && (cfg->display.width != vd->cfg->display.width
379 || cfg->display.height != vd->cfg->display.height)
380 && vout_window_SetSize (sys->window,
381 cfg->display.width, cfg->display.height))
385 vout_display_place_t place;
387 vout_display_PlacePicture (&place, src, cfg, false);
388 glViewport (0, 0, place.width, place.height);
392 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
393 case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
395 const vout_display_cfg_t *cfg = vd->cfg;
396 const video_format_t *src = va_arg (ap, const video_format_t *);
397 vout_display_place_t place;
399 vout_display_PlacePicture (&place, src, cfg, false);
400 glViewport (0, 0, place.width, place.height);
404 case VOUT_DISPLAY_GET_OPENGL:
406 vlc_gl_t **gl = va_arg (ap, vlc_gl_t **);
413 msg_Err (vd, "Unknown request %d", query);