diff --git a/tests/color-representation-common.c b/tests/color-representation-common.c new file mode 100644 index 000000000..0c5c78cc5 --- /dev/null +++ b/tests/color-representation-common.c @@ -0,0 +1,326 @@ +/* + * Copyright 2025 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "config.h" + +#include "color-representation-common.h" + +#include "image-iter.h" +#include "pixel-formats.h" +#include "shared/weston-drm-fourcc.h" +#include "xdg-client-helper.h" + +static void +presentation_feedback_handle_sync_output(void *data, + struct wp_presentation_feedback *feedback, + struct wl_output *output) +{ +} + +static void +presentation_feedback_handle_presented(void *data, + struct wp_presentation_feedback *feedback, + uint32_t tv_sec_hi, + uint32_t tv_sec_lo, + uint32_t tv_nsec, + uint32_t refresh, + uint32_t seq_hi, + uint32_t seq_lo, + uint32_t flags) +{ + enum feedback_result *result = data; + bool zero_copy = flags & WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY; + + if (zero_copy) + *result = FB_PRESENTED_ZERO_COPY; + else + *result = FB_PRESENTED; + + wp_presentation_feedback_destroy(feedback); +} + +static void +presentation_feedback_handle_discarded(void *data, + struct wp_presentation_feedback *feedback) +{ + enum feedback_result *result = data; + + *result = FB_DISCARDED; + wp_presentation_feedback_destroy(feedback); +} + +static const struct wp_presentation_feedback_listener presentation_feedback_listener = { + .sync_output = presentation_feedback_handle_sync_output, + .presented = presentation_feedback_handle_presented, + .discarded = presentation_feedback_handle_discarded, +}; + +static void +presentation_wait_nofail(struct client *client, enum feedback_result *result) +{ + while (*result == FB_PENDING) { + if (!test_assert_int_ge(wl_display_dispatch(client->wl_display), 0)) + break; + } + test_assert_u64_ne(*result, FB_PENDING); +} + +static void +x8r8g8b8_to_ycbcr8(uint32_t xrgb, + const struct color_state *color_state, + uint8_t *y_out, uint8_t *cb_out, uint8_t *cr_out) +{ + double y, cb, cr; + double r = (xrgb >> 16) & 0xff; + double g = (xrgb >> 8) & 0xff; + double b = (xrgb >> 0) & 0xff; + + /* normalize to [0.0, 1.0] */ + r /= 255.0; + g /= 255.0; + b /= 255.0; + + /* Y normalized to [0.0, 1.0], Cb and Cr [-0.5, 0.5] */ + switch ((int)color_state->coefficients) { + case 0: + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT709: + /* We choose BT709 as default */ + y = 0.2126 * r + 0.7152 * g + 0.0722 * b; + cr = (r - y) / 1.5748; + cb = (b - y) / 1.8556; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT601: + y = 0.299 * r + 0.587 * g + 0.114 * b; + cr = (r - y) / 1.402; + cb = (b - y) / 1.772; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020: + y = 0.2627 * r + 0.678 * g + 0.0593 * b; + cr = (r - y) / 1.4746; + cb = (b - y) / 1.8814; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY: + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_FCC: + /* For protocol error testing ensure we create invalid output */ + y = 0; + cr = 0; + cb = 0; + break; + default: + test_assert_not_reached("Coefficients not handled"); + } + + switch ((int)color_state->range) { + case 0: + case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_LIMITED: + /* We choose narrow range as default */ + *y_out = round(219.0 * y + 16.0); + if (cr_out) + *cr_out = round(224.0 * cr + 128.0); + if (cb_out) + *cb_out = round(224.0 * cb + 128.0); + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL: + *y_out = round(255.0 * y); + if (cr_out) + *cr_out = round(255.0 * cr + 128.0); + if (cb_out) + *cb_out = round(255.0 * cb + 128.0); + break; + default: + test_assert_not_reached("Range not handled"); + } +} + +static struct client_buffer* +create_and_fill_nv12_buffer_with_cake(struct client *client, + enum client_buffer_type buffer_type, + const struct color_state *color_state) +{ + const struct pixel_format_info *fmt_info; + struct client_buffer *buffer; + pixman_image_t *rgb_image; + struct image_header src; + uint8_t *y_base; + uint16_t *uv_base; + char *fname; + int width, height; + + fmt_info = pixel_format_get_info(DRM_FORMAT_NV12); + width = height = 256; + + switch (buffer_type) { + case CLIENT_BUFFER_TYPE_SHM: + buffer = client_buffer_util_create_shm_buffer(client->wl_shm, + fmt_info, + width, + height); + break; + case CLIENT_BUFFER_TYPE_DMABUF: + buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, + client->dmabuf, + fmt_info, + width, + height); + break; + default: + test_assert_not_reached("Buffer type not handled"); + break; + } + + fname = image_filename("chocolate-cake"); + rgb_image = load_image_from_png(fname); + free(fname); + test_assert_ptr_not_null(rgb_image); + + src = image_header_from(rgb_image); + + y_base = buffer->data + buffer->offsets[0]; + uv_base = (uint16_t *)(buffer->data + buffer->offsets[1]); + + client_buffer_util_maybe_sync_dmabuf_start(buffer); + for (int y = 0; y < src.height; y++) { + uint32_t *rgb_row; + uint8_t *y_row; + uint16_t *uv_row; + + rgb_row = image_header_get_row_u32(&src, y / 2 * 2); + y_row = y_base + y * buffer->strides[0]; + uv_row = uv_base + (y / 2) * (buffer->strides[1] / sizeof(uint16_t)); + + for (int x = 0; x < src.width; x++) { + uint32_t argb; + uint8_t cr; + uint8_t cb; + + /* + * Sub-sample the source image instead, so that U and V + * sub-sampling does not require proper + * filtering/averaging/siting. + */ + argb = *(rgb_row + x / 2 * 2); + + /* + * A stupid way of "sub-sampling" chroma. This does not + * do the necessary filtering/averaging/siting. + */ + if ((y & 1) == 0 && (x & 1) == 0) { + x8r8g8b8_to_ycbcr8(argb, color_state, y_row + x, + &cb, &cr); + *(uv_row + x / 2) = ((uint16_t) cb) | + ((uint16_t) cr << 8); + } else { + x8r8g8b8_to_ycbcr8(argb, color_state, y_row + x, + NULL, NULL); + } + } + } + client_buffer_util_maybe_sync_dmabuf_end(buffer); + + pixman_image_unref(rgb_image); + + return buffer; +} + +/* + * Test that a fullscreen client with smaller-than-fullscreen-sized NV12 buffer + * is correctly rendered with various YCbCr matrix coefficients and range + * combinations. + */ +enum test_result_code +test_color_representation(const struct color_state *color_state, + enum client_buffer_type buffer_type, + enum feedback_result expected_result) +{ + struct xdg_client *xdg_client; + struct client *client; + struct xdg_surface_data *xdg_surface; + struct wl_surface *surface; + struct client_buffer *buffer; + struct wp_presentation_feedback *presentation_feedback; + struct wp_color_representation_surface_v1 *color_representation_surface = NULL; + enum feedback_result result; + struct buffer *screenshot; + bool match; + + xdg_client = create_xdg_client(); + client = xdg_client->client; + xdg_surface = create_xdg_surface(xdg_client); + surface = xdg_surface->surface->wl_surface; + + xdg_surface_make_toplevel(xdg_surface, + "weston.test.color-representation", "one"); + xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); + xdg_surface_wait_configure(xdg_surface); + + buffer = create_and_fill_nv12_buffer_with_cake(client, buffer_type, + color_state); + + wl_surface_attach(surface, buffer->wl_buffer, 0, 0); + wl_surface_damage(surface, 0, 0, INT32_MAX, INT32_MAX); + xdg_surface_maybe_ack_configure(xdg_surface); + + if (color_state->create_color_representation_surface) { + color_representation_surface = + wp_color_representation_manager_v1_get_surface( + client->color_representation, surface); + if (color_state->coefficients != 0) + wp_color_representation_surface_v1_set_coefficients_and_range( + color_representation_surface, + color_state->coefficients, color_state->range); + } + + result = FB_PENDING; + presentation_feedback = wp_presentation_feedback(client->presentation, + surface); + wp_presentation_feedback_add_listener(presentation_feedback, + &presentation_feedback_listener, + &result); + wl_surface_commit(surface); + presentation_wait_nofail(client, &result); + + test_assert_enum(result, expected_result); + + screenshot = client_capture_output(client, client->output, + WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER, + CLIENT_BUFFER_TYPE_SHM); + test_assert_ptr_not_null(screenshot); + + client_buffer_util_maybe_sync_dmabuf_start(screenshot->buf); + match = verify_image(screenshot->image, "color-representation", 0, + NULL, 0); + client_buffer_util_maybe_sync_dmabuf_end(screenshot->buf); + + buffer_destroy(screenshot); + if (color_representation_surface) + wp_color_representation_surface_v1_destroy(color_representation_surface); + client_buffer_util_destroy_buffer(buffer); + destroy_xdg_surface(xdg_surface); + xdg_client_destroy(xdg_client); + + test_assert_true(match); + + return RESULT_OK; +} diff --git a/tests/color-representation-common.h b/tests/color-representation-common.h new file mode 100644 index 000000000..2a9cea247 --- /dev/null +++ b/tests/color-representation-common.h @@ -0,0 +1,66 @@ +/* + * Copyright 2025 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include "weston-test-client-helper.h" + +struct setup_args { + struct fixture_metadata meta; + enum weston_renderer_type renderer; + enum client_buffer_type buffer_type; + bool gl_force_import_yuv_fallback; +}; + +struct color_state { + bool create_color_representation_surface; + enum wp_color_representation_surface_v1_coefficients coefficients; + enum wp_color_representation_surface_v1_range range; +}; + +static const struct color_state color_state_cases[] = { +#define CRS(x) WP_COLOR_REPRESENTATION_SURFACE_V1_ ##x + { false, 0, 0 }, + { true, 0, 0 }, + { true, CRS(COEFFICIENTS_BT601), CRS(RANGE_LIMITED) }, + { true, CRS(COEFFICIENTS_BT601), CRS(RANGE_FULL) }, + { true, CRS(COEFFICIENTS_BT709), CRS(RANGE_LIMITED) }, + { true, CRS(COEFFICIENTS_BT709), CRS(RANGE_FULL) }, + { true, CRS(COEFFICIENTS_BT2020), CRS(RANGE_LIMITED) }, + { true, CRS(COEFFICIENTS_BT2020), CRS(RANGE_FULL) }, +#undef CRS +}; + +enum feedback_result { + FB_PENDING = 0, + FB_PRESENTED, + FB_PRESENTED_ZERO_COPY, + FB_DISCARDED +}; + +enum test_result_code +test_color_representation(const struct color_state *color_state, + enum client_buffer_type buffer_type, + enum feedback_result expected_result); diff --git a/tests/color-representation-drm-test.c b/tests/color-representation-drm-test.c new file mode 100644 index 000000000..28a3cba58 --- /dev/null +++ b/tests/color-representation-drm-test.c @@ -0,0 +1,74 @@ +/* + * Copyright © 2025 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "config.h" + +#include "color-representation-common.h" + +#include "image-iter.h" +#include "pixel-formats.h" +#include "shared/weston-drm-fourcc.h" +#include "shared/xalloc.h" +#include "weston-test-client-helper.h" +#include "weston-test-assert.h" +#include "xdg-client-helper.h" + +static const struct setup_args my_setup_args[] = { + { + .meta.name = "GL - dmabuf renderer", + .renderer = WESTON_RENDERER_GL, + .buffer_type = CLIENT_BUFFER_TYPE_DMABUF, + }, +}; + +static enum test_result_code +fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg) +{ + struct compositor_setup setup; + + compositor_setup_defaults(&setup); + setup.backend = WESTON_BACKEND_DRM; + setup.renderer = arg->renderer; + setup.logging_scopes = "log,drm-backend"; + + /* Currently enforced by vkms. Set as a reminder for the future. */ + setup.width = 1024; + setup.height = 768; + + setup.test_quirks.required_capabilities = WESTON_CAP_COLOR_REP; + setup.test_quirks.gl_force_import_yuv_fallback = + arg->gl_force_import_yuv_fallback; + + return weston_test_harness_execute_as_client(harness, &setup); +} +DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, my_setup_args, meta); + +TEST_P(color_representation_drm, color_state_cases) { + const struct color_state *color_state = data; + const struct setup_args *args = &my_setup_args[get_test_fixture_index()]; + + return test_color_representation(color_state, args->buffer_type, + FB_PRESENTED_ZERO_COPY); +} diff --git a/tests/color-representation-renderer-test.c b/tests/color-representation-renderer-test.c new file mode 100644 index 000000000..352a8f5ea --- /dev/null +++ b/tests/color-representation-renderer-test.c @@ -0,0 +1,250 @@ +/* + * Copyright 2025 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "config.h" + +#include "color-representation-common.h" + +#include "pixel-formats.h" +#include "shared/weston-drm-fourcc.h" +#include "weston-test-assert.h" +#include "xdg-client-helper.h" + +static const struct setup_args my_setup_args[] = { + { + .meta.name = "GL - shm", + .renderer = WESTON_RENDERER_GL, + .buffer_type = CLIENT_BUFFER_TYPE_SHM, + }, + { + .meta.name = "GL - dmabuf renderer", + .renderer = WESTON_RENDERER_GL, + .buffer_type = CLIENT_BUFFER_TYPE_DMABUF, + }, + { + .meta.name = "GL - dmabuf renderer + force-import-yuv-fallback", + .renderer = WESTON_RENDERER_GL, + .buffer_type = CLIENT_BUFFER_TYPE_DMABUF, + .gl_force_import_yuv_fallback = true, + }, +}; + +static enum test_result_code +fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg) +{ + struct compositor_setup setup; + + compositor_setup_defaults(&setup); + setup.renderer = arg->renderer; + setup.refresh = HIGHEST_OUTPUT_REFRESH; + setup.logging_scopes = "log"; + + /* Required for test that also run on DRM */ + setup.width = 1024; + setup.height = 768; + + setup.test_quirks.required_capabilities = WESTON_CAP_COLOR_REP; + setup.test_quirks.gl_force_import_yuv_fallback = + arg->gl_force_import_yuv_fallback; + + return weston_test_harness_execute_as_client(harness, &setup); +} +DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, my_setup_args, meta); + +TEST_P(color_representation_renderer, color_state_cases) { + const struct color_state *color_state = data; + const struct setup_args *args = &my_setup_args[get_test_fixture_index()]; + + return test_color_representation(color_state, args->buffer_type, + FB_PRESENTED); +} + +static struct client_buffer* +create_and_fill_nv12_buffer(struct client *client, + enum client_buffer_type buffer_type, int width, + int height) +{ + const struct pixel_format_info *fmt_info; + struct client_buffer *buffer; + uint8_t *y_base; + uint16_t *uv_base; + + fmt_info = pixel_format_get_info(DRM_FORMAT_NV12); + + switch (buffer_type) { + case CLIENT_BUFFER_TYPE_SHM: + buffer = client_buffer_util_create_shm_buffer(client->wl_shm, + fmt_info, + width, + height); + break; + case CLIENT_BUFFER_TYPE_DMABUF: + buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, + client->dmabuf, + fmt_info, + width, + height); + break; + default: + test_assert_not_reached("Buffer type not handled"); + break; + } + + y_base = buffer->data + buffer->offsets[0]; + uv_base = (uint16_t *)(buffer->data + buffer->offsets[1]); + + client_buffer_util_maybe_sync_dmabuf_start(buffer); + for (int y = 0; y < height; y++) { + uint8_t *y_row; + uint16_t *uv_row; + + y_row = y_base + y * buffer->strides[0]; + uv_row = uv_base + (y / 2) * (buffer->strides[1] / sizeof(uint16_t)); + + for (int x = 0; x < width; x++) { + *(y_row + x) = 0x30; + *(uv_row + x / 2) = 0x5050; + } + } + client_buffer_util_maybe_sync_dmabuf_end(buffer); + + return buffer; +} + +static void +buffer_release(void *data, struct wl_buffer *buffer) +{ + wl_buffer_destroy(buffer); +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +/* + * Test that the same NV12 buffer can be attached to multiple wl_surfaces with + * different color representation values. + */ +TEST(drm_color_representation_reuse_buffer) +{ + const struct setup_args *args = &my_setup_args[get_test_fixture_index()]; + struct xdg_client *xdg_client; + struct client *client; + struct xdg_surface_data *xdg_surface; + struct wl_surface *toplevel_surface; + int n_color_state_cases = ARRAY_LENGTH(color_state_cases); + struct wl_surface *surface[n_color_state_cases]; + struct wl_subsurface *subsurface[n_color_state_cases]; + struct wl_buffer *toplevel_buffer; + struct client_buffer *buffer; + struct wp_viewport *toplevel_viewport; + struct wp_color_representation_surface_v1 *color_representation_surface[n_color_state_cases]; + struct rectangle clip = { .width = 128, .height = 128 }; + bool match; + + xdg_client = create_xdg_client(); + client = xdg_client->client; + xdg_surface = create_xdg_surface(xdg_client); + toplevel_surface = xdg_surface->surface->wl_surface; + + xdg_surface_make_toplevel(xdg_surface, + "weston.test.color-representation", "one"); + xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); + xdg_surface_wait_configure(xdg_surface); + + toplevel_viewport = wp_viewporter_get_viewport(client->viewporter, + toplevel_surface); + wp_viewport_set_destination(toplevel_viewport, + xdg_surface->configure.width, xdg_surface->configure.height); + toplevel_buffer = + wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, + 0x0, 0x0, 0x0, 0x0); + wl_surface_attach(toplevel_surface, toplevel_buffer, 0, 0); + wl_buffer_add_listener(toplevel_buffer, &buffer_listener, NULL); + wl_surface_damage_buffer(toplevel_surface, 0, 0, 1, 1); + + buffer = create_and_fill_nv12_buffer(client, args->buffer_type, + clip.width / 4, clip.height / 2 - 4); + + for (int i = 0; i < n_color_state_cases; i++) { + surface[i] = wl_compositor_create_surface(client->wl_compositor); + subsurface[i] = + wl_subcompositor_get_subsurface(client->wl_subcompositor, + surface[i], toplevel_surface); + } + + wl_subsurface_set_position(subsurface[0], 0, 4); + wl_subsurface_set_position(subsurface[1], 0, clip.height / 2); + wl_subsurface_set_position(subsurface[2], clip.width / 4, 4); + wl_subsurface_set_position(subsurface[3], clip.width / 4, + clip.height / 2); + wl_subsurface_set_position(subsurface[4], clip.width / 4 * 2, 4); + wl_subsurface_set_position(subsurface[5], clip.width / 4 * 2, + clip.height / 2); + wl_subsurface_set_position(subsurface[6], clip.width / 4 * 3, 4); + wl_subsurface_set_position(subsurface[7], clip.width / 4 * 3, + clip.height / 2); + + for (int i = 0; i < n_color_state_cases; i++) { + if (color_state_cases[i].create_color_representation_surface) { + color_representation_surface[i] = + wp_color_representation_manager_v1_get_surface( + client->color_representation, + surface[i]); + if (color_state_cases[i].coefficients != 0) + wp_color_representation_surface_v1_set_coefficients_and_range( + color_representation_surface[i], + color_state_cases[i].coefficients, + color_state_cases[i].range); + } else { + color_representation_surface[i] = NULL; + } + + wl_surface_attach(surface[i], buffer->wl_buffer, 0, 0); + wl_surface_damage(surface[i], 0, 0, INT32_MAX, INT32_MAX); + wl_surface_commit(surface[i]); + } + + xdg_surface_maybe_ack_configure(xdg_surface); + wl_surface_commit(toplevel_surface); + + match = verify_screen_content(client, "color-representation", 1, + &clip, 0, NULL, NO_DECORATIONS); + + for (int i = 0; i < n_color_state_cases; i++) { + if (color_representation_surface[i]) + wp_color_representation_surface_v1_destroy(color_representation_surface[i]); + wl_subsurface_destroy(subsurface[i]); + wl_surface_destroy(surface[i]); + } + wp_viewport_destroy(toplevel_viewport); + client_buffer_util_destroy_buffer(buffer); + destroy_xdg_surface(xdg_surface); + xdg_client_destroy(xdg_client); + + test_assert_true(match); + + return RESULT_OK; +} diff --git a/tests/meson.build b/tests/meson.build index 82f5952a0..40d36af4a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -142,6 +142,21 @@ tests = [ dep_libdisplay_info, ], }, + { 'name': 'color-representation-drm', + 'sources': [ + 'color-representation-common.c', + 'color-representation-common.h', + 'color-representation-drm-test.c', + ], + 'run_exclusive': true + }, + { 'name': 'color-representation-renderer', + 'sources': [ + 'color-representation-common.c', + 'color-representation-common.h', + 'color-representation-renderer-test.c', + ], + }, { 'name': 'commit-timing', }, { 'name': 'config-parser', }, { diff --git a/tests/reference/color-representation-00.png b/tests/reference/color-representation-00.png new file mode 100644 index 000000000..46fbd7d30 Binary files /dev/null and b/tests/reference/color-representation-00.png differ diff --git a/tests/reference/color-representation-01.png b/tests/reference/color-representation-01.png new file mode 100644 index 000000000..6b7b49046 Binary files /dev/null and b/tests/reference/color-representation-01.png differ