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
*
@ -31,7 +31,12 @@
#define _WSIALLOC_H_
#include <stdint.h>
#include <stdbool.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <drm_fourcc.h>
#pragma GCC diagnostic pop
#ifdef __cplusplus
extern "C" {
@ -57,9 +62,10 @@ extern "C" {
* Version History:
* 1 - Initial wsialloc interface
* 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 2
#define WSIALLOC_INTERFACE_VERSION 3
#define WSIALLOC_CONCAT(x, y) x##y
#define WSIALLOC_SYMBOL_VERSION(symbol, version) WSIALLOC_CONCAT(symbol, version)
@ -159,63 +165,75 @@ typedef struct wsialloc_format
typedef struct wsialloc_allocate_info
{
wsialloc_format *formats; /** List of formats to select from for the allocation */
unsigned format_count; /** Number of elements in formats array */
wsialloc_format *formats; /** List of formats to select from for the allocation. */
unsigned format_count; /** Number of elements in formats array. */
uint32_t width; /** The number of pixel columns 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. */
} 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
*
* 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.
*
* 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.
*
* 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
* underlying window system. @p strides must be examined to determine the number of bytes between subsequent rows
* in each of the buffer's planes. Only positive strides are allowed.
* underlying window system. @p result::average_row_strides must be examined to determine the number of bytes between
* 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:
* - @p 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.
* - @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 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
* in case it contains non-zero values.
* Even if @p result::buffer_fds are all different or @p result::format is for a single plane, then the client must inspect
* @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).
*
* 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,
* 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
* 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
* row of blocks to the start of the next. It may also have format specific meaning for formats not in those categories.
* @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 of blocks divided by the block height. It may also have format specific meaning for formats not in those
* 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 allocator is a currently valid WSI Allocator from wsialloc_new()
* @post The allocated buffer will be zeroed.
*
* @param allocator The WSI Allocator to allocate from.
* @param[in] info The requested allocation information.
* @param[out] format The selected format for allocation.
* @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.
* @param[out] result The allocation's result.
* @retval WSIALLOC_ERROR_NONE on successful buffer allocation.
* @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_format *format, int *strides, int *buffer_fds, uint32_t *offsets);
wsialloc_allocate_result *result);
#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
*
@ -44,7 +44,7 @@
*
* 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. */
#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_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);
@ -109,7 +110,9 @@ static int allocate(int fd, size_t size, uint32_t heap_id)
assert(fd != -1);
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);
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,
const wsialloc_format *format, const int *strides, const uint32_t *offsets)
wsialloc_allocate_result *result)
{
if (allocator == NULL)
{
return false;
}
else if (!strides || !offsets)
else if (!result)
{
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_format *format, int *strides, int *buffer_fds, uint32_t *offsets)
wsialloc_allocate_result *result)
{
assert(allocator != NULL);
assert(info != NULL);
assert(format != NULL);
assert(strides != NULL);
assert(offsets != NULL);
assert(result != NULL);
if (!validate_parameters(allocator, info, format, strides, offsets))
if (!validate_parameters(allocator, info, result))
{
return WSIALLOC_ERROR_INVALID;
}
@ -355,13 +356,16 @@ wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allo
if (err == WSIALLOC_ERROR_NONE)
{
*format = selected_format_desc.format;
*strides = local_strides[0];
*offsets = local_offsets[0];
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))
{
*buffer_fds = local_fds[0];
result->buffer_fds[0] = local_fds[0];
}
result->is_disjoint = false;
}
return err;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Arm Limited.
* Copyright (c) 2022-2024 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -82,6 +82,11 @@ public:
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.
*/
@ -90,6 +95,11 @@ public:
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.
*/
@ -98,6 +108,11 @@ public:
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.
*/

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
*
@ -273,11 +273,13 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl
image_create_info.extent.width, image_create_info.extent.height,
allocation_flags };
std::array<int, MAX_PLANES> strides{};
std::array<int, MAX_PLANES> buffer_fds{ -1, -1, -1, -1 };
std::array<uint32_t, MAX_PLANES> offsets{};
const auto res =
wsialloc_alloc(m_wsi_allocator, &alloc_info, allocated_format, strides.data(), buffer_fds.data(), offsets.data());
wsialloc_allocate_result alloc_result = { 0 };
/* Clear fds for error purposes */
for (int i = 0; i < WSIALLOC_MAX_PLANES; ++i)
{
alloc_result.buffer_fds[i] = -1;
}
const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &alloc_result);
if (res != WSIALLOC_ERROR_NONE)
{
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;
}
*allocated_format = alloc_result.format;
auto &external_memory = image_data->external_mem;
external_memory.set_strides(strides);
external_memory.set_buffer_fds(buffer_fds);
external_memory.set_offsets(offsets);
external_memory.set_strides(alloc_result.average_row_strides);
external_memory.set_buffer_fds(alloc_result.buffer_fds);
external_memory.set_offsets(alloc_result.offsets);
external_memory.set_memory_handle_type(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
return VK_SUCCESS;
}