Extend wsialloc_alloc with disjoint information

Extends wsialloc_alloc to return whether or not the allocation will be
disjoint.

Groups wsialloc_alloc's return values to a struct.

Change-Id: I7542e37d8af16ce7989ab235c02305d562f3c667
Signed-off-by: Iason Paraskevopoulos <iason.paraskevopoulos@arm.com>
This commit is contained in:
Iason Paraskevopoulos 2024-05-23 14:53:26 +01:00
parent 8a74233de2
commit b02486ff87
4 changed files with 97 additions and 57 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2019, 2021-2022 Arm Limited. * Copyright (c) 2017-2024 Arm Limited.
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
@ -31,7 +31,12 @@
#define _WSIALLOC_H_ #define _WSIALLOC_H_
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <drm_fourcc.h> #include <drm_fourcc.h>
#pragma GCC diagnostic pop
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -57,9 +62,10 @@ extern "C" {
* Version History: * Version History:
* 1 - Initial wsialloc interface * 1 - Initial wsialloc interface
* 2 - Added WSIALLOC_ALLOCATE_HIGHEST_FIXED_RATE_COMPRESSION * 2 - Added WSIALLOC_ALLOCATE_HIGHEST_FIXED_RATE_COMPRESSION
* 3 - Grouped the return values of wsialloc_alloc to wsialloc_allocate_result and added another value for returning
* whether or not the allocation will be disjoint.
*/ */
#define WSIALLOC_INTERFACE_VERSION 3
#define WSIALLOC_INTERFACE_VERSION 2
#define WSIALLOC_CONCAT(x, y) x##y #define WSIALLOC_CONCAT(x, y) x##y
#define WSIALLOC_SYMBOL_VERSION(symbol, version) WSIALLOC_CONCAT(symbol, version) #define WSIALLOC_SYMBOL_VERSION(symbol, version) WSIALLOC_CONCAT(symbol, version)
@ -159,63 +165,75 @@ typedef struct wsialloc_format
typedef struct wsialloc_allocate_info typedef struct wsialloc_allocate_info
{ {
wsialloc_format *formats; /** List of formats to select from for the allocation */ wsialloc_format *formats; /** List of formats to select from for the allocation. */
unsigned format_count; /** Number of elements in formats array */ unsigned format_count; /** Number of elements in formats array. */
uint32_t width; /** The number of pixel columns required in the buffer. */ uint32_t width; /** The number of pixel columns required in the buffer. */
uint32_t height; /** The number of pixel rows required in the buffer. */ uint32_t height; /** The number of pixel rows required in the buffer. */
uint64_t flags; /** Set of @r wsialloc_allocate_flag allocation flags. */ uint64_t flags; /** Set of @r wsialloc_allocate_flag allocation flags. */
} wsialloc_allocate_info; } wsialloc_allocate_info;
typedef struct wsialloc_allocate_result
{
wsialloc_format format; /** The selected format for allocation. */
/** Per plane distance between rows of blocks divided by the block height measured in bytes. */
int average_row_strides[WSIALLOC_MAX_PLANES];
/** Per plane offset into the file descriptor for the start of the plane. */
uint32_t offsets[WSIALLOC_MAX_PLANES];
int buffer_fds[WSIALLOC_MAX_PLANES]; /** Per plane file descriptor for the buffer. */
bool is_disjoint; /** Whether different fds will be used for each plane. */
} wsialloc_allocate_result;
/** /**
* @brief Allocate a buffer from the WSI Allocator * @brief Allocate a buffer from the WSI Allocator
* *
* Allocate a buffer of size @p info::width x @p info::height in a way that is suitable for the underlying * Allocate a buffer of size @p info::width x @p info::height in a way that is suitable for the underlying
* window system and GPU. * window system and GPU.
* *
* The allocation is made using a format from the list specified in @p info::formats . On success, @p format is set with * The allocation is made using a format from the list specified in @p info::formats . On success, @p result::format is set with
* the selected format that was used for the allocation. * the selected format that was used for the allocation.
* *
* Each plane is returned as a file descriptor. All other information returned about the buffer is also per-plane. It is * Each plane is returned as a file descriptor. All other information returned about the buffer is also per-plane. It is
* assumed the caller already knows how many planes are implied by the @p format that was selected. * assumed the caller already knows how many planes are implied by the @p result::format that was selected.
* *
* Each row in the buffer may be larger than @p info::width to account for buffer alignment requirements in the * Each row in the buffer may be larger than @p info::width to account for buffer alignment requirements in the
* underlying window system. @p strides must be examined to determine the number of bytes between subsequent rows * underlying window system. @p result::average_row_strides must be examined to determine the number of bytes between
* in each of the buffer's planes. Only positive strides are allowed. * subsequent rows in each of the buffer's planes. Only positive average_row_strides are allowed.
* *
* The client may free the buffer's planes by invoking close() on some or all of the elements of @p buffer_fds * The client may free the buffer's planes by invoking close() on some or all of the elements of @p result::buffer_fds
* *
* The same file descriptor ('fd') may be written to different elements of @p buffer_fds more than once, for some or all * The same file descriptor ('fd') may be written to different elements of @p result::buffer_fds more than once, for some or all
* of the planes. In this case: * of the planes. In this case:
* - @p offsets @b must be used to determine where each plane starts in the file descriptor * - @p result::offsets @b must be used to determine where each plane starts in the file descriptor
* - When the client frees the buffer, each unique fd in @p buffer_fds must only be closed once. * - When the client frees the buffer, each unique fd in @p result::buffer_fds must only be closed once.
* *
* Even if @p buffer_fds are all different or @p format is for a single plane, then the client must inspect @p offsets * Even if @p result::buffer_fds are all different or @p result::format is for a single plane, then the client must inspect
* in case it contains non-zero values. * @p result::offsets in case it contains non-zero values.
* *
* @note The implementation might not export the file descriptors in @p buffer_fds in such a way that allows the client * If @p result::buffer_fds are different then @p result::disjoint should be set to true.
*
* @note The implementation might not export the file descriptors in @p result::buffer_fds in such a way that allows the client
* to directly map them on the CPU as writable (PROT_WRITE). * to directly map them on the CPU as writable (PROT_WRITE).
* *
* The selected @p format modifier allows for a fourcc_mod_code() (as defined in drm_fourcc.h) to define * The selected @p result::format modifier allows for a fourcc_mod_code() (as defined in drm_fourcc.h) to define
* a reordering or other modification of the data in the buffer's planes (e.g. compression, * a reordering or other modification of the data in the buffer's planes (e.g. compression,
* change in number of planes, etc). * change in number of planes, etc).
* *
* @p strides is the per plane row byte stride of the @p format. For linear formats this is the number of bytes from the * @p result::average_row_strides are per plane row average byte strides of the @p result::format. This is the number of bytes from the
* start of a row to the start of the next row. For block based formats it is the number of bytes from the start of one * start of a row of blocks divided by the block height. It may also have format specific meaning for formats not in those
* row of blocks to the start of the next. It may also have format specific meaning for formats not in those categories. * categories.
* *
* @p strides and @p offsets may have modifier-specific meaning when a @p format with modifier is selected. * @p result::average_row_strides and @p result::offsets may have modifier-specific
* meaning when a @p result::format with modifier is selected.
* *
* @pre @p strides, @p buffer_fds, @p offsets are pointers to storage large enough to hold per-plane information * @pre @p result::average_row_strides, @p result::buffer_fds, @p result::offsets
* are pointers to storage large enough to hold per-plane information.
* @pre @p info::width >=1 && @p info::height >= 1 * @pre @p info::width >=1 && @p info::height >= 1
* @pre @p allocator is a currently valid WSI Allocator from wsialloc_new() * @pre @p allocator is a currently valid WSI Allocator from wsialloc_new()
* @post The allocated buffer will be zeroed. * @post The allocated buffer will be zeroed.
* *
* @param allocator The WSI Allocator to allocate from. * @param allocator The WSI Allocator to allocate from.
* @param[in] info The requested allocation information. * @param[in] info The requested allocation information.
* @param[out] format The selected format for allocation. * @param[out] result The allocation's result.
* @param[out] strides Per-plane row byte stride of the buffer.
* @param[out] buffer_fds Per-plane file descriptors for the buffer.
* @param[out] offsets Per-plane offset into the file descriptor for the start of the plane.
* @retval WSIALLOC_ERROR_NONE on successful buffer allocation. * @retval WSIALLOC_ERROR_NONE on successful buffer allocation.
* @retval WSIALLOC_ERROR_INVALID is returned for invalid parameters. * @retval WSIALLOC_ERROR_INVALID is returned for invalid parameters.
@ -226,7 +244,7 @@ typedef struct wsialloc_allocate_info
*/ */
wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info, wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info,
wsialloc_format *format, int *strides, int *buffer_fds, uint32_t *offsets); wsialloc_allocate_result *result);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2019, 2021-2022 Arm Limited. * Copyright (c) 2017-2024 Arm Limited.
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
@ -44,7 +44,7 @@
* *
* This should only be increased when this implementation is updated to match newer versions of wsialloc.h. * This should only be increased when this implementation is updated to match newer versions of wsialloc.h.
*/ */
#define WSIALLOC_IMPLEMENTATION_VERSION 2 #define WSIALLOC_IMPLEMENTATION_VERSION 3
/* Ensure we are implementing the wsialloc version matching the wsialloc.h header we are using. */ /* Ensure we are implementing the wsialloc version matching the wsialloc.h header we are using. */
#if WSIALLOC_IMPLEMENTATION_VERSION != WSIALLOC_INTERFACE_VERSION #if WSIALLOC_IMPLEMENTATION_VERSION != WSIALLOC_INTERFACE_VERSION
@ -81,7 +81,8 @@ static int find_alloc_heap_id(int fd)
struct ion_heap_data heaps[ION_NUM_HEAP_IDS]; struct ion_heap_data heaps[ION_NUM_HEAP_IDS];
struct ion_heap_query query = { struct ion_heap_query query = {
.cnt = ION_NUM_HEAP_IDS, .heaps = (uint64_t)(uintptr_t)heaps, .cnt = ION_NUM_HEAP_IDS,
.heaps = (uint64_t)(uintptr_t)heaps,
}; };
int ret = ioctl(fd, ION_IOC_HEAP_QUERY, &query); int ret = ioctl(fd, ION_IOC_HEAP_QUERY, &query);
@ -109,7 +110,9 @@ static int allocate(int fd, size_t size, uint32_t heap_id)
assert(fd != -1); assert(fd != -1);
struct ion_allocation_data alloc = { struct ion_allocation_data alloc = {
.len = size, .heap_id_mask = 1u << heap_id, .flags = 0, .len = size,
.heap_id_mask = 1u << heap_id,
.flags = 0,
}; };
int ret = ioctl(fd, ION_IOC_ALLOC, &alloc); int ret = ioctl(fd, ION_IOC_ALLOC, &alloc);
if (ret < 0) if (ret < 0)
@ -281,13 +284,13 @@ static const fmt_spec *find_format(uint32_t fourcc)
} }
static bool validate_parameters(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info, static bool validate_parameters(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info,
const wsialloc_format *format, const int *strides, const uint32_t *offsets) wsialloc_allocate_result *result)
{ {
if (allocator == NULL) if (allocator == NULL)
{ {
return false; return false;
} }
else if (!strides || !offsets) else if (!result)
{ {
return false; return false;
} }
@ -304,15 +307,13 @@ static bool validate_parameters(const wsialloc_allocator *allocator, const wsial
} }
wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info, wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info,
wsialloc_format *format, int *strides, int *buffer_fds, uint32_t *offsets) wsialloc_allocate_result *result)
{ {
assert(allocator != NULL); assert(allocator != NULL);
assert(info != NULL); assert(info != NULL);
assert(format != NULL); assert(result != NULL);
assert(strides != NULL);
assert(offsets != NULL);
if (!validate_parameters(allocator, info, format, strides, offsets)) if (!validate_parameters(allocator, info, result))
{ {
return WSIALLOC_ERROR_INVALID; return WSIALLOC_ERROR_INVALID;
} }
@ -355,13 +356,16 @@ wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allo
if (err == WSIALLOC_ERROR_NONE) if (err == WSIALLOC_ERROR_NONE)
{ {
*format = selected_format_desc.format; result->format = selected_format_desc.format;
*strides = local_strides[0]; result->average_row_strides[0] = local_strides[0];
*offsets = local_offsets[0]; result->offsets[0] = local_offsets[0];
if (!(info->flags & WSIALLOC_ALLOCATE_NO_MEMORY)) if (!(info->flags & WSIALLOC_ALLOCATE_NO_MEMORY))
{ {
*buffer_fds = local_fds[0]; result->buffer_fds[0] = local_fds[0];
} }
result->is_disjoint = false;
} }
return err; return err;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022 Arm Limited. * Copyright (c) 2022-2024 Arm Limited.
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
@ -82,6 +82,11 @@ public:
m_buffer_fds = buffer_fds; m_buffer_fds = buffer_fds;
} }
void set_buffer_fds(const int *buffer_fds)
{
std::copy(buffer_fds, buffer_fds + MAX_PLANES, m_buffer_fds.begin());
}
/** /**
* @brief Set the per plane stride values. * @brief Set the per plane stride values.
*/ */
@ -90,6 +95,11 @@ public:
m_strides = strides; m_strides = strides;
} }
void set_strides(const int *strides)
{
std::copy(strides, strides + MAX_PLANES, m_strides.begin());
}
/** /**
* @brief Set the per plane offset values. * @brief Set the per plane offset values.
*/ */
@ -98,6 +108,11 @@ public:
m_offsets = offsets; m_offsets = offsets;
} }
void set_offsets(const uint32_t *offsets)
{
std::copy(offsets, offsets + MAX_PLANES, m_offsets.begin());
}
/** /**
* @brief Get the number of planes the external format uses. * @brief Get the number of planes the external format uses.
*/ */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017-2019, 2021-2023 Arm Limited. * Copyright (c) 2017-2019, 2021-2024 Arm Limited.
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
@ -273,11 +273,13 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl
image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.width, image_create_info.extent.height,
allocation_flags }; allocation_flags };
std::array<int, MAX_PLANES> strides{}; wsialloc_allocate_result alloc_result = { 0 };
std::array<int, MAX_PLANES> buffer_fds{ -1, -1, -1, -1 }; /* Clear fds for error purposes */
std::array<uint32_t, MAX_PLANES> offsets{}; for (int i = 0; i < WSIALLOC_MAX_PLANES; ++i)
const auto res = {
wsialloc_alloc(m_wsi_allocator, &alloc_info, allocated_format, strides.data(), buffer_fds.data(), offsets.data()); alloc_result.buffer_fds[i] = -1;
}
const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &alloc_result);
if (res != WSIALLOC_ERROR_NONE) if (res != WSIALLOC_ERROR_NONE)
{ {
WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res)); WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
@ -287,10 +289,11 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl
} }
return VK_ERROR_OUT_OF_HOST_MEMORY; return VK_ERROR_OUT_OF_HOST_MEMORY;
} }
*allocated_format = alloc_result.format;
auto &external_memory = image_data->external_mem; auto &external_memory = image_data->external_mem;
external_memory.set_strides(strides); external_memory.set_strides(alloc_result.average_row_strides);
external_memory.set_buffer_fds(buffer_fds); external_memory.set_buffer_fds(alloc_result.buffer_fds);
external_memory.set_offsets(offsets); external_memory.set_offsets(alloc_result.offsets);
external_memory.set_memory_handle_type(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); external_memory.set_memory_handle_type(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
return VK_SUCCESS; return VK_SUCCESS;
} }