diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 80d62fa8f..0b336cc3d 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -699,12 +699,12 @@ bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) { return true; } -bool drm_connector_commit_state(struct wlr_drm_connector *conn, +struct wlr_output_commit *drm_connector_commit_state(struct wlr_drm_connector *conn, const struct wlr_output_state *base) { struct wlr_drm_backend *drm = conn->backend; if (!drm->session->active) { - return false; + return NULL; } bool ok = false; @@ -780,15 +780,21 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn, out: drm_connector_state_finish(&pending); - return ok; + + if (!ok) { + return NULL; + } + + wlr_output_commit_init(&conn->commit, &conn->output); + return &conn->commit; } -static bool drm_connector_commit(struct wlr_output *output, +static struct wlr_output_commit *drm_connector_commit(struct wlr_output *output, const struct wlr_output_state *state) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); if (!drm_connector_test(output, state)) { - return false; + return NULL; } return drm_connector_commit_state(conn, state); @@ -1711,14 +1717,14 @@ static void handle_page_flip(int fd, unsigned seq, struct wlr_output_event_present present_event = { /* The DRM backend guarantees that the presentation event will be for * the last submitted frame. */ - .commit_seq = conn->output.commit_seq, + .output = &conn->output, .presented = drm->session->active, .when = &present_time, .seq = seq, .refresh = mhz_to_nsec(conn->output.refresh), .flags = present_flags, }; - wlr_output_send_present(&conn->output, &present_event); + wl_signal_emit_mutable(&conn->commit.events.present, &present_event); if (drm->session->active) { wlr_output_send_frame(&conn->output); diff --git a/backend/headless/output.c b/backend/headless/output.c index 406959b49..aea4815c7 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -1,6 +1,8 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include +#include #include #include #include @@ -53,7 +55,7 @@ static bool output_test(struct wlr_output *wlr_output, return true; } -static bool output_commit(struct wlr_output *wlr_output, +static struct wlr_output_commit *output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) { struct wlr_headless_output *output = headless_output_from_output(wlr_output); @@ -62,21 +64,20 @@ static bool output_commit(struct wlr_output *wlr_output, return false; } + if (state->committed & WLR_OUTPUT_STATE_MODE) { output_update_refresh(output, state->custom_mode.refresh); } + wlr_output_commit_init(&output->commit, wlr_output); + if (output_pending_enabled(wlr_output, state)) { - struct wlr_output_event_present present_event = { - .commit_seq = wlr_output->commit_seq + 1, - .presented = true, - }; - output_defer_present(wlr_output, present_event); + output_commit_defer_present(&output->commit); wl_event_source_timer_update(output->frame_timer, output->frame_delay); } - return true; + return &output->commit; } static void output_destroy(struct wlr_output *wlr_output) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index ab6e3eef7..d5e244630 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include @@ -6,6 +7,7 @@ #include #include #include +#include #include #include @@ -101,14 +103,14 @@ static void presentation_feedback_handle_presented(void *data, .tv_nsec = tv_nsec, }; struct wlr_output_event_present event = { - .commit_seq = feedback->commit_seq, .presented = true, + .output = &feedback->output->wlr_output, .when = &t, .seq = ((uint64_t)seq_hi << 32) | seq_lo, .refresh = refresh_ns, .flags = flags, }; - wlr_output_send_present(&feedback->output->wlr_output, &event); + wl_signal_emit_mutable(&feedback->commit.events.present, &event); presentation_feedback_destroy(feedback); } @@ -118,10 +120,10 @@ static void presentation_feedback_handle_discarded(void *data, struct wlr_wl_presentation_feedback *feedback = data; struct wlr_output_event_present event = { - .commit_seq = feedback->commit_seq, .presented = false, + .output = &feedback->output->wlr_output, }; - wlr_output_send_present(&feedback->output->wlr_output, &event); + wl_signal_emit_mutable(&feedback->commit.events.present, &event); presentation_feedback_destroy(feedback); } @@ -520,13 +522,13 @@ static bool commit_layers(struct wlr_wl_output *output, return true; } -static bool output_commit(struct wlr_output *wlr_output, +static struct wlr_output_commit *output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); if (!output_test(wlr_output, state)) { - return false; + return NULL; } if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) { @@ -544,7 +546,7 @@ static bool output_commit(struct wlr_output *wlr_output, struct wlr_wl_buffer *buffer = get_or_create_wl_buffer(output->backend, wlr_buffer); if (buffer == NULL) { - return false; + return NULL; } wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0); @@ -553,9 +555,11 @@ static bool output_commit(struct wlr_output *wlr_output, if ((state->committed & WLR_OUTPUT_STATE_LAYERS) && !commit_layers(output, state->layers, state->layers_len)) { - return false; + return NULL; } + struct wlr_output_commit *commit = NULL; + if (output_pending_enabled(wlr_output, state)) { if (output->frame_callback != NULL) { wl_callback_destroy(output->frame_callback); @@ -576,27 +580,29 @@ static bool output_commit(struct wlr_output *wlr_output, calloc(1, sizeof(*feedback)); if (feedback == NULL) { wp_presentation_feedback_destroy(wp_feedback); - return false; + return NULL; } feedback->output = output; feedback->feedback = wp_feedback; - feedback->commit_seq = output->wlr_output.commit_seq + 1; wl_list_insert(&output->presentation_feedbacks, &feedback->link); wp_presentation_feedback_add_listener(wp_feedback, &presentation_feedback_listener, feedback); + + commit = &feedback->commit; + wlr_output_commit_init(commit, wlr_output); } else { - struct wlr_output_event_present present_event = { - .commit_seq = wlr_output->commit_seq + 1, - .presented = true, - }; - output_defer_present(wlr_output, present_event); + wlr_output_commit_init(commit, wlr_output); + output_commit_defer_present(commit); } + } else { + commit = &output->commit; + wlr_output_commit_init(commit, wlr_output); } wl_display_flush(output->backend->remote_display); - return true; + return commit; } static bool output_set_cursor(struct wlr_output *wlr_output, diff --git a/backend/x11/output.c b/backend/x11/output.c index f5dc527c2..64be76c49 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -105,6 +105,12 @@ static void output_destroy(struct wlr_output *wlr_output) { xcb_render_free_picture(x11->xcb, output->cursor.pic); } + struct wlr_x11_output_commit *commit, *tmp_commit; + wl_list_for_each_safe(commit, tmp_commit, &output->commits, link) { + wl_list_remove(&commit->link); + free(commit); + } + // A zero event mask deletes the event context xcb_present_select_input(x11->xcb, output->present_event_id, output->win, 0); xcb_destroy_window(x11->xcb, output->win); @@ -288,7 +294,7 @@ static struct wlr_x11_buffer *get_or_create_x11_buffer( } static bool output_commit_buffer(struct wlr_x11_output *output, - const struct wlr_output_state *state) { + const struct wlr_output_state *state, uint32_t serial) { struct wlr_x11_backend *x11 = output->x11; struct wlr_buffer *buffer = state->buffer; @@ -328,7 +334,6 @@ static bool output_commit_buffer(struct wlr_x11_output *output, pixman_region32_clear(&output->exposed); - uint32_t serial = output->wlr_output.commit_seq; uint32_t options = 0; uint64_t target_msc = output->last_msc ? output->last_msc + 1 : 0; xcb_present_pixmap(x11->xcb, output->win, x11_buffer->pixmap, serial, @@ -346,13 +351,18 @@ error: return false; } -static bool output_commit(struct wlr_output *wlr_output, +static struct wlr_output_commit *output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) { struct wlr_x11_output *output = get_x11_output_from_output(wlr_output); struct wlr_x11_backend *x11 = output->x11; if (!output_test(wlr_output, state)) { - return false; + return NULL; + } + + struct wlr_x11_output_commit *commit = calloc(1, sizeof(*commit)); + if (!commit){ + return NULL; } if (state->committed & WLR_OUTPUT_STATE_ENABLED) { @@ -368,23 +378,29 @@ static bool output_commit(struct wlr_output *wlr_output, state->custom_mode.width, state->custom_mode.height, state->custom_mode.refresh)) { - return false; + free(commit); + return NULL; } } + uint32_t serial = output->serial++; + + wlr_output_commit_init(&commit->commit, wlr_output); + wl_list_insert(&output->commits, &commit->link); + commit->serial = serial; + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { - if (!output_commit_buffer(output, state)) { - return false; + if (!output_commit_buffer(output, state, serial)) { + return NULL; } } else if (output_pending_enabled(wlr_output, state)) { - uint32_t serial = output->wlr_output.commit_seq; uint64_t target_msc = output->last_msc ? output->last_msc + 1 : 0; xcb_present_notify_msc(x11->xcb, output->win, serial, target_msc, 0, 0); } xcb_flush(x11->xcb); - return true; + return &commit->commit; } static void update_x11_output_cursor(struct wlr_x11_output *output, @@ -541,6 +557,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { } output->x11 = x11; wl_list_init(&output->buffers); + wl_list_init(&output->commits); pixman_region32_init(&output->exposed); struct wlr_output *wlr_output = &output->wlr_output; @@ -724,16 +741,28 @@ void handle_x11_present_event(struct wlr_x11_backend *x11, flags |= WLR_OUTPUT_PRESENT_ZERO_COPY; } + uint32_t serial = complete_notify->serial; + struct wlr_x11_output_commit *commit = NULL; + wl_list_for_each(commit, &output->commits, link) { + if (commit->serial == serial) { + break; + } + } + + assert(commit && commit->serial == serial); + bool presented = complete_notify->mode != XCB_PRESENT_COMPLETE_MODE_SKIP; struct wlr_output_event_present present_event = { .output = &output->wlr_output, - .commit_seq = complete_notify->serial, .presented = presented, .when = &t, .seq = complete_notify->msc, .flags = flags, }; - wlr_output_send_present(&output->wlr_output, &present_event); + wl_signal_emit_mutable(&commit->commit.events.present, &present_event); + + wl_list_remove(&commit->link); + free(commit); wlr_output_send_frame(&output->wlr_output); break; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 694169251..eeba74500 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -133,6 +133,7 @@ struct wlr_drm_connector_state { struct wlr_drm_connector { struct wlr_output output; // only valid if status != DISCONNECTED + struct wlr_output_commit commit; struct wlr_drm_backend *backend; char name[24]; @@ -175,7 +176,7 @@ void scan_drm_connectors(struct wlr_drm_backend *state, void scan_drm_leases(struct wlr_drm_backend *drm); int handle_drm_event(int fd, uint32_t mask, void *data); void destroy_drm_connector(struct wlr_drm_connector *conn); -bool drm_connector_commit_state(struct wlr_drm_connector *conn, +struct wlr_output_commit *drm_connector_commit_state(struct wlr_drm_connector *conn, const struct wlr_output_state *state); bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn); bool drm_connector_supports_vrr(struct wlr_drm_connector *conn); diff --git a/include/backend/headless.h b/include/backend/headless.h index 4c71fb608..0ce5dced9 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -16,6 +16,7 @@ struct wlr_headless_backend { struct wlr_headless_output { struct wlr_output wlr_output; + struct wlr_output_commit commit; struct wlr_headless_backend *backend; struct wl_list link; diff --git a/include/backend/wayland.h b/include/backend/wayland.h index a51595ec9..ee1c2f716 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -62,10 +62,11 @@ struct wlr_wl_buffer { }; struct wlr_wl_presentation_feedback { + struct wlr_output_commit commit; + struct wlr_wl_output *output; - struct wl_list link; + struct wl_list link; // wlr_wl_output.presentation_feedbacks struct wp_presentation_feedback *feedback; - uint32_t commit_seq; }; struct wlr_wl_output_layer { @@ -80,8 +81,11 @@ struct wlr_wl_output_layer { struct wlr_wl_output { struct wlr_output wlr_output; + // commit used when output is disabled or presentation events are not supported + struct wlr_output_commit commit; + struct wlr_wl_backend *backend; - struct wl_list link; + struct wl_list link; // wlr_wl_backend.outputs struct wl_surface *surface; bool own_surface; @@ -89,7 +93,7 @@ struct wlr_wl_output { struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1; - struct wl_list presentation_feedbacks; + struct wl_list presentation_feedbacks; // wlr_wl_presentation_feedback.link bool configured; uint32_t enter_serial; diff --git a/include/backend/x11.h b/include/backend/x11.h index 06834c1cb..acc51731c 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -27,10 +27,17 @@ struct wlr_x11_backend; +struct wlr_x11_output_commit { + struct wl_list link; // wlr_x11_output::commits; + uint32_t serial; + struct wlr_output_commit commit; +}; + struct wlr_x11_output { struct wlr_output wlr_output; struct wlr_x11_backend *x11; struct wl_list link; // wlr_x11_backend.outputs + uint32_t serial; xcb_window_t win; xcb_present_event_t present_event_id; @@ -50,6 +57,8 @@ struct wlr_x11_output { struct wlr_swapchain *swapchain; xcb_render_picture_t pic; } cursor; + + struct wl_list commits; // wlr_x11_output_commit::link }; struct wlr_x11_touchpoint { diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h index e1aea1be1..85afc1cf1 100644 --- a/include/types/wlr_output.h +++ b/include/types/wlr_output.h @@ -21,6 +21,6 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor, int dst_width, int dst_height, enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y); -void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event); +void output_commit_defer_present(struct wlr_output_commit *commit); #endif diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index a51312970..cf0c829f2 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -65,7 +65,8 @@ struct wlr_output_impl { * * If a buffer has been attached, a frame event is scheduled. */ - bool (*commit)(struct wlr_output *output, const struct wlr_output_state *state); + struct wlr_output_commit *(*commit)(struct wlr_output *output, + const struct wlr_output_state *state); /** * Get the maximum number of gamma LUT elements for each channel. * @@ -114,13 +115,6 @@ void wlr_output_update_needs_frame(struct wlr_output *output); * See wlr_output.events.frame. */ void wlr_output_send_frame(struct wlr_output *output); -/** - * Send a present event. - * - * See wlr_output.events.present. - */ -void wlr_output_send_present(struct wlr_output *output, - struct wlr_output_event_present *event); /** * Request the compositor to apply new state. */ diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 95ffc6702..adc58fcb4 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -160,9 +160,6 @@ struct wlr_output { struct wlr_output_state pending; - // Commit sequence number. Incremented on each commit, may overflow. - uint32_t commit_seq; - struct { // Request to render a frame struct wl_signal frame; @@ -176,9 +173,6 @@ struct wlr_output { struct wl_signal precommit; // struct wlr_output_event_precommit // Emitted right after commit struct wl_signal commit; // struct wlr_output_event_commit - // Emitted right after a commit has been presented to the user for - // enabled outputs - struct wl_signal present; // struct wlr_output_event_present // Emitted after a client bound the wl_output global struct wl_signal bind; // struct wlr_output_event_bind struct wl_signal description; @@ -209,6 +203,11 @@ struct wlr_output { struct wlr_addon_set addons; void *data; + + // private state + + // used for when to create a new back buffer + bool not_committed; }; struct wlr_output_event_damage { @@ -227,6 +226,7 @@ struct wlr_output_event_commit { uint32_t committed; // bitmask of enum wlr_output_state_field struct timespec *when; struct wlr_buffer *buffer; // NULL if no buffer is committed + struct wlr_output_commit *commit; }; enum wlr_output_present_flag { @@ -245,9 +245,6 @@ enum wlr_output_present_flag { struct wlr_output_event_present { struct wlr_output *output; - // Frame submission for which this presentation event is for (see - // wlr_output.commit_seq). - uint32_t commit_seq; // Whether the frame was presented at all. bool presented; // Time when the content update turned into light the first time. @@ -270,8 +267,20 @@ struct wlr_output_event_request_state { const struct wlr_output_state *state; }; +struct wlr_output_commit { + struct wlr_output *output; + + struct { + struct wl_signal present; // struct wlr_output_event_present + } events; +}; + struct wlr_surface; + +void wlr_output_commit_init(struct wlr_output_commit *commit, + struct wlr_output *output); + /** * Enables or disables the output. A disabled output is turned off and doesn't * emit `frame` events. @@ -460,7 +469,7 @@ bool wlr_output_test(struct wlr_output *output); * * On failure, the pending changes are rolled back. */ -bool wlr_output_commit(struct wlr_output *output); +struct wlr_output_commit *wlr_output_commit(struct wlr_output *output); /** * Discard the pending output state. */ @@ -477,12 +486,13 @@ bool wlr_output_test_state(struct wlr_output *output, /** * Attempts to apply the state to this output. This function may fail for any * reason and return false. If failed, none of the state would have been applied, - * this function is atomic. If the commit succeeded, true is returned. + * this function is atomic. If the commit succeeded, an wlr_output_commit struct + * is returned. If the commit failed, NULL is returned. * * Note: wlr_output_state_finish() would typically be called after the state * has been committed. */ -bool wlr_output_commit_state(struct wlr_output *output, +struct wlr_output_commit *wlr_output_commit_state(struct wlr_output *output, const struct wlr_output_state *state); /** * Manually schedules a `frame` event. If a `frame` event is already pending, diff --git a/include/wlr/types/wlr_presentation_time.h b/include/wlr/types/wlr_presentation_time.h index a8df292dc..1730a9b44 100644 --- a/include/wlr/types/wlr_presentation_time.h +++ b/include/wlr/types/wlr_presentation_time.h @@ -36,8 +36,6 @@ struct wlr_presentation_feedback { // Only when the wlr_presentation_surface_textured_on_output() or // wlr_presentation_surface_scanned_out_on_output() helper has been called. struct wlr_output *output; - bool output_committed; - uint32_t output_commit_seq; bool zero_copy; struct wl_listener output_commit; diff --git a/types/output/output.c b/types/output/output.c index 57b4c87e2..2394efe2a 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -411,7 +411,6 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, .render_format = DRM_FORMAT_XRGB8888, .transform = WL_OUTPUT_TRANSFORM_NORMAL, .scale = 1, - .commit_seq = 0, }; wl_list_init(&output->modes); @@ -423,7 +422,6 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.needs_frame); wl_signal_init(&output->events.precommit); wl_signal_init(&output->events.commit); - wl_signal_init(&output->events.present); wl_signal_init(&output->events.bind); wl_signal_init(&output->events.description); wl_signal_init(&output->events.request_state); @@ -440,6 +438,8 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); + output->not_committed = true; + if (state) { output_apply_state(output, state); } @@ -780,7 +780,13 @@ bool wlr_output_test(struct wlr_output *output) { return wlr_output_test_state(output, &state); } -bool wlr_output_commit_state(struct wlr_output *output, +void wlr_output_commit_init(struct wlr_output_commit *commit, + struct wlr_output *output) { + wl_signal_init(&commit->events.present); + commit->output = output; +} + +struct wlr_output_commit *wlr_output_commit_state(struct wlr_output *output, const struct wlr_output_state *state) { uint32_t unchanged = output_compare_state(output, state); @@ -791,12 +797,12 @@ bool wlr_output_commit_state(struct wlr_output *output, if (!output_basic_test(output, &pending)) { wlr_log(WLR_ERROR, "Basic output test failed for %s", output->name); - return false; + return NULL; } bool new_back_buffer = false; if (!output_ensure_buffer(output, &pending, &new_back_buffer)) { - return false; + return NULL; } if ((pending.committed & WLR_OUTPUT_STATE_BUFFER) && @@ -815,15 +821,14 @@ bool wlr_output_commit_state(struct wlr_output *output, }; wl_signal_emit_mutable(&output->events.precommit, &pre_event); - if (!output->impl->commit(output, &pending)) { + struct wlr_output_commit *commit = output->impl->commit(output, &pending); + if (!commit) { if (new_back_buffer) { wlr_buffer_unlock(pending.buffer); } return false; } - output->commit_seq++; - if (output_pending_enabled(output, state)) { output->frame_pending = true; output->needs_frame = false; @@ -836,6 +841,7 @@ bool wlr_output_commit_state(struct wlr_output *output, .committed = pending.committed, .when = &now, .buffer = (pending.committed & WLR_OUTPUT_STATE_BUFFER) ? pending.buffer : NULL, + .commit = commit, }; wl_signal_emit_mutable(&output->events.commit, &event); @@ -843,10 +849,12 @@ bool wlr_output_commit_state(struct wlr_output *output, wlr_buffer_unlock(pending.buffer); } - return true; + output->not_committed = false; + + return commit; } -bool wlr_output_commit(struct wlr_output *output) { +struct wlr_output_commit *wlr_output_commit(struct wlr_output *output) { // Make sure the pending state is cleared before the output is committed struct wlr_output_state state = {0}; output_state_move(&state, &output->pending); @@ -860,9 +868,9 @@ bool wlr_output_commit(struct wlr_output *output) { output_clear_back_buffer(output); } - bool ok = wlr_output_commit_state(output, &state); + struct wlr_output_commit *commit = wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); - return ok; + return commit; } void wlr_output_rollback(struct wlr_output *output) { @@ -907,30 +915,9 @@ void wlr_output_schedule_frame(struct wlr_output *output) { wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); } -void wlr_output_send_present(struct wlr_output *output, - struct wlr_output_event_present *event) { - assert(event); - event->output = output; - - struct timespec now; - if (event->presented && event->when == NULL) { - clockid_t clock = wlr_backend_get_presentation_clock(output->backend); - errno = 0; - if (clock_gettime(clock, &now) != 0) { - wlr_log_errno(WLR_ERROR, "failed to send output present event: " - "failed to read clock"); - return; - } - event->when = &now; - } - - wl_signal_emit_mutable(&output->events.present, event); -} - struct deferred_present_event { - struct wlr_output *output; + struct wlr_output_commit *commit; struct wl_event_source *idle_source; - struct wlr_output_event_present event; struct wl_listener output_destroy; }; @@ -941,7 +928,19 @@ static void deferred_present_event_destroy(struct deferred_present_event *deferr static void deferred_present_event_handle_idle(void *data) { struct deferred_present_event *deferred = data; - wlr_output_send_present(deferred->output, &deferred->event); + + clockid_t clock = wlr_backend_get_presentation_clock(deferred->commit->output->backend); + struct timespec now; + clock_gettime(clock, &now); + + struct wlr_output_event_present present_event = { + .presented = true, + .output = deferred->commit->output, + .when = &now, + }; + + wl_signal_emit_mutable(&deferred->commit->events.present, &present_event); + deferred_present_event_destroy(deferred); } @@ -951,19 +950,16 @@ static void deferred_present_event_handle_output_destroy(struct wl_listener *lis deferred_present_event_destroy(deferred); } -void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event) { +void output_commit_defer_present(struct wlr_output_commit *commit) { struct deferred_present_event *deferred = calloc(1, sizeof(*deferred)); if (!deferred) { return; } - *deferred = (struct deferred_present_event){ - .output = output, - .event = event, - }; + deferred->commit = commit; deferred->output_destroy.notify = deferred_present_event_handle_output_destroy; - wl_signal_add(&output->events.destroy, &deferred->output_destroy); + wl_signal_add(&commit->output->events.destroy, &deferred->output_destroy); - struct wl_event_loop *ev = wl_display_get_event_loop(output->display); + struct wl_event_loop *ev = wl_display_get_event_loop(commit->output->display); deferred->idle_source = wl_event_loop_add_idle(ev, deferred_present_event_handle_idle, deferred); } diff --git a/types/output/render.c b/types/output/render.c index a185d8446..a16f4405a 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -155,7 +155,7 @@ bool output_ensure_buffer(struct wlr_output *output, if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { needs_new_buffer = true; } - if (state->allow_artifacts && output->commit_seq == 0 && enabled) { + if (state->allow_artifacts && output->not_committed && enabled) { // On first commit, require a new buffer if the compositor called a // mode-setting function, even if the mode won't change. This makes it // so the swapchain is created now. diff --git a/types/wlr_presentation_time.c b/types/wlr_presentation_time.c index 65c06ce36..9de17c674 100644 --- a/types/wlr_presentation_time.c +++ b/types/wlr_presentation_time.c @@ -269,28 +269,12 @@ static void feedback_unset_output(struct wlr_presentation_feedback *feedback) { wl_list_remove(&feedback->output_destroy.link); } -static void feedback_handle_output_commit(struct wl_listener *listener, - void *data) { - struct wlr_presentation_feedback *feedback = - wl_container_of(listener, feedback, output_commit); - if (feedback->output_committed) { - return; - } - feedback->output_committed = true; - feedback->output_commit_seq = feedback->output->commit_seq; -} - static void feedback_handle_output_present(struct wl_listener *listener, void *data) { struct wlr_presentation_feedback *feedback = wl_container_of(listener, feedback, output_present); struct wlr_output_event_present *output_event = data; - if (!feedback->output_committed || - output_event->commit_seq != feedback->output_commit_seq) { - return; - } - if (output_event->presented) { struct wlr_presentation_event event = {0}; wlr_presentation_event_from_output(&event, output_event); @@ -302,6 +286,20 @@ static void feedback_handle_output_present(struct wl_listener *listener, wlr_presentation_feedback_destroy(feedback); } +static void feedback_handle_output_commit(struct wl_listener *listener, + void *data) { + struct wlr_output_event_commit *event = data; + struct wlr_presentation_feedback *feedback = + wl_container_of(listener, feedback, output_commit); + + // we only care about the first commit + wl_list_remove(&feedback->output_commit.link); + wl_list_init(&feedback->output_commit.link); + + feedback->output_present.notify = feedback_handle_output_present; + wl_signal_add(&event->commit->events.present, &feedback->output_present); +} + static void feedback_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_presentation_feedback *feedback = @@ -324,10 +322,10 @@ static void presentation_surface_queued_on_output( feedback->output_commit.notify = feedback_handle_output_commit; wl_signal_add(&output->events.commit, &feedback->output_commit); - feedback->output_present.notify = feedback_handle_output_present; - wl_signal_add(&output->events.present, &feedback->output_present); feedback->output_destroy.notify = feedback_handle_output_destroy; wl_signal_add(&output->events.destroy, &feedback->output_destroy); + + wl_list_init(&feedback->output_present.link); } void wlr_presentation_surface_textured_on_output(