From c0ef3cf9c2d8db023dd3d5dcdeb2c2c592ad6b58 Mon Sep 17 00:00:00 2001 From: Rostislav Pehlivanov Date: Thu, 21 Jul 2016 12:25:30 +0100 Subject: wayland: port to the new wakeup/wait_events framework This fits natively into the vo/backend and allows to simplify the polling code. One new change is the fact that surface_handle_enter flags VO_EVENT_WIN_STATE and VO_EVENT_RESIZE instead of only VO_EVENT_WIN_STATE. Before this, the code hackily relied on the timeout and the loop in the wait_frame function to track and set the scaling factor. Instead, this triggers mpv to run a schedule_resize and adjust the new VO output dimensions immediately. This is also more accurate since surface_handle_enter() gets called when a surface is created, moved and resized, which is exactly what the rest of the player might be interested in. --- video/out/opengl/context_wayland.c | 15 +++++- video/out/vo_wayland.c | 8 ++-- video/out/wayland_common.c | 94 +++++++++++++------------------------- video/out/wayland_common.h | 7 ++- 4 files changed, 53 insertions(+), 71 deletions(-) (limited to 'video') diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c index e74132bcf2..b1d9a32bca 100644 --- a/video/out/opengl/context_wayland.c +++ b/video/out/opengl/context_wayland.c @@ -207,8 +207,7 @@ static void waylandgl_swap_buffers(MPGLContext *ctx) if (!wl->frame.callback) vo_wayland_request_frame(ctx->vo, NULL, NULL); - if (!vo_wayland_wait_frame(ctx->vo)) - MP_DBG(wl, "discarding frame callback\n"); + vo_wayland_wait_events(ctx->vo, 0); eglSwapBuffers(wl->egl_context.egl.dpy, wl->egl_context.egl_surface); } @@ -225,6 +224,16 @@ static int waylandgl_control(MPGLContext *ctx, int *events, int request, return r; } +static void wayland_wakeup(struct MPGLContext *ctx) +{ + vo_wayland_wakeup(ctx->vo); +} + +static void wayland_wait_events(struct MPGLContext *ctx, int64_t until_time_us) +{ + vo_wayland_wait_events(ctx->vo, until_time_us); +} + static int waylandgl_init(struct MPGLContext *ctx, int flags) { if (!vo_wayland_init(ctx->vo)) @@ -239,5 +248,7 @@ const struct mpgl_driver mpgl_driver_wayland = { .reconfig = waylandgl_reconfig, .swap_buffers = waylandgl_swap_buffers, .control = waylandgl_control, + .wakeup = wayland_wakeup, + .wait_events = wayland_wait_events, .uninit = waylandgl_uninit, }; diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c index 2997b38cde..236421e4ef 100644 --- a/video/out/vo_wayland.c +++ b/video/out/vo_wayland.c @@ -373,8 +373,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) p->original_image = mpi; } - if (!vo_wayland_wait_frame(vo)) - MP_DBG(p->wl, "discarding frame callback\n"); + vo_wayland_wait_events(vo, 0); shm_buffer_t *buf = buffer_pool_get_back(&p->video_bufpool); @@ -513,8 +512,7 @@ static void flip_page(struct vo *vo) if (!p->wl->frame.callback) vo_wayland_request_frame(vo, p, redraw); - if (!vo_wayland_wait_frame(vo)) - MP_DBG(p->wl, "discarding frame callback\n"); + vo_wayland_wait_events(vo, 0); } static int query_format(struct vo *vo, int format) @@ -675,6 +673,8 @@ const struct vo_driver video_out_wayland = { .control = control, .draw_image = draw_image, .flip_page = flip_page, + .wakeup = vo_wayland_wakeup, + .wait_events = vo_wayland_wait_events, .uninit = uninit, .options = (const struct m_option[]) { OPT_FLAG("alpha", enable_alpha, 0), diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 6861c93fca..b216bfde8a 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -40,6 +40,7 @@ #include "vo.h" #include "win_state.h" +#include "osdep/io.h" #include "osdep/timer.h" #include "input/input.h" @@ -225,7 +226,7 @@ static void surface_handle_enter(void *data, } } - wl->window.events |= VO_EVENT_WIN_STATE; + wl->window.events |= VO_EVENT_WIN_STATE | VO_EVENT_RESIZE; } static void surface_handle_leave(void *data, @@ -833,10 +834,6 @@ static void frame_callback(void *data, wl_callback_add_listener(wl->frame.callback, &frame_listener, wl); wl_surface_commit(wl->window.video_surface); - - wl->frame.last_us = mp_time_us(); - wl->frame.pending = true; - wl->frame.dropping = false; } static const struct wl_callback_listener frame_listener = { @@ -1045,7 +1042,7 @@ int vo_wayland_init (struct vo *vo) o->refresh_rate / 1000.0f); } - vo->event_fd = wl->display.display_fd; + mp_make_wakeup_pipe(wl->wakeup_pipe); return true; } @@ -1057,6 +1054,8 @@ void vo_wayland_uninit (struct vo *vo) destroy_window(wl); destroy_display(wl); destroy_input(wl); + for (int n = 0; n < 2; n++) + close(wl->wakeup_pipe[n]); talloc_free(wl); vo->wayland = NULL; } @@ -1096,47 +1095,11 @@ static void vo_wayland_fullscreen (struct vo *vo) } } -static int vo_wayland_poll (struct vo *vo, int timeout_msecs) -{ - struct vo_wayland_state *wl = vo->wayland; - struct wl_display *dp = wl->display.display; - - wl_display_dispatch_pending(dp); - wl_display_flush(dp); - - struct pollfd fd = { - wl->display.display_fd, - POLLIN | POLLERR | POLLHUP, - 0 - }; - - /* wl_display_dispatch is blocking - * wl_dipslay_dispatch_pending is non-blocking but does not read from the fd - * - * when pausing no input events get queued so we have to check if there - * are events to read from the file descriptor through poll */ - int polled; - if ((polled = poll(&fd, 1, timeout_msecs)) > 0) { - if (fd.revents & POLLERR || fd.revents & POLLHUP) { - MP_FATAL(wl, "error occurred on the display fd: " - "closing file descriptor\n"); - close(wl->display.display_fd); - mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN); - } - if (fd.revents & POLLIN) - wl_display_dispatch(dp); - else - wl_display_dispatch_pending(dp); - } - - return polled; -} - -static int vo_wayland_check_events (struct vo *vo) +static int vo_wayland_check_events(struct vo *vo) { struct vo_wayland_state *wl = vo->wayland; - vo_wayland_poll(vo, 0); + vo_wayland_wait_events(vo, 0); /* If drag & drop was ended poll the file descriptor from the offer if * there is data to read. @@ -1331,29 +1294,38 @@ void vo_wayland_request_frame(struct vo *vo, void *data, vo_wayland_frame_cb cb) frame_callback(wl, NULL, 0); } -bool vo_wayland_wait_frame(struct vo *vo) +void vo_wayland_wakeup(struct vo *vo) { struct vo_wayland_state *wl = vo->wayland; + (void)write(wl->wakeup_pipe[1], &(char){0}, 1); +} - if (!wl->frame.callback || wl->frame.dropping) - return false; +void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us) +{ + struct vo_wayland_state *wl = vo->wayland; + struct wl_display *dp = wl->display.display; - // If mpv isn't receiving frame callbacks (for 100ms), this usually means that - // mpv window is not visible and compositor tells kindly to not draw anything. - while (!wl->frame.pending) { - int64_t timeout = wl->frame.last_us + (100 * 1000) - mp_time_us(); + wl_display_dispatch_pending(dp); + wl_display_flush(dp); - if (timeout <= 0) - break; + struct pollfd fds[2] = { + {.fd = wl->display.display_fd, .events = POLLIN }, + {.fd = wl->wakeup_pipe[0], .events = POLLIN }, + }; - if (vo_wayland_poll(vo, timeout) <= 0) - break; - } + int64_t wait_us = until_time_us - mp_time_us(); + int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000); - wl->frame.dropping = !wl->frame.pending; - wl->frame.pending = false; + poll(fds, 2, timeout_ms); - // Return false if the frame callback was not received - // Handler should act accordingly. - return !wl->frame.dropping; + if (fds[0].revents & POLLERR || fds[0].revents & POLLHUP) { + MP_FATAL(wl, "error occurred on the display fd: " + "closing file descriptor\n"); + close(wl->display.display_fd); + mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN); + } else if (fds[0].revents & POLLIN) { + wl_display_dispatch(dp); + } else if (fds[1].revents & POLLIN) { + wl_display_dispatch_pending(dp); + } } diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index ec3f72ce67..cf659fb8e6 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -53,14 +53,12 @@ typedef void (*vo_wayland_frame_cb)(void *data, uint32_t time); struct vo_wayland_state { struct vo *vo; struct mp_log* log; + int wakeup_pipe[2]; struct { void *data; vo_wayland_frame_cb function; struct wl_callback *callback; - uint64_t last_us; - bool pending; - bool dropping; } frame; #if HAVE_GL_WAYLAND @@ -150,8 +148,9 @@ int vo_wayland_init(struct vo *vo); void vo_wayland_uninit(struct vo *vo); bool vo_wayland_config(struct vo *vo); int vo_wayland_control(struct vo *vo, int *events, int request, void *arg); +void vo_wayland_wakeup(struct vo *vo); +void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us); void vo_wayland_request_frame(struct vo *vo, void *data, vo_wayland_frame_cb cb); -bool vo_wayland_wait_frame(struct vo *vo); #endif /* MPLAYER_WAYLAND_COMMON_H */ -- cgit v1.2.3