linux_dmabuf_v1: Introduce main device

Introduce properties for the main renderer and allocator the compositor
wants wlroots to use when it needs to blit to a staging buffer during
multigpu. We need to perform an additional blit if the modifier is not
compatible with the target GPU.
This commit is contained in:
Alexander Orzechowski 2024-02-02 20:38:56 -05:00
parent 5eb9a2ea10
commit b0e8e6eae7
3 changed files with 107 additions and 5 deletions

View file

@ -17,6 +17,8 @@
#include <wlr/render/drm_format_set.h> #include <wlr/render/drm_format_set.h>
struct wlr_surface; struct wlr_surface;
struct wlr_renderer;
struct wlr_allocator;
struct wlr_dmabuf_v1_buffer { struct wlr_dmabuf_v1_buffer {
struct wlr_buffer base; struct wlr_buffer base;
@ -27,6 +29,8 @@ struct wlr_dmabuf_v1_buffer {
// private state // private state
struct wl_listener release; struct wl_listener release;
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
}; };
/** /**
@ -63,7 +67,13 @@ struct wlr_linux_dmabuf_v1 {
int main_device_fd; // to sanity check FDs sent by clients, -1 if unavailable int main_device_fd; // to sanity check FDs sent by clients, -1 if unavailable
// used for multigpu
struct wlr_renderer *main_renderer;
struct wlr_allocator *main_allocator;
struct wl_listener display_destroy; struct wl_listener display_destroy;
struct wl_listener main_renderer_destroy;
struct wl_listener main_allocator_destroy;
bool (*check_dmabuf_callback)(struct wlr_dmabuf_attributes *attribs, void *data); bool (*check_dmabuf_callback)(struct wlr_dmabuf_attributes *attribs, void *data);
void *check_dmabuf_callback_data; void *check_dmabuf_callback_data;
@ -78,6 +88,23 @@ struct wlr_linux_dmabuf_v1 {
struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display, struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display,
uint32_t version, const struct wlr_linux_dmabuf_feedback_v1 *default_feedback); uint32_t version, const struct wlr_linux_dmabuf_feedback_v1 *default_feedback);
/**
* Returns the associated dmabuf object from a generic buffer. Returnns
* NULL if the generic buffer is not a dmabuf.
*/
struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_try_from_buffer(
struct wlr_buffer *buffer);
/**
* Sets the main blit device used for multigpu. With multigpu, dmabufs with
* implicit modifiers or just modifiers that aren't supported by other GPUs
* might need to be blitted into a staging buffer with correct modifiers. This
* will be done with this allocator (to allocate the staging buffer) and renderer
* to render into the staging buffer.
*/
void wlr_linux_dmabuf_v1_set_main_blit_device(struct wlr_linux_dmabuf_v1 *linux_dmabuf,
struct wlr_renderer *renderer, struct wlr_allocator *allocator);
/** /**
* Create the linux-dmabuf-v1 global. * Create the linux-dmabuf-v1 global.
* *
@ -120,6 +147,9 @@ void wlr_linux_dmabuf_feedback_v1_finish(struct wlr_linux_dmabuf_feedback_v1 *fe
struct wlr_linux_dmabuf_feedback_v1_init_options { struct wlr_linux_dmabuf_feedback_v1_init_options {
// Main renderer used by the compositor // Main renderer used by the compositor
struct wlr_renderer *main_renderer; struct wlr_renderer *main_renderer;
// Optional allocator created for the primary GPU used by the default feedback.
// This is used for multi gpu for allocating staging buffers.
struct wlr_allocator *main_allocator;
// Output on which direct scan-out is possible on the primary plane, or NULL // Output on which direct scan-out is possible on the primary plane, or NULL
struct wlr_output *scanout_primary_output; struct wlr_output *scanout_primary_output;
// Output layer feedback event, or NULL // Output layer feedback event, or NULL

View file

@ -7,6 +7,7 @@
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/config.h> #include <wlr/config.h>
#include <wlr/interfaces/wlr_buffer.h> #include <wlr/interfaces/wlr_buffer.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_linux_dmabuf_v1.h>
@ -92,16 +93,19 @@ struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_try_from_buffer_resource(
static const struct wlr_buffer_impl buffer_impl; static const struct wlr_buffer_impl buffer_impl;
static struct wlr_dmabuf_v1_buffer *dmabuf_v1_buffer_from_buffer( struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_try_from_buffer(
struct wlr_buffer *wlr_buffer) { struct wlr_buffer *wlr_buffer) {
assert(wlr_buffer->impl == &buffer_impl); if (wlr_buffer->impl != &buffer_impl) {
return NULL;
}
struct wlr_dmabuf_v1_buffer *buffer = wl_container_of(wlr_buffer, buffer, base); struct wlr_dmabuf_v1_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
return buffer; return buffer;
} }
static void buffer_destroy(struct wlr_buffer *wlr_buffer) { static void buffer_destroy(struct wlr_buffer *wlr_buffer) {
struct wlr_dmabuf_v1_buffer *buffer = struct wlr_dmabuf_v1_buffer *buffer =
dmabuf_v1_buffer_from_buffer(wlr_buffer); wlr_dmabuf_v1_buffer_try_from_buffer(wlr_buffer);
if (buffer->resource != NULL) { if (buffer->resource != NULL) {
wl_resource_set_user_data(buffer->resource, NULL); wl_resource_set_user_data(buffer->resource, NULL);
} }
@ -113,7 +117,7 @@ static void buffer_destroy(struct wlr_buffer *wlr_buffer) {
static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer,
struct wlr_dmabuf_attributes *attribs) { struct wlr_dmabuf_attributes *attribs) {
struct wlr_dmabuf_v1_buffer *buffer = struct wlr_dmabuf_v1_buffer *buffer =
dmabuf_v1_buffer_from_buffer(wlr_buffer); wlr_dmabuf_v1_buffer_try_from_buffer(wlr_buffer);
*attribs = buffer->attributes; *attribs = buffer->attributes;
return true; return true;
} }
@ -368,6 +372,7 @@ static void params_create_common(struct wl_resource *params_resource,
&wl_buffer_impl, buffer, buffer_handle_resource_destroy); &wl_buffer_impl, buffer, buffer_handle_resource_destroy);
buffer->attributes = attribs; buffer->attributes = attribs;
buffer->linux_dmabuf_v1 = linux_dmabuf;
buffer->release.notify = buffer_handle_release; buffer->release.notify = buffer_handle_release;
wl_signal_add(&buffer->base.events.release, &buffer->release); wl_signal_add(&buffer->base.events.release, &buffer->release);
@ -872,6 +877,8 @@ static void linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf) {
} }
wl_list_remove(&linux_dmabuf->display_destroy.link); wl_list_remove(&linux_dmabuf->display_destroy.link);
wl_list_remove(&linux_dmabuf->main_renderer_destroy.link);
wl_list_remove(&linux_dmabuf->main_allocator_destroy.link);
wl_global_destroy(linux_dmabuf->global); wl_global_destroy(linux_dmabuf->global);
free(linux_dmabuf); free(linux_dmabuf);
@ -959,6 +966,8 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *displa
linux_dmabuf->main_device_fd = -1; linux_dmabuf->main_device_fd = -1;
wl_list_init(&linux_dmabuf->surfaces); wl_list_init(&linux_dmabuf->surfaces);
wl_list_init(&linux_dmabuf->main_renderer_destroy.link);
wl_list_init(&linux_dmabuf->main_allocator_destroy.link);
wl_signal_init(&linux_dmabuf->events.destroy); wl_signal_init(&linux_dmabuf->events.destroy);
linux_dmabuf->global = wl_global_create(display, &zwp_linux_dmabuf_v1_interface, linux_dmabuf->global = wl_global_create(display, &zwp_linux_dmabuf_v1_interface,
@ -1161,3 +1170,42 @@ error:
wlr_linux_dmabuf_feedback_v1_finish(feedback); wlr_linux_dmabuf_feedback_v1_finish(feedback);
return false; return false;
} }
static void linux_dmabuf_unregister_main_blit_device(struct wlr_linux_dmabuf_v1 *linux_dmabuf) {
wl_list_remove(&linux_dmabuf->main_renderer_destroy.link);
wl_list_remove(&linux_dmabuf->main_allocator_destroy.link);
wl_list_init(&linux_dmabuf->main_renderer_destroy.link);
wl_list_init(&linux_dmabuf->main_allocator_destroy.link);
linux_dmabuf->main_renderer = NULL;
linux_dmabuf->main_allocator = NULL;
}
static void linux_dmabuf_handle_main_renderer_destroy(struct wl_listener *listener, void *data) {
struct wlr_linux_dmabuf_v1 *linux_dmabuf = wl_container_of(
listener, linux_dmabuf, main_renderer_destroy);
linux_dmabuf_unregister_main_blit_device(linux_dmabuf);
}
static void linux_dmabuf_handle_main_allocator_destroy(struct wl_listener *listener, void *data) {
struct wlr_linux_dmabuf_v1 *linux_dmabuf = wl_container_of(
listener, linux_dmabuf, main_allocator_destroy);
linux_dmabuf_unregister_main_blit_device(linux_dmabuf);
}
void wlr_linux_dmabuf_v1_set_main_blit_device(struct wlr_linux_dmabuf_v1 *linux_dmabuf,
struct wlr_renderer *renderer, struct wlr_allocator *allocator) {
assert(renderer != NULL && allocator != NULL);
wl_list_remove(&linux_dmabuf->main_renderer_destroy.link);
wl_list_remove(&linux_dmabuf->main_allocator_destroy.link);
linux_dmabuf->main_renderer_destroy.notify = linux_dmabuf_handle_main_renderer_destroy;
wl_signal_add(&renderer->events.destroy, &linux_dmabuf->main_renderer_destroy);
linux_dmabuf->main_allocator_destroy.notify = linux_dmabuf_handle_main_allocator_destroy;
wl_signal_add(&allocator->events.destroy, &linux_dmabuf->main_allocator_destroy);
linux_dmabuf->main_renderer = renderer;
linux_dmabuf->main_allocator = allocator;
}

View file

@ -6,8 +6,8 @@
#include <wlr/render/wlr_texture.h> #include <wlr/render/wlr_texture.h>
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_linux_drm_syncobj_v1.h> #include <wlr/types/wlr_linux_drm_syncobj_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_raster.h> #include <wlr/types/wlr_raster.h>
#include <wlr/render/drm_syncobj.h> #include <wlr/render/drm_syncobj.h>
#include <wlr/render/wlr_texture.h> #include <wlr/render/wlr_texture.h>
@ -368,6 +368,30 @@ struct wlr_texture *wlr_raster_obtain_texture_with_allocator(struct wlr_raster *
return texture; return texture;
} }
// if this is a linux_dmabuf_v1 buffer, then we can try to use the
// main device for blitting which should support all the modifiers we
// advertise.
if (raster->buffer) {
struct wlr_dmabuf_v1_buffer *dmabuf_buffer =
wlr_dmabuf_v1_buffer_try_from_buffer(raster->buffer);
if (dmabuf_buffer && dmabuf_buffer->linux_dmabuf_v1->main_renderer) {
struct wlr_linux_dmabuf_v1 *linux_dmabuf = dmabuf_buffer->linux_dmabuf_v1;
struct wlr_texture *texture = wlr_texture_from_buffer(
linux_dmabuf->main_renderer, raster->buffer);
if (texture) {
wlr_raster_attach_with_allocator(raster, texture,
linux_dmabuf->main_allocator);
// try to create a blit but this time through the primary device
texture = raster_try_texture_from_blit(raster, renderer);
if (texture) {
wlr_raster_attach_with_allocator(raster, texture, allocator);
return texture;
}
}
}
}
// as a last resort we need to do a copy through the CPU // as a last resort we need to do a copy through the CPU
texture = raster_try_cpu_copy(raster, renderer); texture = raster_try_cpu_copy(raster, renderer);
if (texture) { if (texture) {