diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index eaa6644f5..838cd358a 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -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. */ diff --git a/libweston/compositor.c b/libweston/compositor.c index 9e29bc3f7..8ea21e4f6 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -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; } diff --git a/tests/paint-node-test.c b/tests/paint-node-test.c index b20789da3..3cd119392 100644 --- a/tests/paint-node-test.c +++ b/tests/paint-node-test.c @@ -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();