render/pixman: Add dmabuf support

Adds linux-dmabuf support to the pixman renderer.  The main reason is so
clients can use GPU-accelerated rendering even if the compositor is
using the pixman renderer for whatever reason.  This also allows the
pixman renderer to import dmabufs (only RGB/ARGB formats, not YUV for
now).

Since after this change all renderers store a DRM FD, I move the drm_fd
from the individual implementations to the shared wlr_renderer base.
This means that renderer_autocreate() can set pixman's drm_fd for it and
the pixman renderer doesn't have to know about DRM at all.

Originally based on
961edfe44e
This commit is contained in:
David Turner 2024-06-10 17:10:20 +01:00
parent 27bbb91abf
commit e4ccc8e822
10 changed files with 36 additions and 42 deletions

View file

@ -41,7 +41,6 @@ struct wlr_gles2_renderer {
struct wlr_renderer wlr_renderer; struct wlr_renderer wlr_renderer;
struct wlr_egl *egl; struct wlr_egl *egl;
int drm_fd;
struct wlr_drm_format_set shm_texture_formats; struct wlr_drm_format_set shm_texture_formats;

View file

@ -38,8 +38,6 @@ struct wlr_vk_device {
VkPhysicalDevice phdev; VkPhysicalDevice phdev;
VkDevice dev; VkDevice dev;
int drm_fd;
bool sync_file_import_export; bool sync_file_import_export;
bool implicit_sync_interop; bool implicit_sync_interop;
bool sampler_ycbcr_conversion; bool sampler_ycbcr_conversion;

View file

@ -25,7 +25,6 @@ struct wlr_renderer_impl {
const struct wlr_drm_format_set *(*get_render_formats)( const struct wlr_drm_format_set *(*get_render_formats)(
struct wlr_renderer *renderer); struct wlr_renderer *renderer);
void (*destroy)(struct wlr_renderer *renderer); void (*destroy)(struct wlr_renderer *renderer);
int (*get_drm_fd)(struct wlr_renderer *renderer);
struct wlr_texture *(*texture_from_buffer)(struct wlr_renderer *renderer, struct wlr_texture *(*texture_from_buffer)(struct wlr_renderer *renderer,
struct wlr_buffer *buffer); struct wlr_buffer *buffer);
struct wlr_render_pass *(*begin_buffer_pass)(struct wlr_renderer *renderer, struct wlr_render_pass *(*begin_buffer_pass)(struct wlr_renderer *renderer,

View file

@ -13,7 +13,6 @@
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
struct wlr_renderer *wlr_pixman_renderer_create(void); struct wlr_renderer *wlr_pixman_renderer_create(void);
bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer); bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_pixman(struct wlr_texture *texture); bool wlr_texture_is_pixman(struct wlr_texture *texture);

View file

@ -55,6 +55,7 @@ struct wlr_renderer {
struct { struct {
const struct wlr_renderer_impl *impl; const struct wlr_renderer_impl *impl;
int drm_fd;
} WLR_PRIVATE; } WLR_PRIVATE;
}; };

View file

@ -182,17 +182,6 @@ static const struct wlr_drm_format_set *gles2_get_render_formats(
return wlr_egl_get_dmabuf_render_formats(renderer->egl); return wlr_egl_get_dmabuf_render_formats(renderer->egl);
} }
static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) {
struct wlr_gles2_renderer *renderer =
gles2_get_renderer(wlr_renderer);
if (renderer->drm_fd < 0) {
renderer->drm_fd = wlr_egl_dup_drm_fd(renderer->egl);
}
return renderer->drm_fd;
}
struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) { struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) {
struct wlr_gles2_renderer *renderer = struct wlr_gles2_renderer *renderer =
gles2_get_renderer(wlr_renderer); gles2_get_renderer(wlr_renderer);
@ -231,8 +220,8 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
wlr_drm_format_set_finish(&renderer->shm_texture_formats); wlr_drm_format_set_finish(&renderer->shm_texture_formats);
if (renderer->drm_fd >= 0) { if (wlr_renderer->drm_fd >= 0) {
close(renderer->drm_fd); close(wlr_renderer->drm_fd);
} }
free(renderer); free(renderer);
@ -356,7 +345,6 @@ static const struct wlr_renderer_impl renderer_impl = {
.destroy = gles2_destroy, .destroy = gles2_destroy,
.get_texture_formats = gles2_get_texture_formats, .get_texture_formats = gles2_get_texture_formats,
.get_render_formats = gles2_get_render_formats, .get_render_formats = gles2_get_render_formats,
.get_drm_fd = gles2_get_drm_fd,
.texture_from_buffer = gles2_texture_from_buffer, .texture_from_buffer = gles2_texture_from_buffer,
.begin_buffer_pass = gles2_begin_buffer_pass, .begin_buffer_pass = gles2_begin_buffer_pass,
.render_timer_create = gles2_render_timer_create, .render_timer_create = gles2_render_timer_create,
@ -533,7 +521,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
renderer->egl = egl; renderer->egl = egl;
renderer->exts_str = exts_str; renderer->exts_str = exts_str;
renderer->drm_fd = -1; renderer->wlr_renderer.drm_fd = -1;
wlr_log(WLR_INFO, "Creating GLES2 renderer"); wlr_log(WLR_INFO, "Creating GLES2 renderer");
wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION)); wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION));
@ -683,7 +671,8 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
get_gles2_shm_formats(renderer, &renderer->shm_texture_formats); get_gles2_shm_formats(renderer, &renderer->shm_texture_formats);
int drm_fd = wlr_renderer_get_drm_fd(&renderer->wlr_renderer); int drm_fd = wlr_egl_dup_drm_fd(renderer->egl);
renderer->wlr_renderer.drm_fd = drm_fd;
uint64_t cap_syncobj_timeline; uint64_t cap_syncobj_timeline;
if (drm_fd >= 0 && drmGetCap(drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap_syncobj_timeline) == 0) { if (drm_fd >= 0 && drmGetCap(drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap_syncobj_timeline) == 0) {
renderer->wlr_renderer.features.timeline = egl->procs.eglDupNativeFenceFDANDROID && renderer->wlr_renderer.features.timeline = egl->procs.eglDupNativeFenceFDANDROID &&

View file

@ -2,6 +2,7 @@
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <pixman.h> #include <pixman.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <wayland-util.h> #include <wayland-util.h>
#include <wlr/render/interface.h> #include <wlr/render/interface.h>
#include <wlr/util/box.h> #include <wlr/util/box.h>
@ -252,6 +253,11 @@ static struct wlr_texture *pixman_texture_from_buffer(
&data, &drm_format, &stride)) { &data, &drm_format, &stride)) {
return NULL; return NULL;
} }
// This looks bad, because we're saying "end access" but also storing the
// pointer for later use. However, we only access the texture data from
// render_pass_add_texture() which does a begin/end access, and
// begin_pixman_data_ptr_access() will handle if the data pointer changes
// between accesses. So everything should be fine.
wlr_buffer_end_data_ptr_access(buffer); wlr_buffer_end_data_ptr_access(buffer);
struct wlr_pixman_texture *texture = pixman_texture_create(renderer, struct wlr_pixman_texture *texture = pixman_texture_create(renderer,
@ -335,8 +341,9 @@ struct wlr_renderer *wlr_pixman_renderer_create(void) {
const uint32_t *formats = get_pixman_drm_formats(&len); const uint32_t *formats = get_pixman_drm_formats(&len);
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
wlr_drm_format_set_add(&renderer->drm_formats, formats[i], // Only support linear buffers. MOD_INVALID could mean the driver
DRM_FORMAT_MOD_INVALID); // can do whatever it thinks appropriate, but pixman definitely
// only supports linear.
wlr_drm_format_set_add(&renderer->drm_formats, formats[i], wlr_drm_format_set_add(&renderer->drm_formats, formats[i],
DRM_FORMAT_MOD_LINEAR); DRM_FORMAT_MOD_LINEAR);
} }

View file

@ -1153,6 +1153,11 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
struct wlr_vk_instance *ini = dev->instance; struct wlr_vk_instance *ini = dev->instance;
vulkan_device_destroy(dev); vulkan_device_destroy(dev);
vulkan_instance_destroy(ini); vulkan_instance_destroy(ini);
if (wlr_renderer->drm_fd > 0) {
close(wlr_renderer->drm_fd);
}
free(renderer); free(renderer);
} }
@ -1402,11 +1407,6 @@ destroy_image:
return false; return false;
} }
static int vulkan_get_drm_fd(struct wlr_renderer *wlr_renderer) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
return renderer->dev->drm_fd;
}
static struct wlr_render_pass *vulkan_begin_buffer_pass(struct wlr_renderer *wlr_renderer, static struct wlr_render_pass *vulkan_begin_buffer_pass(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *buffer, const struct wlr_buffer_pass_options *options) { struct wlr_buffer *buffer, const struct wlr_buffer_pass_options *options) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
@ -1431,7 +1431,6 @@ static const struct wlr_renderer_impl renderer_impl = {
.get_texture_formats = vulkan_get_texture_formats, .get_texture_formats = vulkan_get_texture_formats,
.get_render_formats = vulkan_get_render_formats, .get_render_formats = vulkan_get_render_formats,
.destroy = vulkan_destroy, .destroy = vulkan_destroy,
.get_drm_fd = vulkan_get_drm_fd,
.texture_from_buffer = vulkan_texture_from_buffer, .texture_from_buffer = vulkan_texture_from_buffer,
.begin_buffer_pass = vulkan_begin_buffer_pass, .begin_buffer_pass = vulkan_begin_buffer_pass,
}; };
@ -2442,7 +2441,8 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev
wl_list_init(&renderer->pipeline_layouts); wl_list_init(&renderer->pipeline_layouts);
uint64_t cap_syncobj_timeline; uint64_t cap_syncobj_timeline;
if (dev->drm_fd >= 0 && drmGetCap(dev->drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap_syncobj_timeline) == 0) { if (renderer->wlr_renderer.drm_fd >= 0 &&
drmGetCap(renderer->wlr_renderer.drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap_syncobj_timeline) == 0) {
renderer->wlr_renderer.features.timeline = dev->sync_file_import_export && cap_syncobj_timeline != 0; renderer->wlr_renderer.features.timeline = dev->sync_file_import_export && cap_syncobj_timeline != 0;
} }
@ -2513,9 +2513,11 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
// Do not use the drm_fd that was passed in: we should prefer the render // Do not use the drm_fd that was passed in: we should prefer the render
// node even if a primary node was provided // node even if a primary node was provided
dev->drm_fd = vulkan_open_phdev_drm_fd(phdev); int render_drm_fd = vulkan_open_phdev_drm_fd(phdev);
return vulkan_renderer_create_for_device(dev); struct wlr_renderer *wlr_renderer = vulkan_renderer_create_for_device(dev);
wlr_renderer->drm_fd = render_drm_fd;
return wlr_renderer;
} }
VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer) { VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer) {

View file

@ -458,7 +458,6 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
dev->phdev = phdev; dev->phdev = phdev;
dev->instance = ini; dev->instance = ini;
dev->drm_fd = -1;
// For dmabuf import we require at least the external_memory_fd, // For dmabuf import we require at least the external_memory_fd,
// external_memory_dma_buf, queue_family_foreign, // external_memory_dma_buf, queue_family_foreign,
@ -665,10 +664,6 @@ void vulkan_device_destroy(struct wlr_vk_device *dev) {
vkDestroyDevice(dev->dev, NULL); vkDestroyDevice(dev->dev, NULL);
} }
if (dev->drm_fd > 0) {
close(dev->drm_fd);
}
wlr_drm_format_set_finish(&dev->dmabuf_render_formats); wlr_drm_format_set_finish(&dev->dmabuf_render_formats);
wlr_drm_format_set_finish(&dev->dmabuf_texture_formats); wlr_drm_format_set_finish(&dev->dmabuf_texture_formats);
wlr_drm_format_set_finish(&dev->shm_texture_formats); wlr_drm_format_set_finish(&dev->shm_texture_formats);

View file

@ -267,6 +267,14 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int
if ((is_auto && !has_render_node(backend)) || strcmp(renderer_name, "pixman") == 0) { if ((is_auto && !has_render_node(backend)) || strcmp(renderer_name, "pixman") == 0) {
renderer = wlr_pixman_renderer_create(); renderer = wlr_pixman_renderer_create();
if (open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) {
wlr_log(WLR_DEBUG, "Creating pixman renderer with DRM FD %d", drm_fd);
renderer->drm_fd = drm_fd;
} else {
wlr_log(WLR_DEBUG, "Creating pixman renderer without DRM");
renderer->drm_fd = -1;
}
if (renderer) { if (renderer) {
goto out; goto out;
} else { } else {
@ -297,11 +305,8 @@ struct wlr_renderer *wlr_renderer_autocreate(struct wlr_backend *backend) {
return renderer_autocreate(backend, -1); return renderer_autocreate(backend, -1);
} }
int wlr_renderer_get_drm_fd(struct wlr_renderer *r) { int wlr_renderer_get_drm_fd(struct wlr_renderer *renderer) {
if (!r->impl->get_drm_fd) { return renderer->drm_fd;
return -1;
}
return r->impl->get_drm_fd(r);
} }
struct wlr_render_pass *wlr_renderer_begin_buffer_pass(struct wlr_renderer *renderer, struct wlr_render_pass *wlr_renderer_begin_buffer_pass(struct wlr_renderer *renderer,