summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/out/vo_wayland.c472
-rw-r--r--video/out/wayland/buffer.c137
-rw-r--r--video/out/wayland/buffer.h102
-rw-r--r--video/out/wayland/memfile.c105
-rw-r--r--video/out/wayland/memfile.h26
-rw-r--r--wscript_build.py2
6 files changed, 502 insertions, 342 deletions
diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c
index dc9fc748a1..86c52a440e 100644
--- a/video/out/vo_wayland.c
+++ b/video/out/vo_wayland.c
@@ -17,14 +17,8 @@
*/
#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
#include <stdbool.h>
-
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
+#include <assert.h>
#include <libavutil/common.h>
@@ -35,17 +29,15 @@
#include "video/mp_image.h"
#include "video/sws_utils.h"
#include "video/memcpy_pic.h"
-
#include "sub/osd.h"
#include "sub/img_convert.h"
-
#include "common/msg.h"
#include "input/input.h"
-
#include "osdep/timer.h"
#include "wayland_common.h"
-#include "wayland-version.h"
+
+#include "video/out/wayland/buffer.h"
static void draw_image(struct vo *vo, mp_image_t *mpi);
static void draw_osd(struct vo *vo);
@@ -53,15 +45,8 @@ static void draw_osd(struct vo *vo);
static const struct wl_callback_listener frame_listener;
static const struct wl_buffer_listener buffer_listener;
-struct fmtentry {
- enum wl_shm_format wl_fmt;
- enum mp_imgfmt mp_fmt;
-};
-
-// the first 2 Formats should be available on most platforms
-// all other formats are optional
-// the waylad byte order is sometimes reversed
-static const struct fmtentry fmttable[] = {
+// TODO: pay attention to the reported subpixel order
+static const format_t const format_table[] = {
{WL_SHM_FORMAT_ARGB8888, IMGFMT_BGRA}, // 8b 8g 8r 8a
{WL_SHM_FORMAT_XRGB8888, IMGFMT_BGR0},
{WL_SHM_FORMAT_RGB332, IMGFMT_RGB8}, // 3b 3g 2r
@@ -94,38 +79,24 @@ static const struct fmtentry fmttable[] = {
{WL_SHM_FORMAT_BGRA8888, IMGFMT_ARGB},
};
-#define MAX_FORMAT_ENTRIES (sizeof(fmttable) / sizeof(fmttable[0]))
+#define MAX_FORMAT_ENTRIES (sizeof(format_table) / sizeof(format_table[0]))
#define DEFAULT_FORMAT_ENTRY 1
#define DEFAULT_ALPHA_FORMAT_ENTRY 0
struct priv;
-struct buffer {
- struct wl_buffer *wlbuf;
- bool is_busy;
- bool is_new;
- bool is_attached;
- bool to_resize;
- void *shm_data;
- size_t shm_size;
- struct wl_shm_pool *shm_pool; // shares memory
-};
-
+// We only use double buffering but the creation and usage is still open to
+// triple buffering. Tripple buffering is now removed, because double buffering
+// is now pixel-perfect.
struct buffer_pool {
- struct buffer *buffers;
- struct buffer *front_buffer; // just pointers to any of the buffers
- struct buffer *middle_buffer; // just pointers to any of the buffers
- struct buffer *back_buffer;
+ shm_buffer_t **buffers;
+ shm_buffer_t *front_buffer; // just pointers to any of the buffers
+ shm_buffer_t *back_buffer;
uint32_t buffer_no;
- uint32_t size;
- uint32_t stride;
- uint32_t bytes_per_pixel;
- enum wl_shm_format format; // TODO use fmtentry here
- struct wl_shm *shm;
};
struct supported_format {
- const struct fmtentry *fmt;
+ format_t format;
bool is_alpha;
struct wl_list link;
};
@@ -134,11 +105,8 @@ struct priv {
struct vo *vo;
struct vo_wayland_state *wl;
- struct wl_surface *osd_surfaces[MAX_OSD_PARTS];
- struct wl_subsurface *osd_subsurfaces[MAX_OSD_PARTS];
-
struct wl_list format_list;
- const struct fmtentry *video_format;
+ const format_t *video_format; // pointer to element in supported_format list
struct mp_rect src;
struct mp_rect dst;
@@ -152,8 +120,6 @@ 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;
int width; // width of the original image
@@ -161,6 +127,9 @@ struct priv {
int x, y; // coords for resizing
+ struct wl_surface *osd_surfaces[MAX_OSD_PARTS];
+ struct wl_subsurface *osd_subsurfaces[MAX_OSD_PARTS];
+ shm_buffer_t *osd_buffers[MAX_OSD_PARTS];
// this id tells us if the subtitle part has changed or not
int bitmap_pos_id[MAX_OSD_PARTS];
@@ -169,236 +138,79 @@ struct priv {
// options
int enable_alpha;
int use_rgb565;
- int use_triplebuffering;
};
-/* copied from weston clients */
-static int set_cloexec_or_close(int fd)
-{
- long flags;
-
- if (fd == -1)
- return -1;
-
- if ((flags = fcntl(fd, F_GETFD)) == -1)
- goto err;
-
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
- goto err;
-
- return fd;
-
-err:
- close(fd);
- return -1;
-}
-
-static int create_tmpfile_cloexec(char *tmpname)
+static bool is_alpha_format(const format_t *fmt)
{
- int fd;
-
-#ifdef HAVE_MKOSTEMP
- fd = mkostemp(tmpname, O_CLOEXEC);
- if (fd >= 0)
- unlink(tmpname);
-#else
- fd = mkstemp(tmpname);
- if (fd >= 0) {
- fd = set_cloexec_or_close(fd);
- unlink(tmpname);
- }
-#endif
-
- return fd;
+ return !!(mp_imgfmt_get_desc(fmt->mp_format).flags & MP_IMGFLAG_ALPHA);
}
-static int os_create_anonymous_file(off_t size)
-{
- static const char template[] = "/mpv-temp-XXXXXX";
- const char *path;
- char *name;
- int fd;
-
- path = getenv("XDG_RUNTIME_DIR");
- if (!path) {
- errno = ENOENT;
- return -1;
- }
-
- name = malloc(strlen(path) + sizeof(template));
- if (!name)
- return -1;
-
- strcpy(name, path);
- strcat(name, template);
-
- fd = create_tmpfile_cloexec(name);
-
- free(name);
-
- if (fd < 0)
- return -1;
-
- if (ftruncate(fd, size) < 0) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-static bool is_alpha_format(const struct fmtentry *fmt)
-{
- return !!(mp_imgfmt_get_desc(fmt->mp_fmt).flags & MP_IMGFLAG_ALPHA);
-}
-
-static const struct fmtentry * is_wayland_format_supported(struct priv *p,
- enum wl_shm_format fmt)
+static const format_t* is_wayland_format_supported(struct priv *p,
+ enum wl_shm_format fmt)
{
struct supported_format *sf;
// find the matching format first
wl_list_for_each(sf, &p->format_list, link) {
- if (sf->fmt->wl_fmt == fmt) {
- return sf->fmt;
+ if (sf->format.wl_format == fmt) {
+ return &sf->format;
}
}
return NULL;
}
-// buffer functions
+// additinal buffer functions
-static void buffer_finalise_front(struct buffer *buf)
+static void buffer_finalise_front(shm_buffer_t *buf)
{
- buf->is_new = false; // is_busy is reset on handle_release
- buf->is_busy = true;
- buf->is_attached = true;
+ SHM_BUFFER_SET_BUSY(buf);
+ SHM_BUFFER_CLEAR_DIRTY(buf);
}
-static void buffer_finalise_back(struct buffer *buf)
+static void buffer_finalise_back(shm_buffer_t *buf)
{
- buf->is_new = true;
-}
-
-static void buffer_destroy_content(struct buffer *buf)
-{
- if (buf->wlbuf) {
- wl_buffer_destroy(buf->wlbuf);
- buf->wlbuf = NULL;
- }
- if (buf->shm_data) {
- munmap(buf->shm_data, buf->shm_size);
- buf->shm_data = NULL;
- buf->shm_size = 0;
- }
-}
-
-static bool buffer_create_content(struct buffer_pool *pool,
- struct buffer *buf,
- int width,
- int height)
-{
- int fd;
- void *data;
- struct wl_shm_pool *shm_pool;
-
- fd = os_create_anonymous_file(pool->size);
- if (fd < 0) {
- return false;
- }
-
- data = mmap(NULL, pool->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- close(fd);
- return false;
- }
-
- // wl-buffers of the same shm_pool share it's content which might be useful
- // if we resize the buffers (from the docs).
- shm_pool = wl_shm_create_pool(pool->shm, fd, pool->size);
- buf->wlbuf = wl_shm_pool_create_buffer(shm_pool, 0, width, height,
- pool->stride, pool->format);
- wl_buffer_add_listener(buf->wlbuf, &buffer_listener, buf);
-
- wl_shm_pool_destroy(shm_pool);
- close(fd);
-
- buf->shm_size = pool->size;
- buf->shm_data = data;
- buf->is_new = false;
- buf->is_busy = false;
- return true;
-}
-
-static bool buffer_resize(struct buffer_pool *pool, struct buffer *buf,
- uint32_t width, uint32_t height)
-{
- if (buf->is_attached) {
- buf->to_resize = true;
- return true;
- }
-
- if (buf->shm_size == pool->size)
- return true;
-
- buf->to_resize = false;
- buffer_destroy_content(buf);
- return buffer_create_content(pool, buf, width, height);
+ SHM_BUFFER_SET_DIRTY(buf);
}
static struct mp_image buffer_get_mp_image(struct priv *p,
- struct buffer_pool *pool,
- struct buffer *buf)
+ shm_buffer_t *buf)
{
struct mp_image img = {0};
mp_image_set_params(&img, &p->sws->dst);
- img.planes[0] = buf->shm_data;
- img.stride[0] = pool->stride;
+ img.w = buf->stride / buf->bytes;
+ img.h = buf->height;
+ img.planes[0] = buf->data;
+ img.stride[0] = buf->stride;
return img;
}
-
// buffer pool functions
static void buffer_pool_reinit(struct priv *p,
struct buffer_pool *pool,
uint32_t buffer_no,
uint32_t width, uint32_t height,
- const struct fmtentry *fmt,
+ format_t fmt,
struct wl_shm *shm)
{
- pool->shm = shm;
-
if (!pool->buffers)
- pool->buffers = calloc(buffer_no, sizeof(struct buffer));
+ pool->buffers = calloc(buffer_no, sizeof(shm_buffer_t*));
pool->buffer_no = buffer_no;
- pool->format = fmt->wl_fmt;
- pool->bytes_per_pixel = mp_imgfmt_get_desc(fmt->mp_fmt).bytes[0];
- pool->stride = FFALIGN(width * pool->bytes_per_pixel, SWS_MIN_BYTE_ALIGN);
- pool->size = pool->stride * height;
-
- for (uint32_t i = 0; i < buffer_no; ++i)
- buffer_resize(pool, &pool->buffers[i], width, height);
-
- if (buffer_no == 3) {
- pool->back_buffer = &pool->buffers[0];
- pool->middle_buffer = &pool->buffers[1];
- pool->front_buffer = &pool->buffers[2];
- }
- else if (buffer_no == 2) {
- pool->back_buffer = &pool->buffers[0];
- pool->front_buffer = &pool->buffers[1];
- pool->middle_buffer = NULL;
- }
- else {
- pool->back_buffer = NULL;
- pool->middle_buffer = NULL;
- pool->front_buffer = NULL;
+
+ for (uint32_t i = 0; i < buffer_no; ++i) {
+ if (pool->buffers[i] == NULL)
+ pool->buffers[i] = shm_buffer_create(width, height, fmt,
+ shm, &buffer_listener);
+ else
+ shm_buffer_resize(pool->buffers[i], width, height);
}
+
+ pool->back_buffer = pool->buffers[0];
+ pool->front_buffer = pool->buffers[1];
}
static bool buffer_pool_resize(struct buffer_pool *pool,
@@ -407,11 +219,8 @@ static bool buffer_pool_resize(struct buffer_pool *pool,
{
bool ret = true;
- pool->stride = FFALIGN(width * pool->bytes_per_pixel, SWS_MIN_BYTE_ALIGN);
- pool->size = pool->stride * height;
-
for (uint32_t i = 0; ret && i < pool->buffer_no; ++i)
- ret = buffer_resize(pool, &pool->buffers[i], width, height);
+ shm_buffer_resize(pool->buffers[i], width, height);
return ret;
}
@@ -419,7 +228,7 @@ static bool buffer_pool_resize(struct buffer_pool *pool,
static void buffer_pool_destroy(struct buffer_pool *pool)
{
for (uint32_t i = 0; i < pool->buffer_no; ++i)
- buffer_destroy_content(&pool->buffers[i]);
+ shm_buffer_destroy(pool->buffers[i]);
free(pool->buffers);
pool->front_buffer = NULL;
@@ -429,54 +238,27 @@ static void buffer_pool_destroy(struct buffer_pool *pool)
static void buffer_pool_swap(struct buffer_pool *pool)
{
- if (pool->buffer_no == 3) {
- if (pool->back_buffer->is_new) {
- struct buffer *tmp = pool->back_buffer;
- pool->back_buffer = pool->middle_buffer;
- pool->middle_buffer = tmp;
- }
- if (!pool->front_buffer->is_busy && !pool->front_buffer->is_new) {
- struct buffer *tmp = pool->front_buffer;
- pool->front_buffer = pool->middle_buffer;
- pool->middle_buffer = tmp;
- }
- }
- else if (pool->buffer_no == 2) {
- if (pool->back_buffer->is_new) {
- struct buffer *tmp = pool->back_buffer;
- pool->back_buffer = pool->front_buffer;
- pool->front_buffer = tmp;
- }
+ if (SHM_BUFFER_IS_DIRTY(pool->back_buffer)) {
+ shm_buffer_t *tmp = pool->back_buffer;
+ pool->back_buffer = pool->front_buffer;
+ pool->front_buffer = tmp;
}
}
// returns NULL if the back buffer is busy
-static struct buffer * buffer_pool_get_back(struct buffer_pool *pool)
+static shm_buffer_t * buffer_pool_get_back(struct buffer_pool *pool)
{
- if (!pool->back_buffer || pool->back_buffer->is_busy)
+ if (!pool->back_buffer || SHM_BUFFER_IS_BUSY(pool->back_buffer))
return NULL;
return pool->back_buffer;
}
-// returns NULL if the front buffer is not new
-static struct buffer * buffer_pool_get_front(struct buffer_pool *pool)
+static shm_buffer_t * buffer_pool_get_front(struct buffer_pool *pool)
{
- if (!pool->front_buffer || !pool->front_buffer->is_new)
- return NULL;
-
- pool->front_buffer->is_busy = true;
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)
{
draw_image(p->vo, NULL);
@@ -495,6 +277,9 @@ static bool resize(struct priv *p)
{
struct vo_wayland_state *wl = p->wl;
+ if (SHM_BUFFER_IS_BUSY(p->video_bufpool.back_buffer))
+ return false; // skip resizing if we can't garantuee pixel perfectness!
+
int32_t x = wl->window.sh_x;
int32_t y = wl->window.sh_y;
wl->vo->dwidth = wl->window.sh_width;
@@ -522,7 +307,7 @@ static bool resize(struct priv *p)
mp_sws_set_from_cmdline(p->sws, p->vo->opts->sws_opts);
p->sws->src = p->in_format;
p->sws->dst = (struct mp_image_params) {
- .imgfmt = p->video_format->mp_fmt,
+ .imgfmt = p->video_format->mp_format,
.w = p->dst_w,
.h = p->dst_h,
.d_w = p->dst_w,
@@ -538,20 +323,6 @@ static bool resize(struct priv *p)
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->osd_subsurfaces[i]);
- struct wl_surface *s = p->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->osd_subsurfaces[i]);
- }
wl->window.width = p->dst_w;
wl->window.height = p->dst_h;
@@ -576,11 +347,18 @@ static bool resize(struct priv *p)
/* wayland listeners */
-
static void buffer_handle_release(void *data, struct wl_buffer *buffer)
{
- struct buffer *buf = data;
- buf->is_busy = false;
+ shm_buffer_t *buf = data;
+
+ if (SHM_BUFFER_IS_ONESHOT(buf)) {
+ shm_buffer_destroy(buf);
+ return;
+ }
+
+ SHM_BUFFER_CLEAR_BUSY(buf);
+ // does nothing and returns 0 if no pending resize flag was set
+ shm_buffer_pending_resize(buf);
}
static const struct wl_buffer_listener buffer_listener = {
@@ -593,11 +371,10 @@ static void frame_handle_redraw(void *data,
{
struct priv *p = data;
struct vo_wayland_state *wl = p->wl;
- buffer_pool_swap(&p->video_bufpool);
- struct buffer *buf = buffer_pool_get_front(&p->video_bufpool);
+ shm_buffer_t *buf = buffer_pool_get_front(&p->video_bufpool);
if (buf) {
- wl_surface_attach(wl->window.video_surface, buf->wlbuf, p->x, p->y);
+ wl_surface_attach(wl->window.video_surface, buf->buffer, p->x, p->y);
wl_surface_damage(wl->window.video_surface, 0, 0, p->dst_w, p->dst_h);
if (callback)
@@ -608,18 +385,11 @@ static void frame_handle_redraw(void *data,
wl_surface_commit(wl->window.video_surface);
buffer_finalise_front(buf);
- // resize 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);
- }
- p->attached_buffer = buf;
- buffer_finalise_front(buf);
-
p->x = 0;
p->y = 0;
}
else {
+ MP_WARN(wl, "Should not happen anymore (frame)\n");
if (callback)
wl_callback_destroy(callback);
@@ -638,12 +408,12 @@ static void shm_handle_format(void *data,
{
struct priv *p = data;
for (uint32_t i = 0; i < MAX_FORMAT_ENTRIES; ++i) {
- if (fmttable[i].wl_fmt == format) {
+ if (format_table[i].wl_format == format) {
MP_INFO(p->wl, "format %s supported by hw\n",
- mp_imgfmt_to_name(fmttable[i].mp_fmt));
+ mp_imgfmt_to_name(format_table[i].mp_format));
struct supported_format *sf = talloc(p, struct supported_format);
- sf->fmt = &fmttable[i];
- sf->is_alpha = is_alpha_format(sf->fmt);
+ sf->format = format_table[i];
+ sf->is_alpha = is_alpha_format(&sf->format);
wl_list_insert(&p->format_list, &sf->link);
}
}
@@ -659,7 +429,7 @@ static const struct wl_shm_listener shm_listener = {
static void draw_image(struct vo *vo, mp_image_t *mpi)
{
struct priv *p = vo->priv;
- struct buffer *buf = buffer_pool_get_back(&p->video_bufpool);
+ shm_buffer_t *buf = buffer_pool_get_back(&p->video_bufpool);
if (mpi) {
talloc_free(p->original_image);
@@ -667,19 +437,13 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
}
if (!buf) {
+ // TODO: use similar handling of busy buffers as the osd buffers
+ // if the need arises
MP_VERBOSE(p->wl, "can't draw, back buffer is busy\n");
return;
}
- if (buf->to_resize) {
- if (buf->is_attached) {
- MP_WARN(p->wl, "resizing attached buffer, use triple-buffering\n");
- buf->is_attached = false;
- }
- buffer_resize(&p->video_bufpool, buf, p->dst_w, p->dst_h);
- }
-
- struct mp_image img = buffer_get_mp_image(p, &p->video_bufpool, buf);
+ struct mp_image img = buffer_get_mp_image(p, buf);
if (p->original_image) {
struct mp_image src = *p->original_image;
@@ -704,9 +468,6 @@ static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs)
int id = imgs->render_index;
struct wl_surface *s = p->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;
@@ -715,25 +476,50 @@ static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs)
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);
+ int width = mp_rect_w(bb);
+ int height = mp_rect_h(bb);
- for (int n = 0; n < imgs->num_parts; n++) {
- struct sub_bitmap *sub = &imgs->parts[n];
+ if (!p->osd_buffers[id]) {
+ p->osd_buffers[id] = shm_buffer_create(width,
+ height,
+ format_table[DEFAULT_ALPHA_FORMAT_ENTRY],
+ p->wl->display.shm,
+ &buffer_listener);
+ }
+ else if (SHM_BUFFER_IS_BUSY(p->osd_buffers[id])) {
+ // freed on release in buffer_listener
+ // garantuees pixel perfect resizing of subtitles and osd
+ SHM_BUFFER_SET_ONESHOT(p->osd_buffers[id]);
+ p->osd_buffers[id] = shm_buffer_create(width,
+ height,
+ format_table[DEFAULT_ALPHA_FORMAT_ENTRY],
+ p->wl->display.shm,
+ &buffer_listener);
+ }
+ else {
+ shm_buffer_resize(p->osd_buffers[id], width, height);
+ }
+
+ shm_buffer_t *buf = p->osd_buffers[id];
+ SHM_BUFFER_SET_BUSY(buf);
- size_t dst = (bb.y0) * wlimg.stride[0] +
- (bb.x0) * 4;
+ struct mp_image wlimg = buffer_get_mp_image(p, buf);
- memcpy_pic(wlimg.planes[0] + dst, sub->bitmap, sub->w * 4, sub->h,
+ for (int n = 0; n < imgs->num_parts; n++) {
+ struct sub_bitmap *sub = &imgs->parts[n];
+ memcpy_pic(wlimg.planes[0], sub->bitmap, sub->w * 4, sub->h,
wlimg.stride[0], sub->stride);
}
+
wl_subsurface_set_position(p->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_attach(s, buf->buffer, bb.x0, bb.y0);
+ wl_surface_damage(s, 0, 0, width, height);
wl_surface_commit(s);
}
else {
- wl_surface_attach(s, buf->wlbuf, 0, 0);
+ // p->osd_buffer, garantueed to exist here
+ assert(p->osd_buffers[id]);
+ wl_surface_attach(s, p->osd_buffers[id]->buffer, 0, 0);
wl_surface_commit(s);
}
}
@@ -745,6 +531,7 @@ static const bool osd_formats[SUBBITMAP_COUNT] = {
static void draw_osd(struct vo *vo)
{
struct priv *p = vo->priv;
+
// 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
@@ -776,7 +563,7 @@ static int query_format(struct vo *vo, uint32_t format)
struct priv *p = vo->priv;
struct supported_format *sf;
wl_list_for_each_reverse(sf, &p->format_list, link) {
- if (sf->fmt->mp_fmt == format)
+ if (sf->format.mp_format == format)
return VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_CSP_SUPPORTED;
}
@@ -799,8 +586,10 @@ static int reconfig(struct vo *vo, struct mp_image_params *fmt, int flags)
// find the matching format first
wl_list_for_each(sf, &p->format_list, link) {
- if (sf->fmt->mp_fmt == fmt->imgfmt && (p->enable_alpha == sf->is_alpha)) {
- p->video_format = sf->fmt;
+ if (sf->format.mp_format == fmt->imgfmt &&
+ (p->enable_alpha == sf->is_alpha))
+ {
+ p->video_format = &sf->format;
break;
}
}
@@ -808,24 +597,23 @@ static int reconfig(struct vo *vo, struct mp_image_params *fmt, int flags)
if (!p->video_format) {
// if use default is enable overwrite the auto selected one
if (p->enable_alpha)
- p->video_format = &fmttable[DEFAULT_ALPHA_FORMAT_ENTRY];
+ p->video_format = &format_table[DEFAULT_ALPHA_FORMAT_ENTRY];
else
- p->video_format = &fmttable[DEFAULT_FORMAT_ENTRY];
+ p->video_format = &format_table[DEFAULT_FORMAT_ENTRY];
}
// overides alpha
// use rgb565 if performance is your main concern
if (p->use_rgb565) {
- const struct fmtentry *entry =
+ MP_INFO(p->wl, "using rgb565\n");
+ const format_t *entry =
is_wayland_format_supported(p, WL_SHM_FORMAT_RGB565);
if (entry)
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);
- buffer_pool_reinit(p, &p->osd_bufpool, MAX_OSD_PARTS, p->width, p->height,
- &fmttable[DEFAULT_ALPHA_FORMAT_ENTRY], p->wl->display.shm);
+ buffer_pool_reinit(p, &p->video_bufpool, 2, p->width, p->height,
+ *p->video_format, p->wl->display.shm);
vo_wayland_config(vo, flags);
@@ -838,7 +626,6 @@ 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);
@@ -846,6 +633,7 @@ static void uninit(struct vo *vo)
talloc_free(p->original_image);
for (int i = 0; i < MAX_OSD_PARTS; ++i) {
+ shm_buffer_destroy(p->osd_buffers[i]);
wl_subsurface_destroy(p->osd_subsurfaces[i]);
wl_surface_destroy(p->osd_surfaces[i]);
}
@@ -891,7 +679,6 @@ static int preinit(struct vo *vo)
}
wl_region_destroy(input);
-
return 0;
}
@@ -902,8 +689,10 @@ static int control(struct vo *vo, uint32_t request, void *data)
case VOCTRL_GET_PANSCAN:
return VO_TRUE;
case VOCTRL_SET_PANSCAN:
+ {
resize(p);
return VO_TRUE;
+ }
case VOCTRL_REDRAW_FRAME:
return redraw_frame(p);
case VOCTRL_SCREENSHOT:
@@ -943,7 +732,6 @@ const struct vo_driver video_out_wayland = {
.options = (const struct m_option[]) {
OPT_FLAG("alpha", enable_alpha, 0),
OPT_FLAG("rgb565", use_rgb565, 0),
- OPT_FLAG("triple-buffering", use_triplebuffering, 0),
{0}
},
};
diff --git a/video/out/wayland/buffer.c b/video/out/wayland/buffer.c
new file mode 100644
index 0000000000..26fd3d1cc8
--- /dev/null
+++ b/video/out/wayland/buffer.c
@@ -0,0 +1,137 @@
+/*
+ * This file is part of mpv video player.
+ * Copyright © 2014 Alexander Preisinger <alexander.preisinger@gmail.com>
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "buffer.h"
+#include "memfile.h"
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+int8_t format_get_bytes(const format_t *fmt)
+{
+ return mp_imgfmt_get_desc(fmt->mp_format).bytes[0];
+}
+
+shm_buffer_t* shm_buffer_create(uint32_t width,
+ uint32_t height,
+ format_t fmt,
+ struct wl_shm *shm,
+ const struct wl_buffer_listener *listener)
+{
+ int8_t bytes = format_get_bytes(&fmt);
+ uint32_t stride = SHM_BUFFER_STRIDE(width, bytes);
+ uint32_t size = stride * height;
+
+ shm_buffer_t *buffer = calloc(1, sizeof(shm_buffer_t));
+ int fd = memfile_create(size);
+
+ if (fd < 0)
+ return NULL;
+
+ buffer->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (buffer->data == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+
+ buffer->shm_pool = wl_shm_create_pool(shm, fd, size);
+ buffer->buffer = wl_shm_pool_create_buffer(buffer->shm_pool,
+ 0, width, height, stride,
+ fmt.wl_format);
+
+ wl_buffer_add_listener(buffer->buffer, listener, buffer);
+
+ buffer->fd = fd;
+ buffer->height = height;
+ buffer->stride = stride;
+ buffer->format = fmt;
+ buffer->bytes = bytes;
+ buffer->pool_size = size;
+ buffer->pending_height = 0;
+ buffer->pending_width = 0;
+
+ return buffer;
+}
+
+int shm_buffer_resize(shm_buffer_t *buffer, uint32_t width, uint32_t height)
+{
+ uint32_t new_stride = SHM_BUFFER_STRIDE(width, buffer->bytes);
+ uint32_t new_size = new_stride * height;
+
+ if (!!(buffer->flags & SHM_BUFFER_BUSY)) {
+ buffer->flags |= SHM_BUFFER_RESIZE_LATER;
+ buffer->pending_width = width;
+ buffer->pending_height = height;
+ return SHM_BUFFER_BUSY;
+ }
+
+ buffer->flags &= ~SHM_BUFFER_RESIZE_LATER;
+
+ if (new_size > buffer->pool_size) {
+ munmap(buffer->data, buffer->pool_size);
+ ftruncate(buffer->fd, new_size);
+
+ buffer->data = mmap(NULL, new_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, buffer->fd, 0);
+
+ // TODO: the buffer should be destroyed when -1 is return
+ if (buffer->data == MAP_FAILED)
+ return -1;
+
+ wl_shm_pool_resize(buffer->shm_pool, new_size);
+ buffer->pool_size = new_size;
+ }
+
+ const void *listener = wl_proxy_get_listener((struct wl_proxy*)buffer->buffer);
+
+ wl_buffer_destroy(buffer->buffer);
+ buffer->buffer = wl_shm_pool_create_buffer(buffer->shm_pool,
+ 0, width, height, new_stride,
+ buffer->format.wl_format);
+
+ wl_buffer_add_listener(buffer->buffer, listener, buffer);
+
+ buffer->height = height;
+ buffer->stride = new_stride;
+
+ return 0;
+}
+
+int shm_buffer_pending_resize(shm_buffer_t *buffer)
+{
+ if (SHM_BUFFER_PENDING_RESIZE(buffer)) {
+ SHM_BUFFER_CLEAR_PNDNG_RSZ(buffer);
+ return shm_buffer_resize(buffer, buffer->pending_width, buffer->pending_height);
+ }
+ else {
+ return 0;
+ }
+}
+
+void shm_buffer_destroy(shm_buffer_t *buffer)
+{
+ if (!buffer)
+ return;
+
+ wl_buffer_destroy(buffer->buffer);
+ wl_shm_pool_destroy(buffer->shm_pool);
+ munmap(buffer->data, buffer->pool_size);
+ close(buffer->fd);
+ free(buffer);
+}
diff --git a/video/out/wayland/buffer.h b/video/out/wayland/buffer.h
new file mode 100644
index 0000000000..04e94b9d7f
--- /dev/null
+++ b/video/out/wayland/buffer.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of mpv video player.
+ * Copyright © 2014 Alexander Preisinger <alexander.preisinger@gmail.com>
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MPLAYER_WAYLAND_BUFFER_H
+#define MPLAYER_WAYLAND_BUFFER_H
+
+#include <libavutil/common.h>
+#include "video/sws_utils.h"
+#include "video/img_format.h"
+#include "video/out/wayland_common.h"
+
+#define SHM_BUFFER_STRIDE(width, bytes) \
+ FFALIGN((width) * (bytes), SWS_MIN_BYTE_ALIGN)
+
+typedef struct format {
+ enum wl_shm_format wl_format;
+ enum mp_imgfmt mp_format;
+} format_t;
+
+int8_t format_get_bytes(const format_t *fmt);
+
+typedef enum shm_buffer_flags {
+ SHM_BUFFER_BUSY = 1 << 0, // in use by the compositor
+ SHM_BUFFER_DIRTY = 1 << 1, // buffer contains new content
+ SHM_BUFFER_ONESHOT = 1 << 2, // free after release
+ SHM_BUFFER_RESIZE_LATER = 1 << 3, // free after release
+} shm_buffer_flags_t;
+
+#define SHM_BUFFER_IS_BUSY(b) (!!((b)->flags & SHM_BUFFER_BUSY))
+#define SHM_BUFFER_IS_DIRTY(b) (!!((b)->flags & SHM_BUFFER_DIRTY))
+#define SHM_BUFFER_IS_ONESHOT(b) (!!((b)->flags & SHM_BUFFER_ONESHOT))
+#define SHM_BUFFER_PENDING_RESIZE(b) (!!((b)->flags & SHM_BUFFER_RESIZE_LATER))
+
+#define SHM_BUFFER_SET_BUSY(b) (b)->flags |= SHM_BUFFER_BUSY
+#define SHM_BUFFER_SET_DIRTY(b) (b)->flags |= SHM_BUFFER_DIRTY
+#define SHM_BUFFER_SET_ONESHOT(b) (b)->flags |= SHM_BUFFER_ONESHOT
+#define SHM_BUFFER_SET_PNDNG_RSZ(b) (b)->flags |= SHM_BUFFER_RESIZE_LATER
+
+#define SHM_BUFFER_CLEAR_BUSY(b) (b)->flags &= ~SHM_BUFFER_BUSY
+#define SHM_BUFFER_CLEAR_DIRTY(b) (b)->flags &= ~SHM_BUFFER_DIRT