summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Preisinger <alexander.preisinger@gmail.com>2014-01-28 13:07:00 +0100
committerAlexander Preisinger <alexander.preisinger@gmail.com>2014-04-16 16:38:54 +0200
commit5528ad3031148ce19583ad8cd3c949fa4df4eb54 (patch)
tree220e9f1cbd6ca9799844c7df3c40db21e74570de
parent6fcec75baa6bb8b33be284aad108cf3f9920ef15 (diff)
downloadmpv-5528ad3031148ce19583ad8cd3c949fa4df4eb54.tar.bz2
mpv-5528ad3031148ce19583ad8cd3c949fa4df4eb54.tar.xz
wayland/shm: Use subsurfaces for OSD
-rw-r--r--video/out/gl_wayland.c2
-rw-r--r--video/out/vo_wayland.c121
-rw-r--r--video/out/wayland_common.c30
-rw-r--r--video/out/wayland_common.h9
4 files changed, 133 insertions, 29 deletions
diff --git a/video/out/gl_wayland.c b/video/out/gl_wayland.c
index 797f1648ac..3decda4bb6 100644
--- a/video/out/gl_wayland.c
+++ b/video/out/gl_wayland.c
@@ -131,7 +131,7 @@ static void egl_create_window(struct vo_wayland_state *wl,
uint32_t width,
uint32_t height)
{
- wl->egl_context.egl_window = wl_egl_window_create(wl->window.surface,
+ wl->egl_context.egl_window = wl_egl_window_create(wl->window.video_surface,
wl->window.width,
wl->window.height);
diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c
index 77f0eb9a97..715db800d2 100644
--- a/video/out/vo_wayland.c
+++ b/video/out/vo_wayland.c
@@ -48,7 +48,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi);
static const struct wl_callback_listener frame_listener;
static const struct wl_buffer_listener buffer_listener;
-static const struct wl_shm_listener shm_listener;
struct fmtentry {
enum wl_shm_format wl_fmt;
@@ -105,6 +104,7 @@ struct buffer {
bool to_resize;
void *shm_data;
size_t shm_size;
+ struct wl_shm_pool *shm_pool; // shares memory
};
struct buffer_pool {
@@ -145,6 +145,7 @@ struct priv {
struct wl_callback *redraw_callback;
struct buffer_pool video_bufpool;
+ struct buffer_pool osd_bufpool;
struct buffer *attached_buffer;
struct mp_image *original_image;
@@ -153,6 +154,9 @@ struct priv {
int x, y; // coords for resizing
+ // this id tells us if the subtitle part has changed or not
+ int bitmap_pos_id[MAX_OSD_PARTS];
+
// options
int enable_alpha;
int use_rgb565;
@@ -256,18 +260,16 @@ static const struct fmtentry * is_wayland_format_supported(struct priv *p,
// buffer functions
-static bool buffer_finalise_back(struct buffer *buf)
-{
- buf->is_new = true;
- return true;
-}
-
-static bool buffer_finalise_front(struct buffer *buf)
+static void buffer_finalise_front(struct buffer *buf)
{
buf->is_new = false; // is_busy is reset on handle_release
buf->is_busy = true;
buf->is_attached = true;
- return true;
+}
+
+static void buffer_finalise_back(struct buffer *buf)
+{
+ buf->is_new = true;
}
static void buffer_destroy_content(struct buffer *buf)
@@ -456,6 +458,14 @@ static struct buffer * buffer_pool_get_front(struct buffer_pool *pool)
return pool->front_buffer;
}
+static struct buffer * buffer_pool_get_no(struct buffer_pool *pool, uint32_t no)
+{
+ if (no >= pool->buffer_no)
+ return NULL;
+
+ return &pool->buffers[no];
+}
+
static bool redraw_frame(struct priv *p)
{
@@ -516,10 +526,24 @@ static bool resize(struct priv *p)
return false;
if (!buffer_pool_resize(&p->video_bufpool, p->dst_w, p->dst_h)) {
- MP_ERR(wl, "failed to resize buffers\n");
+ MP_ERR(wl, "failed to resize video buffers\n");
+ return false;
+ }
+ if (!buffer_pool_resize(&p->osd_bufpool, p->dst_w, p->dst_h)) {
+ MP_ERR(wl, "failed to resize osd buffers\n");
return false;
}
+ // attach NULL buffers to the surfaces to avoid artifacts
+ for (int i = 0; i < MAX_OSD_PARTS; ++i) {
+ wl_subsurface_set_desync(p->wl->window.osd_subsurfaces[i]);
+ struct wl_surface *s = p->wl->window.osd_surfaces[i];
+ wl_surface_attach(s, NULL, 0, 0);
+ wl_surface_damage(s, 0, 0, p->dst_w, p->dst_h);
+ wl_surface_commit(s);
+ wl_subsurface_set_sync(p->wl->window.osd_subsurfaces[i]);
+ }
+
wl->window.width = p->dst_w;
wl->window.height = p->dst_h;
@@ -529,7 +553,7 @@ static bool resize(struct priv *p)
struct wl_region *opaque =
wl_compositor_create_region(wl->display.compositor);
wl_region_add(opaque, 0, 0, p->dst_w, p->dst_h);
- wl_surface_set_opaque_region(wl->window.surface, opaque);
+ wl_surface_set_opaque_region(wl->window.video_surface, opaque);
wl_region_destroy(opaque);
}
@@ -564,18 +588,19 @@ static void frame_handle_redraw(void *data,
struct buffer *buf = buffer_pool_get_front(&p->video_bufpool);
if (buf) {
- wl_surface_attach(wl->window.surface, buf->wlbuf, p->x, p->y);
- wl_surface_damage(wl->window.surface, 0, 0, p->dst_w, p->dst_h);
+ wl_surface_attach(wl->window.video_surface, buf->wlbuf, p->x, p->y);
+ wl_surface_damage(wl->window.video_surface, 0, 0, p->dst_w, p->dst_h);
if (callback)
wl_callback_destroy(callback);
- p->redraw_callback = wl_surface_frame(wl->window.surface);
+ p->redraw_callback = wl_surface_frame(wl->window.video_surface);
wl_callback_add_listener(p->redraw_callback, &frame_listener, p);
- wl_surface_commit(wl->window.surface);
+ wl_surface_commit(wl->window.video_surface);
+ buffer_finalise_front(buf);
// resize attached buffer
- if (p->attached_buffer) {
+ if (p->attached_buffer) {
p->attached_buffer->is_attached = false;
buffer_resize(&p->video_bufpool, p->attached_buffer, p->dst_w, p->dst_h);
}
@@ -652,14 +677,64 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
buffer_finalise_back(buf);
}
+static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs)
+{
+ struct priv *p = ctx;
+ int id = imgs->render_index;
+
+ struct wl_surface *s = p->wl->window.osd_surfaces[id];
+ struct buffer * buf = buffer_pool_get_no(&p->osd_bufpool, id);
+ if (!buf)
+ return;
+
+ if (imgs->bitmap_pos_id != p->bitmap_pos_id[id]) {
+ p->bitmap_pos_id[id] = imgs->bitmap_pos_id;
+
+ struct mp_rect bb;
+ if (!mp_sub_bitmaps_bb(imgs, &bb))
+ return;
+
+ struct mp_image wlimg = buffer_get_mp_image(p, &p->osd_bufpool, buf);
+ mp_image_clear(&wlimg, 0, 0, wlimg.w, wlimg.h);
+
+ for (int n = 0; n < imgs->num_parts; n++) {
+ struct sub_bitmap *sub = &imgs->parts[n];
+
+ size_t dst = (bb.y0) * wlimg.stride[0] +
+ (bb.x0) * 4;
+
+ memcpy_pic(wlimg.planes[0] + dst, sub->bitmap, sub->w * 4, sub->h,
+ wlimg.stride[0], sub->stride);
+ }
+ wl_subsurface_set_position(p->wl->window.osd_subsurfaces[id], 0, 0);
+ wl_surface_attach(s, buf->wlbuf, 0, 0);
+ wl_surface_damage(s, bb.x0, bb.y0, bb.x1, bb.y1);
+ wl_surface_commit(s);
+ }
+ else {
+ wl_surface_attach(s, buf->wlbuf, 0, 0);
+ wl_surface_commit(s);
+ }
+}
+
+static const bool osd_formats[SUBBITMAP_COUNT] = {
+ [SUBBITMAP_RGBA] = true,
+};
+
static void draw_osd(struct vo *vo, struct osd_state *osd)
{
struct priv *p = vo->priv;
- struct buffer *buf = buffer_pool_get_back(&p->video_bufpool);
- if (buf) {
- struct mp_image img = buffer_get_mp_image(p, &p->video_bufpool, buf);
- osd_draw_on_image(osd, p->osd, osd_get_vo_pts(osd), 0, &img);
+ // deattach all buffers and attach all needed buffers in osd_draw
+ // only the most recent attach & commit is applied once the parent surface
+ // is committed
+ for (int i = 0; i < MAX_OSD_PARTS; ++i) {
+ struct wl_surface *s = p->wl->window.osd_surfaces[i];
+ wl_surface_attach(s, NULL, 0, 0);
+ wl_surface_damage(s, 0, 0, p->dst_w, p->dst_h);
+ wl_surface_commit(s);
}
+
+ osd_draw(osd, p->osd, osd_get_vo_pts(osd), 0, osd_formats, draw_osd_cb, p);
}
static void flip_page(struct vo *vo)
@@ -725,9 +800,10 @@ static int reconfig(struct vo *vo, struct mp_image_params *fmt, int flags)
p->video_format = entry;
}
-
buffer_pool_reinit(p, &p->video_bufpool, (p->use_triplebuffering ? 3 : 2),
- p->width, p->height, p->video_format, p->wl->display.shm);
+ p->width, p->height, p->video_format, p->wl->display.shm);
+ buffer_pool_reinit(p, &p->osd_bufpool, MAX_OSD_PARTS, p->width, p->height,
+ &fmttable[DEFAULT_ALPHA_FORMAT_ENTRY], p->wl->display.shm);
vo_wayland_config(vo, vo->dwidth, vo->dheight, flags);
@@ -741,6 +817,7 @@ static void uninit(struct vo *vo)
{
struct priv *p = vo->priv;
buffer_pool_destroy(&p->video_bufpool);
+ buffer_pool_destroy(&p->osd_bufpool);
if (p->redraw_callback)
wl_callback_destroy(p->redraw_callback);
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index b60fa6fb0a..3d803ffb42 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -610,6 +610,12 @@ static void registry_handle_global (void *data,
wl->input.devman, wl->input.seat);
wl_data_device_add_listener(wl->input.datadev, &data_device_listener, wl);
}
+
+ else if (strcmp(interface, "wl_subcompositor") == 0) {
+
+ wl->display.subcomp = wl_registry_bind(reg, id,
+ &wl_subcompositor_interface, 1);
+ }
}
static void registry_handle_global_remove (void *data,
@@ -793,9 +799,23 @@ static void destroy_display (struct vo_wayland_state *wl)
static bool create_window (struct vo_wayland_state *wl)
{
- wl->window.surface = wl_compositor_create_surface(wl->display.compositor);
- wl->window.shell_surface = wl_shell_get_shell_surface(wl->display.shell,
- wl->window.surface);
+ wl->window.video_surface =
+ wl_compositor_create_surface(wl->display.compositor);
+ wl->window.shell_surface =
+ wl_shell_get_shell_surface(wl->display.shell, wl->window.video_surface);
+
+ // Commits on surfaces bound to a subsurface are cached until the parent
+ // surface is commited, in this case the video surface.
+ // Which means we can call commit anywhere.
+ for (int i = 0; i < MAX_OSD_PARTS; ++i) {
+ wl->window.osd_surfaces[i] =
+ wl_compositor_create_surface(wl->display.compositor);
+ wl->window.osd_subsurfaces[i] =
+ wl_subcompositor_get_subsurface(wl->display.subcomp,
+ wl->window.osd_surfaces[i],
+ wl->window.video_surface); // parent
+ wl_subsurface_set_sync(wl->window.osd_subsurfaces[i]);
+ }
if (!wl->window.shell_surface) {
MP_ERR(wl, "creating shell surface failed\n");
@@ -816,8 +836,8 @@ static void destroy_window (struct vo_wayland_state *wl)
if (wl->window.shell_surface)
wl_shell_surface_destroy(wl->window.shell_surface);
- if (wl->window.surface)
- wl_surface_destroy(wl->window.surface);
+ if (wl->window.video_surface)
+ wl_surface_destroy(wl->window.video_surface);
}
static bool create_cursor (struct vo_wayland_state *wl)
diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h
index 3bad89b367..020282761a 100644
--- a/video/out/wayland_common.h
+++ b/video/out/wayland_common.h
@@ -27,6 +27,8 @@
#include "config.h"
+#include "sub/osd.h"
+
#if HAVE_GL_WAYLAND
#include <wayland-egl.h>
#include <EGL/egl.h>
@@ -77,6 +79,8 @@ struct vo_wayland_state {
int display_fd;
struct wl_shm *shm;
+
+ struct wl_subcompositor *subcomp;
} display;
struct {
@@ -95,11 +99,14 @@ struct vo_wayland_state {
int32_t fs_width; // fullscreen sizes
int32_t fs_height;
- struct wl_surface *surface;
+ struct wl_surface *video_surface;
int32_t mouse_x; // mouse position inside the surface
int32_t mouse_y;
struct wl_shell_surface *shell_surface;
int events; /* mplayer events (VO_EVENT_RESIZE) */
+
+ struct wl_surface *osd_surfaces[MAX_OSD_PARTS];
+ struct wl_subsurface *osd_subsurfaces[MAX_OSD_PARTS];
} window;
struct {