diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 5d4b0b618..b5060d3c4 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -13,6 +13,7 @@ #include #include #include +#include struct wlr_buffer; struct wlr_renderer; @@ -21,6 +22,9 @@ struct wlr_texture_impl; struct wlr_texture { const struct wlr_texture_impl *impl; uint32_t width, height; + + struct wlr_raster *raster; + struct wl_list link; }; /** diff --git a/include/wlr/types/wlr_raster.h b/include/wlr/types/wlr_raster.h new file mode 100644 index 000000000..1cc9cabc3 --- /dev/null +++ b/include/wlr/types/wlr_raster.h @@ -0,0 +1,78 @@ +/* + * 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_raster { + // May be NULL + struct wlr_buffer *buffer; + uint32_t width, height; + + struct wl_list sources; // struct wlr_texture + + struct { + struct wl_signal destroy; + } events; + + // private state + + size_t n_locks; +}; + +/** + * Creates a new wlr_raster being backed by the given buffer. + * The creation funciton is referenced: once the creator is done with the raster, + * wlr_raster_unlock must be called. + */ +struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer); + +/** + * Removes and unlocks the buffer assolated with this raster. A raster must be + * created with a buffer so that there is a source of information for textures + * to be created from it, but once there is a texture, that can be used + * as the source of truth and so the buffer can be removed early for other + * purposes. + */ +void wlr_raster_remove_buffer(struct wlr_raster *raster); + +/** + * Lock the raster for use. As long as the raster has at least one lock, it + * will not be destroyed. The raster will be created with a reference count at 1 + * meaning that whatever produced the raster, must call this funciton. + */ +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. + */ +void wlr_raster_unlock(struct wlr_raster *raster); + +/** + * Attaches a wlr_texture to the raster. Consumers of the raster can use the + * given texture for their rendering if needed. The pixel contents of the texture + * must be the same as the source buffer and other textures in the raster. + */ +void wlr_raster_attach(struct wlr_raster *raster, struct wlr_texture *texture); + +/** + * Detaches a wlr_texture from the raster. Once the texture is detached, ownership + * of the texture is given to the caller such that the caller may mutate the + * raster if it wishes. + */ +void wlr_raster_detach(struct wlr_raster *raster, struct wlr_texture *texture); + +#endif diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 7a59af30d..162656c16 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "types/wlr_buffer.h" void wlr_texture_init(struct wlr_texture *texture, @@ -15,7 +16,16 @@ void wlr_texture_init(struct wlr_texture *texture, } void wlr_texture_destroy(struct wlr_texture *texture) { - if (texture && texture->impl && texture->impl->destroy) { + if (!texture) { + return; + } + + if (texture->raster) { + wlr_raster_detach(texture->raster, texture); + texture->raster = NULL; + } + + if (texture->impl && texture->impl->destroy) { texture->impl->destroy(texture); } else { free(texture); diff --git a/types/meson.build b/types/meson.build index 53bf852b8..4b86c00b3 100644 --- a/types/meson.build +++ b/types/meson.build @@ -58,6 +58,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..63ccf9bf4 --- /dev/null +++ b/types/wlr_raster.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include "util/signal.h" + +struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer) { + struct wlr_raster *raster = calloc(1, sizeof(*raster)); + if (!raster) { + return NULL; + } + + wl_list_init(&raster->sources); + wl_signal_init(&raster->events.destroy); + + assert(buffer); + raster->width = buffer->width; + raster->height = buffer->height; + raster->buffer = wlr_buffer_lock(buffer); + + raster->n_locks = 1; + + return raster; +} + +void wlr_raster_remove_buffer(struct wlr_raster *raster) { + assert(raster->buffer); + assert(!wl_list_empty(&raster->sources)); + + wlr_buffer_unlock(raster->buffer); + raster->buffer = NULL; +} + +static void raster_consider_destroy(struct wlr_raster *raster) { + if (raster->n_locks > 0) { + return; + } + + wlr_signal_emit_safe(&raster->events.destroy, NULL); + + struct wlr_texture *texture, *texture_tmp; + wl_list_for_each_safe(texture, texture_tmp, &raster->sources, link) { + wlr_texture_destroy(texture); + } + + wlr_buffer_unlock(raster->buffer); + 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); +} + +void wlr_raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) { + assert(texture); + assert(!texture->raster); + assert(texture->width == raster->width && texture->height == raster->height); + + wl_list_insert(&raster->sources, &texture->link); + texture->raster = raster; +} + +void wlr_raster_detach(struct wlr_raster *raster, struct wlr_texture *texture) { + if (!texture) { + return; + } + + assert(texture->raster == raster); + texture->raster = NULL; + wl_list_remove(&texture->link); +}