backend/wayland: listen to wl_buffer.release events
Previously, we just assumed submitting a new frame would make the compositor release the current one. This isn't always the case, for instance Sway retains old buffers when a transaction is pending. This resulted in synchronization issues with clients writing in front-buffers. Fix this by un-referencing a wlr_buffer when the parent compositor sends wl_buffer.release. Tested by running a fullscreen mpv instance in Sway with the Wayland backend.
This commit is contained in:
parent
b5cb6de232
commit
e6fd880686
|
@ -109,25 +109,39 @@ static bool output_attach_render(struct wlr_output *wlr_output,
|
|||
buffer_age);
|
||||
}
|
||||
|
||||
static bool output_attach_buffer(struct wlr_output *wlr_output,
|
||||
struct wlr_buffer *buffer) {
|
||||
struct wlr_wl_output *output =
|
||||
get_wl_output_from_output(wlr_output);
|
||||
struct wlr_wl_backend *wl = output->backend;
|
||||
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
if (!wlr_buffer_get_dmabuf(buffer, &attribs)) {
|
||||
return false;
|
||||
static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
|
||||
if (buffer == NULL) {
|
||||
return;
|
||||
}
|
||||
wl_buffer_destroy(buffer->wl_buffer);
|
||||
wlr_buffer_unref(buffer->buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
if (attribs.width != wlr_output->width ||
|
||||
attribs.height != wlr_output->height) {
|
||||
return false;
|
||||
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
|
||||
struct wlr_wl_buffer *buffer = data;
|
||||
destroy_wl_buffer(buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
.release = buffer_handle_release,
|
||||
};
|
||||
|
||||
static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl,
|
||||
struct wlr_buffer *wlr_buffer,
|
||||
int required_width, int required_height) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
if (!wlr_buffer_get_dmabuf(wlr_buffer, &attribs)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (attribs.width != required_width || attribs.height != required_height) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats,
|
||||
attribs.format, attribs.modifier)) {
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t modifier_hi = attribs.modifier >> 32;
|
||||
|
@ -153,12 +167,33 @@ static bool output_attach_buffer(struct wlr_output *wlr_output,
|
|||
params, attribs.width, attribs.height, attribs.format, flags);
|
||||
// TODO: handle create() errors
|
||||
|
||||
wl_surface_attach(output->surface, wl_buffer, 0, 0);
|
||||
|
||||
if (output->pending_wl_buffer != NULL) {
|
||||
wl_buffer_destroy(output->pending_wl_buffer);
|
||||
struct wlr_wl_buffer *buffer = calloc(1, sizeof(struct wlr_wl_buffer));
|
||||
if (buffer == NULL) {
|
||||
wl_buffer_destroy(wl_buffer);
|
||||
return NULL;
|
||||
}
|
||||
output->pending_wl_buffer = wl_buffer;
|
||||
buffer->wl_buffer = wl_buffer;
|
||||
buffer->buffer = wlr_buffer_ref(wlr_buffer);
|
||||
|
||||
wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static bool output_attach_buffer(struct wlr_output *wlr_output,
|
||||
struct wlr_buffer *wlr_buffer) {
|
||||
struct wlr_wl_output *output =
|
||||
get_wl_output_from_output(wlr_output);
|
||||
struct wlr_wl_backend *wl = output->backend;
|
||||
|
||||
struct wlr_wl_buffer *buffer = create_wl_buffer(wl, wlr_buffer,
|
||||
wlr_output->width, wlr_output->height);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
destroy_wl_buffer(output->pending_buffer);
|
||||
output->pending_buffer = buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -182,13 +217,6 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
}
|
||||
|
||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
wlr_buffer_unref(output->current_buffer);
|
||||
output->current_buffer = NULL;
|
||||
if (output->current_wl_buffer != NULL) {
|
||||
wl_buffer_destroy(output->current_wl_buffer);
|
||||
output->current_wl_buffer = NULL;
|
||||
}
|
||||
|
||||
struct wp_presentation_feedback *wp_feedback = NULL;
|
||||
if (output->backend->presentation != NULL) {
|
||||
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
||||
|
@ -216,6 +244,10 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
}
|
||||
break;
|
||||
case WLR_OUTPUT_STATE_BUFFER_SCANOUT:
|
||||
assert(output->pending_buffer != NULL);
|
||||
wl_surface_attach(output->surface,
|
||||
output->pending_buffer->wl_buffer, 0, 0);
|
||||
|
||||
if (damage == NULL) {
|
||||
wl_surface_damage_buffer(output->surface,
|
||||
0, 0, INT32_MAX, INT32_MAX);
|
||||
|
@ -231,9 +263,7 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
}
|
||||
wl_surface_commit(output->surface);
|
||||
|
||||
output->current_buffer = wlr_buffer_ref(wlr_output->pending.buffer);
|
||||
output->current_wl_buffer = output->pending_wl_buffer;
|
||||
output->pending_wl_buffer = NULL;
|
||||
output->pending_buffer = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -359,6 +389,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
presentation_feedback_destroy(feedback);
|
||||
}
|
||||
|
||||
destroy_wl_buffer(output->pending_buffer);
|
||||
|
||||
wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface);
|
||||
wl_egl_window_destroy(output->egl_window);
|
||||
if (output->zxdg_toplevel_decoration_v1) {
|
||||
|
|
|
@ -47,6 +47,11 @@ struct wlr_wl_backend {
|
|||
struct wlr_drm_format_set linux_dmabuf_v1_formats;
|
||||
};
|
||||
|
||||
struct wlr_wl_buffer {
|
||||
struct wlr_buffer *buffer;
|
||||
struct wl_buffer *wl_buffer;
|
||||
};
|
||||
|
||||
struct wlr_wl_presentation_feedback {
|
||||
struct wlr_wl_output *output;
|
||||
struct wl_list link;
|
||||
|
@ -67,8 +72,7 @@ struct wlr_wl_output {
|
|||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
||||
struct wl_egl_window *egl_window;
|
||||
EGLSurface egl_surface;
|
||||
struct wl_buffer *pending_wl_buffer, *current_wl_buffer;
|
||||
struct wlr_buffer *current_buffer;
|
||||
struct wlr_wl_buffer *pending_buffer;
|
||||
struct wl_list presentation_feedbacks;
|
||||
|
||||
uint32_t enter_serial;
|
||||
|
|
Loading…
Reference in New Issue