diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index 8fd38905e..30c0310c2 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -44,9 +44,11 @@ enum wlr_buffer_cap { * A buffer containing pixel data. * * A buffer has a single producer (the party who created the buffer) and - * multiple consumers (parties reading the buffer). When all consumers are done - * with the buffer, it gets released and can be re-used by the producer. When - * the producer and all consumers are done with the buffer, it gets destroyed. + * multiple consumers (parties reading the buffer). Initially, a buffer is + * released. When the consumer passes the buffer to a consumer, the buffer is + * acquired. When all consumers are done with the buffer, it gets released and + * can be re-used by the producer. When the producer and all consumers are done + * with the buffer, it gets destroyed. */ struct wlr_buffer { const struct wlr_buffer_impl *impl; @@ -70,10 +72,20 @@ struct wlr_buffer { * they are done with the buffer. */ void wlr_buffer_drop(struct wlr_buffer *buffer); +/** + * Acquire the buffer. This function should be called by producers when they + * pass a released buffer to a consumer. The consumer is responsible for + * calling wlr_buffer_unlock() once they are done with the buffer. + * + * This function aborts if the buffer has already been acquired. + */ +struct wlr_buffer *wlr_buffer_acquire(struct wlr_buffer *buffer); /** * Lock the buffer. This function should be called by consumers to make * sure the buffer can be safely read from. Once the consumer is done with the * buffer, they should call wlr_buffer_unlock(). + * + * This function aborts if the buffer hasn't been acquired. */ struct wlr_buffer *wlr_buffer_lock(struct wlr_buffer *buffer); /** diff --git a/render/swapchain.c b/render/swapchain.c index 24d6f1a87..6667a5603 100644 --- a/render/swapchain.c +++ b/render/swapchain.c @@ -76,7 +76,7 @@ static struct wlr_buffer *slot_acquire(struct wlr_swapchain *swapchain, slot->release.notify = slot_handle_release; wl_signal_add(&slot->buffer->events.release, &slot->release); - return wlr_buffer_lock(slot->buffer); + return wlr_buffer_acquire(slot->buffer); } struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain) { diff --git a/types/buffer/buffer.c b/types/buffer/buffer.c index d56255b0d..cd8f68b16 100644 --- a/types/buffer/buffer.c +++ b/types/buffer/buffer.c @@ -52,7 +52,14 @@ void wlr_buffer_drop(struct wlr_buffer *buffer) { buffer_consider_destroy(buffer); } +struct wlr_buffer *wlr_buffer_acquire(struct wlr_buffer *buffer) { + assert(buffer->n_locks == 0); + buffer->n_locks++; + return buffer; +} + struct wlr_buffer *wlr_buffer_lock(struct wlr_buffer *buffer) { + assert(buffer->n_locks > 0); buffer->n_locks++; return buffer; } diff --git a/types/buffer/client.c b/types/buffer/client.c index 5bc670334..76a7f854c 100644 --- a/types/buffer/client.c +++ b/types/buffer/client.c @@ -127,7 +127,7 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer, client_buffer->renderer_destroy.notify = client_buffer_handle_renderer_destroy; // Ensure the buffer will be released before being destroyed - wlr_buffer_lock(&client_buffer->base); + wlr_buffer_acquire(&client_buffer->base); wlr_buffer_drop(&client_buffer->base); return client_buffer; diff --git a/types/buffer/resource.c b/types/buffer/resource.c index 14d8f82d1..fc7d29162 100644 --- a/types/buffer/resource.c +++ b/types/buffer/resource.c @@ -57,5 +57,12 @@ struct wlr_buffer *wlr_buffer_try_from_resource(struct wl_resource *resource) { return NULL; } - return wlr_buffer_lock(buffer); + // If the buffer is released, we want to acquire it. If the buffer is + // already acquired (e.g. because it has been attached to another surface), + // we want to lock it. + if (buffer->n_locks > 0) { + return wlr_buffer_lock(buffer); + } else { + return wlr_buffer_acquire(buffer); + } }