]> git.sesse.net Git - vlc/blobdiff - modules/video_output/egl.c
flac: don't overwrite bitspersample
[vlc] / modules / video_output / egl.c
index 1d24726d3b4122c4f98f38c19ca1a32ad33c30f8..e8bc6beb5de44483c2a44601dac1d90fbcafc96a 100644 (file)
@@ -1,24 +1,24 @@
 /**
  * @file egl.c
- * @brief EGL video output module
+ * @brief EGL OpenGL extension module
  */
 /*****************************************************************************
- * Copyright © 2010 Rémi Denis-Courmont
+ * Copyright © 2010-2011 Rémi Denis-Courmont
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- ****************************************************************************/
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_vout_display.h>
-#include <vlc_vout_opengl.h>
-#include "opengl.h"
+#include <vlc_opengl.h>
+#include <vlc_vout_window.h>
 #ifdef __unix__
 # include <vlc_xlib.h>
 #endif
 
-#if USE_OPENGL_ES
-# define VLC_API_NAME "OpenGL_ES"
-# define VLC_API EGL_OPENGL_ES_API
-# if USE_OPENGL_ES == 2
-#  define VLC_RENDERABLE_BIT EGL_OPENGL_ES2_BIT
-# else
-#  define VLC_RENDERABLE_BIT EGL_OPENGL_ES_BIT
-# endif
-#else
-# define VLC_API_NAME "OpenGL"
-# define VLC_API EGL_OPENGL_API
-# define VLC_RENDERABLE_BIT EGL_OPENGL_BIT
-#endif
-
-#ifdef __unix__
-# include <dlfcn.h>
-#endif
-
 /* Plugin callbacks */
-static int Open (vlc_object_t *);
+static int OpenGLES2 (vlc_object_t *);
+static int OpenGLES (vlc_object_t *);
+static int OpenGL (vlc_object_t *);
 static void Close (vlc_object_t *);
 
 vlc_module_begin ()
     set_shortname (N_("EGL"))
-    set_description (N_("EGL video output"))
+    set_description (N_("EGL extension for OpenGL"))
     set_category (CAT_VIDEO)
     set_subcategory (SUBCAT_VIDEO_VOUT)
-    set_capability ("vout display", 0)
-    set_callbacks (Open, Close)
+    set_capability ("opengl", 50)
+    set_callbacks (OpenGL, Close)
+
+    add_submodule ()
+    set_capability ("opengl es2", 50)
+    set_callbacks (OpenGLES2, Close)
+
+    add_submodule ()
+    set_capability ("opengl es", 50)
+    set_callbacks (OpenGLES, Close)
+
 vlc_module_end ()
 
-struct vout_display_sys_t
+typedef struct vlc_gl_sys_t
 {
     EGLDisplay display;
     EGLSurface surface;
+    EGLContext context;
+} vlc_gl_sys_t;
 
-    vout_opengl_t gl;
-    vout_display_opengl_t vgl;
-
-    picture_pool_t *pool;
-    vout_window_t *window;
-};
-
-/* Display callbacks */
-static picture_pool_t *Pool (vout_display_t *, unsigned);
-static void PictureRender (vout_display_t *, picture_t *);
-static void PictureDisplay (vout_display_t *, picture_t *);
-static int Control (vout_display_t *, int, va_list);
 /* OpenGL callbacks */
-static void SwapBuffers (vout_opengl_t *gl);
+static int MakeCurrent (vlc_gl_t *);
+static void ReleaseCurrent (vlc_gl_t *);
+static void SwapBuffers (vlc_gl_t *);
+static void *GetSymbol(vlc_gl_t *, const char *);
 
 static bool CheckAPI (EGLDisplay dpy, const char *api)
 {
@@ -96,6 +81,8 @@ static bool CheckAPI (EGLDisplay dpy, const char *api)
     /* Cannot use strtok_r() on constant string... */
     do
     {
+        while (*apis == ' ')
+            apis++;
         if (!strncmp (apis, api, apilen)
           && (memchr (" ", apis[apilen], 2) != NULL))
             return true;
@@ -107,45 +94,50 @@ static bool CheckAPI (EGLDisplay dpy, const char *api)
     return false;
 }
 
-static vout_window_t *MakeWindow (vout_display_t *vd, EGLNativeWindowType *id)
+struct gl_api
 {
-    vout_window_cfg_t wnd_cfg;
-
-    memset (&wnd_cfg, 0, sizeof (wnd_cfg));
-#if defined (WIN32)
-    wnd_cfg.type = VOUT_WINDOW_TYPE_HWND;
-#elif defined (__unix__)
-    wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
-#else
-# error Unknown native window type!
-#endif
-    wnd_cfg.x = var_InheritInteger (vd, "video-x");
-    wnd_cfg.y = var_InheritInteger (vd, "video-y");
-    wnd_cfg.width  = vd->cfg->display.width;
-    wnd_cfg.height = vd->cfg->display.height;
-
-    vout_window_t *wnd = vout_display_NewWindow (vd, &wnd_cfg);
-    if (wnd != NULL)
-#if defined (WIN32)
-        *id = wnd->handle.hwnd;
-#elif defined (__unix__)
-        *id = wnd->handle.xid;
-#endif
-    else
-        msg_Err (vd, "parent window not available");
-    return wnd;
-}
+   const char name[10];
+   EGLenum    api;
+   EGLint     min_minor;
+   EGLint     render_bit;
+   EGLint     attr[3];
+};
 
 /**
  * Probe EGL display availability
  */
-static int Open (vlc_object_t *obj)
+static int Open (vlc_object_t *obj, const struct gl_api *api)
 {
-#ifdef __unix__
+    vlc_gl_t *gl = (vlc_gl_t *)obj;
+
+    /* <EGL/eglplatform.h> defines the list and order of platforms */
+#if defined(_WIN32) || defined(__VC32__) \
+ && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+# define vlc_eglGetWindow(w) ((w)->handle.hwnd)
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */
+# error Symbian EGL not supported.
+
+#elif defined(WL_EGL_PLATFORM)
+# error Wayland EGL not supported.
+
+#elif defined(__GBM__)
+# error Glamor EGL not supported.
+
+#elif defined(ANDROID)
+# error Android EGL not supported
+
+#elif defined(__unix__) /* X11 */
+# define vlc_eglGetWindow(w) ((w)->handle.xid)
+    /* EGL can only use the default X11 display */
+    if (gl->surface->display.x11 != NULL)
+        return VLC_EGENERIC;
     if (!vlc_xlib_init (obj))
         return VLC_EGENERIC;
+
+#else
+# error EGL platform not recognized.
 #endif
-    vout_display_t *vd = (vout_display_t *)obj;
 
     /* Initialize EGL display */
     /* TODO: support various display types */
@@ -153,24 +145,11 @@ static int Open (vlc_object_t *obj)
     if (dpy == EGL_NO_DISPLAY)
         return VLC_EGENERIC;
 
-    vout_display_sys_t *sys = malloc (sizeof (*sys));
+    vlc_gl_sys_t *sys = malloc (sizeof (*sys));
     if (unlikely(sys == NULL))
         return VLC_ENOMEM;
-    vd->sys = sys;
+    gl->sys = sys;
     sys->display = dpy;
-    sys->gl.sys = NULL;
-    sys->pool = NULL;
-
-    /* XXX Explicit hack!
-     * Mesa EGL plugins (as of version 7.8.2) are not properly linked to
-     * libEGL.so even though they import some of its symbols. This is
-     * typically not a problem. Unfortunately, LibVLC loads plugins as
-     * RTLD_LOCAL so that they do not pollute the namespace. Then the
-     * libEGL symbols are not visible to EGL plugins, and the run-time
-     * linker exits the whole process. */
-#ifdef __unix__
-    dlopen ("libEGL.so", RTLD_GLOBAL|RTLD_LAZY);
-#endif
 
     EGLint major, minor;
     if (eglInitialize (dpy, &major, &minor) != EGL_TRUE)
@@ -180,18 +159,8 @@ static int Open (vlc_object_t *obj)
         return VLC_EGENERIC;
     }
 
-    if (major != 1)
-        goto abort;
-#if USE_OPENGL_ES == 2
-    if (minor < 3) /* Well well, this wouldn't compile with 1.2 anyway */
-        goto abort;
-#elif USE_OPENGL_ES == 0
-    if (minor < 4)
-        goto abort;
-#endif
-
-    if (!CheckAPI (dpy, VLC_API_NAME))
-        goto abort;
+    if (major != 1 || minor < api->min_minor || !CheckAPI (dpy, api->name))
+        goto error;
 
     msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION),
              eglQueryString (dpy, EGL_VENDOR));
@@ -201,11 +170,11 @@ static int Open (vlc_object_t *obj)
             msg_Dbg (obj, " extensions: %s", ext);
     }
 
-    static const EGLint conf_attr[] = {
+    const EGLint conf_attr[] = {
         EGL_RED_SIZE, 5,
         EGL_GREEN_SIZE, 5,
         EGL_BLUE_SIZE, 5,
-        EGL_RENDERABLE_TYPE, VLC_RENDERABLE_BIT,
+        EGL_RENDERABLE_TYPE, api->render_bit,
         EGL_NONE
     };
     EGLConfig cfgv[1];
@@ -213,14 +182,13 @@ static int Open (vlc_object_t *obj)
 
     if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
      || cfgc == 0)
-        goto abort;
+    {
+        msg_Err (obj, "cannot choose EGL configuration");
+        goto error;
+    }
 
     /* Create a drawing surface */
-    EGLNativeWindowType win;
-    sys->window = MakeWindow (vd, &win);
-    if (sys->window == NULL)
-        goto abort;
-
+    EGLNativeWindowType win = vlc_eglGetWindow(gl->surface);
     EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL);
     if (surface == EGL_NO_SURFACE)
     {
@@ -229,186 +197,99 @@ static int Open (vlc_object_t *obj)
     }
     sys->surface = surface;
 
-    if (eglBindAPI (VLC_API) != EGL_TRUE)
+    if (eglBindAPI (api->api) != EGL_TRUE)
     {
         msg_Err (obj, "cannot bind EGL API");
         goto error;
     }
 
-    static const EGLint ctx_attr[] = {
-#if USE_OPENGL_ES
-        EGL_CONTEXT_CLIENT_VERSION, USE_OPENGL_ES,
-#endif
-        EGL_NONE
-    };   
-
     EGLContext ctx = eglCreateContext (dpy, cfgv[0], EGL_NO_CONTEXT,
-                                       ctx_attr);
+                                       api->attr);
     if (ctx == EGL_NO_CONTEXT)
     {
         msg_Err (obj, "cannot create EGL context");
         goto error;
     }
-
-    if (eglMakeCurrent (dpy, surface, surface, ctx) != EGL_TRUE)
-        goto error;
+    sys->context = ctx;
 
     /* Initialize OpenGL callbacks */
-    sys->gl.lock = NULL;
-    sys->gl.unlock = NULL;
-    sys->gl.swap = SwapBuffers;
-    sys->gl.sys = sys;
-
-    if (vout_display_opengl_Init (&sys->vgl, &vd->fmt, &sys->gl))
-        goto error;
-
-    /* Initialize video display */
-    vd->info.has_pictures_invalid = false;
-    vd->info.has_event_thread = false;
-    vd->pool = Pool;
-    vd->prepare = PictureRender;
-    vd->display = PictureDisplay;
-    vd->control = Control;
-    vd->manage = NULL;
-
+    gl->sys = sys;
+    gl->makeCurrent = MakeCurrent;
+    gl->releaseCurrent = ReleaseCurrent;
+    gl->swap = SwapBuffers;
+    gl->getProcAddress = GetSymbol;
+    gl->lock = NULL;
+    gl->unlock = NULL;
     return VLC_SUCCESS;
+
 error:
-    vout_display_DeleteWindow (vd, sys->window);
-abort:
-    eglTerminate (dpy);
-    free (sys);
+    Close (obj);
     return VLC_EGENERIC;
 }
 
-
-/**
- * Destrisconnect from the X server.
- */
-static void Close (vlc_object_t *obj)
+static int OpenGLES2 (vlc_object_t *obj)
 {
-    vout_display_t *vd = (vout_display_t *)obj;
-    vout_display_sys_t *sys = vd->sys;
-    EGLDisplay dpy = sys->display;
-
-    if (sys->gl.sys != NULL)
-        vout_display_opengl_Clean (&sys->vgl);
-    eglTerminate (dpy);
-    vout_display_DeleteWindow (vd, sys->window);
-    free (sys);
+    static const struct gl_api api = {
+        "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
+        { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
+    };
+    return Open (obj, &api);
 }
 
-static void SwapBuffers (vout_opengl_t *gl)
+static int OpenGLES (vlc_object_t *obj)
 {
-    vout_display_sys_t *sys = gl->sys;
+    static const struct gl_api api = {
+        "OpenGL_ES", EGL_OPENGL_ES_API, 0, EGL_OPENGL_ES_BIT,
+        { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
+    };
+    return Open (obj, &api);
+}
 
-    eglSwapBuffers (sys->display, sys->surface);
+static int OpenGL (vlc_object_t *obj)
+{
+    static const struct gl_api api = {
+        "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
+        { EGL_NONE },
+    };
+    return Open (obj, &api);
 }
 
-/**
- * Return a direct buffer
- */
-static picture_pool_t *Pool (vout_display_t *vd, unsigned count)
+static void Close (vlc_object_t *obj)
 {
-    vout_display_sys_t *sys = vd->sys;
+    vlc_gl_t *gl = (vlc_gl_t *)obj;
+    vlc_gl_sys_t *sys = gl->sys;
 
-    if (!sys->pool)
-        sys->pool = vout_display_opengl_GetPool (&sys->vgl);
-    (void) count;
-    return sys->pool;
+    eglTerminate (sys->display);
+    free (sys);
 }
 
-static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
+static int MakeCurrent (vlc_gl_t *gl)
 {
-    vout_display_sys_t *sys = vd->sys;
+    vlc_gl_sys_t *sys = gl->sys;
 
-    vout_display_opengl_Prepare (&sys->vgl, pic);
-    (void)subpicture;
+    if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
+                        sys->context) != EGL_TRUE)
+        return VLC_EGENERIC;
+    return VLC_SUCCESS;
 }
 
-static void PictureDisplay (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
+static void ReleaseCurrent (vlc_gl_t *gl)
 {
-    vout_display_sys_t *sys = vd->sys;
+    vlc_gl_sys_t *sys = gl->sys;
 
-    vout_display_opengl_Display (&sys->vgl, &vd->source);
-    picture_Release (pic);
-    (void)subpicture;
+    eglMakeCurrent (sys->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                    EGL_NO_CONTEXT);
 }
 
-static int Control (vout_display_t *vd, int query, va_list ap)
+static void SwapBuffers (vlc_gl_t *gl)
 {
-    vout_display_sys_t *sys = vd->sys;
+    vlc_gl_sys_t *sys = gl->sys;
 
-    switch (query)
-    {
-      case VOUT_DISPLAY_HIDE_MOUSE:
-      case VOUT_DISPLAY_RESET_PICTURES: // not needed?
-          break;
-
-      case VOUT_DISPLAY_CHANGE_FULLSCREEN:
-      {
-        const vout_display_cfg_t *cfg =
-            va_arg (ap, const vout_display_cfg_t *);
-
-        return vout_window_SetFullScreen (sys->window, cfg->is_fullscreen);
-      }
-
-      case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
-      {
-        unsigned state = va_arg (ap, unsigned);
-
-        return vout_window_SetState (sys->window, state);
-      }
-
-      case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
-      case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
-      case VOUT_DISPLAY_CHANGE_ZOOM:
-      {
-        const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *);
-        const video_format_t *src = &vd->source;
-
-        if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
-        {
-            bool force = false;
-
-            force = va_arg (ap, int);
-            if (force
-             && (cfg->display.width  != vd->cfg->display.width
-              || cfg->display.height != vd->cfg->display.height)
-             && vout_window_SetSize (sys->window,
-                                     cfg->display.width, cfg->display.height))
-                return VLC_EGENERIC;
-        }
-
-        vout_display_place_t place;
-
-        vout_display_PlacePicture (&place, src, cfg, false);
-        glViewport (0, 0, place.width, place.height);
-        return VLC_SUCCESS;
-      }
-
-      case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
-      case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
-      {
-        const vout_display_cfg_t *cfg = vd->cfg;
-        const video_format_t *src = va_arg (ap, const video_format_t *);
-        vout_display_place_t place;
-
-        vout_display_PlacePicture (&place, src, cfg, false);
-        glViewport (0, 0, place.width, place.height);
-        return VLC_SUCCESS;
-      }
-
-      case VOUT_DISPLAY_GET_OPENGL:
-      {
-        vout_opengl_t **gl = va_arg (ap, vout_opengl_t **);
-
-        *gl = &sys->gl;
-        return VLC_SUCCESS;
-      }
-
-      default:
-        msg_Err (vd, "Unknown request %d", query);
-    }
-    return VLC_EGENERIC;
+    eglSwapBuffers (sys->display, sys->surface);
 }
 
+static void *GetSymbol(vlc_gl_t *gl, const char *procname)
+{
+    (void) gl;
+    return (void *)eglGetProcAddress (procname);
+}