Merge 'Add dma_buf_heaps wsialloc implementation' into 'main'

See merge request mesa/vulkan-wsi-layer!124
This commit is contained in:
Iason Paraskevopoulos 2024-11-11 14:20:33 +00:00
commit 4bd840fdb6
6 changed files with 468 additions and 209 deletions

View file

@ -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)
@ -101,19 +102,29 @@ 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")
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_HEADER_DIR)
target_include_directories(wsialloc PRIVATE "${KERNEL_HEADER_DIR}")
else()
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()
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

View file

@ -89,8 +89,8 @@ 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
the `KERNEL_DIR` option must be defined as the root of the Linux kernel
a graphics memory allocator (currently only ion and dma_buf_heaps are supported) and
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
@ -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

View file

@ -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 <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <linux/dma-heap.h>
/**
* @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);
}

View file

@ -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 <assert.h>
/** 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(&current_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;
}

View file

@ -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);

View file

@ -23,7 +23,7 @@
*/
#include "wsialloc.h"
#include "format_table.h"
#include "wsialloc_helpers.h"
#include <assert.h>
#include <errno.h>
@ -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(&current_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);
}