aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/types/wlr_buffer.h28
-rw-r--r--types/wlr_buffer.c77
2 files changed, 105 insertions, 0 deletions
diff --git a/include/types/wlr_buffer.h b/include/types/wlr_buffer.h
index 8abb68d6..85a8d8b4 100644
--- a/include/types/wlr_buffer.h
+++ b/include/types/wlr_buffer.h
@@ -26,6 +26,34 @@ struct wlr_shm_client_buffer *shm_client_buffer_create(
struct wl_resource *resource);
/**
+ * A read-only buffer that holds a data pointer.
+ *
+ * This is suitable for passing raw pixel data to a function that accepts a
+ * wlr_buffer.
+ */
+struct wlr_readonly_data_buffer {
+ struct wlr_buffer base;
+
+ const void *data;
+ uint32_t format;
+ size_t stride;
+
+ void *saved_data;
+};
+
+/**
+ * Wraps a read-only data pointer into a wlr_buffer. The data pointer may be
+ * accessed until readonly_data_buffer_drop() is called.
+ */
+struct wlr_readonly_data_buffer *readonly_data_buffer_create(uint32_t format,
+ size_t stride, uint32_t width, uint32_t height, const void *data);
+/**
+ * Drops ownership of the buffer (see wlr_buffer_drop() for more details) and
+ * perform a copy of the data pointer if a consumer still has the buffer locked.
+ */
+bool readonly_data_buffer_drop(struct wlr_readonly_data_buffer *buffer);
+
+/**
* Buffer capabilities.
*
* These bits indicate the features supported by a wlr_buffer. There is one bit
diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c
index 147205b9..ca5c743c 100644
--- a/types/wlr_buffer.c
+++ b/types/wlr_buffer.c
@@ -451,3 +451,80 @@ struct wlr_shm_client_buffer *shm_client_buffer_create(
return buffer;
}
+
+static const struct wlr_buffer_impl readonly_data_buffer_impl;
+
+static struct wlr_readonly_data_buffer *readonly_data_buffer_from_buffer(
+ struct wlr_buffer *buffer) {
+ assert(buffer->impl == &readonly_data_buffer_impl);
+ return (struct wlr_readonly_data_buffer *)buffer;
+}
+
+static void readonly_data_buffer_destroy(struct wlr_buffer *wlr_buffer) {
+ struct wlr_readonly_data_buffer *buffer =
+ readonly_data_buffer_from_buffer(wlr_buffer);
+ free(buffer->saved_data);
+ free(buffer);
+}
+
+static bool readonly_data_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
+ void **data, uint32_t *format, size_t *stride) {
+ struct wlr_readonly_data_buffer *buffer =
+ readonly_data_buffer_from_buffer(wlr_buffer);
+ if (buffer->data == NULL) {
+ return false;
+ }
+ *data = (void*)buffer->data;
+ *format = buffer->format;
+ *stride = buffer->stride;
+ return true;
+}
+
+static void readonly_data_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
+ // This space is intentionally left blank
+}
+
+static const struct wlr_buffer_impl readonly_data_buffer_impl = {
+ .destroy = readonly_data_buffer_destroy,
+ .begin_data_ptr_access = readonly_data_buffer_begin_data_ptr_access,
+ .end_data_ptr_access = readonly_data_buffer_end_data_ptr_access,
+};
+
+struct wlr_readonly_data_buffer *readonly_data_buffer_create(uint32_t format,
+ size_t stride, uint32_t width, uint32_t height, const void *data) {
+ struct wlr_readonly_data_buffer *buffer = calloc(1, sizeof(*buffer));
+ if (buffer == NULL) {
+ return NULL;
+ }
+ wlr_buffer_init(&buffer->base, &readonly_data_buffer_impl, width, height);
+
+ buffer->data = data;
+ buffer->format = format;
+ buffer->stride = stride;
+
+ return buffer;
+}
+
+bool readonly_data_buffer_drop(struct wlr_readonly_data_buffer *buffer) {
+ bool ok = true;
+
+ if (buffer->base.n_locks > 0) {
+ size_t size = buffer->stride * buffer->base.height;
+ buffer->saved_data = malloc(size);
+ if (buffer->saved_data == NULL) {
+ wlr_log_errno(WLR_ERROR, "Allocation failed");
+ ok = false;
+ buffer->data = NULL;
+ // We can't destroy the buffer, or we risk use-after-free in the
+ // consumers. We can't allow accesses to buffer->data anymore, so
+ // set it to NULL and make subsequent begin_data_ptr_access()
+ // calls fail.
+ } else {
+ memcpy(buffer->saved_data, buffer->data, size);
+ buffer->data = buffer->saved_data;
+ }
+ }
+
+ wlr_buffer_drop(&buffer->base);
+ return ok;
+}