Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

buffer: drop wlr_client_buffer.resource #3039

Merged
merged 5 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions include/wlr/types/wlr_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,22 @@ struct wlr_buffer *wlr_buffer_from_resource(struct wlr_renderer *renderer,
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;
/**
* The buffer's texture, if any. A buffer will not have a texture if the
* client destroys the buffer before it has been released.
*/
struct wlr_texture *texture;
/**
* The buffer this client buffer was created from. NULL if destroyed.
*/
struct wlr_buffer *source;

// private state

struct wl_listener source_destroy;

struct wl_listener resource_destroy;
// If the client buffer has been created from a wl_shm buffer
uint32_t shm_source_format;
};

/**
Expand Down
98 changes: 47 additions & 51 deletions types/wlr_buffer.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <assert.h>
#include <drm_fourcc.h>
#include <stdlib.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
Expand Down Expand Up @@ -120,54 +121,42 @@ static struct wlr_client_buffer *client_buffer_from_buffer(
return client_buffer;
}

static void client_buffer_destroy(struct wlr_buffer *_buffer) {
struct wlr_client_buffer *buffer = client_buffer_from_buffer(_buffer);
wl_list_remove(&buffer->resource_destroy.link);
wlr_texture_destroy(buffer->texture);
free(buffer);
static void client_buffer_destroy(struct wlr_buffer *buffer) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
wl_list_remove(&client_buffer->source_destroy.link);
wlr_texture_destroy(client_buffer->texture);
free(client_buffer);
}

static bool client_buffer_get_dmabuf(struct wlr_buffer *_buffer,
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);
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);

if (buffer->resource == NULL) {
if (client_buffer->source == 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;
return wlr_buffer_get_dmabuf(client_buffer->source, attribs);
}

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,
static void client_buffer_handle_source_destroy(struct wl_listener *listener,
void *data) {
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);
buffer->resource = NULL;

// At this point, if the wl_buffer comes from linux-dmabuf or wl_drm, we
// still haven't released it (ie. we'll read it in the future) but the
// client destroyed it. Reading the texture itself should be fine because
// we still hold a reference to the DMA-BUF via the texture. However the
// client could decide to re-use the same DMA-BUF for something else, in
// which case we'll read garbage. We decide to accept this risk.
struct wlr_client_buffer *client_buffer =
wl_container_of(listener, client_buffer, source_destroy);
wl_list_remove(&client_buffer->source_destroy.link);
wl_list_init(&client_buffer->source_destroy.link);
client_buffer->source = NULL;
}

static bool buffer_is_shm_client_buffer(struct wlr_buffer *buffer);
static struct wlr_shm_client_buffer *shm_client_buffer_from_buffer(
struct wlr_buffer *buffer);

struct wlr_buffer *wlr_buffer_from_resource(struct wlr_renderer *renderer,
struct wl_resource *resource) {
assert(resource && wlr_resource_is_buffer(resource));
Expand Down Expand Up @@ -218,11 +207,19 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
}
wlr_buffer_init(&client_buffer->base, &client_buffer_impl,
texture->width, texture->height);
client_buffer->resource = resource;
client_buffer->source = buffer;
client_buffer->texture = texture;

wl_resource_add_destroy_listener(resource, &client_buffer->resource_destroy);
client_buffer->resource_destroy.notify = client_buffer_resource_handle_destroy;
wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy);
client_buffer->source_destroy.notify = client_buffer_handle_source_destroy;

if (buffer_is_shm_client_buffer(buffer)) {
struct wlr_shm_client_buffer *shm_client_buffer =
shm_client_buffer_from_buffer(buffer);
client_buffer->shm_source_format = shm_client_buffer->format;
} else {
client_buffer->shm_source_format = DRM_FORMAT_INVALID;
}

// Ensure the buffer will be released before being destroyed
wlr_buffer_lock(&client_buffer->base);
Expand All @@ -232,26 +229,26 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
}

struct wlr_client_buffer *wlr_client_buffer_apply_damage(
struct wlr_client_buffer *buffer, struct wl_resource *resource,
struct wlr_client_buffer *client_buffer, struct wl_resource *resource,
pixman_region32_t *damage) {
assert(wlr_resource_is_buffer(resource));

if (buffer->base.n_locks > 1) {
if (client_buffer->base.n_locks > 1) {
// Someone else still has a reference to the buffer
return NULL;
}

struct wl_shm_buffer *shm_buf = wl_shm_buffer_get(resource);
struct wl_shm_buffer *old_shm_buf = wl_shm_buffer_get(buffer->resource);
if (shm_buf == NULL || old_shm_buf == NULL) {
if (shm_buf == NULL ||
client_buffer->shm_source_format == DRM_FORMAT_INVALID) {
// Uploading only damaged regions only works for wl_shm buffers and
// mutable textures (created from wl_shm buffer)
return NULL;
}

enum wl_shm_format new_fmt = wl_shm_buffer_get_format(shm_buf);
enum wl_shm_format old_fmt = wl_shm_buffer_get_format(old_shm_buf);
if (new_fmt != old_fmt) {
enum wl_shm_format new_shm_fmt = wl_shm_buffer_get_format(shm_buf);
if (convert_wl_shm_format_to_drm(new_shm_fmt) !=
client_buffer->shm_source_format) {
// Uploading to textures can't change the format
return NULL;
}
Expand All @@ -260,8 +257,8 @@ struct wlr_client_buffer *wlr_client_buffer_apply_damage(
int32_t width = wl_shm_buffer_get_width(shm_buf);
int32_t height = wl_shm_buffer_get_height(shm_buf);

if ((uint32_t)width != buffer->texture->width ||
(uint32_t)height != buffer->texture->height) {
if ((uint32_t)width != client_buffer->texture->width ||
(uint32_t)height != client_buffer->texture->height) {
return NULL;
}

Expand All @@ -272,7 +269,7 @@ struct wlr_client_buffer *wlr_client_buffer_apply_damage(
pixman_box32_t *rects = pixman_region32_rectangles(damage, &n);
for (int i = 0; i < n; ++i) {
pixman_box32_t *r = &rects[i];
if (!wlr_texture_write_pixels(buffer->texture, stride,
if (!wlr_texture_write_pixels(client_buffer->texture, stride,
r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
r->x1, r->y1, data)) {
wl_shm_buffer_end_access(shm_buf);
Expand All @@ -282,19 +279,18 @@ struct wlr_client_buffer *wlr_client_buffer_apply_damage(

wl_shm_buffer_end_access(shm_buf);

wl_list_remove(&buffer->resource_destroy.link);
wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
buffer->resource_destroy.notify = client_buffer_resource_handle_destroy;

buffer->resource = resource;
return buffer;
return client_buffer;
}

static const struct wlr_buffer_impl shm_client_buffer_impl;

static bool buffer_is_shm_client_buffer(struct wlr_buffer *buffer) {
return buffer->impl == &shm_client_buffer_impl;
}

static struct wlr_shm_client_buffer *shm_client_buffer_from_buffer(
struct wlr_buffer *buffer) {
assert(buffer->impl == &shm_client_buffer_impl);
assert(buffer_is_shm_client_buffer(buffer));
return (struct wlr_shm_client_buffer *)buffer;
}

Expand Down