From 3ce2ea9e16fcd1bfab4ec9d5994fa721c5d58dcd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Aug 2021 09:33:19 +0200 Subject: Move allocator stuff into new directory Add render/allocator/ and include/render/allocator/ to hold everything allocator-related. --- backend/backend.c | 2 +- backend/drm/renderer.c | 2 +- backend/headless/backend.c | 1 - backend/wayland/backend.c | 1 - backend/x11/backend.c | 1 - include/render/allocator.h | 55 -------- include/render/allocator/allocator.h | 54 ++++++++ include/render/allocator/drm_dumb.h | 37 ++++++ include/render/allocator/gbm.h | 34 +++++ include/render/allocator/shm.h | 23 ++++ include/render/drm_dumb_allocator.h | 37 ------ include/render/gbm_allocator.h | 33 ----- include/render/shm_allocator.h | 23 ---- render/allocator.c | 93 ------------- render/allocator/allocator.c | 93 +++++++++++++ render/allocator/drm_dumb.c | 248 +++++++++++++++++++++++++++++++++++ render/allocator/gbm.c | 236 +++++++++++++++++++++++++++++++++ render/allocator/meson.build | 9 ++ render/allocator/shm.c | 116 ++++++++++++++++ render/drm_dumb_allocator.c | 248 ----------------------------------- render/gbm_allocator.c | 236 --------------------------------- render/meson.build | 9 +- render/shm_allocator.c | 116 ---------------- render/swapchain.c | 2 +- types/wlr_output.c | 2 +- 25 files changed, 856 insertions(+), 855 deletions(-) delete mode 100644 include/render/allocator.h create mode 100644 include/render/allocator/allocator.h create mode 100644 include/render/allocator/drm_dumb.h create mode 100644 include/render/allocator/gbm.h create mode 100644 include/render/allocator/shm.h delete mode 100644 include/render/drm_dumb_allocator.h delete mode 100644 include/render/gbm_allocator.h delete mode 100644 include/render/shm_allocator.h delete mode 100644 render/allocator.c create mode 100644 render/allocator/allocator.c create mode 100644 render/allocator/drm_dumb.c create mode 100644 render/allocator/gbm.c create mode 100644 render/allocator/meson.build create mode 100644 render/allocator/shm.c delete mode 100644 render/drm_dumb_allocator.c delete mode 100644 render/gbm_allocator.c delete mode 100644 render/shm_allocator.c diff --git a/backend/backend.c b/backend/backend.c index ef1d523c..1cdddd16 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -18,7 +18,7 @@ #include #include "backend/backend.h" #include "backend/multi.h" -#include "render/allocator.h" +#include "render/allocator/allocator.h" #include "util/signal.h" #if WLR_HAS_DRM_BACKEND diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index adda8fd5..4f1b102a 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -14,7 +14,7 @@ #include "backend/drm/drm.h" #include "backend/drm/util.h" #include "render/drm_format_set.h" -#include "render/allocator.h" +#include "render/allocator/allocator.h" #include "render/pixel_format.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" diff --git a/backend/headless/backend.c b/backend/headless/backend.c index cf7f6026..51217f8b 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -12,7 +12,6 @@ #include "backend/backend.h" #include "backend/headless.h" #include "render/drm_format_set.h" -#include "render/gbm_allocator.h" #include "render/wlr_renderer.h" #include "util/signal.h" diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 207c17d2..c11d25ca 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -17,7 +17,6 @@ #include "backend/backend.h" #include "backend/wayland.h" -#include "render/allocator.h" #include "render/drm_format_set.h" #include "render/pixel_format.h" #include "render/wlr_renderer.h" diff --git a/backend/x11/backend.c b/backend/x11/backend.c index acdd3f39..f55238cb 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -31,7 +31,6 @@ #include "backend/backend.h" #include "backend/x11.h" -#include "render/allocator.h" #include "render/drm_format_set.h" #include "util/signal.h" diff --git a/include/render/allocator.h b/include/render/allocator.h deleted file mode 100644 index c33ab126..00000000 --- a/include/render/allocator.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef RENDER_ALLOCATOR -#define RENDER_ALLOCATOR - -#include -#include -#include -#include - -struct wlr_allocator; -struct wlr_backend; -struct wlr_renderer; - -struct wlr_allocator_interface { - struct wlr_buffer *(*create_buffer)(struct wlr_allocator *alloc, - int width, int height, const struct wlr_drm_format *format); - void (*destroy)(struct wlr_allocator *alloc); -}; - -struct wlr_allocator { - const struct wlr_allocator_interface *impl; - - // Capabilites of the buffers created with this allocator - uint32_t buffer_caps; - - struct { - struct wl_signal destroy; - } events; -}; - -/** - * Creates the adequate wlr_allocator given a backend and a renderer - */ -struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, - struct wlr_renderer *renderer); -/** - * Destroy the allocator. - */ -void wlr_allocator_destroy(struct wlr_allocator *alloc); -/** - * Allocate a new buffer. - * - * When the caller is done with it, they must unreference it by calling - * wlr_buffer_drop. - */ -struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, - int width, int height, const struct wlr_drm_format *format); - -// For wlr_allocator implementors -void wlr_allocator_init(struct wlr_allocator *alloc, - const struct wlr_allocator_interface *impl, uint32_t buffer_caps); - -struct wlr_allocator *allocator_autocreate_with_drm_fd( - struct wlr_backend *backend, struct wlr_renderer *renderer, int drm_fd); - -#endif diff --git a/include/render/allocator/allocator.h b/include/render/allocator/allocator.h new file mode 100644 index 00000000..d67116cd --- /dev/null +++ b/include/render/allocator/allocator.h @@ -0,0 +1,54 @@ +#ifndef RENDER_ALLOCATOR_ALLOCATOR_H +#define RENDER_ALLOCATOR_ALLOCATOR_H + +#include +#include +#include + +struct wlr_allocator; +struct wlr_backend; +struct wlr_renderer; + +struct wlr_allocator_interface { + struct wlr_buffer *(*create_buffer)(struct wlr_allocator *alloc, + int width, int height, const struct wlr_drm_format *format); + void (*destroy)(struct wlr_allocator *alloc); +}; + +struct wlr_allocator { + const struct wlr_allocator_interface *impl; + + // Capabilites of the buffers created with this allocator + uint32_t buffer_caps; + + struct { + struct wl_signal destroy; + } events; +}; + +/** + * Creates the adequate wlr_allocator given a backend and a renderer + */ +struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, + struct wlr_renderer *renderer); +/** + * Destroy the allocator. + */ +void wlr_allocator_destroy(struct wlr_allocator *alloc); +/** + * Allocate a new buffer. + * + * When the caller is done with it, they must unreference it by calling + * wlr_buffer_drop. + */ +struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, + int width, int height, const struct wlr_drm_format *format); + +// For wlr_allocator implementors +void wlr_allocator_init(struct wlr_allocator *alloc, + const struct wlr_allocator_interface *impl, uint32_t buffer_caps); + +struct wlr_allocator *allocator_autocreate_with_drm_fd( + struct wlr_backend *backend, struct wlr_renderer *renderer, int drm_fd); + +#endif diff --git a/include/render/allocator/drm_dumb.h b/include/render/allocator/drm_dumb.h new file mode 100644 index 00000000..7e37acfb --- /dev/null +++ b/include/render/allocator/drm_dumb.h @@ -0,0 +1,37 @@ +#ifndef RENDER_ALLOCATOR_DRM_DUMB_H +#define RENDER_ALLOCATOR_DRM_DUMB_H + +#include +#include +#include "render/allocator/allocator.h" + +struct wlr_drm_dumb_buffer { + struct wlr_buffer base; + struct wl_list link; // wlr_drm_dumb_allocator::buffers + + int drm_fd; // -1 if the allocator has been destroyed + struct wlr_dmabuf_attributes dmabuf; + + uint32_t format; + uint32_t handle; + uint32_t stride; + uint32_t width, height; + + uint64_t size; + void *data; +}; + +struct wlr_drm_dumb_allocator { + struct wlr_allocator base; + struct wl_list buffers; // wlr_drm_dumb_buffer::link + int drm_fd; +}; + +/** + * Creates a new drm dumb allocator from a DRM FD. + * + * Does not take ownership over the FD. + */ +struct wlr_allocator *wlr_drm_dumb_allocator_create(int fd); + +#endif diff --git a/include/render/allocator/gbm.h b/include/render/allocator/gbm.h new file mode 100644 index 00000000..eb112e7c --- /dev/null +++ b/include/render/allocator/gbm.h @@ -0,0 +1,34 @@ +#ifndef RENDER_ALLOCATOR_GBM_H +#define RENDER_ALLOCATOR_GBM_H + +#include +#include +#include +#include "render/allocator/allocator.h" + +struct wlr_gbm_buffer { + struct wlr_buffer base; + + struct wl_list link; // wlr_gbm_allocator.buffers + + struct gbm_bo *gbm_bo; // NULL if the gbm_device has been destroyed + struct wlr_dmabuf_attributes dmabuf; +}; + +struct wlr_gbm_allocator { + struct wlr_allocator base; + + int fd; + struct gbm_device *gbm_device; + + struct wl_list buffers; // wlr_gbm_buffer.link +}; + +/** + * Creates a new GBM allocator from a DRM FD. + * + * Does not take ownership over the FD. + */ +struct wlr_allocator *wlr_gbm_allocator_create(int drm_fd); + +#endif diff --git a/include/render/allocator/shm.h b/include/render/allocator/shm.h new file mode 100644 index 00000000..4b80e475 --- /dev/null +++ b/include/render/allocator/shm.h @@ -0,0 +1,23 @@ +#ifndef RENDER_ALLOCATOR_SHM_H +#define RENDER_ALLOCATOR_SHM_H + +#include +#include "render/allocator/allocator.h" + +struct wlr_shm_buffer { + struct wlr_buffer base; + struct wlr_shm_attributes shm; + void *data; + size_t size; +}; + +struct wlr_shm_allocator { + struct wlr_allocator base; +}; + +/** + * Creates a new shared memory allocator. + */ +struct wlr_allocator *wlr_shm_allocator_create(void); + +#endif diff --git a/include/render/drm_dumb_allocator.h b/include/render/drm_dumb_allocator.h deleted file mode 100644 index ff10d54b..00000000 --- a/include/render/drm_dumb_allocator.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef RENDER_DRM_DUMB_ALLOCATOR_H -#define RENDER_DRM_DUMB_ALLOCATOR_H - -#include "render/allocator.h" - -#include - -struct wlr_drm_dumb_buffer { - struct wlr_buffer base; - struct wl_list link; // wlr_drm_dumb_allocator::buffers - - int drm_fd; // -1 if the allocator has been destroyed - struct wlr_dmabuf_attributes dmabuf; - - uint32_t format; - uint32_t handle; - uint32_t stride; - uint32_t width, height; - - uint64_t size; - void *data; -}; - -struct wlr_drm_dumb_allocator { - struct wlr_allocator base; - struct wl_list buffers; // wlr_drm_dumb_buffer::link - int drm_fd; -}; - -/** - * Creates a new drm dumb allocator from a DRM FD. - * - * Does not take ownership over the FD. - */ -struct wlr_allocator *wlr_drm_dumb_allocator_create(int fd); - -#endif diff --git a/include/render/gbm_allocator.h b/include/render/gbm_allocator.h deleted file mode 100644 index df6b5e39..00000000 --- a/include/render/gbm_allocator.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RENDER_GBM_ALLOCATOR_H -#define RENDER_GBM_ALLOCATOR_H - -#include -#include -#include "render/allocator.h" - -struct wlr_gbm_buffer { - struct wlr_buffer base; - - struct wl_list link; // wlr_gbm_allocator.buffers - - struct gbm_bo *gbm_bo; // NULL if the gbm_device has been destroyed - struct wlr_dmabuf_attributes dmabuf; -}; - -struct wlr_gbm_allocator { - struct wlr_allocator base; - - int fd; - struct gbm_device *gbm_device; - - struct wl_list buffers; // wlr_gbm_buffer.link -}; - -/** - * Creates a new GBM allocator from a DRM FD. - * - * Does not take ownership over the FD. - */ -struct wlr_allocator *wlr_gbm_allocator_create(int drm_fd); - -#endif diff --git a/include/render/shm_allocator.h b/include/render/shm_allocator.h deleted file mode 100644 index d1f48f7f..00000000 --- a/include/render/shm_allocator.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef RENDER_SHM_ALLOCATOR_H -#define RENDER_SHM_ALLOCATOR_H - -#include -#include "render/allocator.h" - -struct wlr_shm_buffer { - struct wlr_buffer base; - struct wlr_shm_attributes shm; - void *data; - size_t size; -}; - -struct wlr_shm_allocator { - struct wlr_allocator base; -}; - -/** - * Creates a new shared memory allocator. - */ -struct wlr_allocator *wlr_shm_allocator_create(void); - -#endif diff --git a/render/allocator.c b/render/allocator.c deleted file mode 100644 index 5b7e27ff..00000000 --- a/render/allocator.c +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include -#include "backend/backend.h" -#include "render/allocator.h" -#include "render/gbm_allocator.h" -#include "render/shm_allocator.h" -#include "render/drm_dumb_allocator.h" -#include "render/wlr_renderer.h" - -void wlr_allocator_init(struct wlr_allocator *alloc, - const struct wlr_allocator_interface *impl, uint32_t buffer_caps) { - assert(impl && impl->destroy && impl->create_buffer); - alloc->impl = impl; - alloc->buffer_caps = buffer_caps; - wl_signal_init(&alloc->events.destroy); -} - -struct wlr_allocator *allocator_autocreate_with_drm_fd( - struct wlr_backend *backend, struct wlr_renderer *renderer, - int drm_fd) { - uint32_t backend_caps = backend_get_buffer_caps(backend); - uint32_t renderer_caps = renderer_get_render_buffer_caps(renderer); - - struct wlr_allocator *alloc = NULL; - uint32_t gbm_caps = WLR_BUFFER_CAP_DMABUF; - if ((backend_caps & gbm_caps) && (renderer_caps & gbm_caps) - && drm_fd != -1) { - wlr_log(WLR_DEBUG, "Trying to create gbm allocator"); - if ((alloc = wlr_gbm_allocator_create(drm_fd)) != NULL) { - return alloc; - } - wlr_log(WLR_DEBUG, "Failed to create gbm allocator"); - } - - uint32_t shm_caps = WLR_BUFFER_CAP_SHM | WLR_BUFFER_CAP_DATA_PTR; - if ((backend_caps & shm_caps) && (renderer_caps & shm_caps)) { - wlr_log(WLR_DEBUG, "Trying to create shm allocator"); - if ((alloc = wlr_shm_allocator_create()) != NULL) { - return alloc; - } - wlr_log(WLR_DEBUG, "Failed to create shm allocator"); - } - - uint32_t drm_caps = WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_DATA_PTR; - if ((backend_caps & drm_caps) && (renderer_caps & drm_caps) - && drm_fd != -1) { - wlr_log(WLR_DEBUG, "Trying to create drm dumb allocator"); - if ((alloc = wlr_drm_dumb_allocator_create(drm_fd)) != NULL) { - return alloc; - } - wlr_log(WLR_DEBUG, "Failed to create drm dumb allocator"); - } - - wlr_log(WLR_ERROR, "Failed to create allocator"); - return NULL; -} - -struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, - struct wlr_renderer *renderer) { - // Note, drm_fd may be negative if unavailable - int drm_fd = wlr_backend_get_drm_fd(backend); - return allocator_autocreate_with_drm_fd(backend, renderer, drm_fd); -} - -void wlr_allocator_destroy(struct wlr_allocator *alloc) { - if (alloc == NULL) { - return; - } - wl_signal_emit(&alloc->events.destroy, NULL); - alloc->impl->destroy(alloc); -} - -struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, - int width, int height, const struct wlr_drm_format *format) { - struct wlr_buffer *buffer = - alloc->impl->create_buffer(alloc, width, height, format); - if (buffer == NULL) { - return NULL; - } - if (alloc->buffer_caps & WLR_BUFFER_CAP_DATA_PTR) { - assert(buffer->impl->begin_data_ptr_access && - buffer->impl->end_data_ptr_access); - } - if (alloc->buffer_caps & WLR_BUFFER_CAP_DMABUF) { - assert(buffer->impl->get_dmabuf); - } - if (alloc->buffer_caps & WLR_BUFFER_CAP_SHM) { - assert(buffer->impl->get_shm); - } - return buffer; -} diff --git a/render/allocator/allocator.c b/render/allocator/allocator.c new file mode 100644 index 00000000..8664202f --- /dev/null +++ b/render/allocator/allocator.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include "backend/backend.h" +#include "render/allocator/allocator.h" +#include "render/allocator/drm_dumb.h" +#include "render/allocator/gbm.h" +#include "render/allocator/shm.h" +#include "render/wlr_renderer.h" + +void wlr_allocator_init(struct wlr_allocator *alloc, + const struct wlr_allocator_interface *impl, uint32_t buffer_caps) { + assert(impl && impl->destroy && impl->create_buffer); + alloc->impl = impl; + alloc->buffer_caps = buffer_caps; + wl_signal_init(&alloc->events.destroy); +} + +struct wlr_allocator *allocator_autocreate_with_drm_fd( + struct wlr_backend *backend, struct wlr_renderer *renderer, + int drm_fd) { + uint32_t backend_caps = backend_get_buffer_caps(backend); + uint32_t renderer_caps = renderer_get_render_buffer_caps(renderer); + + struct wlr_allocator *alloc = NULL; + uint32_t gbm_caps = WLR_BUFFER_CAP_DMABUF; + if ((backend_caps & gbm_caps) && (renderer_caps & gbm_caps) + && drm_fd != -1) { + wlr_log(WLR_DEBUG, "Trying to create gbm allocator"); + if ((alloc = wlr_gbm_allocator_create(drm_fd)) != NULL) { + return alloc; + } + wlr_log(WLR_DEBUG, "Failed to create gbm allocator"); + } + + uint32_t shm_caps = WLR_BUFFER_CAP_SHM | WLR_BUFFER_CAP_DATA_PTR; + if ((backend_caps & shm_caps) && (renderer_caps & shm_caps)) { + wlr_log(WLR_DEBUG, "Trying to create shm allocator"); + if ((alloc = wlr_shm_allocator_create()) != NULL) { + return alloc; + } + wlr_log(WLR_DEBUG, "Failed to create shm allocator"); + } + + uint32_t drm_caps = WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_DATA_PTR; + if ((backend_caps & drm_caps) && (renderer_caps & drm_caps) + && drm_fd != -1) { + wlr_log(WLR_DEBUG, "Trying to create drm dumb allocator"); + if ((alloc = wlr_drm_dumb_allocator_create(drm_fd)) != NULL) { + return alloc; + } + wlr_log(WLR_DEBUG, "Failed to create drm dumb allocator"); + } + + wlr_log(WLR_ERROR, "Failed to create allocator"); + return NULL; +} + +struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, + struct wlr_renderer *renderer) { + // Note, drm_fd may be negative if unavailable + int drm_fd = wlr_backend_get_drm_fd(backend); + return allocator_autocreate_with_drm_fd(backend, renderer, drm_fd); +} + +void wlr_allocator_destroy(struct wlr_allocator *alloc) { + if (alloc == NULL) { + return; + } + wl_signal_emit(&alloc->events.destroy, NULL); + alloc->impl->destroy(alloc); +} + +struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, + int width, int height, const struct wlr_drm_format *format) { + struct wlr_buffer *buffer = + alloc->impl->create_buffer(alloc, width, height, format); + if (buffer == NULL) { + return NULL; + } + if (alloc->buffer_caps & WLR_BUFFER_CAP_DATA_PTR) { + assert(buffer->impl->begin_data_ptr_access && + buffer->impl->end_data_ptr_access); + } + if (alloc->buffer_caps & WLR_BUFFER_CAP_DMABUF) { + assert(buffer->impl->get_dmabuf); + } + if (alloc->buffer_caps & WLR_BUFFER_CAP_SHM) { + assert(buffer->impl->get_shm); + } + return buffer; +} diff --git a/render/allocator/drm_dumb.c b/render/allocator/drm_dumb.c new file mode 100644 index 00000000..a47df624 --- /dev/null +++ b/render/allocator/drm_dumb.c @@ -0,0 +1,248 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "render/allocator/drm_dumb.h" +#include "render/pixel_format.h" + +static const struct wlr_buffer_impl buffer_impl; + +static struct wlr_drm_dumb_buffer *drm_dumb_buffer_from_buffer( + struct wlr_buffer *wlr_buf) { + assert(wlr_buf->impl == &buffer_impl); + return (struct wlr_drm_dumb_buffer *)wlr_buf; +} + +static void finish_buffer(struct wlr_drm_dumb_buffer *buf) { + if (buf->data) { + munmap(buf->data, buf->size); + } + + wlr_dmabuf_attributes_finish(&buf->dmabuf); + + if (buf->drm_fd >= 0) { + struct drm_mode_destroy_dumb destroy = { .handle = buf->handle }; + if (drmIoctl(buf->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy)) { + wlr_log_errno(WLR_ERROR, "Failed to destroy DRM dumb buffer"); + } + } + + wl_list_remove(&buf->link); +} + +static struct wlr_drm_dumb_buffer *create_buffer( + struct wlr_drm_dumb_allocator *alloc, int width, int height, + const struct wlr_drm_format *format) { + struct wlr_drm_dumb_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + return NULL; + } + wlr_buffer_init(&buffer->base, &buffer_impl, width, height); + wl_list_insert(&alloc->buffers, &buffer->link); + + const struct wlr_pixel_format_info *info = + drm_get_pixel_format_info(format->format); + if (info == NULL) { + wlr_log(WLR_ERROR, "DRM format 0x%"PRIX32" not supported", + format->format); + goto create_err; + } + + struct drm_mode_create_dumb create = {0}; + create.width = (uint32_t)width; + create.height = (uint32_t)height; + create.bpp = info->bpp; + + if (drmIoctl(alloc->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create) != 0) { + wlr_log_errno(WLR_ERROR, "Failed to create DRM dumb buffer"); + goto create_err; + } + + buffer->width = create.width; + buffer->height = create.height; + + buffer->stride = create.pitch; + buffer->handle = create.handle; + buffer->format = format->format; + + buffer->drm_fd = alloc->drm_fd; + + struct drm_mode_map_dumb map = {0}; + map.handle = buffer->handle; + + if (drmIoctl(alloc->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map) != 0) { + wlr_log_errno(WLR_ERROR, "Failed to map DRM dumb buffer"); + goto create_destroy; + } + + buffer->data = mmap(NULL, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, + alloc->drm_fd, map.offset); + if (buffer->data == MAP_FAILED) { + wlr_log_errno(WLR_ERROR, "Failed to mmap DRM dumb buffer"); + goto create_destroy; + } + + buffer->size = create.size; + + memset(buffer->data, 0, create.size); + + int prime_fd; + if (drmPrimeHandleToFD(alloc->drm_fd, buffer->handle, DRM_CLOEXEC, + &prime_fd) != 0) { + wlr_log_errno(WLR_ERROR, "Failed to get PRIME handle from GEM handle"); + goto create_destroy; + } + + buffer->dmabuf = (struct wlr_dmabuf_attributes){ + .width = buffer->width, + .height = buffer->height, + .format = format->format, + .modifier = DRM_FORMAT_MOD_INVALID, + .n_planes = 1, + .offset[0] = 0, + .stride[0] = buffer->stride, + .fd[0] = prime_fd, + }; + + wlr_log(WLR_DEBUG, "Allocated %"PRIu32"x%"PRIu32" DRM dumb buffer", + buffer->width, buffer->height); + + return buffer; + +create_destroy: + finish_buffer(buffer); +create_err: + free(buffer); + return NULL; +} + +static bool drm_dumb_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, + void **data, uint32_t *format, size_t *stride) { + struct wlr_drm_dumb_buffer *buf = drm_dumb_buffer_from_buffer(wlr_buffer); + *data = buf->data; + *stride = buf->stride; + *format = buf->format; + return true; +} + +static void drm_dumb_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) { + // This space is intentionally left blank +} + +static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, + struct wlr_dmabuf_attributes *attribs) { + struct wlr_drm_dumb_buffer *buf = drm_dumb_buffer_from_buffer(wlr_buffer); + memcpy(attribs, &buf->dmabuf, sizeof(buf->dmabuf)); + return true; +} + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_drm_dumb_buffer *buf = drm_dumb_buffer_from_buffer(wlr_buffer); + finish_buffer(buf); + free(buf); +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .get_dmabuf = buffer_get_dmabuf, + .begin_data_ptr_access = drm_dumb_buffer_begin_data_ptr_access, + .end_data_ptr_access = drm_dumb_buffer_end_data_ptr_access, +}; + +static const struct wlr_allocator_interface allocator_impl; + +static struct wlr_drm_dumb_allocator *drm_dumb_alloc_from_alloc( + struct wlr_allocator *wlr_alloc) { + assert(wlr_alloc->impl == &allocator_impl); + return (struct wlr_drm_dumb_allocator *)wlr_alloc; +} + +static struct wlr_buffer *allocator_create_buffer( + struct wlr_allocator *wlr_alloc, int width, int height, + const struct wlr_drm_format *drm_format) { + struct wlr_drm_dumb_allocator *alloc = drm_dumb_alloc_from_alloc(wlr_alloc); + struct wlr_drm_dumb_buffer *buffer = create_buffer(alloc, width, height, + drm_format); + if (buffer == NULL) { + return NULL; + } + return &buffer->base; +} + +static void allocator_destroy(struct wlr_allocator *wlr_alloc) { + struct wlr_drm_dumb_allocator *alloc = drm_dumb_alloc_from_alloc(wlr_alloc); + + struct wlr_drm_dumb_buffer *buf, *buf_tmp; + wl_list_for_each_safe(buf, buf_tmp, &alloc->buffers, link) { + buf->drm_fd = -1; + wl_list_remove(&buf->link); + wl_list_init(&buf->link); + } + + close(alloc->drm_fd); + free(alloc); +} + +static const struct wlr_allocator_interface allocator_impl = { + .create_buffer = allocator_create_buffer, + .destroy = allocator_destroy, +}; + +struct wlr_allocator *wlr_drm_dumb_allocator_create(int fd) { + if (!drmIsMaster(fd)) { + wlr_log(WLR_ERROR, "Cannot use DRM dumb buffers with non-master DRM FD"); + return NULL; + } + + /* Re-open the DRM node to avoid GEM handle ref'counting issues. See: + * https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/110 + * TODO: don't assume we have the permission to just open the DRM node, + * find another way to re-open it. + */ + char *path = drmGetDeviceNameFromFd2(fd); + int drm_fd = open(path, O_RDWR | O_CLOEXEC); + if (drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open DRM node %s", path); + free(path); + return NULL; + } + + uint64_t has_dumb = 0; + if (drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM capabilities"); + free(path); + return NULL; + } + + if (has_dumb == 0) { + wlr_log(WLR_ERROR, "DRM dumb buffers not supported"); + free(path); + return NULL; + } + + struct wlr_drm_dumb_allocator *alloc = calloc(1, sizeof(*alloc)); + if (alloc == NULL) { + free(path); + return NULL; + } + wlr_allocator_init(&alloc->base, &allocator_impl, + WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF); + + alloc->drm_fd = drm_fd; + wl_list_init(&alloc->buffers); + + wlr_log(WLR_DEBUG, "Created DRM dumb allocator with node %s", path); + free(path); + return &alloc->base; +} diff --git a/render/allocator/gbm.c b/render/allocator/gbm.c new file mode 100644 index 00000000..ace7ca68 --- /dev/null +++ b/render/allocator/gbm.c @@ -0,0 +1,236 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include "render/allocator/gbm.h" + +static const struct wlr_buffer_impl buffer_impl; + +static struct wlr_gbm_buffer *get_gbm_buffer_from_buffer( + struct wlr_buffer *buffer) { + assert(buffer->impl == &buffer_impl); + return (struct wlr_gbm_buffer *)buffer; +} + +static bool export_gbm_bo(struct gbm_bo *bo, + struct wlr_dmabuf_attributes *out) { + struct wlr_dmabuf_attributes attribs = {0}; + + attribs.n_planes = gbm_bo_get_plane_count(bo); + if (attribs.n_planes > WLR_DMABUF_MAX_PLANES) { + wlr_log(WLR_ERROR, "GBM BO contains too many planes (%d)", + attribs.n_planes); + return false; + } + + attribs.width = gbm_bo_get_width(bo); + attribs.height = gbm_bo_get_height(bo); + attribs.format = gbm_bo_get_format(bo); + attribs.modifier = gbm_bo_get_modifier(bo); + + int i; + int32_t handle = -1; + for (i = 0; i < attribs.n_planes; ++i) { +#if HAS_GBM_BO_GET_FD_FOR_PLANE + attribs.fd[i] = gbm_bo_get_fd_for_plane(bo, i); + (void)handle; +#else + // GBM is lacking a function to get a FD for a given plane. Instead, + // check all planes have the same handle. We can't use + // drmPrimeHandleToFD because that messes up handle ref'counting in + // the user-space driver. + union gbm_bo_handle plane_handle = gbm_bo_get_handle_for_plane(bo, i); + if (plane_handle.s32 < 0) { + wlr_log(WLR_ERROR, "gbm_bo_get_handle_for_plane failed"); + goto error_fd; + } + if (i == 0) { + handle = plane_handle.s32; + } else if (plane_handle.s32 != handle) { + wlr_log(WLR_ERROR, "Failed to export GBM BO: " + "all planes don't have the same GEM handle"); + goto error_fd; + } + + attribs.fd[i] = gbm_bo_get_fd(bo); +#endif + + if (attribs.fd[i] < 0) { + wlr_log(WLR_ERROR, "gbm_bo_get_fd failed"); + goto error_fd; + } + + attribs.offset[i] = gbm_bo_get_offset(bo, i); + attribs.stride[i] = gbm_bo_get_stride_for_plane(bo, i); + } + + memcpy(out, &attribs, sizeof(attribs)); + return true; + +error_fd: + for (int j = 0; j < i; ++j) { + close(attribs.fd[j]); + } + return false; +} + +static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc, + int width, int height, const struct wlr_drm_format *format) { + struct gbm_device *gbm_device = alloc->gbm_device; + + struct gbm_bo *bo = NULL; + bool has_modifier = true; + if (format->len > 0) { + bo = gbm_bo_create_with_modifiers(gbm_device, width, height, + format->format, format->modifiers, format->len); + } + if (bo == NULL) { + uint32_t usage = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; + if (format->len == 1 && + format->modifiers[0] == DRM_FORMAT_MOD_LINEAR) { + usage |= GBM_BO_USE_LINEAR; + } + bo = gbm_bo_create(gbm_device, width, height, format->format, usage); + has_modifier = false; + } + if (bo == NULL) { + wlr_log(WLR_ERROR, "gbm_bo_create failed"); + return NULL; + } + + struct wlr_gbm_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + gbm_bo_destroy(bo); + return NULL; + } + wlr_buffer_init(&buffer->base, &buffer_impl, width, height); + buffer->gbm_bo = bo; + wl_list_insert(&alloc->buffers, &buffer->link); + + if (!export_gbm_bo(bo, &buffer->dmabuf)) { + free(buffer); + gbm_bo_destroy(bo); + return NULL; + } + + // If the buffer has been allocated with an implicit modifier, make sure we + // don't populate the modifier field: other parts of the stack may not + // understand modifiers, and they can't strip the modifier. + if (!has_modifier) { + buffer->dmabuf.modifier = DRM_FORMAT_MOD_INVALID; + } + + wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer (format 0x%"PRIX32", " + "modifier 0x%"PRIX64")", buffer->base.width, buffer->base.height, + buffer->dmabuf.format, buffer->dmabuf.modifier); + + return buffer; +} + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_gbm_buffer *buffer = + get_gbm_buffer_from_buffer(wlr_buffer); + wlr_dmabuf_attributes_finish(&buffer->dmabuf); + if (buffer->gbm_bo != NULL) { + gbm_bo_destroy(buffer->gbm_bo); + } + wl_list_remove(&buffer->link); + free(buffer); +} + +static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, + struct wlr_dmabuf_attributes *attribs) { + struct wlr_gbm_buffer *buffer = + get_gbm_buffer_from_buffer(wlr_buffer); + memcpy(attribs, &buffer->dmabuf, sizeof(buffer->dmabuf)); + return true; +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .get_dmabuf = buffer_get_dmabuf, +}; + +static const struct wlr_allocator_interface allocator_impl; + +static struct wlr_gbm_allocator *get_gbm_alloc_from_alloc( + struct wlr_allocator *alloc) { + assert(alloc->impl == &allocator_impl); + return (struct wlr_gbm_allocator *)alloc; +} + +struct wlr_allocator *wlr_gbm_allocator_create(int drm_fd) { + int fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); + if (fd < 0) { + wlr_log(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); + return NULL; + } + + uint64_t cap; + if (drmGetCap(fd, DRM_CAP_PRIME, &cap) || + !(cap & DRM_PRIME_CAP_EXPORT)) { + wlr_log(WLR_ERROR, "PRIME export not supported"); + return NULL; + } + + struct wlr_gbm_allocator *alloc = calloc(1, sizeof(*alloc)); + if (alloc == NULL) { + return NULL; + } + wlr_allocator_init(&alloc->base, &allocator_impl, WLR_BUFFER_CAP_DMABUF); + + alloc->fd = fd; + wl_list_init(&alloc->buffers); + + alloc->gbm_device = gbm_create_device(fd); + if (alloc->gbm_device == NULL) { + wlr_log(WLR_ERROR, "gbm_create_device failed"); + free(alloc); + return NULL; + } + + wlr_log(WLR_DEBUG, "Created GBM allocator with backend %s", + gbm_device_get_backend_name(alloc->gbm_device)); + char *drm_name = drmGetDeviceNameFromFd2(fd); + wlr_log(WLR_DEBUG, "Using DRM node %s", drm_name); + free(drm_name); + + return &alloc->base; +} + +static void allocator_destroy(struct wlr_allocator *wlr_alloc) { + struct wlr_gbm_allocator *alloc = get_gbm_alloc_from_alloc(wlr_alloc); + + // The gbm_bo objects need to be destroyed before the gbm_device + struct wlr_gbm_buffer *buf, *buf_tmp; + wl_list_for_each_safe(buf, buf_tmp, &alloc->buffers, link) { + gbm_bo_destroy(buf->gbm_bo); + buf->gbm_bo = NULL; + wl_list_remove(&buf->link); + wl_list_init(&buf->link); + } + + gbm_device_destroy(alloc->gbm_device); + close(alloc->fd); + free(alloc); +} + +static struct wlr_buffer *allocator_create_buffer( + struct wlr_allocator *wlr_alloc, int width, int height, + const struct wlr_drm_format *format) { + struct wlr_gbm_allocator *alloc = get_gbm_alloc_from_alloc(wlr_alloc); + struct wlr_gbm_buffer *buffer = create_buffer(alloc, width, height, format); + if (buffer == NULL) { + return NULL; + } + return &buffer->base; +} + +static const struct wlr_allocator_interface allocator_impl = { + .destroy = allocator_destroy, + .create_buffer = allocator_create_buffer, +}; diff --git a/render/allocator/meson.build b/render/allocator/meson.build new file mode 100644 index 00000000..db17ccb2 --- /dev/null +++ b/render/allocator/meson.build @@ -0,0 +1,9 @@ +wlr_files += files( + 'allocator.c', + 'gbm.c', + 'shm.c', + 'drm_dumb.c', +) + +has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm]) +add_project_arguments('-DHAS_GBM_BO_GET_FD_FOR_PLANE=@0@'.format(has.to_int()), language: 'c') diff --git a/render/allocator/shm.c b/render/allocator/shm.c new file mode 100644 index 00000000..7b32cf8d --- /dev/null +++ b/render/allocator/shm.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include "render/pixel_format.h" +#include "render/allocator/shm.h" +#include "util/shm.h" + +static const struct wlr_buffer_impl buffer_impl; + +static struct wlr_shm_buffer *shm_buffer_from_buffer( + struct wlr_buffer *wlr_buffer) { + assert(wlr_buffer->impl == &buffer_impl); + return (struct wlr_shm_buffer *)wlr_buffer; +} + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_shm_buffer *buffer = shm_buffer_from_buffer(wlr_buffer); + munmap(buffer->data, buffer->size); + close(buffer->shm.fd); + free(buffer); +} + +static bool buffer_get_shm(struct wlr_buffer *wlr_buffer, + struct wlr_shm_attributes *shm) { + struct wlr_shm_buffer *buffer = shm_buffer_from_buffer(wlr_buffer); + memcpy(shm, &buffer->shm, sizeof(*shm)); + return true; +} + +static bool shm_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, + void **data, uint32_t *format, size_t *stride) { + struct wlr_shm_buffer *buffer = shm_buffer_from_buffer(wlr_buffer); + *data = buffer->data; + *format = buffer->shm.format; + *stride = buffer->shm.stride; + return true; +} + +static void shm_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) { + // This space is intentionally left blank +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .get_shm = buffer_get_shm, + .begin_data_ptr_access = shm_buffer_begin_data_ptr_access, + .end_data_ptr_access = shm_buffer_end_data_ptr_access, +}; + +static struct wlr_buffer *allocator_create_buffer( + struct wlr_allocator *wlr_allocator, int width, int height, + const struct wlr_drm_format *format) { + const struct wlr_pixel_format_info *info = + drm_get_pixel_format_info(format->format); + if (info == NULL) { + wlr_log(WLR_ERROR, "Unsupported pixel format 0x%"PRIX32, format->format); + return NULL; + } + + struct wlr_shm_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + return NULL; + } + wlr_buffer_init(&buffer->base, &buffer_impl, width, height); + + // TODO: consider using a single file for multiple buffers + int bytes_per_pixel = info->bpp / 8; + int stride = width * bytes_per_pixel; // TODO: align? + buffer->size = stride * height; + buffer->shm.fd = allocate_shm_file(buffer->size); + if (buffer->shm.fd < 0) { + free(buffer); + return NULL; + } + + buffer->shm.format = format->format; + buffer->shm.width = width; + buffer->shm.height = height; + buffer->shm.stride = stride; + buffer->shm.offset = 0; + + buffer->data = mmap(NULL, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, + buffer->shm.fd, 0); + if (buffer->data == MAP_FAILED) { + wlr_log_errno(WLR_ERROR, "mmap failed"); + close(buffer->shm.fd); + free(buffer); + return NULL; + } + + return &buffer->base; +} + +static void allocator_destroy(struct wlr_allocator *wlr_allocator) { + free(wlr_allocator); +} + +static const struct wlr_allocator_interface allocator_impl = { + .destroy = allocator_destroy, + .create_buffer = allocator_create_buffer, +}; + +struct wlr_allocator *wlr_shm_allocator_create(void) { + struct wlr_shm_allocator *allocator = calloc(1, sizeof(*allocator)); + if (allocator == NULL) { + return NULL; + } + wlr_allocator_init(&allocator->base, &allocator_impl, + WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_SHM); + + wlr_log(WLR_DEBUG, "Created shm allocator"); + return &allocator->base; +} diff --git a/render/drm_dumb_allocator.c b/render/drm_dumb_allocator.c deleted file mode 100644 index c0038dff..00000000 --- a/render/drm_dumb_allocator.c +++ /dev/null @@ -1,248 +0,0 @@ -#define _POSIX_C_SOURCE 200809L - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "render/drm_dumb_allocator.h" -#include "render/pixel_format.h" - -static const struct wlr_buffer_impl buffer_impl; - -static struct wlr_drm_dumb_buffer *drm_dumb_buffer_from_buffer( - struct wlr_buffer *wlr_buf) { - assert(wlr_buf->impl == &buffer_impl); - return (struct wlr_drm_dumb_buffer *)wlr_buf; -} - -static void finish_buffer(struct wlr_drm_dumb_buffer *buf) { - if (buf->data) { - munmap(buf->data, buf->size); - } - - wlr_dmabuf_attributes_finish(&buf->dmabuf); - - if (buf->drm_fd >= 0) { - struct drm_mode_destroy_dumb destroy = { .handle = buf->handle }; - if (drmIoctl(buf->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy)) { - wlr_log_errno(WLR_ERROR, "Failed to destroy DRM dumb buffer"); - } - } - - wl_list_remove(&buf->link); -} - -static struct wlr_drm_dumb_buffer *create_buffer( - struct wlr_drm_dumb_allocator *alloc, int width, int height, - const struct wlr_drm_format *format) { - struct wlr_drm_dumb_buffer *buffer = calloc(1, sizeof(*buffer)); - if (buffer == NULL) { - return NULL; - } - wlr_buffer_init(&buffer->base, &buffer_impl, width, height); - wl_list_insert(&alloc->buffers, &buffer->link); - - const struct wlr_pixel_format_info *info = - drm_get_pixel_format_info(format->format); - if (info == NULL) { - wlr_log(WLR_ERROR, "DRM format 0x%"PRIX32" not supported", - format->format); - goto create_err; - } - - struct drm_mode_create_dumb create = {0}; - create.width = (uint32_t)width; - create.height = (uint32_t)height; - create.bpp = info->bpp; - - if (drmIoctl(alloc->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create) != 0) { - wlr_log_errno(WLR_ERROR, "Failed to create DRM dumb buffer"); - goto create_err; - } - - buffer->width = create.width; - buffer->height = create.height; - - buffer->stride = create.pitch; - buffer->handle = create.handle; - buffer->format = format->format; - - buffer->drm_fd = alloc->drm_fd; - - struct drm_mode_map_dumb map = {0}; - map.handle = buffer->handle; - - if (drmIoctl(alloc->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map) != 0) { - wlr_log_errno(WLR_ERROR, "Failed to map DRM dumb buffer"); - goto create_destroy; - } - - buffer->data = mmap(NULL, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, - alloc->drm_fd, map.offset); - if (buffer->data == MAP_FAILED) { - wlr_log_errno(WLR_ERROR, "Failed to mmap DRM dumb buffer"); - goto create_destroy; - } - - buffer->size = create.size; - - memset(buffer->data, 0, create.size); - - int prime_fd; - if (drmPrimeHandleToFD(alloc->drm_fd, buffer->handle, DRM_CLOEXEC, - &prime_fd) != 0) { - wlr_log_errno(WLR_ERROR, "Failed to get PRIME handle from GEM handle"); - goto create_destroy; - } - - buffer->dmabuf = (struct wlr_dmabuf_attributes){ - .width = buffer->width, - .height = buffer->height, - .format = format->format, - .modifier = DRM_FORMAT_MOD_INVALID, - .n_planes = 1, - .offset[0] = 0, - .stride[0] = buffer->stride, - .fd[0] = prime_fd, - }; - - wlr_log(WLR_DEBUG, "Allocated %"PRIu32"x%"PRIu32" DRM dumb buffer", - buffer->width, buffer->height); - - return buffer; - -create_destroy: - finish_buffer(buffer); -create_err: - free(buffer); - return NULL; -} - -static bool drm_dumb_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, - void **data, uint32_t *format, size_t *stride) { - struct wlr_drm_dumb_buffer *buf = drm_dumb_buffer_from_buffer(wlr_buffer); - *data = buf->data; - *stride = buf->stride; - *format = buf->format; - return true; -} - -static void drm_dumb_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) { - // This space is intentionally left blank -} - -static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, - struct wlr_dmabuf_attributes *attribs) { - struct wlr_drm_dumb_buffer *buf = drm_dumb_buffer_from_buffer(wlr_buffer); - memcpy(attribs, &buf->dmabuf, sizeof(buf->dmabuf)); - return true; -} - -static void buffer_destroy(struct wlr_buffer *wlr_buffer) { - struct wlr_drm_dumb_buffer *buf = drm_dumb_buffer_from_buffer(wlr_buffer); - finish_buffer(buf); - free(buf); -} - -static const struct wlr_buffer_impl buffer_impl = { - .destroy = buffer_destroy, - .get_dmabuf = buffer_get_dmabuf, - .begin_data_ptr_access = drm_dumb_buffer_begin_data_ptr_access, - .end_data_ptr_access = drm_dumb_buffer_end_data_ptr_access, -}; - -static const struct wlr_allocator_interface allocator_impl; - -static struct wlr_drm_dumb_allocator *drm_dumb_alloc_from_alloc( - struct wlr_allocator *wlr_alloc) { - assert(wlr_alloc->impl == &allocator_impl); - return (struct wlr_drm_dumb_allocator *)wlr_alloc; -} - -static struct wlr_buffer *allocator_create_buffer( - struct wlr_allocator *wlr_alloc, int width, int height, - const struct wlr_drm_format *drm_format) { - struct wlr_drm_dumb_allocator *alloc = drm_dumb_alloc_from_alloc(wlr_alloc); - struct wlr_drm_dumb_buffer *buffer = create_buffer(alloc, width, height, - drm_format); - if (buffer == NULL) { - return NULL; - } - return &buffer->base; -} - -static void allocator_destroy(struct wlr_allocator *wlr_alloc) { - struct wlr_drm_dumb_allocator *alloc = drm_dumb_alloc_from_alloc(wlr_alloc); - - struct wlr_drm_dumb_buffer *buf, *buf_tmp; - wl_list_for_each_safe(buf, buf_tmp, &alloc->buffers, link) { - buf->drm_fd = -1; - wl_list_remove(&buf->link); - wl_list_init(&buf->link); - } - - close(alloc->drm_fd); - free(alloc); -} - -static const struct wlr_allocator_interface allocator_impl = { - .create_buffer = allocator_create_buffer, - .destroy = allocator_destroy, -}; - -struct wlr_allocator *wlr_drm_dumb_allocator_create(int fd) { - if (!drmIsMaster(fd)) { - wlr_log(WLR_ERROR, "Cannot use DRM dumb buffers with non-master DRM FD"); - return NULL; - } - - /* Re-open the DRM node to avoid GEM handle ref'counting issues. See: - * https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/110 - * TODO: don't assume we have the permission to just open the DRM node, - * find another way to re-open it. - */ - char *path = drmGetDeviceNameFromFd2(fd); - int drm_fd = open(path, O_RDWR | O_CLOEXEC); - if (drm_fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open DRM node %s", path); - free(path); - return NULL; - } - - uint64_t has_dumb = 0; - if (drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) { - wlr_log(WLR_ERROR, "Failed to get DRM capabilities"); - free(path); - return NULL; - } - - if (has_dumb == 0) { - wlr_log(WLR_ERROR, "DRM dumb buffers not supported"); - free(path); - return NULL; - } - - struct wlr_drm_dumb_allocator *alloc = calloc(1, sizeof(*alloc)); - if (alloc == NULL) { - free(path); - return NULL; - } - wlr_allocator_init(&alloc->base, &allocator_impl, - WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF); - - alloc->drm_fd = drm_fd; - wl_list_init(&alloc->buffers); - - wlr_log(WLR_DEBUG, "Created DRM dumb allocator with node %s", path); - free(path); - return &alloc->base; -} diff --git a/render/gbm_allocator.c b/render/gbm_allocator.c deleted file mode 100644 index 154e5137..00000000 --- a/render/gbm_allocator.c +++ /dev/null @@ -1,236 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include "render/gbm_allocator.h" - -static const struct wlr_buffer_impl buffer_impl; - -static struct wlr_gbm_buffer *get_gbm_buffer_from_buffer( - struct wlr_buffer *buffer) { - assert(buffer->impl == &buffer_impl); - return (struct wlr_gbm_buffer *)buffer; -} - -static bool export_gbm_bo(struct gbm_bo *bo, - struct wlr_dmabuf_attributes *out) { - struct wlr_dmabuf_attributes attribs = {0}; - - attribs.n_planes = gbm_bo_get_plane_count(bo); - if (attribs.n_planes > WLR_DMABUF_MAX_PLANES) { - wlr_log(WLR_ERROR, "GBM BO contains too many planes (%d)", - attribs.n_planes); - return false; - } - - attribs.width = gbm_bo_get_width(bo); - attribs.height = gbm_bo_get_height(bo); - attribs.format = gbm_bo_get_format(bo); - attribs.modifier = gbm_bo_get_modifier(bo); - - int i; - int32_t handle = -1; - for (i = 0; i < attribs.n_planes; ++i) { -#if HAS_GBM_BO_GET_FD_FOR_PLANE - attribs.fd[i] = gbm_bo_get_fd_for_plane(bo, i); - (void)handle; -#else - // GBM is lacking a function to get a FD for a given plane. Instead, - // check all planes have the same handle. We can't use - // drmPrimeHandleToFD because that messes up handle ref'counting in - // the user-space driver. - union gbm_bo_handle plane_handle = gbm_bo_get_handle_for_plane(bo, i); - if (plane_handle.s32 < 0) { - wlr_log(WLR_ERROR, "gbm_bo_get_handle_for_plane failed"); - goto error_fd; - } - if (i == 0) { - handle = plane_handle.s32; - } else if (plane_handle.s32 != handle) { - wlr_log(WLR_ERROR, "Failed to export GBM BO: " - "all planes don't have the same GEM handle"); - goto error_fd; - } - - attribs.fd[i] = gbm_bo_get_fd(bo); -#endif - - if (attribs.fd[i] < 0) { - wlr_log(WLR_ERROR, "gbm_bo_get_fd failed"); - goto error_fd; - } - - attribs.offset[i] = gbm_bo_get_offset(bo, i); - attribs.stride[i] = gbm_bo_get_stride_for_plane(bo, i); - } - - memcpy(out, &attribs, sizeof(attribs)); - return true; - -error_fd: - for (int j = 0; j < i; ++j) { - close(attribs.fd[j]); - } - return false; -} - -static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc, - int width, int height, const struct wlr_drm_format *format) { - struct gbm_device *gbm_device = alloc->gbm_device; - - struct gbm_bo *bo = NULL; - bool has_modifier = true; - if (format->len > 0) { - bo = gbm_bo_create_with_modifiers(gbm_device, width, height, - format->format, format->modifiers, format->len); - } - if (bo == NULL) { - uint32_t usage = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; - if (format->len == 1 && - format->modifiers[0] == DRM_FORMAT_MOD_LINEAR) { - usage |= GBM_BO_USE_LINEAR; - } - bo = gbm_bo_create(gbm_device, width, height, format->format, usage); - has_modifier = false; - } - if (bo == NULL) { - wlr_log(WLR_ERROR, "gbm_bo_create failed"); - return NULL; - } - - struct wlr_gbm_buffer *buffer = calloc(1, sizeof(*buffer)); - if (buffer == NULL) { - gbm_bo_destroy(bo); - return NULL; - } - wlr_buffer_init(&buffer->base, &buffer_impl, width, height); - buffer->gbm_bo = bo; - wl_list_insert(&alloc->buffers, &buffer->link); - - if (!export_gbm_bo(bo, &buffer->dmabuf)) { - free(buffer); - gbm_bo_destroy(bo); - return NULL; - } - - // If the buffer has been allocated with an implicit modifier, make sure we - // don't populate the modifier field: other parts of the stack may not - // understand modifiers, and they can't strip the modifier. - if (!has_modifier) { - buffer->dmabuf.modifier = DRM_FORMAT_MOD_INVALID; - } - - wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer (format 0x%"PRIX32", " - "modifier 0x%"PRIX64")", buffer->base.width, buffer->base.height, - buffer->dmabuf.format, buffer->dmabuf.modifier); - - return buffer; -} - -static void buffer_destroy(struct wlr_buffer *wlr_buffer) { - struct wlr_gbm_buffer *buffer = - get_gbm_buffer_from_buffer(wlr_buffer); - wlr_dmabuf_attributes_finish(&buffer->dmabuf); - if (buffer->gbm_bo != NULL) { - gbm_bo_destroy(buffer->gbm_bo); - } - wl_list_remove(&buffer->link); - free(buffer); -} - -static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, - struct wlr_dmabuf_attributes *attribs) { - struct wlr_gbm_buffer *buffer = - get_gbm_buffer_from_buffer(wlr_buffer); - memcpy(attribs, &buffer->dmabuf, sizeof(buffer->dmabuf)); - return true; -} - -static const struct wlr_buffer_impl buffer_impl = { - .destroy = buffer_destroy, - .get_dmabuf = buffer_get_dmabuf, -}; - -static const struct wlr_allocator_interface allocator_impl; - -static struct wlr_gbm_allocator *get_gbm_alloc_from_alloc( - struct wlr_allocator *alloc) { - assert(alloc->impl == &allocator_impl); - return (struct wlr_gbm_allocator *)alloc; -} - -struct wlr_allocator *wlr_gbm_allocator_create(int drm_fd) { - int fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); - if (fd < 0) { - wlr_log(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); - return NULL; - } - - uint64_t cap; - if (drmGetCap(fd, DRM_CAP_PRIME, &cap) || - !(cap & DRM_PRIME_CAP_EXPORT)) { - wlr_log(WLR_ERROR, "PRIME export not supported"); - return NULL; - } - - struct wlr_gbm_allocator *alloc = calloc(1, sizeof(*alloc)); - if (alloc == NULL) { - return NULL; - } - wlr_allocator_init(&alloc->base, &allocator_impl, WLR_BUFFER_CAP_DMABUF); - - alloc->fd = fd; - wl_list_init(&alloc->buffers); - - alloc->gbm_device = gbm_create_device(fd); - if (alloc->gbm_device == NULL) { - wlr_log(WLR_ERROR, "gbm_create_device failed"); - free(alloc); - return NULL; - } - - wlr_log(WLR_DEBUG, "Created GBM allocator with backend %s", - gbm_device_get_backend_name(alloc->gbm_device)); - char *drm_name = drmGetDeviceNameFromFd2(fd); - wlr_log(WLR_DEBUG, "Using DRM node %s", drm_name); - free(drm_name); - - return &alloc->base; -} - -static void allocator_destroy(struct wlr_allocator *wlr_alloc) { - struct wlr_gbm_allocator *alloc = get_gbm_alloc_from_alloc(wlr_alloc); - - // The gbm_bo objects need to be destroyed before the gbm_device - struct wlr_gbm_buffer *buf, *buf_tmp; - wl_list_for_each_safe(buf, buf_tmp, &alloc->buffers, link) { - gbm_bo_destroy(buf->gbm_bo); - buf->gbm_bo = NULL; - wl_list_remove(&buf->link); - wl_list_init(&buf->link); - } - - gbm_device_destroy(alloc->gbm_device); - close(alloc->fd); - free(alloc); -} - -static struct wlr_buffer *allocator_create_buffer( - struct wlr_allocator *wlr_alloc, int width, int height, - const struct wlr_drm_format *format) { - struct wlr_gbm_allocator *alloc = get_gbm_alloc_from_alloc(wlr_alloc); - struct wlr_gbm_buffer *buffer = create_buffer(alloc, width, height, format); - if (buffer == NULL) { - return NULL; - } - return &buffer->base; -} - -static const struct wlr_allocator_interface allocator_impl = { - .destroy = allocator_destroy, - .create_buffer = allocator_create_buffer, -}; diff --git a/render/meson.build b/render/meson.build index 8c1793f1..b35ba7c9 100644 --- a/render/meson.build +++ b/render/meson.build @@ -6,21 +6,14 @@ elif 'auto' in renderers and get_option('auto_features').disabled() endif wlr_files += files( - 'allocator.c', 'dmabuf.c', 'drm_format_set.c', - 'gbm_allocator.c', 'pixel_format.c', - 'shm_allocator.c', 'swapchain.c', 'wlr_renderer.c', 'wlr_texture.c', - 'drm_dumb_allocator.c', ) -has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm]) -add_project_arguments('-DHAS_GBM_BO_GET_FD_FOR_PLANE=@0@'.format(has.to_int()), language: 'c') - egl = dependency('egl', required: 'gles2' in renderers) if egl.found() wlr_deps += egl @@ -32,3 +25,5 @@ if 'gles2' in renderers or 'auto' in renderers endif subdir('pixman') + +subdir('allocator') diff --git a/render/shm_allocator.c b/render/shm_allocator.c deleted file mode 100644 index 1797433f..00000000 --- a/render/shm_allocator.c +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "render/pixel_format.h" -#include "render/shm_allocator.h" -#include "util/shm.h" - -static const struct wlr_buffer_impl buffer_impl; - -static struct wlr_shm_buffer *shm_buffer_from_buffer( - struct wlr_buffer *wlr_buffer) { - assert(wlr_buffer->impl == &buffer_impl); - return (struct wlr_shm_buffer *)wlr_buffer; -} - -static void buffer_destroy(struct wlr_buffer *wlr_buffer) { - struct wlr_shm_buffer *buffer = shm_buffer_from_buffer(wlr_buffer); - munmap(buffer->data, buffer->size); - close(buffer->shm.fd); - free(buffer); -} - -static bool buffer_get_shm(struct wlr_buffer *wlr_buffer, - struct wlr_shm_attributes *shm) { - struct wlr_shm_buffer *buffer = shm_buffer_from_buffer(wlr_buffer); - memcpy(shm, &buffer->shm, sizeof(*shm)); - return true; -} - -static bool shm_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, - void **data, uint32_t *format, size_t *stride) { - struct wlr_shm_buffer *buffer = shm_buffer_from_buffer(wlr_buffer); - *data = buffer->data; - *format = buffer->shm.format; - *stride = buffer->shm.stride; - return true; -} - -static void shm_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) { - // This space is intentionally left blank -} - -static const struct wlr_buffer_impl buffer_impl = { - .destroy = buffer_destroy, - .get_shm = buffer_get_shm, - .begin_data_ptr_access = shm_buffer_begin_data_ptr_access, - .end_data_ptr_access = shm_buffer_end_data_ptr_access, -}; - -static struct wlr_buffer *allocator_create_buffer( - struct wlr_allocator *wlr_allocator, int width, int height, - const struct wlr_drm_format *format) { - const struct wlr_pixel_format_info *info = - drm_get_pixel_format_info(format->format); - if (info == NULL) { - wlr_log(WLR_ERROR, "Unsupported pixel format 0x%"PRIX32, format->format); - return NULL; - } - - struct wlr_shm_buffer *buffer = calloc(1, sizeof(*buffer)); - if (buffer == NULL) { - return NULL; - } - wlr_buffer_init(&buffer->base, &buffer_impl, width, height); - - // TODO: consider using a single file for multiple buffers - int bytes_per_pixel = info->bpp / 8; - int stride = width * bytes_per_pixel; // TODO: align? - buffer->size = stride * height; - buffer->shm.fd = allocate_shm_file(buffer->size); - if (buffer->shm.fd < 0) { - free(buffer); - return NULL; - } - - buffer->shm.format = format->format; - buffer->shm.width = width; - buffer->shm.height = height; - buffer->shm.stride = stride; - buffer->shm.offset = 0; - - buffer->data = mmap(NULL, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, - buffer->shm.fd, 0); - if (buffer->data == MAP_FAILED) { - wlr_log_errno(WLR_ERROR, "mmap failed"); - close(buffer->shm.fd); - free(buffer); - return NULL; - } - - return &buffer->base; -} - -static void allocator_destroy(struct wlr_allocator *wlr_allocator) { - free(wlr_allocator); -} - -static const struct wlr_allocator_interface allocator_impl = { - .destroy = allocator_destroy, - .create_buffer = allocator_create_buffer, -}; - -struct wlr_allocator *wlr_shm_allocator_create(void) { - struct wlr_shm_allocator *allocator = calloc(1, sizeof(*allocator)); - if (allocator == NULL) { - return NULL; - } - wlr_allocator_init(&allocator->base, &allocator_impl, - WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_SHM); - - wlr_log(WLR_DEBUG, "Created shm allocator"); - return &allocator->base; -} diff --git a/render/swapchain.c b/render/swapchain.c index fd9f8725..8d3b55f0 100644 --- a/render/swapchain.c +++ b/render/swapchain.c @@ -2,7 +2,7 @@ #include #include #include -#include "render/allocator.h" +#include "render/allocator/allocator.h" #include "render/drm_format_set.h" #include "render/swapchain.h" diff --git a/types/wlr_output.c b/types/wlr_output.c index eea282dc..65c1d926 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -17,7 +17,7 @@ #include #include #include "backend/backend.h" -#include "render/allocator.h" +#include "render/allocator/allocator.h" #include "render/drm_format_set.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" -- cgit v1.2.3