mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-05 13:40:36 +02:00
compositor: add .present event to struct wlr_surface_output
For the implementation of fifo-v1, we need to be able to track the presentation of individual surface commits. This is done already in `wlr_presentation_time`, but the way that is implemented is suited only for use by clients through the protocol interface (.feedback requests). Here we use the `surface_output` structure, which is a low-level structure that links wlr_surfaces with wlr_outputs. Within this structure we listen to the surface's and the output's .commit events. Through these 2 we link a surface commit to an output commit. Then, a new struct wlr_surface_output_commit is created which listens to the output's .present event. For the interface to this functionality, 2 elements are introduced: the new .present event in struct wlr_surface_output, which signals listeners whether a particular pair of (surface_seq, output_seq) has been presented or discarded, and the wlr_surface_textured_on_output() function, used by the scene logic to inform the implementation that the surface's buffer has been textured on a particular output. Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
This commit is contained in:
parent
71e9b16235
commit
bd91aed2c9
3 changed files with 138 additions and 0 deletions
|
|
@ -118,14 +118,47 @@ struct wlr_surface_role {
|
|||
void (*destroy)(struct wlr_surface *surface);
|
||||
};
|
||||
|
||||
struct wlr_surface_output_event_present {
|
||||
struct wlr_surface_output_commit *commit;
|
||||
struct timespec when;
|
||||
};
|
||||
|
||||
struct wlr_surface_output_commit {
|
||||
struct wlr_surface_output *surface_output;
|
||||
|
||||
uint32_t surface_seq;
|
||||
uint32_t output_seq;
|
||||
bool committed_on_surface;
|
||||
bool textured_on_output;
|
||||
bool committed_on_output;
|
||||
bool presented_on_output;
|
||||
|
||||
struct wl_list link; // wlr_surface_output.commits
|
||||
|
||||
struct {
|
||||
struct wl_listener output_present;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_surface_output {
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_output *output;
|
||||
|
||||
struct wl_list link; // wlr_surface.current_outputs
|
||||
|
||||
struct wlr_surface_output_commit current_commit;
|
||||
struct wl_list commits; // wlr_surface_output_commit.link
|
||||
struct {
|
||||
/**
|
||||
* Signals that a surface commit has been presented or discarded on the output.
|
||||
*/
|
||||
struct wl_signal present;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener bind;
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
|
@ -399,6 +432,12 @@ void wlr_surface_send_enter(struct wlr_surface *surface,
|
|||
void wlr_surface_send_leave(struct wlr_surface *surface,
|
||||
struct wlr_output *output);
|
||||
|
||||
/**
|
||||
* Mark the current surface's buffer as textured on the given output.
|
||||
*/
|
||||
void wlr_surface_textured_on_output(struct wlr_surface *surface,
|
||||
struct wlr_output *output);
|
||||
|
||||
/**
|
||||
* Complete the queued frame callbacks for this surface.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ static void handle_scene_buffer_output_sample(
|
|||
} else {
|
||||
wlr_presentation_surface_textured_on_output(surface->surface, output);
|
||||
}
|
||||
|
||||
wlr_surface_textured_on_output(surface->surface, output);
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_frame_done(
|
||||
|
|
|
|||
|
|
@ -1051,9 +1051,18 @@ struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface,
|
|||
|
||||
static void surface_output_destroy(struct wlr_surface_output *surface_output) {
|
||||
wl_list_remove(&surface_output->bind.link);
|
||||
wl_list_remove(&surface_output->output_commit.link);
|
||||
wl_list_remove(&surface_output->surface_commit.link);
|
||||
wl_list_remove(&surface_output->destroy.link);
|
||||
wl_list_remove(&surface_output->link);
|
||||
|
||||
struct wlr_surface_output_commit *commit, *tmp;
|
||||
wl_list_for_each_safe(commit, tmp, &surface_output->commits, link) {
|
||||
wl_list_remove(&commit->link);
|
||||
wl_list_remove(&commit->output_present.link);
|
||||
free(commit);
|
||||
}
|
||||
|
||||
free(surface_output);
|
||||
}
|
||||
|
||||
|
|
@ -1069,6 +1078,87 @@ static void surface_handle_output_bind(struct wl_listener *listener,
|
|||
}
|
||||
}
|
||||
|
||||
static void commit_handle_output_present(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_surface_output_commit *commit =
|
||||
wl_container_of(listener, commit, output_present);
|
||||
struct wlr_surface_output *surface_output = commit->surface_output;
|
||||
|
||||
struct wlr_output_event_present *output_event = data;
|
||||
assert(commit->output_seq >= output_event->commit_seq);
|
||||
|
||||
if (commit->output_seq > output_event->commit_seq) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_surface_output_event_present surface_output_event_present = {0};
|
||||
surface_output_event_present.commit = commit;
|
||||
surface_output_event_present.when = output_event->when;
|
||||
commit->presented_on_output = output_event->presented;
|
||||
wl_signal_emit_mutable(&surface_output->events.present, &surface_output_event_present);
|
||||
|
||||
wl_list_remove(&commit->link);
|
||||
wl_list_remove(&commit->output_present.link);
|
||||
free(commit);
|
||||
}
|
||||
|
||||
static void surface_handle_output_commit(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_surface_output *surface_output =
|
||||
wl_container_of(listener, surface_output, output_commit);
|
||||
if (!surface_output->current_commit.textured_on_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_surface_output_commit *commit = calloc(1, sizeof(*commit));
|
||||
*commit = surface_output->current_commit;
|
||||
commit->committed_on_output = true;
|
||||
commit->output_present.notify = commit_handle_output_present;
|
||||
wl_signal_add(&surface_output->output->events.present, &commit->output_present);
|
||||
wl_list_insert(&surface_output->commits, &commit->link);
|
||||
|
||||
// reset current commit
|
||||
surface_output->current_commit = (struct wlr_surface_output_commit){0};
|
||||
}
|
||||
|
||||
void wlr_surface_textured_on_output(struct wlr_surface *surface,
|
||||
struct wlr_output *output) {
|
||||
struct wlr_surface_output *surface_output;
|
||||
wl_list_for_each(surface_output, &surface->current_outputs, link) {
|
||||
if (surface_output->output == output) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(surface_output->output == output);
|
||||
|
||||
if (!surface_output->current_commit.committed_on_surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
surface_output->current_commit.textured_on_output = true;
|
||||
surface_output->current_commit.output_seq = surface_output->output->commit_seq+1;
|
||||
}
|
||||
|
||||
static void surface_handle_surface_commit(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_surface_output *surface_output =
|
||||
wl_container_of(listener, surface_output, surface_commit);
|
||||
if (wl_list_empty(&surface_output->events.present.listener_list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_surface_output_commit *current_commit = &surface_output->current_commit;
|
||||
// if a surface commit is replaced by another one before it is latched onto the output,
|
||||
// it won't be presented.
|
||||
if (current_commit->committed_on_surface) {
|
||||
struct wlr_surface_output_event_present event_present = { .commit = current_commit };
|
||||
wl_signal_emit_mutable(&surface_output->events.present, &event_present);
|
||||
}
|
||||
current_commit->surface_output = surface_output;
|
||||
current_commit->committed_on_surface = true;
|
||||
current_commit->surface_seq = surface_output->surface->current.seq;
|
||||
}
|
||||
|
||||
static void surface_handle_output_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_surface_output *surface_output =
|
||||
|
|
@ -1093,10 +1183,17 @@ void wlr_surface_send_enter(struct wlr_surface *surface,
|
|||
return;
|
||||
}
|
||||
surface_output->bind.notify = surface_handle_output_bind;
|
||||
surface_output->output_commit.notify = surface_handle_output_commit;
|
||||
surface_output->surface_commit.notify = surface_handle_surface_commit;
|
||||
surface_output->destroy.notify = surface_handle_output_destroy;
|
||||
|
||||
wl_signal_add(&output->events.bind, &surface_output->bind);
|
||||
wl_signal_add(&output->events.commit, &surface_output->output_commit);
|
||||
wl_signal_add(&output->events.destroy, &surface_output->destroy);
|
||||
wl_signal_add(&surface->events.commit, &surface_output->surface_commit);
|
||||
|
||||
wl_signal_init(&surface_output->events.present);
|
||||
wl_list_init(&surface_output->commits);
|
||||
|
||||
surface_output->surface = surface;
|
||||
surface_output->output = output;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue