Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wayland: add icc support using xx-color-management-v4 #15178

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions video/out/opengl/context_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ static void wayland_egl_wait_events(struct ra_ctx *ctx, int64_t until_time_ns)
static void wayland_egl_update_render_opts(struct ra_ctx *ctx)
{
struct vo_wayland_state *wl = ctx->vo->wl;
vo_wayland_set_icc_file(wl);
vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha);
wl_surface_commit(wl->surface);
}
Expand Down
3 changes: 3 additions & 0 deletions video/out/vo_dmabuf_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,9 @@ static int control(struct vo *vo, uint32_t request, void *data)
int ret;

switch (request) {
case VOCTRL_UPDATE_RENDER_OPTS:
vo_wayland_set_icc_file(vo->wl);
return VO_TRUE;
case VOCTRL_RESET:
p->destroy_buffers = true;
return VO_TRUE;
Expand Down
3 changes: 3 additions & 0 deletions video/out/vo_wlshm.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ static int resize(struct vo *vo)
static int control(struct vo *vo, uint32_t request, void *data)
{
switch (request) {
case VOCTRL_UPDATE_RENDER_OPTS:
vo_wayland_set_icc_file(vo->wl);
return VO_TRUE;
case VOCTRL_SET_PANSCAN:
resize(vo);
return VO_TRUE;
Expand Down
1 change: 1 addition & 0 deletions video/out/vulkan/context_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ static void wayland_vk_wait_events(struct ra_ctx *ctx, int64_t until_time_ns)
static void wayland_vk_update_render_opts(struct ra_ctx *ctx)
{
struct vo_wayland_state *wl = ctx->vo->wl;
vo_wayland_set_icc_file(wl);
vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha);
wl_surface_commit(wl->surface);
}
Expand Down
186 changes: 181 additions & 5 deletions video/out/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
#include "input/input.h"
#include "input/keycodes.h"
#include "options/m_config.h"
#include "options/path.h"
#include "osdep/io.h"
#include "osdep/poll_wrapper.h"
#include "osdep/timer.h"
#include "present_sync.h"
#include "video/out/gpu/video.h"
#include "wayland_common.h"
#include "win_state.h"

Expand Down Expand Up @@ -169,6 +171,11 @@ struct vo_wayland_feedback_pool {
struct vo_wayland_output {
struct vo_wayland_state *wl;
struct wl_output *output;
struct xx_color_management_output_v4 *color_output;
struct xx_image_description_v4 *output_description;
struct xx_image_description_info_v4 *output_information;
void *icc_file;
uint32_t icc_size;
struct mp_rect geometry;
bool has_surface;
uint32_t id;
Expand Down Expand Up @@ -835,6 +842,100 @@ static const struct wl_data_device_listener data_device_listener = {
data_device_handle_selection,
};

static void info_done(void *data, struct xx_image_description_info_v4 *image_description_info)
{
}

static void icc_file(void *data, struct xx_image_description_info_v4 *image_description_info,
int32_t icc, uint32_t icc_size)
{
struct vo_wayland_output *output = data;
void *map = mmap(NULL, icc_size, PROT_READ, MAP_PRIVATE, icc, 0);
if (map != MAP_FAILED) {
output->icc_file = map;
output->icc_size = icc_size;
}
}

static void primaries(void *data, struct xx_image_description_info_v4 *image_description_info,
int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x,
int32_t b_y, int32_t w_x, int32_t w_y)
{
}

static void primaries_named(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t primaries)
{
}

static void tf_power(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t eexp)
{
}

static void tf_named(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t tf)
{
}

static void luminances(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum)
{
}

static void target_primaries(void *data, struct xx_image_description_info_v4 *image_description_info,
int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x,
int32_t b_y, int32_t w_x, int32_t w_y)
{
}

static void target_luminance(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t min_lum, uint32_t max_lum)
{
}

static void target_max_cll(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t max_cll)
{
}

static void target_max_fall(void *data, struct xx_image_description_info_v4 *image_description_info,
uint32_t max_fall)
{
}

static const struct xx_image_description_info_v4_listener image_description_info_listener = {
info_done,
icc_file,
primaries,
primaries_named,
tf_power,
tf_named,
luminances,
target_primaries,
target_luminance,
target_max_cll,
target_max_fall,
};

static void image_description_changed(void *data, struct xx_color_management_output_v4 *color_output)
{
struct vo_wayland_output *output = data;

if (output->output_description)
xx_image_description_v4_destroy(output->output_description);
output->output_description = xx_color_management_output_v4_get_image_description(output->color_output);

if (output->output_information)
xx_image_description_info_v4_destroy(output->output_information);
output->output_information = xx_image_description_v4_get_information(output->output_description);
xx_image_description_info_v4_add_listener(output->output_information, &image_description_info_listener, output);
}

static const struct xx_color_management_output_v4_listener color_output_listener = {
image_description_changed,
};

static void output_handle_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t phys_width,
int32_t phys_height, int32_t subpixel,
Expand Down Expand Up @@ -892,6 +993,14 @@ static void output_handle_done(void *data, struct wl_output *wl_output)
prepare_resize(wl);
}

if (o->color_output)
xx_color_management_output_v4_destroy(o->color_output);

if (wl->color_manager) {
o->color_output = xx_color_manager_v4_get_output(wl->color_manager, o->output);
xx_color_management_output_v4_add_listener(o->color_output, &color_output_listener, o);
}

wl->pending_vo_events |= VO_EVENT_WIN_STATE;
}

Expand Down Expand Up @@ -1373,7 +1482,8 @@ static void image_description_ready(void *data, struct xx_image_description_v4 *
uint32_t identity)
{
struct vo_wayland_state *wl = data;
xx_color_management_surface_v4_set_image_description(wl->color_surface, wl->image_description, 0);
if (wl->color_surface)
xx_color_management_surface_v4_set_image_description(wl->color_surface, wl->image_description, 0);
}

static const struct xx_image_description_v4_listener image_description_listener = {
Expand Down Expand Up @@ -2364,6 +2474,12 @@ static void remove_output(struct vo_wayland_output *out)
out->model, out->id);
wl_list_remove(&out->link);
wl_output_destroy(out->output);
if (out->color_output)
xx_color_management_output_v4_destroy(out->color_output);
if (out->output_description)
xx_image_description_v4_destroy(out->output_description);
if (out->output_information)
xx_image_description_info_v4_destroy(out->output_information);
talloc_free(out->make);
talloc_free(out->model);
talloc_free(out);
Expand Down Expand Up @@ -2916,6 +3032,15 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
*(char ***)arg = get_displays_spanned(wl);
return VO_TRUE;
}
case VOCTRL_GET_ICC_PROFILE: {
if (!wl->current_output)
return VO_FALSE;
void *icc_file = wl->current_output->icc_file;
if (!icc_file)
return VO_FALSE;
*(bstr *)arg = bstrdup(NULL, (bstr){icc_file, wl->current_output->icc_size});
return VO_TRUE;
}
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
int *s = arg;
if (wl->opts->window_maximized || wl->tiled) {
Expand Down Expand Up @@ -3202,12 +3327,17 @@ bool vo_wayland_init(struct vo *vo)
* before mpv does anything else. */
wl_display_roundtrip(wl->display);

// Only bind to vo_dmabuf_wayland for now to avoid conflicting with VK_hdr_layer
if (wl->color_manager && wl->supports_parametric && !strcmp(wl->vo->driver->name, "dmabuf-wayland")) {
// Only bind color surface to vo_dmabuf_wayland for now to avoid conflicting with VK_hdr_layer
if (wl->color_manager && wl->supports_parametric && !strcmp(wl->vo->driver->name, "dmabuf-wayland"))
wl->color_surface = xx_color_manager_v4_get_surface(wl->color_manager, wl->callback_surface);
} else {

if (wl->color_manager && !wl->supports_parametric)
MP_VERBOSE(wl, "Compositor does not support parametic image descriptions!\n");
}

if (wl->color_manager && !wl->supports_icc)
MP_VERBOSE(wl, "Compositor does not support reading icc profiles!\n");

vo_wayland_set_icc_file(wl);

return true;

Expand Down Expand Up @@ -3265,6 +3395,49 @@ bool vo_wayland_reconfig(struct vo *vo)
return true;
}

void vo_wayland_set_icc_file(struct vo_wayland_state *wl)
{
if (!wl->color_manager)
return;

if (!wl->icc_creator)
wl->icc_creator = xx_color_manager_v4_new_icc_creator(wl->color_manager);

struct mp_icc_opts *icc_opts = NULL;
char *fname = NULL;
uint32_t fd = -1;

icc_opts = mp_get_config_group(NULL, wl->vo->global, &mp_icc_conf);
if (!icc_opts->profile || !icc_opts->profile[0])
goto done;

fname = mp_get_user_path(NULL, wl->vo->global, icc_opts->profile);
fd = open(fname, O_RDONLY);
if (fd == -1) {
MP_WARN(wl, "Failed to open icc fd: %s\n", mp_strerror(errno));
goto done;
}

struct stat st;
if (fstat(fd, &st) == 0) {
if (st.st_size > 4000000) {
MP_WARN(wl, "File size of '%ld' exceeds 4MB limit allowed by the protocol!", st.st_size);
goto done;
}
xx_image_description_creator_icc_v4_set_icc_file(wl->icc_creator, fd, 0, st.st_size);
wl->image_description = xx_image_description_creator_icc_v4_create(wl->icc_creator);
wl->icc_creator = NULL;
xx_image_description_v4_add_listener(wl->image_description, &image_description_listener, wl);
}

done:
if (fname)
talloc_free(fname);
if (icc_opts)
talloc_free(icc_opts);
close(fd);
}

void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, bool alpha)
{
const int32_t width = mp_rect_w(wl->geometry);
Expand Down Expand Up @@ -3314,6 +3487,9 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->color_surface)
xx_color_management_surface_v4_destroy(wl->color_surface);

if (wl->icc_creator)
xx_image_description_creator_icc_v4_destroy(wl->icc_creator);

if (wl->image_creator_params)
xx_image_description_creator_params_v4_destroy(wl->image_creator_params);

Expand Down
4 changes: 3 additions & 1 deletion video/out/wayland_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ struct vo_wayland_state {
/* color-management */
struct xx_color_manager_v4 *color_manager;
struct xx_color_management_surface_v4 *color_surface;
struct xx_image_description_v4 *image_description;
struct xx_image_description_creator_icc_v4 *icc_creator;
struct xx_image_description_creator_params_v4 *image_creator_params;
struct xx_image_description_v4 *image_description;
struct mp_image_params target_params;
bool supports_icc;
bool supports_parametric;
Expand Down Expand Up @@ -187,6 +188,7 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg);

void vo_wayland_handle_color(struct vo_wayland_state *wl);
void vo_wayland_handle_scale(struct vo_wayland_state *wl);
void vo_wayland_set_icc_file(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);
void vo_wayland_uninit(struct vo *vo);
Expand Down