mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-30 00:15:58 +01:00
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
2 changed files with 64 additions and 28 deletions
|
@ -109,25 +109,39 @@ static bool output_attach_render(struct wlr_output *wlr_output,
|
||||||
buffer_age);
|
buffer_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool output_attach_buffer(struct wlr_output *wlr_output,
|
static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
|
||||||
struct wlr_buffer *buffer) {
|
if (buffer == NULL) {
|
||||||
struct wlr_wl_output *output =
|
return;
|
||||||
get_wl_output_from_output(wlr_output);
|
}
|
||||||
struct wlr_wl_backend *wl = output->backend;
|
wl_buffer_destroy(buffer->wl_buffer);
|
||||||
|
wlr_buffer_unref(buffer->buffer);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
struct wlr_dmabuf_attributes attribs;
|
||||||
if (!wlr_buffer_get_dmabuf(buffer, &attribs)) {
|
if (!wlr_buffer_get_dmabuf(wlr_buffer, &attribs)) {
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attribs.width != wlr_output->width ||
|
if (attribs.width != required_width || attribs.height != required_height) {
|
||||||
attribs.height != wlr_output->height) {
|
return NULL;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats,
|
if (!wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats,
|
||||||
attribs.format, attribs.modifier)) {
|
attribs.format, attribs.modifier)) {
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t modifier_hi = attribs.modifier >> 32;
|
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);
|
params, attribs.width, attribs.height, attribs.format, flags);
|
||||||
// TODO: handle create() errors
|
// TODO: handle create() errors
|
||||||
|
|
||||||
wl_surface_attach(output->surface, wl_buffer, 0, 0);
|
struct wlr_wl_buffer *buffer = calloc(1, sizeof(struct wlr_wl_buffer));
|
||||||
|
if (buffer == NULL) {
|
||||||
if (output->pending_wl_buffer != NULL) {
|
wl_buffer_destroy(wl_buffer);
|
||||||
wl_buffer_destroy(output->pending_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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,13 +217,6 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
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;
|
struct wp_presentation_feedback *wp_feedback = NULL;
|
||||||
if (output->backend->presentation != NULL) {
|
if (output->backend->presentation != NULL) {
|
||||||
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
||||||
|
@ -216,6 +244,10 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WLR_OUTPUT_STATE_BUFFER_SCANOUT:
|
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) {
|
if (damage == NULL) {
|
||||||
wl_surface_damage_buffer(output->surface,
|
wl_surface_damage_buffer(output->surface,
|
||||||
0, 0, INT32_MAX, INT32_MAX);
|
0, 0, INT32_MAX, INT32_MAX);
|
||||||
|
@ -231,9 +263,7 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
wl_surface_commit(output->surface);
|
wl_surface_commit(output->surface);
|
||||||
|
|
||||||
output->current_buffer = wlr_buffer_ref(wlr_output->pending.buffer);
|
output->pending_buffer = NULL;
|
||||||
output->current_wl_buffer = output->pending_wl_buffer;
|
|
||||||
output->pending_wl_buffer = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,6 +389,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
presentation_feedback_destroy(feedback);
|
presentation_feedback_destroy(feedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy_wl_buffer(output->pending_buffer);
|
||||||
|
|
||||||
wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface);
|
wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface);
|
||||||
wl_egl_window_destroy(output->egl_window);
|
wl_egl_window_destroy(output->egl_window);
|
||||||
if (output->zxdg_toplevel_decoration_v1) {
|
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_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_presentation_feedback {
|
||||||
struct wlr_wl_output *output;
|
struct wlr_wl_output *output;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
@ -67,8 +72,7 @@ struct wlr_wl_output {
|
||||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
||||||
struct wl_egl_window *egl_window;
|
struct wl_egl_window *egl_window;
|
||||||
EGLSurface egl_surface;
|
EGLSurface egl_surface;
|
||||||
struct wl_buffer *pending_wl_buffer, *current_wl_buffer;
|
struct wlr_wl_buffer *pending_buffer;
|
||||||
struct wlr_buffer *current_buffer;
|
|
||||||
struct wl_list presentation_feedbacks;
|
struct wl_list presentation_feedbacks;
|
||||||
|
|
||||||
uint32_t enter_serial;
|
uint32_t enter_serial;
|
||||||
|
|
Loading…
Reference in a new issue