backend/wayland: re-use wl_buffers

Instead of re-importing a buffer each time we submit a new frame, re-use
the wl_buffer objects if possible.
This commit is contained in:
Simon Ser 2020-12-11 18:14:58 +01:00
parent de896caceb
commit defcd9b025
3 changed files with 46 additions and 4 deletions

View file

@ -210,6 +210,11 @@ static void backend_destroy(struct wlr_backend *backend) {
wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats); wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats);
struct wlr_wl_buffer *buffer, *tmp_buffer;
wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) {
destroy_wl_buffer(buffer);
}
destroy_wl_seats(wl); destroy_wl_seats(wl);
if (wl->zxdg_decoration_manager_v1) { if (wl->zxdg_decoration_manager_v1) {
zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1); zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1);
@ -270,6 +275,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
wl_list_init(&wl->devices); wl_list_init(&wl->devices);
wl_list_init(&wl->outputs); wl_list_init(&wl->outputs);
wl_list_init(&wl->seats); wl_list_init(&wl->seats);
wl_list_init(&wl->buffers);
wl->remote_display = wl_display_connect(remote); wl->remote_display = wl_display_connect(remote);
if (!wl->remote_display) { if (!wl->remote_display) {

View file

@ -133,24 +133,33 @@ static bool output_attach_render(struct wlr_output *wlr_output,
return true; return true;
} }
static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) { void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
if (buffer == NULL) { if (buffer == NULL) {
return; return;
} }
wl_list_remove(&buffer->buffer_destroy.link);
wl_list_remove(&buffer->link);
wl_buffer_destroy(buffer->wl_buffer); wl_buffer_destroy(buffer->wl_buffer);
wlr_buffer_unlock(buffer->buffer);
free(buffer); free(buffer);
} }
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) { static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
struct wlr_wl_buffer *buffer = data; struct wlr_wl_buffer *buffer = data;
destroy_wl_buffer(buffer); buffer->released = true;
wlr_buffer_unlock(buffer->buffer); // might free buffer
} }
static const struct wl_buffer_listener buffer_listener = { static const struct wl_buffer_listener buffer_listener = {
.release = buffer_handle_release, .release = buffer_handle_release,
}; };
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
void *data) {
struct wlr_wl_buffer *buffer =
wl_container_of(listener, buffer, buffer_destroy);
destroy_wl_buffer(buffer);
}
static bool test_buffer(struct wlr_wl_backend *wl, static bool test_buffer(struct wlr_wl_backend *wl,
struct wlr_buffer *wlr_buffer) { struct wlr_buffer *wlr_buffer) {
struct wlr_dmabuf_attributes attribs; struct wlr_dmabuf_attributes attribs;
@ -207,12 +216,33 @@ static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl,
} }
buffer->wl_buffer = wl_buffer; buffer->wl_buffer = wl_buffer;
buffer->buffer = wlr_buffer_lock(wlr_buffer); buffer->buffer = wlr_buffer_lock(wlr_buffer);
wl_list_insert(&wl->buffers, &buffer->link);
wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer); wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy);
return buffer; return buffer;
} }
static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
struct wlr_buffer *wlr_buffer) {
struct wlr_wl_buffer *buffer;
wl_list_for_each(buffer, &wl->buffers, link) {
// We can only re-use a wlr_wl_buffer if the parent compositor has
// released it, because wl_buffer.release is per-wl_buffer, not per
// wl_surface.commit.
if (buffer->buffer == wlr_buffer && buffer->released) {
buffer->released = false;
wlr_buffer_lock(buffer->buffer);
return buffer;
}
}
return create_wl_buffer(wl, wlr_buffer);
}
static bool output_test(struct wlr_output *wlr_output) { static bool output_test(struct wlr_output *wlr_output) {
struct wlr_wl_output *output = struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output); get_wl_output_from_output(wlr_output);
@ -287,7 +317,7 @@ static bool output_commit(struct wlr_output *wlr_output) {
} }
struct wlr_wl_buffer *buffer = struct wlr_wl_buffer *buffer =
create_wl_buffer(output->backend, wlr_buffer); get_or_create_wl_buffer(output->backend, wlr_buffer);
if (buffer == NULL) { if (buffer == NULL) {
return false; return false;
} }

View file

@ -25,9 +25,11 @@ struct wlr_wl_backend {
struct wlr_renderer *renderer; struct wlr_renderer *renderer;
struct wlr_drm_format *format; struct wlr_drm_format *format;
struct wlr_allocator *allocator; struct wlr_allocator *allocator;
struct wl_list buffers; // wlr_wl_buffer.link
size_t requested_outputs; size_t requested_outputs;
size_t last_output_num; size_t last_output_num;
struct wl_listener local_display_destroy; struct wl_listener local_display_destroy;
/* remote state */ /* remote state */
struct wl_display *remote_display; struct wl_display *remote_display;
struct wl_event_source *remote_display_src; struct wl_event_source *remote_display_src;
@ -47,6 +49,9 @@ struct wlr_wl_backend {
struct wlr_wl_buffer { struct wlr_wl_buffer {
struct wlr_buffer *buffer; struct wlr_buffer *buffer;
struct wl_buffer *wl_buffer; struct wl_buffer *wl_buffer;
bool released;
struct wl_list link; // wlr_wl_backend.buffers
struct wl_listener buffer_destroy;
}; };
struct wlr_wl_presentation_feedback { struct wlr_wl_presentation_feedback {
@ -130,6 +135,7 @@ struct wlr_wl_input_device *create_wl_input_device(
struct wlr_wl_seat *seat, enum wlr_input_device_type type); struct wlr_wl_seat *seat, enum wlr_input_device_type type);
bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl);
void destroy_wl_seats(struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl);
void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
extern const struct wl_seat_listener seat_listener; extern const struct wl_seat_listener seat_listener;