Commit e55de111 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

EGL: convert to OpenGL provider

parent 801fcb35
/** /**
* @file egl.c * @file egl.c
* @brief EGL video output module * @brief EGL OpenGL extension module
*/ */
/***************************************************************************** /*****************************************************************************
* Copyright © 2010-2011 Rémi Denis-Courmont * Copyright © 2010-2011 Rémi Denis-Courmont
...@@ -30,63 +30,47 @@ ...@@ -30,63 +30,47 @@
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_vout_display.h>
#include <vlc_opengl.h> #include <vlc_opengl.h>
#include "opengl.h" #include <vlc_vout_window.h>
#ifdef __unix__ #ifdef __unix__
# include <vlc_xlib.h> # 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> # include <dlfcn.h>
#endif #endif
/* Plugin callbacks */ /* 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 *); static void Close (vlc_object_t *);
vlc_module_begin () vlc_module_begin ()
set_shortname (N_("EGL")) set_shortname (N_("EGL"))
set_description (N_("EGL video output")) set_description (N_("EGL extension for OpenGL"))
set_category (CAT_VIDEO) set_category (CAT_VIDEO)
set_subcategory (SUBCAT_VIDEO_VOUT) set_subcategory (SUBCAT_VIDEO_VOUT)
set_capability ("vout display", 0) set_capability ("opengl", 50)
set_callbacks (Open, Close) 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 () vlc_module_end ()
struct vout_display_sys_t typedef struct vlc_gl_sys_t
{ {
EGLDisplay display; EGLDisplay display;
EGLSurface surface; EGLSurface surface;
EGLContext context;
} vlc_gl_sys_t;
vlc_gl_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 *, subpicture_t *);
static void PictureDisplay (vout_display_t *, picture_t *, subpicture_t *);
static int Control (vout_display_t *, int, va_list);
/* OpenGL callbacks */ /* OpenGL callbacks */
static void SwapBuffers (vlc_gl_t *gl); static int MakeCurrent (vlc_gl_t *);
static void SwapBuffers (vlc_gl_t *);
static bool CheckAPI (EGLDisplay dpy, const char *api) static bool CheckAPI (EGLDisplay dpy, const char *api)
{ {
...@@ -107,45 +91,29 @@ static bool CheckAPI (EGLDisplay dpy, const char *api) ...@@ -107,45 +91,29 @@ static bool CheckAPI (EGLDisplay dpy, const char *api)
return false; return false;
} }
static vout_window_t *MakeWindow (vout_display_t *vd, EGLNativeWindowType *id) struct gl_api
{ {
vout_window_cfg_t wnd_cfg; const char name[10];
EGLenum api;
memset (&wnd_cfg, 0, sizeof (wnd_cfg)); EGLint min_minor;
#if defined (WIN32) EGLint render_bit;
wnd_cfg.type = VOUT_WINDOW_TYPE_HWND; EGLint attr[3];
#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;
}
/** /**
* Probe EGL display availability * Probe EGL display availability
*/ */
static int Open (vlc_object_t *obj) static int Open (vlc_object_t *obj, const struct gl_api *api)
{ {
vlc_gl_t *gl = (vlc_gl_t *)obj;
#ifdef __unix__ #ifdef __unix__
/* EGL can only use the default X11 display */
if (gl->surface->display.x11 != NULL)
return VLC_EGENERIC;
if (!vlc_xlib_init (obj)) if (!vlc_xlib_init (obj))
return VLC_EGENERIC; return VLC_EGENERIC;
#endif #endif
vout_display_t *vd = (vout_display_t *)obj;
/* Initialize EGL display */ /* Initialize EGL display */
/* TODO: support various display types */ /* TODO: support various display types */
...@@ -153,13 +121,11 @@ static int Open (vlc_object_t *obj) ...@@ -153,13 +121,11 @@ static int Open (vlc_object_t *obj)
if (dpy == EGL_NO_DISPLAY) if (dpy == EGL_NO_DISPLAY)
return VLC_EGENERIC; return VLC_EGENERIC;
vout_display_sys_t *sys = malloc (sizeof (*sys)); vlc_gl_sys_t *sys = malloc (sizeof (*sys));
if (unlikely(sys == NULL)) if (unlikely(sys == NULL))
return VLC_ENOMEM; return VLC_ENOMEM;
vd->sys = sys; gl->sys = sys;
sys->display = dpy; sys->display = dpy;
sys->gl.sys = NULL;
sys->pool = NULL;
#ifdef __unix__ #ifdef __unix__
/* XXX Explicit hack! /* XXX Explicit hack!
...@@ -183,18 +149,8 @@ static int Open (vlc_object_t *obj) ...@@ -183,18 +149,8 @@ static int Open (vlc_object_t *obj)
return VLC_EGENERIC; return VLC_EGENERIC;
} }
if (major != 1) if (major != 1 || minor < api->min_minor || !CheckAPI (dpy, api->name))
goto abort; goto error;
#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;
msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION), msg_Dbg (obj, "EGL version %s by %s", eglQueryString (dpy, EGL_VERSION),
eglQueryString (dpy, EGL_VENDOR)); eglQueryString (dpy, EGL_VENDOR));
...@@ -204,11 +160,11 @@ static int Open (vlc_object_t *obj) ...@@ -204,11 +160,11 @@ static int Open (vlc_object_t *obj)
msg_Dbg (obj, " extensions: %s", ext); msg_Dbg (obj, " extensions: %s", ext);
} }
static const EGLint conf_attr[] = { const EGLint conf_attr[] = {
EGL_RED_SIZE, 5, EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 5, EGL_GREEN_SIZE, 5,
EGL_BLUE_SIZE, 5, EGL_BLUE_SIZE, 5,
EGL_RENDERABLE_TYPE, VLC_RENDERABLE_BIT, EGL_RENDERABLE_TYPE, api->render_bit,
EGL_NONE EGL_NONE
}; };
EGLConfig cfgv[1]; EGLConfig cfgv[1];
...@@ -216,13 +172,14 @@ static int Open (vlc_object_t *obj) ...@@ -216,13 +172,14 @@ static int Open (vlc_object_t *obj)
if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE if (eglChooseConfig (dpy, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
|| cfgc == 0) || cfgc == 0)
goto abort; goto error;
/* Create a drawing surface */ /* Create a drawing surface */
EGLNativeWindowType win; #if defined (WIN32)
sys->window = MakeWindow (vd, &win); EGLNativeWindowType win = gl->surface->handle.hwnd;
if (sys->window == NULL) #elif defined (__unix__)
goto abort; EGLNativeWindowType win = gl->surface->handle.xid;
#endif
EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL); EGLSurface surface = eglCreateWindowSurface (dpy, cfgv[0], win, NULL);
if (surface == EGL_NO_SURFACE) if (surface == EGL_NO_SURFACE)
...@@ -232,186 +189,83 @@ static int Open (vlc_object_t *obj) ...@@ -232,186 +189,83 @@ static int Open (vlc_object_t *obj)
} }
sys->surface = surface; sys->surface = surface;
if (eglBindAPI (VLC_API) != EGL_TRUE) if (eglBindAPI (api->api) != EGL_TRUE)
{ {
msg_Err (obj, "cannot bind EGL API"); msg_Err (obj, "cannot bind EGL API");
goto error; 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, EGLContext ctx = eglCreateContext (dpy, cfgv[0], EGL_NO_CONTEXT,
ctx_attr); api->attr);
if (ctx == EGL_NO_CONTEXT) if (ctx == EGL_NO_CONTEXT)
{ {
msg_Err (obj, "cannot create EGL context"); msg_Err (obj, "cannot create EGL context");
goto error; goto error;
} }
sys->context = ctx;
if (eglMakeCurrent (dpy, surface, surface, ctx) != EGL_TRUE)
goto error;
/* Initialize OpenGL callbacks */ /* Initialize OpenGL callbacks */
sys->gl.lock = NULL; gl->sys = sys;
sys->gl.unlock = NULL; gl->makeCurrent = MakeCurrent;
sys->gl.swap = SwapBuffers; gl->swap = SwapBuffers;
sys->gl.sys = sys; gl->lock = NULL;
gl->unlock = NULL;
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;
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
vout_display_DeleteWindow (vd, sys->window); Close (obj);
abort:
eglTerminate (dpy);
free (sys);
return VLC_EGENERIC; return VLC_EGENERIC;
} }
static int OpenGLES2 (vlc_object_t *obj)
/**
* Destrisconnect from the X server.
*/
static void Close (vlc_object_t *obj)
{ {
vout_display_t *vd = (vout_display_t *)obj; static const struct gl_api api = {
vout_display_sys_t *sys = vd->sys; "OpenGL_ES", EGL_OPENGL_ES_API, 3, EGL_OPENGL_ES2_BIT,
EGLDisplay dpy = sys->display; { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE },
};
if (sys->gl.sys != NULL) return Open (obj, &api);
vout_display_opengl_Clean (&sys->vgl);
eglTerminate (dpy);
vout_display_DeleteWindow (vd, sys->window);
free (sys);
} }
static void SwapBuffers (vlc_gl_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,
eglSwapBuffers (sys->display, sys->surface); { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE },
};
return Open (obj, &api);
} }
/** static int OpenGL (vlc_object_t *obj)
* Return a direct buffer
*/
static picture_pool_t *Pool (vout_display_t *vd, unsigned count)
{ {
vout_display_sys_t *sys = vd->sys; static const struct gl_api api = {
"OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
if (!sys->pool) { EGL_NONE },
sys->pool = vout_display_opengl_GetPool (&sys->vgl); };
(void) count; return Open (obj, &api);
return sys->pool;
} }
static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture) 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;
vout_display_opengl_Prepare (&sys->vgl, pic); eglTerminate (sys->display);
(void)subpicture; free (sys);
} }
static void PictureDisplay (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_Display (&sys->vgl, &vd->source); if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
picture_Release (pic); sys->context) != EGL_TRUE)
(void)subpicture; return VLC_EGENERIC;
return VLC_SUCCESS;
} }
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) eglSwapBuffers (sys->display, sys->surface);
{
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:
{
vlc_gl_t **gl = va_arg (ap, vlc_gl_t **);
*gl = &sys->gl;
return VLC_SUCCESS;
}
default:
msg_Err (vd, "Unknown request %d", query);
}
return VLC_EGENERIC;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment