mirror of https://github.com/mpv-player/mpv
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:
parent
8f51418ca4
commit
c0ef3cf9c2
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue