wayland: add wayland support

All wayland only specific routines are placed in wayland_common.
This makes it easier to write other video outputs.

The EGL specific parts, as well as opengl context creation, are in gl_common.

This backend works for:
    * opengl-old
    * opengl
    * opengl-hq

To use it just specify the opengl backend
    --vo=opengl:backend=wayland
or disable the x11 build.

Don't forget to set EGL_PLATFORM to wayland.

Co-Author: Scott Moreau
(Sorry I lost the old commit history due to the file structure changes)
This commit is contained in:
Alexander Preisinger 2013-02-28 19:55:02 +01:00
parent f143eec611
commit bf9b9c3bd0
10 changed files with 1506 additions and 4 deletions

View File

@ -386,6 +386,8 @@ opengl
Win32/WGL
x11
X11/GLX
wayland
Wayland/EGL
indirect
Do YUV conversion and scaling as separate passes. This will
@ -643,6 +645,8 @@ opengl-old
Win32/WGL
x11
X11/GLX
waylnad
Wayland/EGL
sdl
SDL 2.0+ Render video output driver, depending on system with or without

View File

@ -99,6 +99,7 @@ SOURCES-$(ENCODING) += video/out/vo_lavc.c audio/out/ao_lavc.c \
core/encode_lavc.c
SOURCES-$(GL_WIN32) += video/out/w32_common.c
SOURCES-$(GL_X11) += video/out/x11_common.c
SOURCES-$(GL_WAYLAND) += video/out/wayland_common.c
SOURCES-$(JACK) += audio/out/ao_jack.c
SOURCES-$(JOYSTICK) += core/input/joystick.c

38
configure vendored
View File

@ -353,6 +353,7 @@ Video output:
--enable-vm enable XF86VidMode support [autodetect]
--enable-xinerama enable Xinerama support [autodetect]
--enable-x11 enable X11 video output [autodetect]
--enable-wayland enable Wayland video output [autodetect]
--disable-xss disable screensaver support via xss [autodetect]
--disable-corevideo disable CoreVideo video output [autodetect]
--disable-cocoa disable Cocoa OpenGL backend [autodetect]
@ -416,6 +417,7 @@ _prefix="/usr/local"
ffmpeg=auto
_encoding=yes
_x11=auto
_wayland=auto
_xss=auto
_xv=auto
_vdpau=auto
@ -576,6 +578,8 @@ for ac_option do
--disable-cross-compile) _cross_compile=no ;;
--enable-encoding) _encoding=yes ;;
--disable-encoding) _encoding=no ;;
--enable-wayland) _wayland=yes ;;
--disable-wayland) _wayland=no ;;
--enable-x11) _x11=yes ;;
--disable-x11) _x11=no ;;
--enable-xss) _xss=yes ;;
@ -1829,6 +1833,17 @@ depends_on_application_services(){
fi #if darwin
echocheck "Wayland"
if test "$_wayland" != no; then
_wayland="no"
pkg_config_add "wayland-client >= 1.0.0 wayland-egl >= 1.0.0 wayland-cursor >= 1.0.0 xkbcommon >= 0.2.0" \
&& _wayland="yes"
res_comment=""
else
_wayland="no"
res_comment=""
fi
echores "$_wayland"
echocheck "X11 headers presence"
_x11_headers="no"
@ -2105,20 +2120,23 @@ fi
# conflicts between -lGL and -framework OpenGL
echocheck "OpenGL"
#Note: this test is run even with --enable-gl since we autodetect linker flags
if (test "$_x11" = yes || test "$_cocoa" = yes || win32) && test "$_gl" != no ; then
if (test "$_x11" = yes || test "$_wayland" = yes || test "$_cocoa" = yes || win32) && test "$_gl" != no ; then
cat > $TMPC << EOF
#ifdef GL_WIN32
#include <windows.h>
#include <GL/gl.h>
#elif defined(GL_WAYLAND)
#include <EGL/egl.h>
#else
#include <GL/gl.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#endif
#include <GL/gl.h>
int main(int argc, char *argv[]) {
#ifdef GL_WIN32
HDC dc;
wglCreateContext(dc);
#elif defined(GL_WAYLAND)
eglCreateContext(NULL, NULL, EGL_NO_CONTEXT, NULL);
#else
glXCreateContext(NULL, NULL, NULL, True);
#endif
@ -2137,6 +2155,11 @@ EOF
fi
done
fi
if test "$_wayland" = yes && cc_check -DGL_WAYLAND -lGL -lEGL ; then
_gl=yes
_gl_wayland=yes
libs_mplayer="$libs_mplayer -lGL -lEGL"
fi
if win32 && cc_check -DGL_WIN32 -lopengl32 ; then
_gl=yes
_gl_win32=yes
@ -2164,12 +2187,17 @@ if test "$_gl" = yes ; then
def_gl_x11='#define CONFIG_GL_X11 1'
res_comment="$res_comment x11"
fi
if test "$_gl_wayland" = yes ; then
def_gl_wayland='#define CONFIG_GL_WAYLAND'
res_comment="$res_comment wayland"
fi
vomodules="opengl $vomodules"
else
def_gl='#undef CONFIG_GL'
def_gl_cocoa='#undef CONFIG_GL_COCOA'
def_gl_win32='#undef CONFIG_GL_WIN32'
def_gl_x11='#undef CONFIG_GL_X11'
def_gl_wayland='#undef CONFIG_GL_WAYLAND'
novomodules="opengl $novomodules"
fi
echores "$_gl"
@ -3015,6 +3043,7 @@ GL = $_gl
GL_COCOA = $_gl_cocoa
GL_WIN32 = $_gl_win32
GL_X11 = $_gl_x11
GL_WAYLAND = $_gl_wayland
HAVE_POSIX_SELECT = $_posix_select
HAVE_SYS_MMAN_H = $_mman
JACK = $_jack
@ -3056,6 +3085,7 @@ VCD = $_vcd
VDPAU = $_vdpau
VSTREAM = $_vstream
X11 = $_x11
WAYLAND = $_wayland
XV = $_xv
# FFmpeg
@ -3251,12 +3281,14 @@ $def_gl
$def_gl_cocoa
$def_gl_win32
$def_gl_x11
$def_gl_wayland
$def_jpeg
$def_mng
$def_v4l2
$def_vdpau
$def_vm
$def_x11
$def_wayland
$def_xdpms
$def_xf86keysym
$def_xinerama

View File

@ -1302,6 +1302,259 @@ static void swapGlBuffers_x11(MPGLContext *ctx)
}
#endif
#ifdef CONFIG_GL_WAYLAND
#include "wayland_common.h"
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <assert.h>
struct egl_context {
EGLSurface egl_surface;
struct wl_egl_window *egl_window;
struct {
EGLDisplay dpy;
EGLContext ctx;
EGLConfig conf;
} egl;
};
static void egl_resize_func(struct vo_wayland_state *wl,
struct egl_context *ctx)
{
int32_t x, y, scaled_height;
double ratio;
int minimum_size = 50;
if (wl->window->pending_width < minimum_size)
wl->window->pending_width = minimum_size;
if (wl->window->pending_height < minimum_size)
wl->window->pending_height = minimum_size;
ratio = (double) wl->vo->aspdat.orgw / wl->vo->aspdat.orgh;
scaled_height = wl->window->pending_height * ratio;
if (wl->window->pending_width > scaled_height) {
wl->window->pending_height = wl->window->pending_width / ratio;
} else {
wl->window->pending_width = scaled_height;
}
if (wl->window->edges & WL_SHELL_SURFACE_RESIZE_LEFT)
x = wl->window->width - wl->window->pending_width;
else
x = 0;
if (wl->window->edges & WL_SHELL_SURFACE_RESIZE_TOP)
y = wl->window->height - wl->window->pending_height;
else
y = 0;
wl_egl_window_resize(ctx->egl_window,
wl->window->pending_width,
wl->window->pending_height,
x, y);
wl->window->width = wl->window->pending_width;
wl->window->height = wl->window->pending_height;
/* set size for mplayer */
wl->vo->dwidth = wl->window->pending_width;
wl->vo->dheight = wl->window->pending_height;
wl->window->events |= VO_EVENT_RESIZE;
wl->window->edges = 0;
wl->window->resize_needed = 0;
}
static bool egl_create_context(struct vo_wayland_state *wl,
struct egl_context *egl_ctx,
MPGLContext *ctx)
{
EGLint major, minor, n;
EGLBoolean ret;
GL *gl = ctx->gl;
void *(*getProcAddress)(const GLubyte *);
const char *(*eglExtStr)(EGLDisplay *, int);
const char *eglstr = "";
egl_ctx->egl.dpy = eglGetDisplay(wl->display->display);
if (!egl_ctx->egl.dpy)
return false;
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
};
/* major and minor here returns the supported EGL version (e.g.: 1.4) */
ret = eglInitialize(egl_ctx->egl.dpy, &major, &minor);
if (ret != EGL_TRUE)
return false;
EGLint context_attribs[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR,
MPGL_VER_GET_MAJOR(ctx->requested_gl_version),
/* EGL_CONTEXT_MINOR_VERSION_KHR, */
/* MPGL_VER_GET_MINOR(ctx->requested_gl_version), */
/* EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, 0, */
/* Segfaults on anything else than the major version */
EGL_NONE
};
ret = eglBindAPI(EGL_OPENGL_API);
assert(ret == EGL_TRUE);
ret = eglChooseConfig(egl_ctx->egl.dpy, config_attribs,
&egl_ctx->egl.conf, 1, &n);
assert(ret && n == 1);
egl_ctx->egl.ctx = eglCreateContext(egl_ctx->egl.dpy,
egl_ctx->egl.conf,
EGL_NO_CONTEXT,
context_attribs);
if (!egl_ctx->egl.ctx)
return false;
ret = eglMakeCurrent(egl_ctx->egl.dpy,
NULL,
NULL,
egl_ctx->egl.ctx);
assert(ret == EGL_TRUE);
getProcAddress = getdladdr("eglGetProcAddress");
if (!getProcAddress)
mp_msg(MSGT_VO, MSGL_WARN, "[egl] No eglGetProcAdress");
eglExtStr = getdladdr("eglQueryString");
if (eglExtStr)
eglstr = eglExtStr(egl_ctx->egl.dpy, EGL_EXTENSIONS);
getFunctions(gl, (void*(*)(const GLubyte*))eglGetProcAddress, eglstr);
if (!gl->BindProgram)
getFunctions(gl, NULL, eglstr);
return true;
}
static void egl_create_window(struct vo_wayland_state *wl,
struct egl_context *egl_ctx,
uint32_t width,
uint32_t height)
{
EGLBoolean ret;
wl->window->pending_width = width;
wl->window->pending_height = height;
wl->window->width = width;
wl->window->height = height;
egl_ctx->egl_window = wl_egl_window_create(wl->window->surface,
wl->window->width,
wl->window->height);
egl_ctx->egl_surface = eglCreateWindowSurface(egl_ctx->egl.dpy,
egl_ctx->egl.conf,
egl_ctx->egl_window,
NULL);
ret = eglMakeCurrent(egl_ctx->egl.dpy,
egl_ctx->egl_surface,
egl_ctx->egl_surface,
egl_ctx->egl.ctx);
assert(ret == EGL_TRUE);
wl_display_dispatch_pending(wl->display->display);
}
static bool config_window_wayland(struct MPGLContext *ctx,
uint32_t d_width,
uint32_t d_height,
uint32_t flags)
{
struct egl_context * egl_ctx = ctx->priv;
struct vo_wayland_state * wl = ctx->vo->wayland;
bool ret = false;
wl->window->pending_width = d_width;
wl->window->pending_height = d_height;
wl->window->width = d_width;
wl->window->height = d_height;
vo_wayland_update_window_title(ctx->vo);
if ((VOFLAG_FULLSCREEN & flags) && wl->window->type != TYPE_FULLSCREEN)
vo_wayland_fullscreen(ctx->vo);
if (!egl_ctx->egl.ctx) {
/* Create OpenGL context */
ret = egl_create_context(wl, egl_ctx, ctx);
/* If successfully created the context and we don't want to hide the
* window than also create the window immediately */
if (ret && !(VOFLAG_HIDDEN & flags))
egl_create_window(wl, egl_ctx, d_width, d_height);
return ret;
}
else {
/* If the window exists just resize it */
if (egl_ctx->egl_window)
egl_resize_func(wl, egl_ctx);
else {
/* If the context exists and the hidden flag is unset then
* create the window */
if (!(VOFLAG_HIDDEN & flags))
egl_create_window(wl, egl_ctx, d_width, d_height);
}
return true;
}
}
static void releaseGlContext_wayland(MPGLContext *ctx)
{
GL *gl = ctx->gl;
struct egl_context * egl_ctx = ctx->priv;
gl->Finish();
eglMakeCurrent(egl_ctx->egl.dpy, NULL, NULL, EGL_NO_CONTEXT);
eglDestroyContext(egl_ctx->egl.dpy, egl_ctx->egl.ctx);
eglTerminate(egl_ctx->egl.dpy);
eglReleaseThread();
wl_egl_window_destroy(egl_ctx->egl_window);
egl_ctx->egl.ctx = NULL;
}
static void swapGlBuffers_wayland(MPGLContext *ctx)
{
struct egl_context * egl_ctx = ctx->priv;
struct vo_wayland_state *wl = ctx->vo->wayland;
eglSwapBuffers(egl_ctx->egl.dpy, egl_ctx->egl_surface);
/* resize window after the buffers have swapped
* makes resizing more fluid */
if (wl->window->resize_needed) {
wl_egl_window_get_attached_size(egl_ctx->egl_window,
&wl->window->width,
&wl->window->height);
egl_resize_func(wl, egl_ctx);
}
}
#endif
struct backend {
const char *name;
@ -1313,6 +1566,7 @@ static struct backend backends[] = {
{"cocoa", GLTYPE_COCOA},
{"win", GLTYPE_W32},
{"x11", GLTYPE_X11},
{"wayland", GLTYPE_WAYLAND},
{0}
};
@ -1335,7 +1589,10 @@ MPGLContext *mpgl_init(enum MPGLType type, struct vo *vo)
ctx = mpgl_init(GLTYPE_W32, vo);
if (ctx)
return ctx;
return mpgl_init(GLTYPE_X11, vo);
ctx = mpgl_init(GLTYPE_X11, vo);
if (ctx)
return ctx;
return mpgl_init(GLTYPE_WAYLAND, vo);
}
ctx = talloc_zero(NULL, MPGLContext);
*ctx = (MPGLContext) {
@ -1389,6 +1646,21 @@ MPGLContext *mpgl_init(enum MPGLType type, struct vo *vo)
ctx->vo_init = vo_x11_init;
ctx->vo_uninit = vo_x11_uninit;
break;
#endif
#ifdef CONFIG_GL_WAYLAND
case GLTYPE_WAYLAND:
ctx->priv = talloc_zero(ctx, struct egl_context);
ctx->config_window = config_window_wayland;
ctx->releaseGlContext = releaseGlContext_wayland;
ctx->swapGlBuffers = swapGlBuffers_wayland;
ctx->update_xinerama_info = vo_wayland_update_screeninfo;
ctx->border = vo_wayland_border;
ctx->check_events = vo_wayland_check_events;
ctx->fullscreen = vo_wayland_fullscreen;
ctx->ontop = vo_wayland_ontop;
ctx->vo_init = vo_wayland_init;
ctx->vo_uninit = vo_wayland_uninit;
break;
#endif
}
if (ctx->vo_init && ctx->vo_init(vo))

View File

@ -77,6 +77,7 @@ enum MPGLType {
GLTYPE_COCOA,
GLTYPE_W32,
GLTYPE_X11,
GLTYPE_WAYLAND,
};
enum {

View File

@ -248,6 +248,7 @@ struct vo {
struct vo_x11_state *x11;
struct vo_w32_state *w32;
struct vo_cocoa_state *cocoa;
struct vo_wayland_state *wayland;
struct mp_fifo *key_fifo;
struct encode_lavc_context *encode_lavc_ctx;
struct input_ctx *input_ctx;

View File

@ -2313,6 +2313,7 @@ static const char help_text[] =
" cocoa: Cocoa/OSX\n"
" win: Win32/WGL\n"
" x11: X11/GLX\n"
" wayland: Wayland/EGL\n"
" indirect\n"
" Do YUV conversion and scaling as separate passes. This will\n"
" first render the video into a video-sized RGB texture, and\n"

View File

@ -2243,6 +2243,7 @@ static int preinit(struct vo *vo, const char *arg)
" cocoa: Cocoa/OSX\n"
" win: Win32/WGL\n"
" x11: X11/GLX\n"
" wayland: Wayland/EGL\n"
"\n");
return -1;
}

1036
video/out/wayland_common.c Normal file

File diff suppressed because it is too large Load Diff

153
video/out/wayland_common.h Normal file
View File

@ -0,0 +1,153 @@
/*
* This file is part of MPlayer.
* Copyright © 2012-2013 Scott Moreau <oreaus@gmail.com>
* Copyright © 2012-2013 Alexander Preisinger <alexander.preisinger@gmail.com>
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer 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.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_WAYLAND_COMMON_H
#define MPLAYER_WAYLAND_COMMON_H
#include <stdint.h>
#include <stdbool.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <xkbcommon/xkbcommon.h>
#include "config.h"
enum vo_wayland_window_type {
TYPE_TOPLEVEL,
TYPE_FULLSCREEN
};
struct vo;
struct vo_wayland_state;
struct vo_wayland_task {
void (*run)(struct vo_wayland_task *task,
uint32_t events,
struct vo_wayland_state *wl);
struct wl_list link;
};
struct vo_wayland_output {
uint32_t id; /* unique name */
struct wl_output *output;
uint32_t flags;
int32_t width;
int32_t height;
struct wl_list link;
};
struct vo_wayland_display {
struct wl_output *output;
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shell *shell;
struct {
struct wl_shm *shm;
struct wl_cursor *default_cursor;
struct wl_cursor_theme *theme;
struct wl_surface *surface;
/* save timer and pointer for fading out */
struct wl_pointer *pointer;
uint32_t serial;
int timer_fd;
struct vo_wayland_task task;
} cursor;
int display_fd, epoll_fd;
struct vo_wayland_task display_task;
struct wl_list output_list;
struct wl_output *fs_output; /* fullscreen output */
int output_mode_received;
uint32_t formats;
uint32_t mask;
};
struct vo_wayland_window {
int32_t width;
int32_t height;
int32_t p_width;
int32_t p_height;
int32_t pending_width;
int32_t pending_height;
uint32_t edges;
int resize_needed;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
struct wl_buffer *buffer;
struct wl_callback *callback;
int events; /* mplayer events */
enum vo_wayland_window_type type; /* is fullscreen */
};
struct vo_wayland_input {
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;
struct {
struct xkb_context *context;
struct xkb_keymap *keymap;
struct xkb_state *state;
xkb_mod_mask_t shift_mask;
xkb_mod_mask_t control_mask;
xkb_mod_mask_t alt_mask;
} xkb;
int modifiers;
int events;
struct {
uint32_t sym;
uint32_t key;
uint32_t time;
int timer_fd;
struct vo_wayland_task task;
} repeat;
};
struct vo_wayland_state {
struct vo *vo;
struct vo_wayland_display *display;
struct vo_wayland_window *window;
struct vo_wayland_input *input;
};
int vo_wayland_init(struct vo *vo);
void vo_wayland_uninit(struct vo *vo);
void vo_wayland_ontop(struct vo *vo);
void vo_wayland_border(struct vo *vo);
void vo_wayland_fullscreen(struct vo *vo);
void vo_wayland_update_screeninfo(struct vo *vo);
int vo_wayland_check_events(struct vo *vo);
void vo_wayland_update_window_title(struct vo *vo);
#endif /* MPLAYER_WAYLAND_COMMON_H */