1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
#include <assert.h>
#include <stdlib.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/util/log.h>
#include "types/wlr_buffer.h"
static const struct wlr_buffer_impl client_buffer_impl;
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *wlr_buffer) {
if (wlr_buffer->impl != &client_buffer_impl) {
return NULL;
}
struct wlr_client_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
return buffer;
}
static struct wlr_client_buffer *client_buffer_from_buffer(
struct wlr_buffer *buffer) {
struct wlr_client_buffer *client_buffer = wlr_client_buffer_get(buffer);
assert(client_buffer != NULL);
return client_buffer;
}
static void client_buffer_destroy(struct wlr_buffer *buffer) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
wlr_buffer_finish(buffer);
wl_list_remove(&client_buffer->source_destroy.link);
wl_list_remove(&client_buffer->renderer_destroy.link);
wlr_texture_destroy(client_buffer->texture);
free(client_buffer);
}
static bool client_buffer_get_dmabuf(struct wlr_buffer *buffer,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
if (client_buffer->source == NULL) {
return false;
}
return wlr_buffer_get_dmabuf(client_buffer->source, attribs);
}
static bool client_buffer_get_shm(struct wlr_buffer *buffer,
struct wlr_shm_attributes *attribs) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
if (client_buffer->source == NULL) {
return false;
}
return wlr_buffer_get_shm(client_buffer->source, attribs);
}
static bool client_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
void **data, uint32_t *format, size_t *stride) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
if (client_buffer->source == NULL) {
return false;
}
return wlr_buffer_begin_data_ptr_access(client_buffer->source, flags, data, format, stride);
}
static void client_buffer_end_data_ptr_access(struct wlr_buffer *buffer) {
struct wlr_client_buffer *client_buffer = client_buffer_from_buffer(buffer);
if (client_buffer->source == NULL) {
return;
}
wlr_buffer_end_data_ptr_access(client_buffer->source);
}
static const struct wlr_buffer_impl client_buffer_impl = {
.destroy = client_buffer_destroy,
.get_dmabuf = client_buffer_get_dmabuf,
.get_shm = client_buffer_get_shm,
.begin_data_ptr_access = client_buffer_begin_data_ptr_access,
.end_data_ptr_access = client_buffer_end_data_ptr_access,
};
static void client_buffer_handle_source_destroy(struct wl_listener *listener,
void *data) {
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 void client_buffer_handle_renderer_destroy(struct wl_listener *listener,
void *data) {
struct wlr_client_buffer *client_buffer =
wl_container_of(listener, client_buffer, renderer_destroy);
wl_list_remove(&client_buffer->renderer_destroy.link);
wl_list_init(&client_buffer->renderer_destroy.link);
client_buffer->texture = NULL;
}
struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
struct wlr_renderer *renderer) {
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, buffer);
if (texture == NULL) {
wlr_log(WLR_ERROR, "Failed to create texture");
return NULL;
}
struct wlr_client_buffer *client_buffer = calloc(1, sizeof(*client_buffer));
if (client_buffer == NULL) {
wlr_texture_destroy(texture);
return NULL;
}
wlr_buffer_init(&client_buffer->base, &client_buffer_impl,
texture->width, texture->height);
client_buffer->source = buffer;
client_buffer->texture = texture;
wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy);
client_buffer->source_destroy.notify = client_buffer_handle_source_destroy;
wl_signal_add(&texture->renderer->events.destroy, &client_buffer->renderer_destroy);
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_drop(&client_buffer->base);
return client_buffer;
}
bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer,
struct wlr_buffer *next, const pixman_region32_t *damage) {
if (client_buffer->base.n_locks - client_buffer->n_ignore_locks > 1) {
// Someone else still has a reference to the buffer
return false;
}
if (client_buffer->texture == NULL) {
return false;
}
return wlr_texture_update_from_buffer(client_buffer->texture, next, damage);
}
|