color-management-v1: add support for mastering display metadata

This commit is contained in:
Simon Ser 2025-01-24 17:31:50 +01:00
parent dcf38e3ea9
commit 95c85af87c
2 changed files with 95 additions and 7 deletions

View file

@ -10,6 +10,7 @@
#define WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
#include <wayland-server.h>
#include <wlr/render/color.h>
#include "color-management-v1-protocol.h"
@ -19,6 +20,14 @@ struct wlr_image_description_v1_data {
uint32_t tf_named; // enum wp_color_manager_v1_transfer_function, zero if unset
uint32_t primaries_named; // enum wp_color_manager_v1_primaries, zero if unset
bool has_mastering_display_primaries;
struct wlr_color_primaries mastering_display_primaries;
bool has_mastering_luminance;
struct {
float min, max; // cd/m²
} mastering_luminance;
uint32_t max_cll, max_fall; // cd/m², zero if unset
};

View file

@ -87,6 +87,10 @@ static int32_t encode_cie1931_coord(float value) {
return round(value * 1000 * 1000);
}
static float decode_cie1931_coord(int32_t raw) {
return (float)raw / (1000 * 1000);
}
static const struct wp_image_description_v1_interface image_desc_impl;
static struct wlr_image_description_v1 *image_desc_from_resource(struct wl_resource *resource) {
@ -404,6 +408,31 @@ image_desc_creator_params_from_resource(struct wl_resource *resource) {
return wl_resource_get_user_data(resource);
}
static bool check_mastering_luminance_range(struct wl_resource *params_resource,
const struct wlr_image_description_v1_data *data,
float value, const char *name) {
if (!data->has_mastering_luminance || value == 0) {
return true;
}
if (value <= data->mastering_luminance.min) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE,
"%s must be greater than min L of the mastering luminance range",
name);
return false;
}
if (value > data->mastering_luminance.max) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE,
"%s must be less or equal to max L of the mastering luminance range",
name);
return false;
}
return true;
}
static void image_desc_creator_params_handle_create(struct wl_client *client,
struct wl_resource *params_resource, uint32_t id) {
struct wlr_image_description_creator_params_v1 *params =
@ -430,6 +459,14 @@ static void image_desc_creator_params_handle_create(struct wl_client *client,
return;
}
if (!check_mastering_luminance_range(params_resource, &params->data, params->data.max_cll, "max_cll") ||
!check_mastering_luminance_range(params_resource, &params->data, params->data.max_fall, "max_fall")) {
return;
}
// TODO: check that the target color volume is contained within the
// primary color volume
image_desc_create_ready(params->manager, params_resource, id, &params->data, false);
}
@ -519,16 +556,59 @@ static void image_desc_creator_params_handle_set_mastering_display_primaries(
struct wl_client *client, struct wl_resource *params_resource,
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) {
struct wlr_image_description_creator_params_v1 *params =
image_desc_creator_params_from_resource(params_resource);
if (!params->manager->features.set_mastering_display_primaries) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE,
"set_mastering_display_primaries is not supported");
return;
}
if (params->data.has_mastering_display_primaries) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET,
"mastering display primaries already set");
return;
}
params->data.has_mastering_display_primaries = true;
params->data.mastering_display_primaries = (struct wlr_color_primaries){
.red = { decode_cie1931_coord(r_x), decode_cie1931_coord(r_y) },
.green = { decode_cie1931_coord(g_x), decode_cie1931_coord(g_y) },
.blue = { decode_cie1931_coord(b_x), decode_cie1931_coord(b_y) },
.white = { decode_cie1931_coord(w_x), decode_cie1931_coord(w_y) },
};
}
static void image_desc_creator_params_handle_set_mastering_luminance(struct wl_client *client,
struct wl_resource *params_resource, uint32_t min_lum, uint32_t max_lum) {
struct wlr_image_description_creator_params_v1 *params =
image_desc_creator_params_from_resource(params_resource);
if (!params->manager->features.set_mastering_display_primaries) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE,
"set_mastering_luminance is not supported");
return;
}
if (params->data.has_mastering_luminance) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET,
"mastering luminance already set");
return;
}
params->data.has_mastering_luminance = true;
params->data.mastering_luminance.min = (float)min_lum / 10000;
params->data.mastering_luminance.max = max_lum;
if (params->data.mastering_luminance.max <= params->data.mastering_luminance.min) {
wl_resource_post_error(params_resource,
WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE,
"max luminance must be greater than min luminance");
return;
}
}
static void image_desc_creator_params_handle_set_max_cll(struct wl_client *client,
@ -822,7 +902,6 @@ struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *disp
assert(!options->features.set_primaries);
assert(!options->features.set_tf_power);
assert(!options->features.set_luminances);
assert(!options->features.set_mastering_display_primaries);
assert(!options->features.extended_target_volume);
assert(!options->features.windows_scrgb);