From 2636ff7430ea441d233dea974162713dd6b90dab Mon Sep 17 00:00:00 2001 From: Joan Torres Date: Tue, 17 Sep 2024 17:36:22 +0200 Subject: [PATCH] tests/wayland: Add color-management test Right now multiple image_descriptions are created with different parameters and are set to a surface. Part-of: --- src/tests/meson.build | 11 + src/tests/wayland-color-management-test.c | 195 ++++++++++++ .../wayland-test-clients/color-management.c | 297 ++++++++++++++++++ src/tests/wayland-test-clients/meson.build | 3 + .../wayland-test-client-utils.c | 6 + .../wayland-test-client-utils.h | 2 + 6 files changed, 514 insertions(+) create mode 100644 src/tests/wayland-color-management-test.c create mode 100644 src/tests/wayland-test-clients/color-management.c diff --git a/src/tests/meson.build b/src/tests/meson.build index f3c74049a..093f33506 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -578,6 +578,17 @@ wayland_test_cases = [ 'wayland-client-tests.c', ], }, + { + 'name': 'wayland-color-management', + 'suite': 'wayland', + 'sources': [ + 'wayland-color-management-test.c', + wayland_test_utils, + ], + 'depends': [ + test_client_executables.get('color-management'), + ], + }, { 'name': 'wayland-drm-lease', 'suite': 'wayland', diff --git a/src/tests/wayland-color-management-test.c b/src/tests/wayland-color-management-test.c new file mode 100644 index 000000000..4a2e99f9c --- /dev/null +++ b/src/tests/wayland-color-management-test.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2024 SUSE Software Solutions Germany GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Written by: + * Joan Torres + */ + +#include "config.h" + +#include "backends/meta-virtual-monitor.h" +#include "core/window-private.h" +#include "meta-test/meta-context-test.h" +#include "tests/meta-test-utils.h" +#include "tests/meta-wayland-test-driver.h" +#include "tests/meta-wayland-test-utils.h" +#include "wayland/meta-wayland-surface-private.h" + +#define TEST_COLOR_EPSILON 0.0001f + +static MetaContext *test_context; +static MetaVirtualMonitor *virtual_monitor; +static MetaWaylandTestDriver *test_driver; + +static void +wait_for_sync_point (unsigned int sync_point) +{ + meta_wayland_test_driver_wait_for_sync_point (test_driver, sync_point); +} + +static void +emit_sync_event (unsigned int sync_point) +{ + meta_wayland_test_driver_emit_sync_event (test_driver, sync_point); +} + +static ClutterColorState * +get_window_color_state (MetaWindow *window) +{ + MetaWaylandSurface *surface; + MetaSurfaceActor *surface_actor; + + surface = meta_window_get_wayland_surface (window); + + if (surface->color_state) + return surface->color_state; + + surface_actor = meta_wayland_surface_get_actor (surface); + + return clutter_actor_get_color_state (CLUTTER_ACTOR (surface_actor)); +} + +static void +color_management (void) +{ + MetaWaylandTestClient *wayland_test_client; + MetaWindow *test_window; + ClutterColorState *color_state; + const ClutterColorimetry *colorimetry; + const ClutterEOTF *eotf; + const ClutterLuminance *lum; + + wayland_test_client = meta_wayland_test_client_new (test_context, + "color-management"); + + test_window = meta_wait_for_client_window (test_context, "color-management"); + + wait_for_sync_point (0); + color_state = get_window_color_state (test_window); + colorimetry = clutter_color_state_get_colorimetry (color_state); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE); + g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_SRGB); + eotf = clutter_color_state_get_eotf (color_state); + g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_NAMED); + g_assert_cmpuint (eotf->tf_name, ==, CLUTTER_TRANSFER_FUNCTION_SRGB); + lum = clutter_color_state_get_luminance (color_state); + g_assert_cmpuint (lum->type, ==, CLUTTER_LUMINANCE_TYPE_DERIVED); + emit_sync_event (0); + + wait_for_sync_point (1); + color_state = get_window_color_state (test_window); + colorimetry = clutter_color_state_get_colorimetry (color_state); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE); + g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_BT2020); + eotf = clutter_color_state_get_eotf (color_state); + g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_NAMED); + g_assert_cmpuint (eotf->tf_name, ==, CLUTTER_TRANSFER_FUNCTION_PQ); + lum = clutter_color_state_get_luminance (color_state); + g_assert_cmpuint (lum->type, ==, CLUTTER_LUMINANCE_TYPE_EXPLICIT); + g_assert_cmpfloat_with_epsilon (lum->min, 0.005f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (lum->max, 10000.0f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (lum->ref, 303.0f, TEST_COLOR_EPSILON); + emit_sync_event (1); + + wait_for_sync_point (2); + color_state = get_window_color_state (test_window); + colorimetry = clutter_color_state_get_colorimetry (color_state); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE); + g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_SRGB); + eotf = clutter_color_state_get_eotf (color_state); + g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_NAMED); + g_assert_cmpuint (eotf->tf_name, ==, CLUTTER_TRANSFER_FUNCTION_SRGB); + lum = clutter_color_state_get_luminance (color_state); + g_assert_cmpuint (lum->type, ==, CLUTTER_LUMINANCE_TYPE_EXPLICIT); + g_assert_cmpfloat_with_epsilon (lum->min, 0.2f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (lum->max, 80.0f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (lum->ref, 70.0f, TEST_COLOR_EPSILON); + emit_sync_event (2); + + wait_for_sync_point (3); + color_state = get_window_color_state (test_window); + colorimetry = clutter_color_state_get_colorimetry (color_state); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_PRIMARIES); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->r_x, 0.64f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->r_y, 0.33f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->g_x, 0.30f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->g_y, 0.60f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->b_x, 0.15f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->b_y, 0.06f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->w_x, 0.34567f, TEST_COLOR_EPSILON); + g_assert_cmpfloat_with_epsilon (colorimetry->primaries->w_y, 0.35850f, TEST_COLOR_EPSILON); + eotf = clutter_color_state_get_eotf (color_state); + g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_GAMMA); + g_assert_cmpfloat_with_epsilon (eotf->gamma_exp, 2.5f, TEST_COLOR_EPSILON); + lum = clutter_color_state_get_luminance (color_state); + g_assert_cmpuint (lum->type, ==, CLUTTER_LUMINANCE_TYPE_DERIVED); + emit_sync_event (3); + + meta_wayland_test_client_finish (wayland_test_client); +} + +static void +on_before_tests (void) +{ + MetaWaylandCompositor *compositor = + meta_context_get_wayland_compositor (test_context); + + test_driver = meta_wayland_test_driver_new (compositor); + + virtual_monitor = meta_create_test_monitor (test_context, + 640, 480, 60.0); +} + +static void +on_after_tests (void) +{ + g_clear_object (&virtual_monitor); + g_clear_object (&test_driver); +} + +static void +init_tests (void) +{ + g_test_add_func ("/wayland/color-management", + color_management); +} + +int +main (int argc, + char *argv[]) +{ + g_autoptr (MetaContext) context = NULL; + + g_setenv ("MUTTER_DEBUG_COLOR_MANAGEMENT_PROTOCOL", "1", TRUE); + + context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS, + META_CONTEXT_TEST_FLAG_NO_X11); + g_assert_true (meta_context_configure (context, &argc, &argv, NULL)); + + test_context = context; + + init_tests (); + + g_signal_connect (context, "before-tests", + G_CALLBACK (on_before_tests), NULL); + g_signal_connect (context, "after-tests", + G_CALLBACK (on_after_tests), NULL); + + return meta_context_test_run_tests (META_CONTEXT_TEST (context), + META_TEST_RUN_FLAG_NONE); +} diff --git a/src/tests/wayland-test-clients/color-management.c b/src/tests/wayland-test-clients/color-management.c new file mode 100644 index 000000000..de3b88818 --- /dev/null +++ b/src/tests/wayland-test-clients/color-management.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2024 SUSE Software Solutions Germany GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Written by: + * Joan Torres + */ + +#include "config.h" + +#include "color-management-v1-client-protocol.h" +#include "wayland-test-client-utils.h" + +typedef struct _ImageDescriptionContext +{ + uint32_t image_description_id; + gboolean creation_failed; +} ImageDescriptionContext; + +typedef struct _Primaries +{ + float r_x, r_y; + float g_x, g_y; + float b_x, b_y; + float w_x, w_y; +} Primaries; + +static gboolean waiting_for_configure = FALSE; +static Primaries custom_primaries = { + .r_x = 0.64f, .r_y = 0.33f, + .g_x = 0.30f, .g_y = 0.60f, + .b_x = 0.15f, .b_y = 0.06f, + .w_x = 0.34567f, .w_y = 0.35850f, +}; + +static void +handle_xdg_toplevel_configure (void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states) +{ +} + +static void +handle_xdg_toplevel_close (void *data, + struct xdg_toplevel *xdg_toplevel) +{ +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, +}; + +static void +handle_xdg_surface_configure (void *data, + struct xdg_surface *xdg_surface, + uint32_t serial) +{ + + xdg_surface_ack_configure (xdg_surface, serial); + + waiting_for_configure = FALSE; +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_xdg_surface_configure, +}; + +static void +wait_for_configure (WaylandDisplay *display) +{ + waiting_for_configure = TRUE; + while (waiting_for_configure) + wayland_display_dispatch (display); +} + +static uint32_t +float_to_scaled_uint32 (float value) +{ + return (uint32_t) (value * 10000); +} + +static void +handle_image_description_failed (void *data, + struct xx_image_description_v4 *image_description_v4, + uint32_t cause, + const char *msg) + +{ + ImageDescriptionContext *image_description_context = data; + + image_description_context->creation_failed = TRUE; +} + +static void +handle_image_description_ready (void *data, + struct xx_image_description_v4 *image_description_v4, + uint32_t identity) +{ + ImageDescriptionContext *image_description_context = data; + + image_description_context->image_description_id = identity; +} + +static const struct xx_image_description_v4_listener image_description_listener = { + handle_image_description_failed, + handle_image_description_ready, +}; + +static void +wait_for_image_description_ready (ImageDescriptionContext *image_description, + WaylandDisplay *display) +{ + while (image_description->image_description_id == 0 && + !image_description->creation_failed) + wayland_display_dispatch (display); +} + +static void +create_image_description_from_params (WaylandDisplay *display, + struct xx_image_description_v4 **image_description, + int primaries_named, + Primaries *primaries, + int tf_named, + float tf_power, + float min_lum, + float max_lum, + float ref_lum) + +{ + struct xx_image_description_creator_params_v4 *creator_params; + ImageDescriptionContext image_description_context; + + creator_params = + xx_color_manager_v4_new_parametric_creator (display->color_management_mgr); + + if (primaries_named != -1) + xx_image_description_creator_params_v4_set_primaries_named ( + creator_params, + primaries_named); + + if (primaries) + xx_image_description_creator_params_v4_set_primaries ( + creator_params, + float_to_scaled_uint32 (primaries->r_x), + float_to_scaled_uint32 (primaries->r_y), + float_to_scaled_uint32 (primaries->g_x), + float_to_scaled_uint32 (primaries->g_y), + float_to_scaled_uint32 (primaries->b_x), + float_to_scaled_uint32 (primaries->b_y), + float_to_scaled_uint32 (primaries->w_x), + float_to_scaled_uint32 (primaries->w_y)); + + if (tf_named != -1) + xx_image_description_creator_params_v4_set_tf_named ( + creator_params, + tf_named); + + if (tf_power >= 1.0f) + xx_image_description_creator_params_v4_set_tf_power ( + creator_params, + float_to_scaled_uint32 (tf_power)); + + if (min_lum >= 0.0f && max_lum > 0.0f && ref_lum >= 0.0f) + xx_image_description_creator_params_v4_set_luminances ( + creator_params, + float_to_scaled_uint32 (min_lum), + (uint32_t) max_lum, + (uint32_t) ref_lum); + + image_description_context.image_description_id = 0; + image_description_context.creation_failed = FALSE; + + *image_description = + xx_image_description_creator_params_v4_create (creator_params); + xx_image_description_v4_add_listener ( + *image_description, + &image_description_listener, + &image_description_context); + + wait_for_image_description_ready (&image_description_context, display); + + g_assert_false (image_description_context.creation_failed); + g_assert_cmpint (image_description_context.image_description_id, >, 0); +} + +int +main (int argc, + char **argv) +{ + g_autoptr (WaylandDisplay) display = NULL; + struct xdg_toplevel *xdg_toplevel; + struct xdg_surface *xdg_surface; + struct wl_surface *surface; + struct xx_color_management_surface_v4 *color_surface; + struct xx_image_description_v4 *image_description; + + display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER); + + surface = wl_compositor_create_surface (display->compositor); + xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base, surface); + xdg_surface_add_listener (xdg_surface, &xdg_surface_listener, display); + xdg_toplevel = xdg_surface_get_toplevel (xdg_surface); + xdg_toplevel_add_listener (xdg_toplevel, &xdg_toplevel_listener, NULL); + xdg_toplevel_set_title (xdg_toplevel, "color-management"); + color_surface = + xx_color_manager_v4_get_surface (display->color_management_mgr, surface); + + wl_surface_commit (surface); + wait_for_configure (display); + + test_driver_sync_point (display->test_driver, 0, NULL); + wait_for_sync_event (display, 0); + + create_image_description_from_params (display, + &image_description, + XX_COLOR_MANAGER_V4_PRIMARIES_BT2020, + NULL, + XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ, + -1.0f, + 0.005f, + 10000.0f, + 303.0f); + xx_color_management_surface_v4_set_image_description ( + color_surface, + image_description, + XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL); + + wl_surface_commit (surface); + + xx_image_description_v4_destroy (image_description); + + test_driver_sync_point (display->test_driver, 1, NULL); + wait_for_sync_event (display, 1); + + create_image_description_from_params (display, + &image_description, + XX_COLOR_MANAGER_V4_PRIMARIES_SRGB, + NULL, + XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB, + -1.0f, + 0.2f, + 80.0f, + 70.0f); + xx_color_management_surface_v4_set_image_description ( + color_surface, + image_description, + XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL); + + wl_surface_commit (surface); + + xx_image_description_v4_destroy (image_description); + + test_driver_sync_point (display->test_driver, 2, NULL); + wait_for_sync_event (display, 2); + + create_image_description_from_params (display, + &image_description, + -1, + &custom_primaries, + -1, + 2.5f, + -1.0f, + -1.0f, + -1.0f); + xx_color_management_surface_v4_set_image_description ( + color_surface, + image_description, + XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL); + + wl_surface_commit (surface); + + xx_image_description_v4_destroy (image_description); + + test_driver_sync_point (display->test_driver, 3, NULL); + wait_for_sync_event (display, 3); + + xx_color_management_surface_v4_destroy (color_surface); + + return EXIT_SUCCESS; +} diff --git a/src/tests/wayland-test-clients/meson.build b/src/tests/wayland-test-clients/meson.build index 0ee977a43..bdea36df3 100644 --- a/src/tests/wayland-test-clients/meson.build +++ b/src/tests/wayland-test-clients/meson.build @@ -18,6 +18,9 @@ wayland_test_clients = [ { 'name': 'buffer-transform', }, + { + 'name': 'color-management', + }, { 'name': 'dma-buf-scanout', }, diff --git a/src/tests/wayland-test-clients/wayland-test-client-utils.c b/src/tests/wayland-test-clients/wayland-test-client-utils.c index b1f8bd792..4f6546700 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.c +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c @@ -344,6 +344,12 @@ handle_registry_global (void *user_data, wl_registry_bind (registry, id, &wp_single_pixel_buffer_manager_v1_interface, 1); } + else if (strcmp (interface, xx_color_manager_v4_interface.name) == 0) + { + display->color_management_mgr = + wl_registry_bind (registry, id, + &xx_color_manager_v4_interface, 1); + } else if (strcmp (interface, wp_viewporter_interface.name) == 0) { display->viewporter = wl_registry_bind (registry, id, diff --git a/src/tests/wayland-test-clients/wayland-test-client-utils.h b/src/tests/wayland-test-clients/wayland-test-client-utils.h index 8e51ddf14..4718a2055 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.h +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.h @@ -6,6 +6,7 @@ #include #include +#include "color-management-v1-client-protocol.h" #include "fractional-scale-v1-client-protocol.h" #include "linux-dmabuf-v1-client-protocol.h" #include "single-pixel-buffer-v1-client-protocol.h" @@ -42,6 +43,7 @@ typedef struct _WaylandDisplay struct zwp_linux_dmabuf_v1 *linux_dmabuf; struct wp_fractional_scale_manager_v1 *fractional_scale_mgr; struct wp_single_pixel_buffer_manager_v1 *single_pixel_mgr; + struct xx_color_manager_v4 *color_management_mgr; struct wp_viewporter *viewporter; struct xdg_wm_base *xdg_wm_base; struct test_driver *test_driver;