aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_buffer.h67
-rw-r--r--include/wlr/types/wlr_surface.h2
-rw-r--r--types/wlr_buffer.c148
-rw-r--r--types/wlr_surface.c22
4 files changed, 154 insertions, 85 deletions
diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h
index 86f8bccb..b46b69a0 100644
--- a/include/wlr/types/wlr_buffer.h
+++ b/include/wlr/types/wlr_buffer.h
@@ -13,15 +13,53 @@
#include <wayland-server-core.h>
#include <wlr/render/dmabuf.h>
+struct wlr_buffer;
+
+struct wlr_buffer_impl {
+ void (*destroy)(struct wlr_buffer *buffer);
+ bool (*get_dmabuf)(struct wlr_buffer *buffer,
+ struct wlr_dmabuf_attributes *attribs);
+};
+
+struct wlr_buffer {
+ const struct wlr_buffer_impl *impl;
+
+ size_t n_refs;
+};
+
+void wlr_buffer_init(struct wlr_buffer *buffer,
+ const struct wlr_buffer_impl *impl);
+/**
+ * Reference the buffer.
+ */
+struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer);
+/**
+ * Unreference the buffer. After this call, `buffer` may not be accessed
+ * anymore.
+ */
+void wlr_buffer_unref(struct wlr_buffer *buffer);
+/**
+ * Reads the DMA-BUF attributes of the buffer. If this buffer isn't a DMA-BUF,
+ * returns false.
+ */
+bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer,
+ struct wlr_dmabuf_attributes *attribs);
+
/**
* A client buffer.
*/
-struct wlr_buffer {
+struct wlr_client_buffer {
+ struct wlr_buffer base;
+
/**
* The buffer resource, if any. Will be NULL if the client destroys it.
*/
struct wl_resource *resource;
/**
+ * Whether a release event has been sent to the resource.
+ */
+ bool resource_released;
+ /**
* The buffer's texture, if any. A buffer will not have a texture if the
* client destroys the buffer before it has been released.
*/
@@ -41,23 +79,13 @@ bool wlr_resource_is_buffer(struct wl_resource *resource);
/**
* Get the size of a wl_buffer resource.
*/
-bool wlr_buffer_get_resource_size(struct wl_resource *resource,
+bool wlr_resource_get_buffer_size(struct wl_resource *resource,
struct wlr_renderer *renderer, int *width, int *height);
-
/**
* Upload a buffer to the GPU and reference it.
*/
-struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer,
- struct wl_resource *resource);
-/**
- * Reference the buffer.
- */
-struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer);
-/**
- * Unreference the buffer. After this call, `buffer` may not be accessed
- * anymore.
- */
-void wlr_buffer_unref(struct wlr_buffer *buffer);
+struct wlr_client_buffer *wlr_client_buffer_create(
+ struct wlr_renderer *renderer, struct wl_resource *resource);
/**
* Try to update the buffer's content. On success, returns the updated buffer
* and destroys the provided `buffer`. On error, `buffer` is intact and NULL is
@@ -66,13 +94,8 @@ void wlr_buffer_unref(struct wlr_buffer *buffer);
* Fails if there's more than one reference to the buffer or if the texture
* isn't mutable.
*/
-struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer,
- struct wl_resource *resource, pixman_region32_t *damage);
-/**
- * Reads the DMA-BUF attributes of the buffer. If this buffer isn't a DMA-BUF,
- * returns false.
- */
-bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer,
- struct wlr_dmabuf_attributes *attribs);
+struct wlr_client_buffer *wlr_client_buffer_apply_damage(
+ struct wlr_client_buffer *buffer, struct wl_resource *resource,
+ pixman_region32_t *damage);
#endif
diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h
index f62171d1..fa9fa6d5 100644
--- a/include/wlr/types/wlr_surface.h
+++ b/include/wlr/types/wlr_surface.h
@@ -59,7 +59,7 @@ struct wlr_surface {
* have a buffer if it has never committed one, has committed a null buffer,
* or something went wrong with uploading the buffer.
*/
- struct wlr_buffer *buffer;
+ struct wlr_client_buffer *buffer;
/**
* The buffer position, in surface-local units.
*/
diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c
index 1a95bcc2..776d82d4 100644
--- a/types/wlr_buffer.c
+++ b/types/wlr_buffer.c
@@ -5,11 +5,46 @@
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/util/log.h>
+void wlr_buffer_init(struct wlr_buffer *buffer,
+ const struct wlr_buffer_impl *impl) {
+ assert(impl->destroy);
+ buffer->impl = impl;
+ buffer->n_refs = 1;
+}
+
+struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer) {
+ buffer->n_refs++;
+ return buffer;
+}
+
+void wlr_buffer_unref(struct wlr_buffer *buffer) {
+ if (buffer == NULL) {
+ return;
+ }
+
+ assert(buffer->n_refs > 0);
+ buffer->n_refs--;
+ if (buffer->n_refs > 0) {
+ return;
+ }
+
+ buffer->impl->destroy(buffer);
+}
+
+bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer,
+ struct wlr_dmabuf_attributes *attribs) {
+ if (!buffer->impl->get_dmabuf) {
+ return false;
+ }
+ return buffer->impl->get_dmabuf(buffer, attribs);
+}
+
+
bool wlr_resource_is_buffer(struct wl_resource *resource) {
return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0;
}
-bool wlr_buffer_get_resource_size(struct wl_resource *resource,
+bool wlr_resource_get_buffer_size(struct wl_resource *resource,
struct wlr_renderer *renderer, int *width, int *height) {
assert(wlr_resource_is_buffer(resource));
@@ -34,10 +69,54 @@ bool wlr_buffer_get_resource_size(struct wl_resource *resource,
return true;
}
+static const struct wlr_buffer_impl client_buffer_impl;
+
+static struct wlr_client_buffer *client_buffer_from_buffer(
+ struct wlr_buffer *buffer) {
+ assert(buffer->impl == &client_buffer_impl);
+ return (struct wlr_client_buffer *) buffer;
+}
+
+static void client_buffer_destroy(struct wlr_buffer *_buffer) {
+ struct wlr_client_buffer *buffer = client_buffer_from_buffer(_buffer);
+
+ if (!buffer->resource_released && buffer->resource != NULL) {
+ wl_buffer_send_release(buffer->resource);
+ }
+
+ wl_list_remove(&buffer->resource_destroy.link);
+ wlr_texture_destroy(buffer->texture);
+ free(buffer);
+}
-static void buffer_resource_handle_destroy(struct wl_listener *listener,
+static bool client_buffer_get_dmabuf(struct wlr_buffer *_buffer,
+ struct wlr_dmabuf_attributes *attribs) {
+ struct wlr_client_buffer *buffer = client_buffer_from_buffer(_buffer);
+
+ if (buffer->resource == NULL) {
+ return false;
+ }
+
+ struct wl_resource *buffer_resource = buffer->resource;
+ if (!wlr_dmabuf_v1_resource_is_buffer(buffer_resource)) {
+ return false;
+ }
+
+ struct wlr_dmabuf_v1_buffer *dmabuf_buffer =
+ wlr_dmabuf_v1_buffer_from_buffer_resource(buffer_resource);
+ memcpy(attribs, &dmabuf_buffer->attributes,
+ sizeof(struct wlr_dmabuf_attributes));
+ return true;
+}
+
+static const struct wlr_buffer_impl client_buffer_impl = {
+ .destroy = client_buffer_destroy,
+ .get_dmabuf = client_buffer_get_dmabuf,
+};
+
+static void client_buffer_resource_handle_destroy(struct wl_listener *listener,
void *data) {
- struct wlr_buffer *buffer =
+ struct wlr_client_buffer *buffer =
wl_container_of(listener, buffer, resource_destroy);
wl_list_remove(&buffer->resource_destroy.link);
wl_list_init(&buffer->resource_destroy.link);
@@ -51,8 +130,8 @@ static void buffer_resource_handle_destroy(struct wl_listener *listener,
// which case we'll read garbage. We decide to accept this risk.
}
-struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer,
- struct wl_resource *resource) {
+struct wlr_client_buffer *wlr_client_buffer_create(
+ struct wlr_renderer *renderer, struct wl_resource *resource) {
assert(wlr_resource_is_buffer(resource));
struct wlr_texture *texture = NULL;
@@ -100,50 +179,27 @@ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer,
return NULL;
}
- struct wlr_buffer *buffer = calloc(1, sizeof(struct wlr_buffer));
+ struct wlr_client_buffer *buffer =
+ calloc(1, sizeof(struct wlr_client_buffer));
if (buffer == NULL) {
wlr_texture_destroy(texture);
wl_resource_post_no_memory(resource);
return NULL;
}
+ wlr_buffer_init(&buffer->base, &client_buffer_impl);
buffer->resource = resource;
buffer->texture = texture;
- buffer->released = released;
- buffer->n_refs = 1;
+ buffer->resource_released = released;
wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
- buffer->resource_destroy.notify = buffer_resource_handle_destroy;
-
- return buffer;
-}
+ buffer->resource_destroy.notify = client_buffer_resource_handle_destroy;
-struct wlr_buffer *wlr_buffer_ref(struct wlr_buffer *buffer) {
- buffer->n_refs++;
return buffer;
}
-void wlr_buffer_unref(struct wlr_buffer *buffer) {
- if (buffer == NULL) {
- return;
- }
-
- assert(buffer->n_refs > 0);
- buffer->n_refs--;
- if (buffer->n_refs > 0) {
- return;
- }
-
- if (!buffer->released && buffer->resource != NULL) {
- wl_buffer_send_release(buffer->resource);
- }
-
- wl_list_remove(&buffer->resource_destroy.link);
- wlr_texture_destroy(buffer->texture);
- free(buffer);
-}
-
-struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer,
- struct wl_resource *resource, pixman_region32_t *damage) {
+struct wlr_client_buffer *wlr_client_buffer_apply_damage(
+ struct wlr_client_buffer *buffer, struct wl_resource *resource,
+ pixman_region32_t *damage) {
assert(wlr_resource_is_buffer(resource));
if (buffer->n_refs > 1) {
@@ -199,27 +255,9 @@ struct wlr_buffer *wlr_buffer_apply_damage(struct wlr_buffer *buffer,
wl_list_remove(&buffer->resource_destroy.link);
wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
- buffer->resource_destroy.notify = buffer_resource_handle_destroy;
+ buffer->resource_destroy.notify = client_buffer_resource_handle_destroy;
buffer->resource = resource;
buffer->released = true;
return buffer;
}
-
-bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer,
- struct wlr_dmabuf_attributes *attribs) {
- if (buffer->resource == NULL) {
- return false;
- }
-
- struct wl_resource *buffer_resource = buffer->resource;
- if (!wlr_dmabuf_v1_resource_is_buffer(buffer_resource)) {
- return false;
- }
-
- struct wlr_dmabuf_v1_buffer *dmabuf_buffer =
- wlr_dmabuf_v1_buffer_from_buffer_resource(buffer_resource);
- memcpy(attribs, &dmabuf_buffer->attributes,
- sizeof(struct wlr_dmabuf_attributes));
- return true;
-}
diff --git a/types/wlr_surface.c b/types/wlr_surface.c
index f44ec53e..d58f0e32 100644
--- a/types/wlr_surface.c
+++ b/types/wlr_surface.c
@@ -142,7 +142,7 @@ static void surface_state_finalize(struct wlr_surface *surface,
struct wlr_surface_state *state) {
if ((state->committed & WLR_SURFACE_STATE_BUFFER)) {
if (state->buffer_resource != NULL) {
- wlr_buffer_get_resource_size(state->buffer_resource,
+ wlr_resource_get_buffer_size(state->buffer_resource,
surface->renderer, &state->buffer_width, &state->buffer_height);
} else {
state->buffer_width = state->buffer_height = 0;
@@ -282,27 +282,33 @@ static void surface_apply_damage(struct wlr_surface *surface) {
struct wl_resource *resource = surface->current.buffer_resource;
if (resource == NULL) {
// NULL commit
- wlr_buffer_unref(surface->buffer);
+ if (surface->buffer != NULL) {
+ wlr_buffer_unref(&surface->buffer->base);
+ }
surface->buffer = NULL;
return;
}
if (surface->buffer != NULL && surface->buffer->released) {
- struct wlr_buffer *updated_buffer = wlr_buffer_apply_damage(
- surface->buffer, resource, &surface->buffer_damage);
+ struct wlr_client_buffer *updated_buffer =
+ wlr_client_buffer_apply_damage(surface->buffer, resource,
+ &surface->buffer_damage);
if (updated_buffer != NULL) {
surface->buffer = updated_buffer;
return;
}
}
- struct wlr_buffer *buffer = wlr_buffer_create(surface->renderer, resource);
+ struct wlr_client_buffer *buffer =
+ wlr_client_buffer_create(surface->renderer, resource);
if (buffer == NULL) {
wlr_log(WLR_ERROR, "Failed to upload buffer");
return;
}
- wlr_buffer_unref(surface->buffer);
+ if (surface->buffer != NULL) {
+ wlr_buffer_unref(&surface->buffer->base);
+ }
surface->buffer = buffer;
}
@@ -573,7 +579,9 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
pixman_region32_fini(&surface->buffer_damage);
pixman_region32_fini(&surface->opaque_region);
pixman_region32_fini(&surface->input_region);
- wlr_buffer_unref(surface->buffer);
+ if (surface->buffer != NULL) {
+ wlr_buffer_unref(&surface->buffer->base);
+ }
free(surface);
}