diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 962b01bcc..6c627b1f9 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -153,6 +153,8 @@ struct wlr_scene_outputs_update_event { struct wlr_scene_output_sample_event { struct wlr_scene_output *output; bool direct_scanout; + struct wlr_drm_syncobj_timeline *release_timeline; + uint64_t release_point; }; struct wlr_scene_frame_done_event { @@ -266,6 +268,8 @@ struct wlr_scene_output { struct wlr_drm_syncobj_timeline *in_timeline; uint64_t in_point; + struct wlr_drm_syncobj_timeline *out_timeline; + uint64_t out_point; } WLR_PRIVATE; }; diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 51373e15a..54c09bbfe 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1553,6 +1553,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren struct wlr_scene_output_sample_event sample_event = { .output = data->output, .direct_scanout = false, + .release_timeline = data->output->in_timeline, + .release_point = data->output->in_point, }; wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event); @@ -1785,7 +1787,10 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, if (drm_fd >= 0 && output->backend->features.timeline && output->renderer != NULL && output->renderer->features.timeline) { scene_output->in_timeline = wlr_drm_syncobj_timeline_create(drm_fd); - if (scene_output->in_timeline == NULL) { + scene_output->out_timeline = wlr_drm_syncobj_timeline_create(drm_fd); + if (scene_output->in_timeline == NULL || scene_output->out_timeline == NULL) { + wlr_drm_syncobj_timeline_unref(scene_output->in_timeline); + wlr_drm_syncobj_timeline_unref(scene_output->out_timeline); return NULL; } } @@ -1840,7 +1845,14 @@ 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); - wlr_drm_syncobj_timeline_unref(scene_output->in_timeline); + if (scene_output->in_timeline != NULL) { + wlr_drm_syncobj_timeline_signal(scene_output->in_timeline, UINT64_MAX); + wlr_drm_syncobj_timeline_unref(scene_output->in_timeline); + } + if (scene_output->out_timeline != NULL) { + wlr_drm_syncobj_timeline_signal(scene_output->out_timeline, UINT64_MAX); + wlr_drm_syncobj_timeline_unref(scene_output->out_timeline); + } wlr_color_transform_unref(scene_output->gamma_lut_color_transform); wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform); wlr_color_transform_unref(scene_output->prev_supplied_color_transform); @@ -2136,6 +2148,12 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout( if (buffer->wait_timeline != NULL) { wlr_output_state_set_wait_timeline(&pending, buffer->wait_timeline, buffer->wait_point); } + + if (scene_output->out_timeline) { + scene_output->out_point++; + wlr_output_state_set_signal_timeline(&pending, scene_output->out_timeline, scene_output->out_point); + } + if (!wlr_output_test_state(scene_output->output, &pending)) { wlr_output_state_finish(&pending); return SCANOUT_CANDIDATE; @@ -2147,6 +2165,8 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout( struct wlr_scene_output_sample_event sample_event = { .output = scene_output, .direct_scanout = true, + .release_timeline = data->output->out_timeline, + .release_point = data->output->out_point, }; wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event); return SCANOUT_SUCCESS; @@ -2606,6 +2626,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, if (scene_output->in_timeline != NULL) { wlr_output_state_set_wait_timeline(state, scene_output->in_timeline, scene_output->in_point); + scene_output->out_point++; + wlr_output_state_set_signal_timeline(state, scene_output->out_timeline, + scene_output->out_point); } if (!render_gamma_lut) {