diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index de3aeec3d..95d5aa51e 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -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. */ diff --git a/include/wlr/types/wlr_linux_dmabuf_v1.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index cf967f952..92106314f 100644 --- a/include/wlr/types/wlr_linux_dmabuf_v1.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -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); diff --git a/types/buffer/client.c b/types/buffer/client.c index 4cfa57a89..68a233d59 100644 --- a/types/buffer/client.c +++ b/types/buffer/client.c @@ -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); } diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 7e5b31363..f5b992689 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -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 = diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 791eb77cb..57ca4bfa4 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -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) { diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 13e82760c..6c399ba2b 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -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; }