mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-20 06:47:19 -04:00
Merge branch 'buffer-release' into 'master'
compositor: implement wl_surface.get_release See merge request wlroots/wlroots!3674
This commit is contained in:
commit
7a72460a0d
4 changed files with 134 additions and 4 deletions
|
|
@ -59,6 +59,18 @@ static const struct wl_callback_listener frame_listener = {
|
||||||
.done = surface_frame_callback
|
.done = surface_frame_callback
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void handle_buffer_release(void *data, struct wl_callback *callback,
|
||||||
|
uint32_t callback_data) {
|
||||||
|
struct wlr_wl_buffer *buffer = data;
|
||||||
|
|
||||||
|
wlr_buffer_unlock(buffer->buffer);
|
||||||
|
wl_callback_destroy(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_callback_listener release_listener = {
|
||||||
|
.done = handle_buffer_release,
|
||||||
|
};
|
||||||
|
|
||||||
static void presentation_feedback_destroy(
|
static void presentation_feedback_destroy(
|
||||||
struct wlr_wl_presentation_feedback *feedback) {
|
struct wlr_wl_presentation_feedback *feedback) {
|
||||||
wl_list_remove(&feedback->link);
|
wl_list_remove(&feedback->link);
|
||||||
|
|
@ -220,7 +232,10 @@ static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl,
|
||||||
buffer->buffer = wlr_buffer_lock(wlr_buffer);
|
buffer->buffer = wlr_buffer_lock(wlr_buffer);
|
||||||
wl_list_insert(&wl->buffers, &buffer->link);
|
wl_list_insert(&wl->buffers, &buffer->link);
|
||||||
|
|
||||||
wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
|
if (wl_compositor_get_version(wl->compositor) <
|
||||||
|
WL_SURFACE_GET_RELEASE_SINCE_VERSION) {
|
||||||
|
wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
|
buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
|
||||||
wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy);
|
wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy);
|
||||||
|
|
@ -232,10 +247,22 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
|
||||||
struct wlr_buffer *wlr_buffer) {
|
struct wlr_buffer *wlr_buffer) {
|
||||||
struct wlr_wl_buffer *buffer;
|
struct wlr_wl_buffer *buffer;
|
||||||
wl_list_for_each(buffer, &wl->buffers, link) {
|
wl_list_for_each(buffer, &wl->buffers, link) {
|
||||||
|
if (buffer->buffer != wlr_buffer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If wl_surface.get_release is supported, we can use per-commit buffer
|
||||||
|
// release events.
|
||||||
|
if (wl_compositor_get_version(wl->compositor) >=
|
||||||
|
WL_SURFACE_GET_RELEASE_SINCE_VERSION) {
|
||||||
|
wlr_buffer_lock(buffer->buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
// We can only re-use a wlr_wl_buffer if the parent compositor has
|
// 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
|
// released it, because wl_buffer.release is per-wl_buffer, not per
|
||||||
// wl_surface.commit.
|
// wl_surface.commit.
|
||||||
if (buffer->buffer == wlr_buffer && buffer->released) {
|
if (buffer->released) {
|
||||||
buffer->released = false;
|
buffer->released = false;
|
||||||
wlr_buffer_lock(buffer->buffer);
|
wlr_buffer_lock(buffer->buffer);
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
@ -456,6 +483,13 @@ static bool output_commit(struct wlr_output *wlr_output,
|
||||||
|
|
||||||
wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0);
|
wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0);
|
||||||
|
|
||||||
|
if (wl_surface_get_version(output->surface) >=
|
||||||
|
WL_SURFACE_GET_RELEASE_SINCE_VERSION) {
|
||||||
|
struct wl_callback *release_callback =
|
||||||
|
wl_surface_get_release(output->surface);
|
||||||
|
wl_callback_add_listener(release_callback, &release_listener, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ enum wlr_surface_state_field {
|
||||||
WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7,
|
WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7,
|
||||||
WLR_SURFACE_STATE_VIEWPORT = 1 << 8,
|
WLR_SURFACE_STATE_VIEWPORT = 1 << 8,
|
||||||
WLR_SURFACE_STATE_OFFSET = 1 << 9,
|
WLR_SURFACE_STATE_OFFSET = 1 << 9,
|
||||||
|
WLR_SURFACE_STATE_RELEASE_CALLBACK_LIST = 1 << 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_surface_state {
|
struct wlr_surface_state {
|
||||||
|
|
@ -44,6 +45,7 @@ struct wlr_surface_state {
|
||||||
enum wl_output_transform transform;
|
enum wl_output_transform transform;
|
||||||
int32_t scale;
|
int32_t scale;
|
||||||
struct wl_list frame_callback_list; // wl_resource
|
struct wl_list frame_callback_list; // wl_resource
|
||||||
|
struct wl_list release_callback_list; // wl_resource
|
||||||
|
|
||||||
int width, height; // in surface-local coordinates
|
int width, height; // in surface-local coordinates
|
||||||
int buffer_width, buffer_height;
|
int buffer_width, buffer_height;
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ internal_config = configuration_data()
|
||||||
|
|
||||||
wayland_project_options = ['tests=false', 'documentation=false']
|
wayland_project_options = ['tests=false', 'documentation=false']
|
||||||
wayland_server = dependency('wayland-server',
|
wayland_server = dependency('wayland-server',
|
||||||
version: '>=1.21',
|
version: '>=1.21.90',
|
||||||
fallback: 'wayland',
|
fallback: 'wayland',
|
||||||
default_options: wayland_project_options,
|
default_options: wayland_project_options,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
#include "types/wlr_subcompositor.h"
|
#include "types/wlr_subcompositor.h"
|
||||||
#include "util/time.h"
|
#include "util/time.h"
|
||||||
|
|
||||||
#define COMPOSITOR_VERSION 5
|
#define COMPOSITOR_VERSION 6
|
||||||
#define CALLBACK_VERSION 1
|
#define CALLBACK_VERSION 1
|
||||||
|
|
||||||
static int min(int fst, int snd) {
|
static int min(int fst, int snd) {
|
||||||
|
|
@ -338,6 +338,11 @@ static void surface_state_move(struct wlr_surface_state *state,
|
||||||
&next->frame_callback_list);
|
&next->frame_callback_list);
|
||||||
wl_list_init(&next->frame_callback_list);
|
wl_list_init(&next->frame_callback_list);
|
||||||
}
|
}
|
||||||
|
if (next->committed & WLR_SURFACE_STATE_RELEASE_CALLBACK_LIST) {
|
||||||
|
wl_list_insert_list(&state->release_callback_list,
|
||||||
|
&next->release_callback_list);
|
||||||
|
wl_list_init(&next->release_callback_list);
|
||||||
|
}
|
||||||
|
|
||||||
state->committed |= next->committed;
|
state->committed |= next->committed;
|
||||||
next->committed = 0;
|
next->committed = 0;
|
||||||
|
|
@ -413,6 +418,69 @@ static void surface_update_input_region(struct wlr_surface *surface) {
|
||||||
0, 0, surface->current.width, surface->current.height);
|
0, 0, surface->current.width, surface->current.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct buffer_release_callback {
|
||||||
|
struct wl_resource *resource;
|
||||||
|
struct wl_listener buffer_release;
|
||||||
|
struct wl_listener resource_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void buffer_release_callback_handle_buffer_release(
|
||||||
|
struct wl_listener *listener, void *data) {
|
||||||
|
struct buffer_release_callback *callback =
|
||||||
|
wl_container_of(listener, callback, buffer_release);
|
||||||
|
wl_callback_send_done(callback->resource, 0);
|
||||||
|
wl_resource_destroy(callback->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buffer_release_callback_handle_resource_destroy(
|
||||||
|
struct wl_listener *listener, void *data) {
|
||||||
|
struct buffer_release_callback *callback =
|
||||||
|
wl_container_of(listener, callback, resource_destroy);
|
||||||
|
wl_list_remove(&callback->buffer_release.link);
|
||||||
|
free(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct buffer_release_callback *buffer_release_callback_create(
|
||||||
|
struct wlr_buffer *buffer, struct wl_resource *resource) {
|
||||||
|
assert(buffer->n_locks > 0); // ensure we'll get a release signal
|
||||||
|
|
||||||
|
struct buffer_release_callback *callback = calloc(1, sizeof(*callback));
|
||||||
|
if (callback == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback->buffer_release.notify = buffer_release_callback_handle_buffer_release;
|
||||||
|
wl_signal_add(&buffer->events.release, &callback->buffer_release);
|
||||||
|
|
||||||
|
callback->resource_destroy.notify = buffer_release_callback_handle_resource_destroy;
|
||||||
|
wl_resource_add_destroy_listener(resource, &callback->resource_destroy);
|
||||||
|
|
||||||
|
struct wl_list *link = wl_resource_get_link(resource);
|
||||||
|
wl_list_remove(link);
|
||||||
|
wl_list_init(link);
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void surface_update_release_callback_list(struct wlr_surface *surface) {
|
||||||
|
if (surface->buffer == NULL) {
|
||||||
|
wl_resource_post_error(surface->resource, WL_SURFACE_ERROR_NO_ATTACH,
|
||||||
|
"wl_surface.get_release without a buffer attached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_buffer *buffer = &surface->buffer->base;
|
||||||
|
|
||||||
|
struct wl_resource *resource, *tmp;
|
||||||
|
wl_resource_for_each_safe(resource, tmp,
|
||||||
|
&surface->current.release_callback_list) {
|
||||||
|
if (buffer_release_callback_create(buffer, resource) == NULL) {
|
||||||
|
wl_resource_post_no_memory(surface->resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void surface_state_init(struct wlr_surface_state *state);
|
static void surface_state_init(struct wlr_surface_state *state);
|
||||||
|
|
||||||
static void surface_cache_pending(struct wlr_surface *surface) {
|
static void surface_cache_pending(struct wlr_surface *surface) {
|
||||||
|
|
@ -467,6 +535,7 @@ static void surface_commit_state(struct wlr_surface *surface,
|
||||||
}
|
}
|
||||||
surface_update_opaque_region(surface);
|
surface_update_opaque_region(surface);
|
||||||
surface_update_input_region(surface);
|
surface_update_input_region(surface);
|
||||||
|
surface_update_release_callback_list(surface);
|
||||||
|
|
||||||
// commit subsurface order
|
// commit subsurface order
|
||||||
struct wlr_subsurface *subsurface;
|
struct wlr_subsurface *subsurface;
|
||||||
|
|
@ -568,6 +637,25 @@ static void surface_handle_offset(struct wl_client *client,
|
||||||
surface->pending.dy = y;
|
surface->pending.dy = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void surface_handle_get_release(struct wl_client *client,
|
||||||
|
struct wl_resource *resource, uint32_t new_id) {
|
||||||
|
struct wlr_surface *surface = wlr_surface_from_resource(resource);
|
||||||
|
|
||||||
|
struct wl_resource *callback_resource = wl_resource_create(client,
|
||||||
|
&wl_callback_interface, CALLBACK_VERSION, new_id);
|
||||||
|
if (callback_resource == NULL) {
|
||||||
|
wl_resource_post_no_memory(resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(callback_resource, NULL, NULL,
|
||||||
|
callback_handle_resource_destroy);
|
||||||
|
|
||||||
|
wl_list_insert(surface->pending.release_callback_list.prev,
|
||||||
|
wl_resource_get_link(callback_resource));
|
||||||
|
|
||||||
|
surface->pending.committed |= WLR_SURFACE_STATE_RELEASE_CALLBACK_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct wl_surface_interface surface_implementation = {
|
static const struct wl_surface_interface surface_implementation = {
|
||||||
.destroy = surface_handle_destroy,
|
.destroy = surface_handle_destroy,
|
||||||
.attach = surface_handle_attach,
|
.attach = surface_handle_attach,
|
||||||
|
|
@ -580,6 +668,7 @@ static const struct wl_surface_interface surface_implementation = {
|
||||||
.set_buffer_scale = surface_handle_set_buffer_scale,
|
.set_buffer_scale = surface_handle_set_buffer_scale,
|
||||||
.damage_buffer = surface_handle_damage_buffer,
|
.damage_buffer = surface_handle_damage_buffer,
|
||||||
.offset = surface_handle_offset,
|
.offset = surface_handle_offset,
|
||||||
|
.get_release = surface_handle_get_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
|
struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
|
||||||
|
|
@ -598,6 +687,7 @@ static void surface_state_init(struct wlr_surface_state *state) {
|
||||||
wl_list_init(&state->subsurfaces_below);
|
wl_list_init(&state->subsurfaces_below);
|
||||||
|
|
||||||
wl_list_init(&state->frame_callback_list);
|
wl_list_init(&state->frame_callback_list);
|
||||||
|
wl_list_init(&state->release_callback_list);
|
||||||
|
|
||||||
pixman_region32_init(&state->surface_damage);
|
pixman_region32_init(&state->surface_damage);
|
||||||
pixman_region32_init(&state->buffer_damage);
|
pixman_region32_init(&state->buffer_damage);
|
||||||
|
|
@ -614,6 +704,10 @@ static void surface_state_finish(struct wlr_surface_state *state) {
|
||||||
wl_resource_destroy(resource);
|
wl_resource_destroy(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wl_resource_for_each_safe(resource, tmp, &state->release_callback_list) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
pixman_region32_fini(&state->surface_damage);
|
pixman_region32_fini(&state->surface_damage);
|
||||||
pixman_region32_fini(&state->buffer_damage);
|
pixman_region32_fini(&state->buffer_damage);
|
||||||
pixman_region32_fini(&state->opaque);
|
pixman_region32_fini(&state->opaque);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue