output: Record paint_node_changes during repaint

When we're going through assign_planes and repaint, give the backend an
opportunity to see what's changed during this repaint.

Signed-off-by: Daniel Stone <daniels@collabora.com>
This commit is contained in:
Daniel Stone 2025-10-09 17:12:14 +01:00 committed by Derek Foreman
parent 7f8c5f984e
commit 0664d5bdc1
3 changed files with 137 additions and 2 deletions

View file

@ -353,6 +353,9 @@ struct weston_output {
/* struct weston_paint_node::output_link */
struct wl_list paint_node_list;
/** Only valid during repaint: changes for this repaint */
enum weston_paint_node_status paint_node_changes;
/** From global to output buffer coordinates. */
struct weston_matrix matrix;
/** From output buffer to global coordinates. */

View file

@ -257,6 +257,7 @@ paint_node_update_early(struct weston_paint_node *pnode)
get_placeholder_color(pnode, &pnode->solid);
}
pnode->output->paint_node_changes |= pnode->status;
pnode->status &= ~(WESTON_PAINT_NODE_VIEW_DIRTY | \
WESTON_PAINT_NODE_OUTPUT_DIRTY);
}
@ -3620,8 +3621,10 @@ weston_output_repaint(struct weston_output *output)
TL_POINT(ec, TLP_CORE_REPAINT_BEGIN, TLP_OUTPUT(output), TLP_END);
/* Rebuild the surface list and update surface transforms up front. */
if (ec->view_list_needs_rebuild)
if (ec->view_list_needs_rebuild) {
weston_compositor_build_view_list(ec);
output->paint_node_changes = WESTON_PAINT_NODE_ALL_DIRTY;
}
/* If the scene graph is empty, we could end up passing a buffer
* we've never drawn into to a hardware plane later. If that hardware
@ -3736,8 +3739,11 @@ weston_output_repaint(struct weston_output *output)
* to trigger a new repaint, so drop it from repaint and hope
* something schedules a successful repaint later.
*/
if (r != 0)
if (r == 0) {
output->paint_node_changes = WESTON_PAINT_NODE_CLEAN;
} else {
weston_output_schedule_repaint_reset(output);
}
return r;
}

View file

@ -80,6 +80,132 @@ DECLARE_LIST_ITERATOR(output, struct weston_compositor, output_list,
DECLARE_LIST_ITERATOR(pnode_from_z, struct weston_output, paint_node_z_order_list,
struct weston_paint_node, z_order_link);
static enum weston_paint_node_status
get_paint_node_status(struct client *client,
struct wet_testsuite_data *suite_data)
{
enum weston_paint_node_status changes;
RUN_INSIDE_BREAKPOINT(client, suite_data) {
struct weston_compositor *compositor;
struct weston_output *output;
struct weston_head *head;
test_assert_enum(breakpoint->template_->breakpoint,
WESTON_TEST_BREAKPOINT_POST_REPAINT);
compositor = breakpoint->compositor;
head = breakpoint->resource;
output = next_output(compositor, NULL);
test_assert_ptr_eq(output, head->output);
test_assert_str_eq(output->name, "headless");
test_assert_ptr_null(next_output(compositor, output));
changes = output->paint_node_changes;
}
return changes;
}
TEST(paint_node_status_on_repaint)
{
struct wet_testsuite_data *suite_data = TEST_GET_SUITE_DATA();
struct client *client;
struct buffer *buf1, *buf2, *buf3;
enum weston_paint_node_status changes;
struct surface *new_surf;
struct rectangle opaque = { .x = 0, .y = 0, .width = 100, .height = 100 };
pixman_color_t red;
color_rgb888(&red, 255, 0, 0);
client = create_client();
test_assert_ptr_not_null(client);
client->surface = create_test_surface(client);
client_push_breakpoint(client, suite_data,
WESTON_TEST_BREAKPOINT_POST_REPAINT,
(struct wl_proxy *) client->output->wl_output);
weston_test_move_surface(client->test->weston_test, client->surface->wl_surface,
50, 50);
buf1 = surface_commit_color(client, client->surface->wl_surface, &red, 100, 100);
changes = get_paint_node_status(client, suite_data);
test_assert_enum(changes, WESTON_PAINT_NODE_ALL_DIRTY);
/* move the surface */
client_push_breakpoint(client, suite_data,
WESTON_TEST_BREAKPOINT_POST_REPAINT,
(struct wl_proxy *) client->output->wl_output);
weston_test_move_surface(client->test->weston_test, client->surface->wl_surface,
80, 80);
wl_surface_attach(client->surface->wl_surface, buf1->proxy, 0, 0);
wl_surface_damage_buffer(client->surface->wl_surface, 0, 0, 200, 200);
wl_surface_commit(client->surface->wl_surface);
changes = get_paint_node_status(client, suite_data);
test_assert_enum(changes,
(WESTON_PAINT_NODE_BUFFER_DIRTY |
WESTON_PAINT_NODE_VIEW_DIRTY |
WESTON_PAINT_NODE_VISIBILITY_DIRTY));
/* a new buffer */
client_push_breakpoint(client, suite_data,
WESTON_TEST_BREAKPOINT_POST_REPAINT,
(struct wl_proxy *) client->output->wl_output);
buf2 = surface_commit_color(client, client->surface->wl_surface, &red, 100, 100);
changes = get_paint_node_status(client, suite_data);
test_assert_enum(changes, WESTON_PAINT_NODE_BUFFER_DIRTY);
/* a buffer with updated dimensions */
client_push_breakpoint(client, suite_data,
WESTON_TEST_BREAKPOINT_POST_REPAINT,
(struct wl_proxy *) client->output->wl_output);
buf3 = surface_commit_color(client, client->surface->wl_surface, &red, 200, 200);
changes = get_paint_node_status(client, suite_data);
test_assert_enum(changes,
(WESTON_PAINT_NODE_BUFFER_DIRTY |
WESTON_PAINT_NODE_VIEW_DIRTY |
WESTON_PAINT_NODE_VISIBILITY_DIRTY));
/* an opaque buffer moving will change visibility */
client_push_breakpoint(client, suite_data,
WESTON_TEST_BREAKPOINT_POST_REPAINT,
(struct wl_proxy *) client->output->wl_output);
surface_set_opaque_rect(client->surface, &opaque);
weston_test_move_surface(client->test->weston_test, client->surface->wl_surface,
100, 100);
wl_surface_attach(client->surface->wl_surface, buf3->proxy, 0, 0);
wl_surface_damage_buffer(client->surface->wl_surface, 0, 0, 200, 200);
wl_surface_commit(client->surface->wl_surface);
changes = get_paint_node_status(client, suite_data);
test_assert_enum(changes,
(WESTON_PAINT_NODE_BUFFER_DIRTY |
WESTON_PAINT_NODE_VIEW_DIRTY |
WESTON_PAINT_NODE_VISIBILITY_DIRTY));
/* a new surface rebuilds the view list */
client_push_breakpoint(client, suite_data,
WESTON_TEST_BREAKPOINT_POST_REPAINT,
(struct wl_proxy *) client->output->wl_output);
new_surf = create_test_surface(client);
weston_test_move_surface(client->test->weston_test,
new_surf->wl_surface,
5, 5);
wl_surface_attach(new_surf->wl_surface, buf1->proxy, 0, 0);
wl_surface_damage_buffer(new_surf->wl_surface, 0, 0, 200, 200);
wl_surface_commit(new_surf->wl_surface);
changes = get_paint_node_status(client, suite_data);
test_assert_enum(changes, WESTON_PAINT_NODE_ALL_DIRTY);
buffer_destroy(buf1);
buffer_destroy(buf2);
buffer_destroy(buf3);
surface_destroy(new_surf);
client_destroy(client);
return RESULT_OK;
}
TEST(top_surface_present_in_output_repaint)
{
struct wet_testsuite_data *suite_data = TEST_GET_SUITE_DATA();