mirror of https://github.com/mpv-player/mpv
wayland: implement HIDPI support
The wayland protocol exposes scaling done by the compositor to compensate for small window sizes on small high DPI displays. If the program ignores the scaling done, what'll happen is the compositor is going to ask the program to be scaled down by N times the window size and then it'll upscale the program's surface by N times. The scaling algorithm seems to be bilinear so the scaling is quite obvious. This commit sets up callbacks to listen for the scaling factor of each output and, on rescale events, notifies the compositor that the surface's scale is what the compositor asked for and changes the player's surface to the appropriate size, causing no scaling to be done by the compositor. Compositors not supporting this interface will ignore the callbacks and do nothing, keeping program behaviour the same. For compositors supporting and using this interface (mutter), this will fix the rendering to be pixel precise as it should be. Both the opengl wayland backend and the wayland vo have been fixed to support this. Verified to not break either on weston and mutter. Signed-off-by: Rostislav Pehlivanov <atomnuker@gmail.com>
This commit is contained in:
parent
9009601c2d
commit
098ff4174c
|
@ -25,10 +25,14 @@ static void egl_resize(struct vo_wayland_state *wl)
|
|||
int32_t y = wl->window.sh_y;
|
||||
int32_t width = wl->window.sh_width;
|
||||
int32_t height = wl->window.sh_height;
|
||||
int32_t scale = 1;
|
||||
|
||||
if (!wl->egl_context.egl_window)
|
||||
return;
|
||||
|
||||
if (wl->display.current_output)
|
||||
scale = wl->display.current_output->scale;
|
||||
|
||||
// get the real size of the window
|
||||
// this improves moving the window while resizing it
|
||||
wl_egl_window_get_attached_size(wl->egl_context.egl_window,
|
||||
|
@ -46,14 +50,15 @@ static void egl_resize(struct vo_wayland_state *wl)
|
|||
if (y != 0)
|
||||
y = wl->window.height - height;
|
||||
|
||||
wl_egl_window_resize(wl->egl_context.egl_window, width, height, x, y);
|
||||
wl_surface_set_buffer_scale(wl->window.video_surface, scale);
|
||||
wl_egl_window_resize(wl->egl_context.egl_window, scale*width, scale*height, x, y);
|
||||
|
||||
wl->window.width = width;
|
||||
wl->window.height = height;
|
||||
|
||||
/* set size for mplayer */
|
||||
wl->vo->dwidth = wl->window.width;
|
||||
wl->vo->dheight = wl->window.height;
|
||||
wl->vo->dwidth = scale*wl->window.width;
|
||||
wl->vo->dheight = scale*wl->window.height;
|
||||
|
||||
wl->vo->want_redraw = true;
|
||||
wl->window.events = 0;
|
||||
|
|
|
@ -249,10 +249,15 @@ static bool resize(struct priv *p)
|
|||
if (!p->video_bufpool.back_buffer || SHM_BUFFER_IS_BUSY(p->video_bufpool.back_buffer))
|
||||
return false; // skip resizing if we can't guarantee pixel perfectness!
|
||||
|
||||
int32_t scale = 1;
|
||||
int32_t x = wl->window.sh_x;
|
||||
int32_t y = wl->window.sh_y;
|
||||
wl->vo->dwidth = wl->window.sh_width;
|
||||
wl->vo->dheight = wl->window.sh_height;
|
||||
|
||||
if (wl->display.current_output)
|
||||
scale = wl->display.current_output->scale;
|
||||
|
||||
wl->vo->dwidth = scale*wl->window.sh_width;
|
||||
wl->vo->dheight = scale*wl->window.sh_height;
|
||||
|
||||
vo_get_src_dst_rects(p->vo, &p->src, &p->dst, &p->osd);
|
||||
p->src_w = p->src.x1 - p->src.x0;
|
||||
|
@ -273,6 +278,7 @@ static bool resize(struct priv *p)
|
|||
if (y != 0)
|
||||
y = wl->window.height - p->dst_h;
|
||||
|
||||
wl_surface_set_buffer_scale(wl->window.video_surface, scale);
|
||||
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) {
|
||||
|
@ -301,7 +307,7 @@ static bool resize(struct priv *p)
|
|||
if (!p->enable_alpha) {
|
||||
struct wl_region *opaque =
|
||||
wl_compositor_create_region(wl->display.compositor);
|
||||
wl_region_add(opaque, 0, 0, p->dst_w, p->dst_h);
|
||||
wl_region_add(opaque, 0, 0, p->dst_w/scale, p->dst_h/scale);
|
||||
wl_surface_set_opaque_region(wl->window.video_surface, opaque);
|
||||
wl_region_destroy(opaque);
|
||||
}
|
||||
|
@ -464,14 +470,19 @@ static const bool osd_formats[SUBBITMAP_COUNT] = {
|
|||
|
||||
static void draw_osd(struct vo *vo)
|
||||
{
|
||||
int32_t scale = 1;
|
||||
struct priv *p = vo->priv;
|
||||
|
||||
if (p->wl && p->wl->display.current_output)
|
||||
scale = p->wl->display.current_output->scale;
|
||||
|
||||
// detach 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->osd_surfaces[i];
|
||||
wl_surface_attach(s, NULL, 0, 0);
|
||||
wl_surface_set_buffer_scale(s, scale);
|
||||
wl_surface_damage(s, 0, 0, p->dst_w, p->dst_h);
|
||||
wl_surface_commit(s);
|
||||
}
|
||||
|
|
|
@ -189,9 +189,22 @@ static void output_handle_mode(void *data,
|
|||
output->refresh_rate = refresh;
|
||||
}
|
||||
|
||||
static void output_handle_done(void* data, struct wl_output *wl_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void output_handle_scale(void* data, struct wl_output *wl_output,
|
||||
int32_t factor)
|
||||
{
|
||||
struct vo_wayland_output *output = data;
|
||||
output->scale = factor;
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
output_handle_geometry,
|
||||
output_handle_mode
|
||||
output_handle_mode,
|
||||
output_handle_done,
|
||||
output_handle_scale
|
||||
};
|
||||
|
||||
|
||||
|
@ -401,11 +414,15 @@ static void pointer_handle_motion(void *data,
|
|||
wl_fixed_t sx_w,
|
||||
wl_fixed_t sy_w)
|
||||
{
|
||||
int32_t scale = 1;
|
||||
struct vo_wayland_state *wl = data;
|
||||
|
||||
if (wl->display.current_output)
|
||||
scale = wl->display.current_output->scale;
|
||||
|
||||
wl->cursor.pointer = pointer;
|
||||
wl->window.mouse_x = wl_fixed_to_int(sx_w);
|
||||
wl->window.mouse_y = wl_fixed_to_int(sy_w);
|
||||
wl->window.mouse_x = scale*wl_fixed_to_int(sx_w);
|
||||
wl->window.mouse_y = scale*wl_fixed_to_int(sy_w);
|
||||
|
||||
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->window.mouse_x,
|
||||
wl->window.mouse_y);
|
||||
|
@ -606,7 +623,8 @@ static void registry_handle_global (void *data,
|
|||
if (strcmp(interface, "wl_compositor") == 0) {
|
||||
|
||||
wl->display.compositor = wl_registry_bind(reg, id,
|
||||
&wl_compositor_interface, 1);
|
||||
&wl_compositor_interface,
|
||||
MPMIN(3, version));
|
||||
}
|
||||
|
||||
else if (strcmp(interface, "wl_shell") == 0) {
|
||||
|
@ -625,7 +643,9 @@ static void registry_handle_global (void *data,
|
|||
talloc_zero(wl, struct vo_wayland_output);
|
||||
|
||||
output->id = id;
|
||||
output->output = wl_registry_bind(reg, id, &wl_output_interface, 1);
|
||||
output->scale = 1;
|
||||
output->output = wl_registry_bind(reg, id, &wl_output_interface,
|
||||
MPMIN(2, version));
|
||||
|
||||
wl_output_add_listener(output->output, &output_listener, output);
|
||||
wl_list_insert(&wl->display.output_list, &output->link);
|
||||
|
@ -1016,9 +1036,10 @@ int vo_wayland_init (struct vo *vo)
|
|||
"\tvendor: %s\n"
|
||||
"\tmodel: %s\n"
|
||||
"\tw: %d, h: %d\n"
|
||||
"\tscale: %d\n"
|
||||
"\tHz: %d\n",
|
||||
o->make, o->model,
|
||||
o->width, o->height,
|
||||
o->width, o->height, o->scale,
|
||||
o->refresh_rate / 1000);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ struct vo_wayland_output {
|
|||
uint32_t flags;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t scale;
|
||||
int32_t refresh_rate; // fps (mHz)
|
||||
const char *make;
|
||||
const char *model;
|
||||
|
|
Loading…
Reference in New Issue