From aa6d72f904dcaa0282f400e765fdc1f6ae9b4e27 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 31 Oct 2023 19:15:25 +0100 Subject: [PATCH 1/2] render/allocator: add DMA-BUF heap allocator --- include/render/allocator/dma_heap.h | 24 ++++++ meson.build | 1 + meson_options.txt | 2 +- render/allocator/dma_heap.c | 120 ++++++++++++++++++++++++++++ render/allocator/meson.build | 11 ++- 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 include/render/allocator/dma_heap.h create mode 100644 render/allocator/dma_heap.c diff --git a/include/render/allocator/dma_heap.h b/include/render/allocator/dma_heap.h new file mode 100644 index 000000000..339cdbd90 --- /dev/null +++ b/include/render/allocator/dma_heap.h @@ -0,0 +1,24 @@ +#ifndef RENDER_ALLOCATOR_DMA_HEAP_H +#define RENDER_ALLOCATOR_DMA_HEAP_H + +#include +#include "render/allocator/allocator.h" + +struct wlr_dma_heap_buffer { + struct wlr_buffer base; + struct wlr_dmabuf_attributes dmabuf; +}; + +struct wlr_dma_heap_allocator { + struct wlr_allocator base; + int fd; +}; + +/** + * Create a new DMA-BUF heap memory allocator. + * + * Takes ownership over the FD. + */ +struct wlr_allocator *wlr_dma_heap_allocator_create(int heap_fd); + +#endif diff --git a/meson.build b/meson.build index fcc562c87..a43633734 100644 --- a/meson.build +++ b/meson.build @@ -72,6 +72,7 @@ features = { 'gles2-renderer': false, 'vulkan-renderer': false, 'gbm-allocator': false, + 'dma-heap-allocator': false, 'session': false, 'color-management': false, } diff --git a/meson_options.txt b/meson_options.txt index 35961b10e..5037b9b3c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,7 +4,7 @@ option('examples', type: 'boolean', value: true, description: 'Build example app option('icon_directory', description: 'Location used to look for cursors (default: ${datadir}/icons)', type: 'string', value: '') option('renderers', type: 'array', choices: ['auto', 'gles2', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], value: ['auto'], description: 'Select built-in backends') -option('allocators', type: 'array', choices: ['auto', 'gbm'], value: ['auto'], +option('allocators', type: 'array', choices: ['auto', 'gbm', 'dma-heap'], value: ['auto'], description: 'Select built-in allocators') option('session', type: 'feature', value: 'auto', description: 'Enable session support') option('color-management', type: 'feature', value: 'auto', description: 'Enable support for color management') diff --git a/render/allocator/dma_heap.c b/render/allocator/dma_heap.c new file mode 100644 index 000000000..57e828cde --- /dev/null +++ b/render/allocator/dma_heap.c @@ -0,0 +1,120 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "render/drm_format_set.h" +#include "render/pixel_format.h" +#include "render/allocator/dma_heap.h" + +static const struct wlr_buffer_impl buffer_impl; +static const struct wlr_allocator_interface allocator_impl; + +static struct wlr_dma_heap_buffer *dma_heap_buffer_from_buffer( + struct wlr_buffer *wlr_buffer) { + assert(wlr_buffer->impl == &buffer_impl); + struct wlr_dma_heap_buffer *buffer = wl_container_of(wlr_buffer, buffer, base); + return buffer; +} + +static struct wlr_dma_heap_allocator *dma_heap_allocator_from_allocator( + struct wlr_allocator *wlr_allocator) { + assert(wlr_allocator->impl == &allocator_impl); + struct wlr_dma_heap_allocator *alloc = wl_container_of(wlr_allocator, alloc, base); + return alloc; +} + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_dma_heap_buffer *buffer = dma_heap_buffer_from_buffer(wlr_buffer); + wlr_dmabuf_attributes_finish(&buffer->dmabuf); + free(buffer); +} + +static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, + struct wlr_dmabuf_attributes *dmabuf) { + struct wlr_dma_heap_buffer *buffer = dma_heap_buffer_from_buffer(wlr_buffer); + *dmabuf = buffer->dmabuf; + return true; +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .get_dmabuf = buffer_get_dmabuf, +}; + +static struct wlr_buffer *allocator_create_buffer( + struct wlr_allocator *wlr_allocator, int width, int height, + const struct wlr_drm_format *format) { + struct wlr_dma_heap_allocator *alloc = dma_heap_allocator_from_allocator(wlr_allocator); + + if (!wlr_drm_format_has(format, DRM_FORMAT_MOD_INVALID) && + !wlr_drm_format_has(format, DRM_FORMAT_MOD_LINEAR)) { + wlr_log(WLR_ERROR, "DMA-BUF heap allocator only supports INVALID and " + "LINEAR modifiers"); + return NULL; + } + + 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_dma_heap_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + return NULL; + } + wlr_buffer_init(&buffer->base, &buffer_impl, width, height); + + size_t stride = pixel_format_info_min_stride(info, width); // TODO: align? + struct dma_heap_allocation_data alloc_data = { + .len = stride * height, + .fd_flags = O_CLOEXEC | O_RDWR, + }; + int ret = ioctl(alloc->fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data); + if (ret != 0) { + wlr_log_errno(WLR_ERROR, "DMA_HEAP_IOCTL_ALLOC failed"); + free(buffer); + return NULL; + } + + buffer->dmabuf = (struct wlr_dmabuf_attributes){ + .width = width, + .height = height, + .format = format->format, + .modifier = DRM_FORMAT_MOD_LINEAR, + .n_planes = 1, + .offset[0] = 0, + .stride[0] = stride, + .fd[0] = alloc_data.fd, + }; + + 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_dma_heap_allocator_create(int heap_fd) { + struct wlr_dma_heap_allocator *allocator = calloc(1, sizeof(*allocator)); + if (allocator == NULL) { + return NULL; + } + wlr_allocator_init(&allocator->base, &allocator_impl, WLR_BUFFER_CAP_DMABUF); + allocator->fd = heap_fd; + return &allocator->base; +} diff --git a/render/allocator/meson.build b/render/allocator/meson.build index 730a2a41b..00a649d74 100644 --- a/render/allocator/meson.build +++ b/render/allocator/meson.build @@ -1,6 +1,6 @@ allocators = get_option('allocators') if 'auto' in allocators and get_option('auto_features').enabled() - allocators = ['gbm'] + allocators = ['gbm', 'dma-heap'] elif 'auto' in allocators and get_option('auto_features').disabled() allocators = [] endif @@ -23,3 +23,12 @@ if gbm.found() has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm]) internal_config.set10('HAVE_GBM_BO_GET_FD_FOR_PLANE', has) endif + +has_dma_heap_header = false +if 'dma-heap' in allocators or 'auto' in allocators + has_dma_heap_header = cc.check_header('linux/dma-heap.h', required: 'dma-heap' in allocators) +endif +if has_dma_heap_header + wlr_files += files('dma_heap.c') + features += { 'dma-heap-allocator': true } +endif From ac2a19e7108f5bdaf232bfae299fcc5f98cba0ce Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Oct 2024 22:12:45 +0200 Subject: [PATCH 2/2] hack: force DMA-BUF heap allocator --- render/allocator/allocator.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/render/allocator/allocator.c b/render/allocator/allocator.c index 27b08fc82..75ee4bd11 100644 --- a/render/allocator/allocator.c +++ b/render/allocator/allocator.c @@ -18,6 +18,8 @@ #include "render/allocator/gbm.h" #endif +#include "render/allocator/dma_heap.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); @@ -96,6 +98,13 @@ struct wlr_allocator *allocator_autocreate_with_drm_fd( int drm_fd) { uint32_t renderer_caps = renderer->render_buffer_caps; + int heap_fd = open("/dev/dma_heap/system", O_RDWR | O_CLOEXEC); + if (heap_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open /dev/dma_heap/system"); + return NULL; + } + return wlr_dma_heap_allocator_create(heap_fd); + struct wlr_allocator *alloc = NULL; uint32_t gbm_caps = WLR_BUFFER_CAP_DMABUF;