Skip to content

Commit

Permalink
wayland: add support for frog-color-management-v1
Browse files Browse the repository at this point in the history
The big color-management MR in wayland-protocols has been in development
for a very long time and honestly that protocol is super complex and
painful to parse. The frog protocol stuff is relatively new but it turns
out that kwin actually has support for this. Additionally, Arch and
Fedora even package these protocols. Given that mpv is certainly a
client that benefits from color stuff, it's not too much work to plug in
this simple protocol so users can actually start using it. This adds an
--wayland-colorspace-hint option which passes hdr metadata to the
compositor. Unlike the existing solution (using vulkan), this is
completely graphics API agnostic and will work with any wayland backend.
  • Loading branch information
Dudemanguy committed Sep 26, 2024
1 parent 92e97d2 commit ca92430
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 0 deletions.
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,8 @@ endforeach
features += {'wayland': wayland_deps and wayland['header'] and wayland['scanner'].found()}

if features['wayland']
frog_protocols = dependency('frog-protocols', required: false)
features += {'frog-protocols': frog_protocols.found()}
subdir(join_paths('video', 'out'))
endif

Expand Down
1 change: 1 addition & 0 deletions options/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ static const m_option_t mp_vo_opt_list[] = {
{"x11-wid-title", OPT_BOOL(x11_wid_title)},
#endif
#if HAVE_WAYLAND
{"wayland-colorspace-hint", OPT_BOOL(wl_colorspace_hint)},
{"wayland-configure-bounds", OPT_CHOICE(wl_configure_bounds,
{"auto", -1}, {"no", 0}, {"yes", 1})},
{"wayland-content-type", OPT_CHOICE(wl_content_type, {"auto", -1}, {"none", 0},
Expand Down
1 change: 1 addition & 0 deletions options/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef struct mp_vo_opts {
bool cursor_passthrough;
bool native_keyrepeat;

bool wl_colorspace_hint;
int wl_configure_bounds;
int wl_content_type;
bool wl_disable_vsync;
Expand Down
5 changes: 5 additions & 0 deletions video/out/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ protocols = [[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml']
wl_protocols_source = []
wl_protocols_headers = []

if features['frog-protocols']
frog_protocol_dir = frog_protocols.get_variable(pkgconfig: 'pkgdatadir', internal: 'pkgdatadir')
protocols += [[frog_protocol_dir, 'frog-color-management-v1.xml']]
endif

foreach v: ['1.32']
features += {'wayland-protocols-' + v.replace('.', '-'):
wayland['deps'][2].version().version_compare('>=' + v)}
Expand Down
2 changes: 2 additions & 0 deletions video/out/opengl/context_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ static void wayland_egl_swap_buffers(struct ra_ctx *ctx)
struct priv *p = ctx->priv;
struct vo_wayland_state *wl = ctx->vo->wl;

vo_wayland_handle_hdr_metadata(wl);

eglSwapBuffers(p->egl_display, p->egl_surface);

if (!wl->opts->wl_disable_vsync)
Expand Down
1 change: 1 addition & 0 deletions video/out/vo_dmabuf_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)

pts = frame->current ? frame->current->pts : 0;
if (frame->current) {
vo_wayland_handle_hdr_metadata(wl);
buf = buffer_get(vo, frame);

if (buf && buf->frame) {
Expand Down
2 changes: 2 additions & 0 deletions video/out/vo_wlshm.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
if (!render)
return;

vo_wayland_handle_hdr_metadata(wl);

buf = p->free_buffers;
if (buf) {
p->free_buffers = buf->next;
Expand Down
2 changes: 2 additions & 0 deletions video/out/vulkan/context_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ static void wayland_vk_swap_buffers(struct ra_ctx *ctx)
{
struct vo_wayland_state *wl = ctx->vo->wl;

vo_wayland_handle_hdr_metadata(wl);

if (!wl->opts->wl_disable_vsync)
vo_wayland_wait_frame(wl);

Expand Down
102 changes: 102 additions & 0 deletions video/out/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "osdep/poll_wrapper.h"
#include "osdep/timer.h"
#include "present_sync.h"
#include "video/mp_image.h"
#include "wayland_common.h"
#include "win_state.h"

Expand All @@ -55,6 +56,10 @@
#include "cursor-shape-v1.h"
#endif

#if HAVE_FROG_PROTOCOLS
#include "frog-color-management-v1.h"
#endif

#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 22
#define HAVE_WAYLAND_1_22
#endif
Expand Down Expand Up @@ -147,6 +152,27 @@ static const struct mp_keymap keymap[] = {
{0, 0}
};

#if HAVE_FROG_PROTOCOLS
static const struct {
enum pl_color_primaries pl_primaries;
int frog_primaries;
} primaries_map[] = {
{PL_COLOR_PRIM_BT_709, FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709},
{PL_COLOR_PRIM_BT_2020, FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020},
{0, 0},
};

static const struct {
enum pl_color_transfer pl_transfer;
int frog_transfer;
} transfer_map[] = {
{PL_COLOR_TRC_SRGB, FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB},
{PL_COLOR_TRC_GAMMA22, FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22},
{PL_COLOR_TRC_PQ, FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ},
{0, 0},
};
#endif

struct vo_wayland_feedback_pool {
struct wp_presentation_feedback **fback;
struct vo_wayland_state *wl;
Expand Down Expand Up @@ -1560,6 +1586,13 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
}
#endif

#if HAVE_FROG_PROTOCOLS
if (!strcmp(interface, frog_color_management_factory_v1_interface.name) && found++) {
ver = 1;
wl->color_management = wl_registry_bind(reg, id, &frog_color_management_factory_v1_interface, ver);
}
#endif

if (!strcmp(interface, wp_presentation_interface.name) && found++) {
ver = 1;
wl->presentation = wl_registry_bind(reg, id, &wp_presentation_interface, ver);
Expand Down Expand Up @@ -2098,6 +2131,26 @@ static int handle_round(int scale, int n)
return (scale * n + WAYLAND_SCALE_FACTOR / 2) / WAYLAND_SCALE_FACTOR;
}

#if HAVE_FROG_PROTOCOLS
static enum pl_color_primaries pl_primaries_to_frog(enum pl_color_primaries primaries)
{
for (int i = 0; primaries_map[i].pl_primaries; i++) {
if (primaries_map[i].pl_primaries == primaries)
return primaries_map[i].frog_primaries;
}
return 0;
}

static enum pl_color_transfer pl_transfer_to_frog(enum pl_color_transfer transfer)
{
for (int i = 0; transfer_map[i].pl_transfer; i++) {
if (transfer_map[i].pl_transfer == transfer)
return transfer_map[i].frog_transfer;
}
return 0;
}
#endif

static void prepare_resize(struct vo_wayland_state *wl)
{
int32_t width = mp_rect_w(wl->geometry) / wl->scaling_factor;
Expand Down Expand Up @@ -2192,6 +2245,17 @@ static void remove_seat(struct vo_wayland_seat *seat)
return;
}

static void set_colorspace(struct vo_wayland_state *wl)
{
if (!wl->color_surface || !wl->vo->target_params)
return;
#if HAVE_FROG_PROTOCOLS
struct pl_color_space color = wl->vo->target_params->color;
frog_color_managed_surface_set_known_container_color_volume(wl->color_surface, pl_primaries_to_frog(color.primaries));
frog_color_managed_surface_set_known_transfer_function(wl->color_surface, pl_transfer_to_frog(color.transfer));
#endif
}

static void set_content_type(struct vo_wayland_state *wl)
{
if (!wl->content_type_manager)
Expand Down Expand Up @@ -2606,6 +2670,8 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
&wl->opts->border);
}
}
if (opt == &opts->wl_colorspace_hint)
vo_wayland_handle_hdr_metadata(wl);
if (opt == &opts->wl_content_type)
set_content_type(wl);
if (opt == &opts->cursor_passthrough)
Expand Down Expand Up @@ -2716,6 +2782,23 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
return VO_NOTIMPL;
}

void vo_wayland_handle_hdr_metadata(struct vo_wayland_state *wl)
{
if (wl->reset_colorspace) {
set_colorspace(wl);
wl->reset_colorspace = false;
}

if (!wl->color_surface || !wl->opts->wl_colorspace_hint || !pl_color_space_is_hdr(&wl->vo->target_params->color))
return;
#if HAVE_FROG_PROTOCOLS
struct pl_hdr_metadata hdr = wl->vo->target_params->color.hdr;
frog_color_managed_surface_set_hdr_metadata(wl->color_surface, hdr.prim.red.x, hdr.prim.red.y, hdr.prim.green.x,
hdr.prim.green.y, hdr.prim.blue.x, hdr.prim.blue.y, hdr.prim.white.x,
hdr.prim.white.y, hdr.max_luma, hdr.min_luma, hdr.max_cll, hdr.max_fall);
#endif
}

void vo_wayland_handle_scale(struct vo_wayland_state *wl)
{
wp_viewport_set_destination(wl->viewport, lround(mp_rect_w(wl->geometry) / wl->scaling_factor),
Expand Down Expand Up @@ -2825,6 +2908,15 @@ bool vo_wayland_init(struct vo *vo)
}
#endif

#if HAVE_FROG_PROTOCOLS
if (wl->color_management) {
wl->color_surface = frog_color_management_factory_v1_get_color_managed_surface(wl->color_management, wl->surface);
} else {
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
frog_color_management_factory_v1_interface.name);
}
#endif

if (wl->dnd_devman) {
struct vo_wayland_seat *seat;
wl_list_for_each(seat, &wl->seat_list, link) {
Expand Down Expand Up @@ -2895,6 +2987,8 @@ bool vo_wayland_reconfig(struct vo *vo)

MP_VERBOSE(wl, "Reconfiguring!\n");

wl->reset_colorspace = true;

if (!wl->current_output) {
wl->current_output = find_output(wl);
if (!wl->current_output)
Expand Down Expand Up @@ -2973,6 +3067,14 @@ void vo_wayland_uninit(struct vo *vo)
wp_cursor_shape_manager_v1_destroy(wl->cursor_shape_manager);
#endif

#if HAVE_FROG_PROTOCOLS
if (wl->color_management)
frog_color_management_factory_v1_destroy(wl->color_management);

if (wl->color_surface)
frog_color_managed_surface_destroy(wl->color_surface);
#endif

if (wl->cursor_surface)
wl_surface_destroy(wl->cursor_surface);

Expand Down
6 changes: 6 additions & 0 deletions video/out/wayland_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ struct vo_wayland_state {
int timeout_count;
int wakeup_pipe[2];

/* color-management */
void *color_management;
void *color_surface;
bool reset_colorspace;

/* content-type */
struct wp_content_type_manager_v1 *content_type_manager;
struct wp_content_type_v1 *content_type;
Expand Down Expand Up @@ -174,6 +179,7 @@ bool vo_wayland_reconfig(struct vo *vo);
int vo_wayland_allocate_memfd(struct vo *vo, size_t size);
int vo_wayland_control(struct vo *vo, int *events, int request, void *arg);

void vo_wayland_handle_hdr_metadata(struct vo_wayland_state *wl);
void vo_wayland_handle_scale(struct vo_wayland_state *wl);
void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, bool alpha);
void vo_wayland_sync_swap(struct vo_wayland_state *wl);
Expand Down

0 comments on commit ca92430

Please sign in to comment.