diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index b6f0d2175..f9c0f1ead 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -149,7 +149,7 @@ struct wlr_scene_buffer { struct wl_signal outputs_update; // struct wlr_scene_outputs_update_event struct wl_signal output_enter; // struct wlr_scene_output struct wl_signal output_leave; // struct wlr_scene_output - struct wl_signal output_present; // struct wlr_scene_output + struct wl_signal output_present; // struct wlr_output_event_present struct wl_signal frame_done; // struct timespec } events; @@ -198,6 +198,7 @@ struct wlr_scene_output { struct wl_listener output_commit; struct wl_listener output_damage; struct wl_listener output_needs_frame; + struct wl_listener output_present; struct wl_list damage_highlight_regions; diff --git a/types/scene/surface.c b/types/scene/surface.c index c58bcd940..fa13bbfbf 100644 --- a/types/scene/surface.c +++ b/types/scene/surface.c @@ -40,15 +40,23 @@ static void handle_scene_buffer_output_present( struct wl_listener *listener, void *data) { struct wlr_scene_surface *surface = wl_container_of(listener, surface, output_present); - struct wlr_scene_output *scene_output = data; + struct wlr_output_event_present *output_event = data; - if (surface->buffer->primary_output == scene_output) { + if (surface->buffer->primary_output->output == output_event->output) { struct wlr_scene *root = scene_node_get_root(&surface->buffer->node); struct wlr_presentation *presentation = root->presentation; if (presentation) { - wlr_presentation_surface_sampled_on_output( - presentation, surface->surface, scene_output->output); + struct wlr_presentation_event event = { + .output = output_event->output, + .tv_sec = (uint64_t)output_event->when->tv_sec, + .tv_nsec = (uint32_t)output_event->when->tv_nsec, + .refresh = (uint32_t)output_event->refresh, + .seq = (uint64_t)output_event->seq, + .flags = output_event->flags, + }; + + wlr_presentation_send_presented(presentation, surface->surface, &event); } } } diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 87ece09e7..ba90f2b61 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1099,8 +1099,17 @@ static void render_texture(struct wlr_output *output, } } -static void scene_node_render(struct wlr_scene_node *node, +struct render_list_entry { + struct wlr_scene_node *node; + bool sent_feedback; + bool visible; + bool presented; +}; + +static void scene_render_list_entry_render(struct render_list_entry *entry, struct wlr_scene_output *scene_output, pixman_region32_t *damage) { + struct wlr_scene_node *node = entry->node; + int x, y; wlr_scene_node_coords(node, &x, &y); x -= scene_output->x; @@ -1119,6 +1128,8 @@ static void scene_node_render(struct wlr_scene_node *node, return; } + entry->presented = true; + struct wlr_box dst_box = { .x = x, .y = y, @@ -1155,8 +1166,6 @@ static void scene_node_render(struct wlr_scene_node *node, render_texture(output, &render_region, texture, &scene_buffer->src_box, &dst_box, matrix); - - wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); break; } @@ -1260,6 +1269,26 @@ static void scene_output_handle_needs_frame(struct wl_listener *listener, void * wlr_output_schedule_frame(scene_output->output); } +static void scene_output_handle_present(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_present); + struct wlr_output_event_present *output_event = data; + + struct wl_array *render_list = &scene_output->render_list; + struct render_list_entry *list_data = render_list->data; + int list_len = render_list->size / sizeof(*list_data); + + for (int i = list_len - 1; i >= 0; i--) { + struct render_list_entry *entry = &list_data[i]; + if (!entry->presented || entry->node->type != WLR_SCENE_NODE_BUFFER) { + continue; + } + + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(entry->node); + wl_signal_emit_mutable(&buffer->events.output_present, output_event); + } +} + struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, struct wlr_output *output) { struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_output)); @@ -1302,6 +1331,9 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->output_needs_frame.notify = scene_output_handle_needs_frame; wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame); + scene_output->output_present.notify = scene_output_handle_present; + wl_signal_add(&output->events.present, &scene_output->output_present); + scene_output_update_geometry(scene_output); return scene_output; @@ -1334,6 +1366,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wl_list_remove(&scene_output->output_commit.link); wl_list_remove(&scene_output->output_damage.link); wl_list_remove(&scene_output->output_needs_frame.link); + wl_list_remove(&scene_output->output_present.link); wl_array_release(&scene_output->render_list); free(scene_output); @@ -1363,12 +1396,6 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output_update_geometry(scene_output); } -struct render_list_entry { - struct wlr_scene_node *node; - bool sent_feedback; - bool visible; -}; - static bool scene_construct_render_list(struct wlr_scene_node *node, struct wl_array *render_list, struct wlr_box *box, bool calculate_visibility, bool enabled) { @@ -1563,7 +1590,7 @@ static bool scene_buffer_try_direct_scanout(struct render_list_entry *entry, return false; } - wl_signal_emit_mutable(&buffer->events.output_present, scene_output); + entry->presented = true; state.committed |= WLR_OUTPUT_STATE_DAMAGE; get_frame_damage(scene_output, &state.damage); @@ -1753,7 +1780,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { continue; } - scene_node_render(entry->node, scene_output, &damage); + scene_render_list_entry_render(entry, scene_output, &damage); if (entry->node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(entry->node);