start using texture sets

There are really two main uses of texture sets: checking if a dmabuf
is importable, and actually importing it for the client buffer's
texture
This commit is contained in:
Austin Shafer 2022-07-27 12:02:09 -04:00
parent a446e1801f
commit 0925a529ab
6 changed files with 54 additions and 19 deletions

View file

@ -142,7 +142,7 @@ struct wlr_client_buffer {
* 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;
struct wlr_texture_set *texture_set;
/**
* The buffer this client buffer was created from. NULL if destroyed.
*/

View file

@ -63,6 +63,9 @@ struct wlr_linux_dmabuf_v1 {
int main_device_fd; // to sanity check FDs sent by clients, -1 if unavailable
// This is only set when the compositor isn't providing a custom renderer.
struct wlr_renderer *main_renderer;
struct wl_listener display_destroy;
bool (*check_dmabuf_callback)(struct wlr_dmabuf_attributes *attribs, void *data);

View file

@ -25,7 +25,7 @@ static struct wlr_client_buffer *client_buffer_from_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);
wlr_texture_set_destroy(client_buffer->texture_set);
free(client_buffer);
}
@ -56,21 +56,21 @@ static void client_buffer_handle_source_destroy(struct wl_listener *listener,
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) {
struct wlr_texture_set *texture_set = wlr_texture_set_from_buffer(renderer, buffer);
if (texture_set == 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);
wlr_texture_set_destroy(texture_set);
return NULL;
}
wlr_buffer_init(&client_buffer->base, &client_buffer_impl,
texture->width, texture->height);
buffer->width, buffer->height);
client_buffer->source = buffer;
client_buffer->texture = texture;
client_buffer->texture_set = texture_set;
wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy);
client_buffer->source_destroy.notify = client_buffer_handle_source_destroy;
@ -89,5 +89,5 @@ bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer,
return false;
}
return wlr_texture_update_from_buffer(client_buffer->texture, next, damage);
return wlr_texture_set_update_from_buffer(client_buffer->texture_set, next, damage);
}

View file

@ -878,7 +878,8 @@ static struct wlr_texture *scene_buffer_get_texture(
struct wlr_client_buffer *client_buffer =
wlr_client_buffer_get(scene_buffer->buffer);
if (client_buffer != NULL) {
return client_buffer->texture;
return wlr_texture_set_get_tex_for_renderer(client_buffer->texture_set,
renderer);
}
scene_buffer->texture =

View file

@ -445,7 +445,11 @@ static void surface_apply_damage(struct wlr_surface *surface) {
}
static void surface_update_opaque_region(struct wlr_surface *surface) {
if (!wlr_surface_has_buffer(surface)) {
/*
* The surface's client_buffer may not have a texture imported yet,
* but if it has a texture set it is tracking a valid buffer.
*/
if (!wlr_surface_has_buffer(surface) || !surface->buffer->texture_set) {
pixman_region32_clear(&surface->opaque_region);
return;
}
@ -817,7 +821,8 @@ struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) {
if (surface->buffer == NULL) {
return NULL;
}
return surface->buffer->texture;
return wlr_texture_set_get_tex_for_renderer(surface->buffer->texture_set,
surface->renderer);
}
bool wlr_surface_has_buffer(struct wlr_surface *surface) {

View file

@ -211,16 +211,39 @@ static bool check_import_dmabuf(struct wlr_dmabuf_attributes *attribs, void *dat
return true;
}
// TODO: check number of planes
for (int i = 0; i < attribs->n_planes; i++) {
uint32_t handle = 0;
if (drmPrimeFDToHandle(linux_dmabuf->main_device_fd, attribs->fd[i], &handle) != 0) {
wlr_log_errno(WLR_DEBUG, "Failed to import DMA-BUF FD");
/*
* Some compositors will be using this linux dmabuf manager with custom renderers,
* while others will use a wlroots-managed wlr_renderer. When checking if a dmabuf
* is valid for import we should treat these differently. In the first case we just
* need to check if the dmabuf is importable into the DRM device, in the wlroots-managed
* renderer case we should check if this dmabuf can be imported into the renderer.
*
* In the case where we have a wlr_renderer we need to check if a texture set can
* be created in order to handle multi-gpu systems. The texture set will handle ensuring
* that the dmabuf is importable on one GPU in the system, instead of only checking
* the main device.
*/
if (linux_dmabuf->main_renderer) {
struct wlr_texture_set *set=
wlr_texture_set_from_dmabuf(linux_dmabuf->main_renderer, attribs);
if (!set) {
return false;
}
if (drmCloseBufferHandle(linux_dmabuf->main_device_fd, handle) != 0) {
wlr_log_errno(WLR_ERROR, "Failed to close buffer handle");
return false;
// We can import the image, good. No need to keep it since wlr_surface will
// import it again on commit.
wlr_texture_set_destroy(set);
} else {
// TODO: check number of planes
for (int i = 0; i < attribs->n_planes; i++) {
uint32_t handle = 0;
if (drmPrimeFDToHandle(linux_dmabuf->main_device_fd, attribs->fd[i], &handle) != 0) {
wlr_log_errno(WLR_DEBUG, "Failed to import DMA-BUF FD");
return false;
}
if (drmCloseBufferHandle(linux_dmabuf->main_device_fd, handle) != 0) {
wlr_log_errno(WLR_ERROR, "Failed to close buffer handle");
return false;
}
}
}
return true;
@ -1001,6 +1024,9 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create_with_renderer(struct wl_d
struct wlr_linux_dmabuf_v1 *linux_dmabuf =
wlr_linux_dmabuf_v1_create(display, version, &feedback);
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
linux_dmabuf->main_renderer = renderer;
return linux_dmabuf;
}