From 8619f42973b5e0a45d9da33b56f05d6c1f559e0d Mon Sep 17 00:00:00 2001 From: Iason Paraskevopoulos Date: Mon, 28 Oct 2024 15:49:19 +0000 Subject: [PATCH 1/3] Add helper functions to wsialloc Moves out the non ion specific code from the wsialloc ion implementation to a new wsialloc_helpers file. Change-Id: I7ca816b27eb7e68fd1f138ec7bda006b204c0cbe Signed-off-by: Iason Paraskevopoulos --- CMakeLists.txt | 2 +- util/wsialloc/wsialloc_helpers.c | 199 ++++++++++++++++++++++++++++ util/wsialloc/wsialloc_helpers.h | 52 ++++++++ util/wsialloc/wsialloc_ion.c | 217 +++---------------------------- 4 files changed, 272 insertions(+), 198 deletions(-) create mode 100644 util/wsialloc/wsialloc_helpers.c create mode 100644 util/wsialloc/wsialloc_helpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1075524..ffc8e17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ if(NOT SELECT_EXTERNAL_ALLOCATOR STREQUAL "none" AND EXTERNAL_WSIALLOC_LIBRARY S set_target_properties(wsialloc PROPERTIES C_STANDARD 99) if(SELECT_EXTERNAL_ALLOCATOR STREQUAL "ion") - target_sources(wsialloc PRIVATE util/wsialloc/wsialloc_ion.c) + target_sources(wsialloc PRIVATE util/wsialloc/wsialloc_ion.c util/wsialloc/wsialloc_helpers.c) target_link_libraries(wsialloc drm_utils) if(DEFINED KERNEL_DIR) target_include_directories(wsialloc PRIVATE "${KERNEL_DIR}/drivers/staging/android/uapi") diff --git a/util/wsialloc/wsialloc_helpers.c b/util/wsialloc/wsialloc_helpers.c new file mode 100644 index 0000000..e7b6c54 --- /dev/null +++ b/util/wsialloc/wsialloc_helpers.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2024 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wsialloc_helpers.h" +#include "format_table.h" + +#include + +/** Default alignment */ +#define WSIALLOCP_MIN_ALIGN_SZ (64u) +/** Maximum image size allowed for each dimension */ +#define MAX_IMAGE_SIZE 128000 + +typedef struct wsialloc_format_descriptor +{ + wsialloc_format format; + fmt_spec format_spec; +} wsialloc_format_descriptor; + +static uint64_t round_size_up_to_align(uint64_t size) +{ + return (size + WSIALLOCP_MIN_ALIGN_SZ - 1) & ~(WSIALLOCP_MIN_ALIGN_SZ - 1); +} + +static wsialloc_error calculate_format_properties(const wsialloc_format_descriptor *descriptor, + const wsialloc_allocate_info *info, int *strides, uint32_t *offsets, + uint64_t *total_size) +{ + assert(descriptor != NULL); + assert(info != NULL); + assert(strides != NULL); + assert(offsets != NULL); + assert(total_size != NULL); + + const uint8_t *bits_per_pixel = descriptor->format_spec.bpp; + const uint64_t flags = descriptor->format.flags; + const uint64_t modifier = descriptor->format.modifier; + const uint32_t num_planes = descriptor->format_spec.nr_planes; + + /* We currently don't support any kind of custom modifiers */ + if (modifier != DRM_FORMAT_MOD_LINEAR) + { + return WSIALLOC_ERROR_NOT_SUPPORTED; + } + /* No multi-plane format support */ + if (num_planes > 1) + { + return WSIALLOC_ERROR_NOT_SUPPORTED; + } + + size_t size = 0; + for (size_t plane = 0; plane < num_planes; plane++) + { + /* Assumes multiple of 8--rework otherwise. */ + const uint32_t plane_bytes_per_pixel = bits_per_pixel[plane] / 8; + assert(plane_bytes_per_pixel * 8 == bits_per_pixel[plane]); + + /* With large enough width, this can overflow as strides are signed. In practice, this shouldn't happen */ + strides[plane] = round_size_up_to_align(info->width * plane_bytes_per_pixel); + + offsets[plane] = size; + + size += strides[plane] * info->height; + } + *total_size = size; + return WSIALLOC_ERROR_NONE; +} + +static const fmt_spec *find_format(uint32_t fourcc) +{ + /* Mask off any bits not necessary for allocation size */ + fourcc = fourcc & (~(uint32_t)DRM_FORMAT_BIG_ENDIAN); + + /* Search table for the format*/ + for (size_t i = 0; i < fourcc_format_table_len; i++) + { + if (fourcc == fourcc_format_table[i].drm_format) + { + const fmt_spec *found_fmt = &fourcc_format_table[i]; + assert(found_fmt->nr_planes <= WSIALLOC_MAX_PLANES); + + return found_fmt; + } + } + + return NULL; +} + +static bool validate_parameters(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info, + wsialloc_allocate_result *result) +{ + if (allocator == NULL) + { + return false; + } + else if (!result) + { + return false; + } + else if (info->format_count == 0 || info->formats == NULL) + { + return false; + } + else if (info->width < 1 || info->height < 1 || info->width > MAX_IMAGE_SIZE || info->height > MAX_IMAGE_SIZE) + { + return false; + } + + return true; +} + +wsialloc_error wsiallocp_alloc(wsialloc_allocator *allocator, wsiallocp_alloc_callback fn_alloc, + const wsialloc_allocate_info *info, wsialloc_allocate_result *result) +{ + if (!validate_parameters(allocator, info, result)) + { + return WSIALLOC_ERROR_INVALID; + } + + int local_strides[WSIALLOC_MAX_PLANES]; + int local_offsets[WSIALLOC_MAX_PLANES]; + wsialloc_error err = WSIALLOC_ERROR_NONE; + wsialloc_format_descriptor selected_format_desc = {}; + + uint64_t total_size = 0; + for (size_t i = 0; i < info->format_count; i++) + { + const wsialloc_format *current_format = &info->formats[i]; + const fmt_spec *format_spec = find_format(current_format->fourcc); + if (!format_spec) + { + err = WSIALLOC_ERROR_NOT_SUPPORTED; + continue; + } + + wsialloc_format_descriptor current_format_desc = { *current_format, *format_spec }; + err = calculate_format_properties(¤t_format_desc, info, local_strides, local_offsets, &total_size); + if (err != WSIALLOC_ERROR_NONE) + { + continue; + } + + /* A compatible format was found */ + selected_format_desc = current_format_desc; + break; + } + + if (err != WSIALLOC_ERROR_NONE) + { + return err; + } + + int local_fds[WSIALLOC_MAX_PLANES] = { -1, -1, -1, -1 }; + if (!(info->flags & WSIALLOC_ALLOCATE_NO_MEMORY)) + { + local_fds[0] = fn_alloc(allocator, info, total_size); + if (local_fds[0] < 0) + { + return WSIALLOC_ERROR_NO_RESOURCE; + } + + assert(result->buffer_fds != NULL); + result->buffer_fds[0] = local_fds[0]; + for (size_t plane = 1; plane < selected_format_desc.format_spec.nr_planes; plane++) + { + result->buffer_fds[plane] = result->buffer_fds[0]; + } + } + result->format = selected_format_desc.format; + for (size_t plane = 0; plane < selected_format_desc.format_spec.nr_planes; plane++) + { + result->average_row_strides[plane] = local_strides[plane]; + result->offsets[plane] = local_offsets[plane]; + } + + result->is_disjoint = false; + return WSIALLOC_ERROR_NONE; +} \ No newline at end of file diff --git a/util/wsialloc/wsialloc_helpers.h b/util/wsialloc/wsialloc_helpers.h new file mode 100644 index 0000000..add8f1d --- /dev/null +++ b/util/wsialloc/wsialloc_helpers.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wsialloc.h" + +/** + * @brief Internal callback used in wsiallocp_alloc(). Different wsialloc implementations define this + * callback and use wsiallocp_alloc to implement the wsialloc_alloc entrypoint. + */ +typedef int (*wsiallocp_alloc_callback)(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info, + uint64_t size); +/** + * + * @brief Allocate a new buffer using the allocator + * + * A helper function to pick the best format out of a list of formats + * and allocate selected format using the allocator + * + * @param allocator The wsialloc allocator + * @param fn_alloc The function that will be called to perform the actual memory allocation + * @param info The requested allocation info + * @param[out] result The allocation result. + * @retval WSIALLOC_ERROR_NONE Indicates success + * @retval WSIALLOC_ERROR_INVALID Indicates failure in formats such as invalid fourcc + * or lack of any formats provided for selection or invalid parameters + * @retval WSIALLOC_ERROR_NOT_SUPPORTED Can indicate multiple errors, namely: + * * None of the formats are supported by the wsialloc implementation + * * The allocator does not support allocating with the selected flags + */ +wsialloc_error wsiallocp_alloc(wsialloc_allocator *allocator, wsiallocp_alloc_callback fn_alloc, + const wsialloc_allocate_info *info, wsialloc_allocate_result *result); \ No newline at end of file diff --git a/util/wsialloc/wsialloc_ion.c b/util/wsialloc/wsialloc_ion.c index 5fe79c1..04db24f 100644 --- a/util/wsialloc/wsialloc_ion.c +++ b/util/wsialloc/wsialloc_ion.c @@ -23,7 +23,7 @@ */ #include "wsialloc.h" -#include "format_table.h" +#include "wsialloc_helpers.h" #include #include @@ -53,11 +53,6 @@ const uint32_t WSIALLOC_IMPLEMENTATION_VERSION_SYMBOL = WSIALLOC_IMPLEMENTATION_VERSION; -/** Default alignment */ -#define WSIALLOCP_MIN_ALIGN_SZ (64u) -/** Maximum image size allowed for each dimension */ -#define MAX_IMAGE_SIZE 128000 - struct wsialloc_allocator { /* File descriptor of /dev/ion. */ @@ -69,12 +64,6 @@ struct wsialloc_allocator bool protected_heap_exists; }; -typedef struct wsialloc_format_descriptor -{ - wsialloc_format format; - fmt_spec format_spec; -} wsialloc_format_descriptor; - static int find_alloc_heap_id(int fd) { assert(fd != -1); @@ -123,47 +112,38 @@ static int allocate(int fd, size_t size, uint32_t heap_id) return alloc.fd; } -static uint64_t round_size_up_to_align(uint64_t size) -{ - return (size + WSIALLOCP_MIN_ALIGN_SZ - 1) & ~(WSIALLOCP_MIN_ALIGN_SZ - 1); -} - wsialloc_error wsialloc_new(wsialloc_allocator **allocator) { assert(allocator != NULL); - wsialloc_error ret = WSIALLOC_ERROR_NONE; - wsialloc_allocator *ion = malloc(sizeof(wsialloc_allocator)); if (NULL == ion) { - ret = WSIALLOC_ERROR_NO_RESOURCE; - goto fail; + wsialloc_delete(ion); + return WSIALLOC_ERROR_NO_RESOURCE; } ion->fd = open("/dev/ion", O_RDONLY); if (ion->fd < 0) { - ret = WSIALLOC_ERROR_NO_RESOURCE; - goto fail; + wsialloc_delete(ion); + return WSIALLOC_ERROR_NO_RESOURCE; } ion->alloc_heap_id = find_alloc_heap_id(ion->fd); if (ion->alloc_heap_id < 0) { - ret = WSIALLOC_ERROR_NO_RESOURCE; - goto fail; + wsialloc_delete(ion); + return WSIALLOC_ERROR_NO_RESOURCE; } ion->protected_heap_exists = false; *allocator = ion; - return ret; -fail: - wsialloc_delete(ion); - return ret; + return WSIALLOC_ERROR_NONE; } void wsialloc_delete(wsialloc_allocator *allocator) { + assert(allocator != NULL); if (NULL == allocator) { return; @@ -172,200 +152,43 @@ void wsialloc_delete(wsialloc_allocator *allocator) if (allocator->fd >= 0) { close(allocator->fd); + allocator->fd = -1; } free(allocator); } -static wsialloc_error calculate_format_properties(const wsialloc_format_descriptor *descriptor, - const wsialloc_allocate_info *info, int *strides, uint32_t *offsets) -{ - assert(descriptor != NULL); - assert(info != NULL); - assert(strides != NULL); - assert(offsets != NULL); - - const uint8_t *bits_per_pixel = descriptor->format_spec.bpp; - const uint64_t flags = descriptor->format.flags; - const uint64_t modifier = descriptor->format.modifier; - const uint32_t num_planes = descriptor->format_spec.nr_planes; - - /* We currently don't support any kind of custom modifiers */ - if (modifier != DRM_FORMAT_MOD_LINEAR) - { - return WSIALLOC_ERROR_NOT_SUPPORTED; - } - /* No multi-plane format support */ - if (num_planes > 1) - { - return WSIALLOC_ERROR_NOT_SUPPORTED; - } - - size_t size = 0; - for (size_t plane = 0; plane < num_planes; plane++) - { - /* Assumes multiple of 8--rework otherwise. */ - const uint32_t plane_bytes_per_pixel = bits_per_pixel[plane] / 8; - assert(plane_bytes_per_pixel * 8 == bits_per_pixel[plane]); - - /* With large enough width, this can overflow as strides are signed. In practice, this shouldn't happen */ - strides[plane] = round_size_up_to_align(info->width * plane_bytes_per_pixel); - - offsets[plane] = size; - - size += strides[plane] * info->height; - } - - return WSIALLOC_ERROR_NONE; -} - -static wsialloc_error allocate_format(const wsialloc_allocator *allocator, const wsialloc_format_descriptor *descriptor, - const wsialloc_allocate_info *info, const int *strides, const uint32_t *offsets, - int *buffer_fds) +static int ion_allocate(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info, uint64_t size) { assert(allocator != NULL); - assert(descriptor != NULL); assert(info != NULL); - assert(offsets != NULL); - assert(strides != NULL); - assert(strides[0] >= 0); - assert(buffer_fds != NULL); - - const uint64_t flags = descriptor->format.flags; - const uint32_t num_planes = descriptor->format_spec.nr_planes; + assert(allocator->fd != -1); + assert(size > 0); /* The only error that can be encountered on allocations is lack of resources. Other parameter validation and * support checks are done on format selection. */ - assert(num_planes == 1); uint32_t alloc_heap_id = allocator->alloc_heap_id; if (info->flags & WSIALLOC_ALLOCATE_PROTECTED) { - /* Exit if we don't support allocating protected memory */ + /* Exit if we don't support allocating protected memory. */ if (!allocator->protected_heap_exists) { - return WSIALLOC_ERROR_NO_RESOURCE; + assert(false); + return -1; } alloc_heap_id = allocator->protected_alloc_heap_id; } - uint64_t total_size = offsets[0] + (uint64_t)strides[0] * info->height; - if (total_size > SIZE_MAX) - { - return WSIALLOC_ERROR_NO_RESOURCE; - } - buffer_fds[0] = allocate(allocator->fd, (size_t)total_size, alloc_heap_id); - - if (buffer_fds[0] < 0) - { - return WSIALLOC_ERROR_NO_RESOURCE; - } - - return WSIALLOC_ERROR_NONE; -} - -static const fmt_spec *find_format(uint32_t fourcc) -{ - /* Mask off any bits not necessary for allocation size */ - fourcc = fourcc & (~(uint32_t)DRM_FORMAT_BIG_ENDIAN); - - /* Search table for the format*/ - for (size_t i = 0; i < fourcc_format_table_len; i++) - { - if (fourcc == fourcc_format_table[i].drm_format) - { - const fmt_spec *found_fmt = &fourcc_format_table[i]; - assert(found_fmt->nr_planes <= WSIALLOC_MAX_PLANES); - - return found_fmt; - } - } - - return NULL; -} - -static bool validate_parameters(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info, - wsialloc_allocate_result *result) -{ - if (allocator == NULL) - { - return false; - } - else if (!result) - { - return false; - } - else if (info->format_count == 0 || info->formats == NULL) - { - return false; - } - else if (info->width < 1 || info->height < 1 || info->width > MAX_IMAGE_SIZE || info->height > MAX_IMAGE_SIZE) - { - return false; - } - - return true; + return allocate(allocator->fd, size, alloc_heap_id); } wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info, wsialloc_allocate_result *result) { - assert(allocator != NULL); - assert(info != NULL); - assert(result != NULL); - - if (!validate_parameters(allocator, info, result)) + if ((info->flags & WSIALLOC_ALLOCATE_PROTECTED) && (!allocator->protected_heap_exists)) { - return WSIALLOC_ERROR_INVALID; + return WSIALLOC_ERROR_NO_RESOURCE; } - int local_strides[WSIALLOC_MAX_PLANES]; - int local_fds[WSIALLOC_MAX_PLANES] = { -1 }; - int local_offsets[WSIALLOC_MAX_PLANES]; - wsialloc_error err = WSIALLOC_ERROR_NONE; - wsialloc_format_descriptor selected_format_desc = {}; - - for (size_t i = 0; i < info->format_count; i++) - { - const wsialloc_format *current_format = &info->formats[i]; - const fmt_spec *format_spec = find_format(current_format->fourcc); - if (!format_spec) - { - err = WSIALLOC_ERROR_NOT_SUPPORTED; - continue; - } - - wsialloc_format_descriptor current_format_desc = { *current_format, *format_spec }; - err = calculate_format_properties(¤t_format_desc, info, local_strides, local_offsets); - if (err != WSIALLOC_ERROR_NONE) - { - continue; - } - - /* A compatible format was found */ - selected_format_desc = current_format_desc; - break; - } - - if (err == WSIALLOC_ERROR_NONE) - { - if (!(info->flags & WSIALLOC_ALLOCATE_NO_MEMORY)) - { - err = allocate_format(allocator, &selected_format_desc, info, local_strides, local_offsets, local_fds); - } - } - - if (err == WSIALLOC_ERROR_NONE) - { - result->format = selected_format_desc.format; - result->average_row_strides[0] = local_strides[0]; - result->offsets[0] = local_offsets[0]; - if (!(info->flags & WSIALLOC_ALLOCATE_NO_MEMORY)) - { - result->buffer_fds[0] = local_fds[0]; - } - - result->is_disjoint = false; - } - - return err; + return wsiallocp_alloc(allocator, ion_allocate, info, result); } From cd19e3827b2ef91986a942d153e927598dc08cae Mon Sep 17 00:00:00 2001 From: Iason Paraskevopoulos Date: Mon, 28 Oct 2024 16:58:52 +0000 Subject: [PATCH 2/3] Add dma_buf_heaps wsialloc implementation Change-Id: I738f8cbfb1aec52a122689ebaeb7f5b898ba200a Signed-off-by: Iason Paraskevopoulos --- CMakeLists.txt | 13 +- README.md | 8 +- util/wsialloc/wsialloc_dma_buf_heaps.c | 174 +++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 util/wsialloc/wsialloc_dma_buf_heaps.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ffc8e17..ee36c7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,8 +60,9 @@ option(BUILD_WSI_HEADLESS "Build with support for VK_EXT_headless_surface" ON) option(BUILD_WSI_WAYLAND "Build with support for VK_KHR_wayland_surface" OFF) option(BUILD_WSI_DISPLAY "Build with support for VK_KHR_display" OFF) -set(SELECT_EXTERNAL_ALLOCATOR "none" CACHE STRING "Select an external system allocator (none, ion)") +set(SELECT_EXTERNAL_ALLOCATOR "none" CACHE STRING "Select an external system allocator (none, ion, dma_buf_heaps)") set(EXTERNAL_WSIALLOC_LIBRARY "" CACHE STRING "External implementation of the wsialloc interface to use") +set(WSIALLOC_MEMORY_HEAP_NAME "linux,cma" CACHE STRING "Heap name used by the dma_buf_heaps allocator") # Optional features option(BUILD_WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN "Build with support for VK_EXT_image_compression_control_swapchain" OFF) @@ -108,12 +109,22 @@ if(NOT SELECT_EXTERNAL_ALLOCATOR STREQUAL "none" AND EXTERNAL_WSIALLOC_LIBRARY S else() message(FATAL_ERROR "KERNEL_DIR must be defined as the root of the Linux kernel source.") endif() + elseif(SELECT_EXTERNAL_ALLOCATOR STREQUAL "dma_buf_heaps") + target_sources(wsialloc PRIVATE util/wsialloc/wsialloc_dma_buf_heaps.c util/wsialloc/wsialloc_helpers.c) + target_link_libraries(wsialloc drm_utils) + if(DEFINED KERNEL_DIR) + target_include_directories(wsialloc PRIVATE "${KERNEL_DIR}/usr/include") + else() + message(FATAL_ERROR "KERNEL_DIR must be defined as the root of the Linux kernel source.") + endif() + add_definitions(-Ulinux -DWSIALLOC_MEMORY_HEAP_NAME=${WSIALLOC_MEMORY_HEAP_NAME}) else() message(FATAL_ERROR "Invalid external allocator selected: ${SELECT_EXTERNAL_ALLOCATOR}") endif() target_include_directories(wsialloc PRIVATE ${VULKAN_CXX_INCLUDE}) target_include_directories(wsialloc PRIVATE util/drm) + target_include_directories(wsialloc PRIVATE util/) endif() # Wayland WSI diff --git a/README.md b/README.md index fc2603c..3c87119 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ make -C build In order to build with Wayland support the `BUILD_WSI_WAYLAND` build option must be used, the `SELECT_EXTERNAL_ALLOCATOR` option has to be set to -a graphics memory allocator (currently only ion is supported) and +a graphics memory allocator (currently only ion and dma_buf_heaps are supported) and the `KERNEL_DIR` option must be defined as the root of the Linux kernel source. @@ -122,9 +122,9 @@ also responsible for selecting a suitable format that can be efficiently shared between the different devices in the system, e.g. GPU, display. It is therefore an important point of integration. It is expected that each system will need a tailored implementation, although the layer -provides a generic ion implementation that may work in systems that support -linear formats. This is selected by the `-DSELECT_EXTERNAL_ALLOCATOR=ion` -option, as shown above. +provides a generic ion and dma_buf_heaps implementations that may work in +systems that support linear formats. This is selected by +the `-DSELECT_EXTERNAL_ALLOCATOR=ion` option, as shown above. ### Wayland support with FIFO presentation mode diff --git a/util/wsialloc/wsialloc_dma_buf_heaps.c b/util/wsialloc/wsialloc_dma_buf_heaps.c new file mode 100644 index 0000000..a4c88f0 --- /dev/null +++ b/util/wsialloc/wsialloc_dma_buf_heaps.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2024 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wsialloc.h" +#include "wsialloc_helpers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Version of the wsialloc interface we are implementing in this file. + * + * This should only be increased when this implementation is updated to match newer versions of wsialloc.h. + */ +#define WSIALLOC_IMPLEMENTATION_VERSION 3 + +/* Ensure we are implementing the wsialloc version matching the wsialloc.h header we are using. */ +#if WSIALLOC_IMPLEMENTATION_VERSION != WSIALLOC_INTERFACE_VERSION +#error "Version mismatch between wsialloc implementation and interface version" +#endif + +const uint32_t WSIALLOC_IMPLEMENTATION_VERSION_SYMBOL = WSIALLOC_IMPLEMENTATION_VERSION; + +/* Some string may contain commas, setting the macro as variadic */ +#define STR_EXPAND(tok...) #tok +#define STR(tok) STR_EXPAND(tok) + +struct wsialloc_allocator +{ + /* File descriptor for a DMA-BUF heap for allocating memory accessible to + * the windowing system (display, compositor, etc.) + */ + int memory_fd; + + /* File descriptor for a DMA-BUF heap for allocating protected memory + * accessible to the windowing system. + */ + int protected_fd; +}; + +static int allocate(int fd, uint64_t size) +{ + assert(size > 0); + assert(fd != -1); + + struct dma_heap_allocation_data heap_data = { + .len = size, + .fd_flags = O_RDWR | O_CLOEXEC, + }; + + int ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &heap_data); + if (ret != 0) + { + return -errno; + } + assert(heap_data.fd > 0); + return heap_data.fd; +} + +static int dma_allocate(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info, uint64_t size) +{ + assert(allocator != NULL); + assert(info != NULL); + assert(size > 0); + + /* The only error that can be encountered on allocations is lack of resources. Other parameter validation and + * support checks are done on format selection. */ + int alloc_fd = allocator->memory_fd; + if (info->flags & WSIALLOC_ALLOCATE_PROTECTED) + { + alloc_fd = allocator->protected_fd; + } + if (alloc_fd < 0) + { + assert(false); + return -1; + } + + return allocate(alloc_fd, size); +} + +wsialloc_error wsialloc_new(wsialloc_allocator **allocator) +{ + assert(allocator != NULL); + + wsialloc_allocator *dma_buf_heaps = malloc(sizeof(*dma_buf_heaps)); + if (NULL == dma_buf_heaps) + { + return WSIALLOC_ERROR_NO_RESOURCE; + } + + dma_buf_heaps->memory_fd = open("/dev/dma_heap/" STR(WSIALLOC_MEMORY_HEAP_NAME), O_RDWR); + dma_buf_heaps->protected_fd = -1; + + if (dma_buf_heaps->memory_fd < 0) + { + free(dma_buf_heaps); + return WSIALLOC_ERROR_NO_RESOURCE; + } + + *allocator = dma_buf_heaps; + return WSIALLOC_ERROR_NONE; +} + +static void close_fd(int fd) +{ + if (fd >= 0) + { + close(fd); + } +} + +void wsialloc_delete(wsialloc_allocator *allocator) +{ + assert(allocator != NULL); + if (NULL == allocator) + { + return; + } + + close_fd(allocator->memory_fd); + close_fd(allocator->protected_fd); + + allocator->memory_fd = -1; + allocator->protected_fd = -1; + + free(allocator); +} + +wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info, + wsialloc_allocate_result *result) +{ + int fd_to_use = allocator->memory_fd; + if (info->flags & WSIALLOC_ALLOCATE_PROTECTED) + { + fd_to_use = allocator->protected_fd; + } + if (fd_to_use < 0) + { + return WSIALLOC_ERROR_NO_RESOURCE; + } + return wsiallocp_alloc(allocator, dma_allocate, info, result); +} From be2fee504365fe89c5e69b3dfe324fe92f9353eb Mon Sep 17 00:00:00 2001 From: Iason Paraskevopoulos Date: Wed, 30 Oct 2024 15:11:52 +0000 Subject: [PATCH 3/3] Rename KERNEL_DIR to KERNEL_HEADER_DIR Renames KERNEL_DIR to KERNEL_HEADER_DIR to allow getting the kernel headers from a directory that is not coupled with the kernel source tree. Change-Id: Ic98b39dd2ec117ef4bc413cb3bf86eee89ebe4fd Signed-off-by: Iason Paraskevopoulos --- CMakeLists.txt | 12 ++++++------ README.md | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee36c7d..a998973 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,18 +104,18 @@ if(NOT SELECT_EXTERNAL_ALLOCATOR STREQUAL "none" AND EXTERNAL_WSIALLOC_LIBRARY S if(SELECT_EXTERNAL_ALLOCATOR STREQUAL "ion") target_sources(wsialloc PRIVATE util/wsialloc/wsialloc_ion.c util/wsialloc/wsialloc_helpers.c) target_link_libraries(wsialloc drm_utils) - if(DEFINED KERNEL_DIR) - target_include_directories(wsialloc PRIVATE "${KERNEL_DIR}/drivers/staging/android/uapi") + if(DEFINED KERNEL_HEADER_DIR) + target_include_directories(wsialloc PRIVATE "${KERNEL_HEADER_DIR}") else() - message(FATAL_ERROR "KERNEL_DIR must be defined as the root of the Linux kernel source.") + message(FATAL_ERROR "KERNEL_HEADER_DIR must be defined as the directory that includes the kernel headers.") endif() elseif(SELECT_EXTERNAL_ALLOCATOR STREQUAL "dma_buf_heaps") target_sources(wsialloc PRIVATE util/wsialloc/wsialloc_dma_buf_heaps.c util/wsialloc/wsialloc_helpers.c) target_link_libraries(wsialloc drm_utils) - if(DEFINED KERNEL_DIR) - target_include_directories(wsialloc PRIVATE "${KERNEL_DIR}/usr/include") + if(DEFINED KERNEL_HEADER_DIR) + target_include_directories(wsialloc PRIVATE "${KERNEL_HEADER_DIR}") else() - message(FATAL_ERROR "KERNEL_DIR must be defined as the root of the Linux kernel source.") + message(FATAL_ERROR "KERNEL_HEADER_DIR must be defined as the directory that includes the kernel headers.") endif() add_definitions(-Ulinux -DWSIALLOC_MEMORY_HEAP_NAME=${WSIALLOC_MEMORY_HEAP_NAME}) else() diff --git a/README.md b/README.md index 3c87119..7df6bc8 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ make -C build In order to build with Wayland support the `BUILD_WSI_WAYLAND` build option must be used, the `SELECT_EXTERNAL_ALLOCATOR` option has to be set to a graphics memory allocator (currently only ion and dma_buf_heaps are supported) and -the `KERNEL_DIR` option must be defined as the root of the Linux kernel +the `KERNEL_HEADER_DIR` option must be defined as the directory that includes the kernel headers. source. ``` @@ -98,7 +98,7 @@ cmake . -DVULKAN_CXX_INCLUDE="path/to/vulkan-header" \ -DBUILD_WSI_HEADLESS=0 \ -DBUILD_WSI_WAYLAND=1 \ -DSELECT_EXTERNAL_ALLOCATOR=ion \ - -DKERNEL_DIR="path/to/linux-kernel-source" + -DKERNEL_HEADER_DIR="path/to/linux-kernel-headers" ``` In the command line above, `-DBUILD_WSI_HEADLESS=0` is used to disable support @@ -111,7 +111,7 @@ using the `EXTERNAL_WSIALLOC_LIBRARY` option. For example, cmake . -DVULKAN_CXX_INCLUDE="path/to/vulkan-header" \ -DBUILD_WSI_WAYLAND=1 \ -DEXTERNAL_WSIALLOC_LIBRARY="path/to/custom/libwsialloc" \ - -DKERNEL_DIR="path/to/linux-kernel-source" + -DKERNEL_HEADER_DIR="path/to/linux-kernel-headers" ``` The `EXTERNAL_WSIALLOC_LIBRARY` option allows to specify the path to a library