From 063a9a0240673eec4650b573d733d7a4c82759d1 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Wed, 21 Jan 2026 10:47:41 +0100 Subject: [PATCH] surface: correctly apply scale/tranform changes when committed without buffer {width,height}_from_buffer include the transformations from set_buffer_transform and set_buffer_scale. Currently {width,height}_from_buffer are only updated when a commit contains a new buffer but not for commits with only transformation changes. If a transform/scale change is commited without new buffer, the old values remain, which results in incorrect rendering or the client is disconnected because weston_surface_is_pending_viewport_source_valid() fails. Make sure to update {width,height}_from_buffer for transformation changes only to avoid this. Add a test to verify that the transformations are handled correctly. It is identical to previous test, except that is spits the buffer attachment and transformation changes into two commits. So it can reuse the existing images for validation. Signed-off-by: Michael Olbrich --- libweston/surface-state.c | 8 ++++++ tests/buffer-transforms-test.c | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/libweston/surface-state.c b/libweston/surface-state.c index 6617d69a6..3c31a0aad 100644 --- a/libweston/surface-state.c +++ b/libweston/surface-state.c @@ -394,6 +394,14 @@ weston_surface_apply_state(struct weston_surface *surface, &state->buffer_release_ref); status |= weston_surface_attach(surface, state, status); + } else if (status & WESTON_SURFACE_DIRTY_SIZE && surface->buffer_ref.buffer) { + bool size_ok; + + size_ok = convert_buffer_size_by_transform_scale(&surface->width_from_buffer, + &surface->height_from_buffer, + surface->buffer_ref.buffer, + &state->buffer_viewport); + weston_assert_true(surface->compositor, size_ok); } weston_buffer_reference(&state->buffer_ref, NULL, BUFFER_WILL_NOT_BE_ACCESSED); diff --git a/tests/buffer-transforms-test.c b/tests/buffer-transforms-test.c index 1a776e884..b9cb468bd 100644 --- a/tests/buffer-transforms-test.c +++ b/tests/buffer-transforms-test.c @@ -160,3 +160,54 @@ TEST_P(buffer_transform, my_buffer_args) return RESULT_OK; } + +TEST_P(buffer_transform_split, my_buffer_args) +{ + const struct buffer_args *bargs = data; + const struct setup_args *oargs; + struct client *client; + bool match; + char *refname; + int ret; + + oargs = &my_setup_args[get_test_fixture_index()]; + + ret = asprintf(&refname, "output_%d-%s_buffer_%d-%s", + oargs->scale, oargs->transform_name, + bargs->scale, bargs->transform_name); + test_assert_int_gt(ret, 0); + + testlog("%s: %s\n", get_test_name(), refname); + + /* + * NOTE! The transform set below is a lie. + * Take that into account when analyzing screenshots. + */ + + client = create_client(); + client->surface = create_test_surface(client); + client->surface->width = 10000; /* used only for damage */ + client->surface->height = 10000; + client->surface->buffer = client_buffer_from_image_file(client, + "basic-test-card", + bargs->scale); + move_client(client, 19, 19); + + /* + * Commit scale and transform separately. Otherwise identical to the + * 'buffer_transform' test so the same validation images can be used. + */ + wl_surface_set_buffer_scale(client->surface->wl_surface, bargs->scale); + wl_surface_set_buffer_transform(client->surface->wl_surface, + bargs->transform); + wl_surface_commit(client->surface->wl_surface); + + match = verify_screen_content(client, refname, 0, NULL, 0, NULL, + NO_DECORATIONS); + test_assert_true(match); + + client_destroy(client); + free(refname); + + return RESULT_OK; +}