From 057fd1a0e3b5b9a714d567679939beb862340ce1 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 14 Sep 2024 17:42:40 -0400 Subject: [PATCH] wlr_raster: Introduce new abstraction --- include/wlr/types/wlr_raster.h | 86 +++++++++++++++++++++++ types/meson.build | 1 + types/wlr_raster.c | 122 +++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 include/wlr/types/wlr_raster.h create mode 100644 types/wlr_raster.c diff --git a/include/wlr/types/wlr_raster.h b/include/wlr/types/wlr_raster.h new file mode 100644 index 000000000..c63cb8ee0 --- /dev/null +++ b/include/wlr/types/wlr_raster.h @@ -0,0 +1,86 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_RASTER_H +#define WLR_TYPES_WLR_RASTER_H + +#include +#include +#include + +struct wlr_buffer; +struct wlr_texture; +struct wlr_renderer; +struct wlr_drm_syncobj_timeline; + +struct wlr_raster { + // May be NULL + struct wlr_buffer *buffer; + + uint32_t width, height; + bool opaque; + + struct wlr_drm_syncobj_timeline *wait_timeline; + uint64_t wait_point; + + struct { + struct wl_signal destroy; + } events; + + // private state + + size_t n_locks; + + struct wl_listener buffer_release; + + struct wlr_texture *texture; + struct wl_listener renderer_destroy; +}; + +struct wlr_raster_create_options { + struct wlr_drm_syncobj_timeline *wait_timeline; + uint64_t wait_point; +}; + +/** + * Creates a new wlr_raster being backed by the given buffer. The raster will + * not lock the given buffer meaning that once it's released, the raster will + * NULL its buffer reference and potentially become invalid. + * The creation function is referenced: once the creator is done with the raster, + * wlr_raster_unlock must be called as the reference count will start at 1 + * from creation. + * + * Options can be NULL. + */ +struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer, + const struct wlr_raster_create_options *options); + +/** + * Lock the raster for use. As long as the raster has at least one lock, it + * will not be destroyed. + */ +struct wlr_raster *wlr_raster_lock(struct wlr_raster *raster); + +/** + * Unlock the raster. This must be called after wlr_raster_lock once the raster + * has been finished being used or after creation from wlr_raster_create. + */ +void wlr_raster_unlock(struct wlr_raster *raster); + +/** + * Returns the texture allocated for this renderer. If there is none, + * a new texture will be created and attached to this wlr_raster. Users do not + * own the texture returned by this function and can only be used for read-only + * purposes. + * + * Will return NULL if the creation was unsuccessful. + */ +struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster, + struct wlr_renderer *renderer); + +#endif diff --git a/types/meson.build b/types/meson.build index ec70d4b7c..032143db6 100644 --- a/types/meson.build +++ b/types/meson.build @@ -68,6 +68,7 @@ wlr_files += files( 'wlr_presentation_time.c', 'wlr_primary_selection_v1.c', 'wlr_primary_selection.c', + 'wlr_raster.c', 'wlr_region.c', 'wlr_relative_pointer_v1.c', 'wlr_screencopy_v1.c', diff --git a/types/wlr_raster.c b/types/wlr_raster.c new file mode 100644 index 000000000..c1ce68438 --- /dev/null +++ b/types/wlr_raster.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include "types/wlr_buffer.h" + +static void raster_handle_buffer_release(struct wl_listener *listener, void *data) { + struct wlr_raster *raster = wl_container_of(listener, raster, buffer_release); + raster->buffer = NULL; + wl_list_remove(&raster->buffer_release.link); + wl_list_init(&raster->buffer_release.link); +} + +struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer, + const struct wlr_raster_create_options *options) { + struct wlr_raster *raster = calloc(1, sizeof(*raster)); + if (!raster) { + return NULL; + } + + wl_signal_init(&raster->events.destroy); + + assert(buffer); + raster->opaque = buffer_is_opaque(buffer); + raster->width = buffer->width; + raster->height = buffer->height; + raster->buffer = buffer; + + raster->n_locks = 1; + + raster->buffer_release.notify = raster_handle_buffer_release; + wl_signal_add(&raster->buffer->events.release, &raster->buffer_release); + + if (options && options->wait_timeline) { + raster->wait_timeline = wlr_drm_syncobj_timeline_ref(options->wait_timeline); + raster->wait_point = options->wait_point; + } + + return raster; +} + +static void raster_consider_destroy(struct wlr_raster *raster) { + if (raster->n_locks > 0) { + return; + } + + wl_signal_emit_mutable(&raster->events.destroy, NULL); + + if (raster->texture) { + wl_list_remove(&raster->renderer_destroy.link); + wlr_texture_destroy(raster->texture); + } + + wl_list_remove(&raster->buffer_release.link); + wlr_drm_syncobj_timeline_unref(raster->wait_timeline); + free(raster); +} + +struct wlr_raster *wlr_raster_lock(struct wlr_raster *raster) { + raster->n_locks++; + return raster; +} + +void wlr_raster_unlock(struct wlr_raster *raster) { + if (!raster) { + return; + } + + assert(raster->n_locks > 0); + + raster->n_locks--; + raster_consider_destroy(raster); +} + +static void raster_detach(struct wlr_raster *raster, struct wlr_texture *texture) { + assert(texture); + assert(raster->texture == texture); + + wl_list_remove(&raster->renderer_destroy.link); + raster->texture = NULL; +} + +static void handle_renderer_destroy(struct wl_listener *listener, void *data) { + struct wlr_raster *raster = wl_container_of(listener, raster, renderer_destroy); + raster_detach(raster, raster->texture); +} + +static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) { + assert(texture->width == raster->width && texture->height == raster->height); + assert(!raster->texture); + + raster->renderer_destroy.notify = handle_renderer_destroy; + wl_signal_add(&texture->renderer->events.destroy, &raster->renderer_destroy); + + raster->texture = texture; +} + +struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster, + struct wlr_renderer *renderer) { + if (raster->texture) { + assert(raster->texture->renderer == renderer); + return raster->texture; + } + + assert(raster->buffer); + + struct wlr_client_buffer *client_buffer = + wlr_client_buffer_get(raster->buffer); + if (client_buffer != NULL) { + return client_buffer->texture; + } + + struct wlr_texture *texture = wlr_texture_from_buffer(renderer, raster->buffer); + if (texture) { + raster_attach(raster, texture); + } + + return texture; +}