Merge branch 'wip/otte/for-main' into 'main'

wayland: Redo the image description code

See merge request GNOME/gtk!7505
This commit is contained in:
Benjamin Otte 2024-07-27 06:09:15 +00:00
commit d301d16aee
5 changed files with 226 additions and 80 deletions

View File

@ -536,7 +536,7 @@ gdk_registry_handle_global (void *data,
} }
else if (strcmp (interface, "xx_color_manager_v4") == 0) else if (strcmp (interface, "xx_color_manager_v4") == 0)
{ {
display_wayland->color = gdk_wayland_color_new (registry, id, version); display_wayland->color = gdk_wayland_color_new (display_wayland, registry, id, version);
} }
else if (strcmp (interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) else if (strcmp (interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0)
{ {

View File

@ -48,6 +48,7 @@ struct _GdkWaylandSurface
GdkWaylandPresentationTime *presentation_time; GdkWaylandPresentationTime *presentation_time;
unsigned int color_state_changed : 1;
unsigned int initial_configure_received : 1; unsigned int initial_configure_received : 1;
unsigned int has_uncommitted_ack_configure : 1; unsigned int has_uncommitted_ack_configure : 1;
unsigned int has_pending_subsurface_commits : 1; unsigned int has_pending_subsurface_commits : 1;

View File

@ -772,6 +772,20 @@ gdk_wayland_surface_sync_viewport (GdkSurface *surface)
self->viewport_dirty = FALSE; self->viewport_dirty = FALSE;
} }
static void
gdk_wayland_surface_sync_color_state (GdkSurface *surface)
{
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
if (!self->color_state_changed)
return;
gdk_wayland_color_surface_set_color_state (self->display_server.color,
gdk_surface_get_color_state (surface));
self->color_state_changed = FALSE;
}
void void
gdk_wayland_surface_sync (GdkSurface *surface) gdk_wayland_surface_sync (GdkSurface *surface)
{ {
@ -779,6 +793,7 @@ gdk_wayland_surface_sync (GdkSurface *surface)
gdk_wayland_surface_sync_opaque_region (surface); gdk_wayland_surface_sync_opaque_region (surface);
gdk_wayland_surface_sync_input_region (surface); gdk_wayland_surface_sync_input_region (surface);
gdk_wayland_surface_sync_buffer_scale (surface); gdk_wayland_surface_sync_buffer_scale (surface);
gdk_wayland_surface_sync_color_state (surface);
gdk_wayland_surface_sync_viewport (surface); gdk_wayland_surface_sync_viewport (surface);
} }
@ -791,6 +806,7 @@ gdk_wayland_surface_needs_commit (GdkSurface *surface)
self->opaque_region_dirty || self->opaque_region_dirty ||
self->input_region_dirty || self->input_region_dirty ||
self->buffer_scale_dirty || self->buffer_scale_dirty ||
self->color_state_changed ||
self->viewport_dirty; self->viewport_dirty;
} }
@ -910,7 +926,11 @@ preferred_changed (GdkWaylandColorSurface *color,
GdkColorState *color_state, GdkColorState *color_state,
gpointer data) gpointer data)
{ {
gdk_surface_set_color_state (GDK_SURFACE (data), color_state); GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (data);
gdk_surface_set_color_state (GDK_SURFACE (self), color_state);
self->color_state_changed = TRUE;
} }
static void static void

View File

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "gdkcolorstateprivate.h" #include "gdkcolorstateprivate.h"
#include "gdkwaylanddisplay.h"
#include <wayland-client.h> #include <wayland-client.h>
typedef struct _GdkWaylandColor GdkWaylandColor; typedef struct _GdkWaylandColor GdkWaylandColor;
GdkWaylandColor * gdk_wayland_color_new (struct wl_registry *registry, GdkWaylandColor * gdk_wayland_color_new (GdkWaylandDisplay *display,
struct wl_registry *registry,
uint32_t id, uint32_t id,
uint32_t version); uint32_t version);

View File

@ -66,14 +66,10 @@ cicp_to_wl_transfer (uint tf)
return 0; return 0;
} }
typedef struct
{
guint cp, tf;
struct xx_image_description_v4 *desc;
} ImageDescEntry;
struct _GdkWaylandColor struct _GdkWaylandColor
{ {
GdkWaylandDisplay *display;
struct xx_color_manager_v4 *color_manager; struct xx_color_manager_v4 *color_manager;
struct { struct {
unsigned int intents; unsigned int intents;
@ -82,9 +78,48 @@ struct _GdkWaylandColor
unsigned int primaries; unsigned int primaries;
} color_manager_supported; } color_manager_supported;
GArray *image_descs; GHashTable *cs_to_desc; /* GdkColorState => xx_image_description_v4 or NULL */
GHashTable *id_to_cs; /* uint32 identifier => GdkColorState */
}; };
static guint
color_state_hash (gconstpointer data)
{
GdkColorState *cs = (GdkColorState *) data;
const GdkCicp *cicp;
cicp = gdk_color_state_get_cicp (cs);
if (cicp)
{
GdkCicp norm;
gdk_cicp_normalize (cicp, &norm);
return norm.color_primaries << 24 | norm.transfer_function;
}
return 0;
}
static gboolean
color_state_equal (gconstpointer a,
gconstpointer b)
{
GdkColorState *csa = (GdkColorState *) a;
GdkColorState *csb = (GdkColorState *) b;
const GdkCicp *cicpa, *cicpb;
GdkCicp norma, normb;
cicpa = gdk_color_state_get_cicp (csa);
cicpb = gdk_color_state_get_cicp (csb);
if (cicpa == NULL || cicpb == NULL)
return FALSE;
gdk_cicp_normalize (cicpa, &norma);
gdk_cicp_normalize (cicpb, &normb);
return norma.color_primaries == normb.color_primaries &&
norma.transfer_function == normb.transfer_function;
}
static void static void
xx_color_manager_v4_supported_intent (void *data, xx_color_manager_v4_supported_intent (void *data,
struct xx_color_manager_v4 *xx_color_manager_v4, struct xx_color_manager_v4 *xx_color_manager_v4,
@ -133,7 +168,8 @@ static struct xx_color_manager_v4_listener color_manager_listener = {
}; };
GdkWaylandColor * GdkWaylandColor *
gdk_wayland_color_new (struct wl_registry *registry, gdk_wayland_color_new (GdkWaylandDisplay *display,
struct wl_registry *registry,
uint32_t id, uint32_t id,
uint32_t version) uint32_t version)
{ {
@ -141,7 +177,15 @@ gdk_wayland_color_new (struct wl_registry *registry,
color = g_new0 (GdkWaylandColor, 1); color = g_new0 (GdkWaylandColor, 1);
color->image_descs = g_array_new (FALSE, FALSE, sizeof (ImageDescEntry)); color->display = display;
color->cs_to_desc = g_hash_table_new_full (color_state_hash,
color_state_equal,
(GDestroyNotify) gdk_color_state_unref,
(GDestroyNotify) xx_image_description_v4_destroy);
color->id_to_cs = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify) gdk_color_state_unref);
color->color_manager = wl_registry_bind (registry, color->color_manager = wl_registry_bind (registry,
id, id,
@ -160,13 +204,8 @@ gdk_wayland_color_free (GdkWaylandColor *color)
{ {
g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy); g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
for (int i = 0; i < color->image_descs->len; i++) g_hash_table_unref (color->cs_to_desc);
{ g_hash_table_unref (color->id_to_cs);
ImageDescEntry *e = &g_array_index (color->image_descs, ImageDescEntry, i);
xx_image_description_v4_destroy (e->desc);
}
g_array_unref (color->image_descs);
g_free (color); g_free (color);
} }
@ -177,60 +216,126 @@ gdk_wayland_color_get_color_manager (GdkWaylandColor *color)
return (struct wl_proxy *) color->color_manager; return (struct wl_proxy *) color->color_manager;
} }
typedef struct _CsImageDescListenerData {
GdkWaylandColor *color;
GdkColorState *color_state;
gboolean sync;
gboolean done;
} CsImageDescListenerData;
static void static void
std_image_desc_failed (void *data, cs_image_listener_data_free (CsImageDescListenerData *csi)
struct xx_image_description_v4 *desc,
uint32_t cause,
const char *msg)
{ {
csi->done = TRUE;
if (csi->sync)
return;
g_free (csi);
}
static void
cs_image_desc_failed (void *data,
struct xx_image_description_v4 *desc,
uint32_t cause,
const char *msg)
{
CsImageDescListenerData *csi = data;
g_warning ("Failed to get one of the standard image descriptions: %s", msg); g_warning ("Failed to get one of the standard image descriptions: %s", msg);
xx_image_description_v4_destroy (desc); xx_image_description_v4_destroy (desc);
g_hash_table_insert (csi->color->cs_to_desc,
gdk_color_state_ref (csi->color_state),
NULL);
cs_image_listener_data_free (csi);
} }
static void static void
std_image_desc_ready (void *data, cs_image_desc_ready (void *data,
struct xx_image_description_v4 *desc, struct xx_image_description_v4 *desc,
uint32_t identity) uint32_t identity)
{ {
struct xx_image_description_v4 **ptr = data; CsImageDescListenerData *csi = data;
*ptr = desc; g_hash_table_insert (csi->color->cs_to_desc,
gdk_color_state_ref (csi->color_state),
desc);
g_hash_table_insert (csi->color->id_to_cs,
GUINT_TO_POINTER (identity),
gdk_color_state_ref (csi->color_state));
cs_image_listener_data_free (csi);
} }
static struct xx_image_description_v4_listener std_image_desc_listener = { static struct xx_image_description_v4_listener cs_image_desc_listener = {
std_image_desc_failed, cs_image_desc_failed,
std_image_desc_ready, cs_image_desc_ready,
}; };
static void static void
create_image_desc (GdkWaylandColor *color, create_image_desc (GdkWaylandColor *color,
uint32_t primaries, GdkColorState *cs,
uint32_t transfer) gboolean sync)
{ {
CsImageDescListenerData data;
struct xx_image_description_creator_params_v4 *creator; struct xx_image_description_creator_params_v4 *creator;
struct xx_image_description_v4 *desc; struct xx_image_description_v4 *desc;
ImageDescEntry entry; const GdkCicp *cicp;
ImageDescEntry *e; GdkCicp norm;
uint32_t primaries, tf;
entry.cp = primaries; cicp = gdk_color_state_get_cicp (cs);
entry.tf = transfer; if (!cicp)
entry.desc = NULL; {
GDK_DEBUG (MISC, "Unsupported color state %s: Not a CICP colorstate",
g_array_append_val (color->image_descs, entry); gdk_color_state_get_name (cs));
e = &g_array_index (color->image_descs, ImageDescEntry, color->image_descs->len - 1); g_hash_table_insert (color->cs_to_desc, gdk_color_state_ref (cs), NULL);
return;
}
gdk_cicp_normalize (cicp, &norm);
primaries = cicp_to_wl_primaries (norm.color_primaries);
tf = cicp_to_wl_transfer (norm.transfer_function);
if ((color->color_manager_supported.primaries & (1 << primaries)) == 0 || if ((color->color_manager_supported.primaries & (1 << primaries)) == 0 ||
(color->color_manager_supported.transfers & (1 << transfer)) == 0) (color->color_manager_supported.transfers & (1 << tf)) == 0)
return; {
GDK_DEBUG (MISC, "Unsupported color state %s: Primaries or transfer function unsupported",
gdk_color_state_get_name (cs));
g_hash_table_insert (color->cs_to_desc, gdk_color_state_ref (cs), NULL);
return;
}
data.color = color;
data.color_state = cs;
data.sync = sync;
data.done = FALSE;
creator = xx_color_manager_v4_new_parametric_creator (color->color_manager); creator = xx_color_manager_v4_new_parametric_creator (color->color_manager);
xx_image_description_creator_params_v4_set_primaries_named (creator, primaries); xx_image_description_creator_params_v4_set_primaries_named (creator, primaries);
xx_image_description_creator_params_v4_set_tf_named (creator, transfer); xx_image_description_creator_params_v4_set_tf_named (creator, tf);
desc = xx_image_description_creator_params_v4_create (creator); desc = xx_image_description_creator_params_v4_create (creator);
xx_image_description_v4_add_listener (desc, &std_image_desc_listener, &e->desc); if (sync)
{
struct wl_event_queue *event_queue;
event_queue = wl_display_create_queue (color->display->wl_display);
wl_proxy_set_queue ((struct wl_proxy *) desc, event_queue);
xx_image_description_v4_add_listener (desc, &cs_image_desc_listener, &data);
while (!data.done)
gdk_wayland_display_dispatch_queue (GDK_DISPLAY (color->display), event_queue);
wl_event_queue_destroy (event_queue);
}
else
{
xx_image_description_v4_add_listener (desc, &cs_image_desc_listener, g_memdup (&data, sizeof data));
}
} }
gboolean gboolean
@ -298,26 +403,18 @@ gdk_wayland_color_prepare (GdkWaylandColor *color)
if (color->color_manager) if (color->color_manager)
{ {
create_image_desc (color, create_image_desc (color, GDK_COLOR_STATE_SRGB, FALSE);
XX_COLOR_MANAGER_V4_PRIMARIES_SRGB,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB);
if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR)) if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR))
create_image_desc (color, create_image_desc (color, GDK_COLOR_STATE_SRGB_LINEAR, FALSE);
XX_COLOR_MANAGER_V4_PRIMARIES_SRGB,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
if (color->color_manager_supported.primaries & (1 << XX_COLOR_MANAGER_V4_PRIMARIES_BT2020)) if (color->color_manager_supported.primaries & (1 << XX_COLOR_MANAGER_V4_PRIMARIES_BT2020))
{ {
if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ)) if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ))
create_image_desc (color, create_image_desc (color, GDK_COLOR_STATE_REC2100_PQ, FALSE);
XX_COLOR_MANAGER_V4_PRIMARIES_BT2020,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ);
if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR)) if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR))
create_image_desc (color, create_image_desc (color, GDK_COLOR_STATE_REC2100_LINEAR, FALSE);
XX_COLOR_MANAGER_V4_PRIMARIES_BT2020,
XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
} }
} }
@ -340,6 +437,8 @@ typedef struct
struct xx_image_description_v4 *image_desc; struct xx_image_description_v4 *image_desc;
struct xx_image_description_info_v4 *info; struct xx_image_description_info_v4 *info;
uint32_t identity;
int32_t icc; int32_t icc;
uint32_t icc_size; uint32_t icc_size;
int32_t r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y; int32_t r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y;
@ -378,7 +477,7 @@ gdk_color_state_from_image_description_bits (ImageDescription *desc)
return gdk_color_state_new_for_cicp (&cicp, NULL); return gdk_color_state_new_for_cicp (&cicp, NULL);
} }
else else
return GDK_COLOR_STATE_SRGB; return NULL;
} }
static void static void
@ -390,13 +489,26 @@ image_desc_info_done (void *data,
GdkColorState *cs; GdkColorState *cs;
cs = gdk_color_state_from_image_description_bits (desc); cs = gdk_color_state_from_image_description_bits (desc);
if (cs)
{
g_hash_table_insert (self->color->cs_to_desc,
gdk_color_state_ref (cs),
desc->image_desc);
g_hash_table_insert (self->color->id_to_cs,
GUINT_TO_POINTER (desc->identity),
gdk_color_state_ref (cs));
}
else
{
cs = GDK_COLOR_STATE_SRGB;
xx_image_description_v4_destroy (desc->image_desc);
}
if (self->callback) if (self->callback)
self->callback (desc->surface, cs, self->data); self->callback (desc->surface, cs, self->data);
gdk_color_state_unref (cs); gdk_color_state_unref (cs);
xx_image_description_v4_destroy (desc->image_desc);
xx_image_description_info_v4_destroy (desc->info); xx_image_description_info_v4_destroy (desc->info);
g_free (desc); g_free (desc);
} }
@ -466,10 +578,10 @@ image_desc_info_tf_named (void *data,
static void static void
image_desc_info_luminances (void *data, image_desc_info_luminances (void *data,
struct xx_image_description_info_v4 *info, struct xx_image_description_info_v4 *info,
uint32_t min_lum, uint32_t min_lum,
uint32_t max_lum, uint32_t max_lum,
uint32_t ref_lum) uint32_t ref_lum)
{ {
ImageDescription *desc = data; ImageDescription *desc = data;
@ -566,8 +678,21 @@ image_desc_ready (void *data,
uint32_t identity) uint32_t identity)
{ {
ImageDescription *desc = data; ImageDescription *desc = data;
GdkWaylandColorSurface *self = desc->surface;
GdkColorState *cs;
cs = g_hash_table_lookup (self->color->id_to_cs, GUINT_TO_POINTER (identity));
if (cs)
{
self->callback (self, cs, self->data);
xx_image_description_v4_destroy (desc->image_desc);
g_free (desc);
return;
}
desc->info = xx_image_description_v4_get_information (image_desc); desc->info = xx_image_description_v4_get_information (image_desc);
desc->identity = identity;
xx_image_description_info_v4_add_listener (desc->info, &info_listener, desc); xx_image_description_info_v4_add_listener (desc->info, &info_listener, desc);
} }
@ -584,6 +709,9 @@ preferred_changed (void *data,
GdkWaylandColorSurface *self = data; GdkWaylandColorSurface *self = data;
ImageDescription *desc; ImageDescription *desc;
if (!self->callback)
return;
desc = g_new0 (ImageDescription, 1); desc = g_new0 (ImageDescription, 1);
desc->surface = self; desc->surface = self;
@ -616,6 +744,7 @@ gdk_wayland_color_surface_new (GdkWaylandColor *color,
self->data = data; self->data = data;
xx_color_management_feedback_surface_v4_add_listener (self->feedback, &color_listener, self); xx_color_management_feedback_surface_v4_add_listener (self->feedback, &color_listener, self);
preferred_changed (self, self->feedback);
return self; return self;
} }
@ -633,25 +762,19 @@ static struct xx_image_description_v4 *
gdk_wayland_color_get_image_description (GdkWaylandColor *color, gdk_wayland_color_get_image_description (GdkWaylandColor *color,
GdkColorState *cs) GdkColorState *cs)
{ {
const GdkCicp *params; gpointer result;
GdkCicp normalized;
params = gdk_color_state_get_cicp (cs); if (g_hash_table_lookup_extended (color->cs_to_desc, cs, NULL, &result))
gdk_cicp_normalize (params, &normalized); return result;
create_image_desc (color, cs, TRUE);
if (params) if (!g_hash_table_lookup_extended (color->cs_to_desc, cs, NULL, &result))
for (int i = 0; i < color->image_descs->len; i++) {
{ g_assert_not_reached ();
ImageDescEntry *e = &g_array_index (color->image_descs, ImageDescEntry, i); }
if (wl_to_cicp_primaries (e->cp) == normalized.color_primaries &&
wl_to_cicp_transfer (e->tf) == normalized.transfer_function) return result;
return e->desc;
}
create_image_desc (color,
cicp_to_wl_primaries (normalized.color_primaries),
cicp_to_wl_transfer (normalized.transfer_function));
return NULL;
} }
void void