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.
This commit is contained in:
Rostislav Pehlivanov 2016-07-21 12:25:30 +01:00 committed by wm4
parent 8f51418ca4
commit c0ef3cf9c2
4 changed files with 59 additions and 77 deletions

View File

@ -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,
};

View File

@ -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),

View File

@ -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;
if (!wl->frame.callback || wl->frame.dropping)
return false;
// 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();
if (timeout <= 0)
break;
if (vo_wayland_poll(vo, timeout) <= 0)
break;
}
wl->frame.dropping = !wl->frame.pending;
wl->frame.pending = false;
// Return false if the frame callback was not received
// Handler should act accordingly.
return !wl->frame.dropping;
(void)write(wl->wakeup_pipe[1], &(char){0}, 1);
}
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;
wl_display_dispatch_pending(dp);
wl_display_flush(dp);
struct pollfd fds[2] = {
{.fd = wl->display.display_fd, .events = POLLIN },
{.fd = wl->wakeup_pipe[0], .events = POLLIN },
};
int64_t wait_us = until_time_us - mp_time_us();
int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000);
poll(fds, 2, timeout_ms);
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);
}
}

View File

@ -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 */