mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2026-05-07 15:38:03 +02:00
Implement a vendor agnostic wsialloc interface
Refactors the wsialloc interface in the layer. This patch ensures that wsialloc interface could be ported to different GPU architectures and systems that could have different requirements Change-Id: I6593f2373abc75fb2074700d156ba3797d7ff058 Signed-off-by: Normunds Rieksts <normunds.rieksts@arm.com> Signed-off-by: Rosen Zhelev <rosen.zhelev@arm.com>
This commit is contained in:
parent
f22b7e33b9
commit
293ae2ab13
3 changed files with 307 additions and 173 deletions
|
|
@ -48,11 +48,6 @@ extern "C" {
|
|||
* @note The bare minimum work is done to provide the buffer. For example, it is up to the client to initialize the data
|
||||
* if that is required for the desired buffer format.
|
||||
*
|
||||
* The client may have already obtained a file descriptor (fd) for a Direct Rendering Manager (DRM) driver so it may
|
||||
* perform other operations (e.g. presenting a buffer). Hence, such an fd is passed in on Allocator Construction so that
|
||||
* the underlying allocator may allocate from the existing fd. However, the underlying implementation is also free to
|
||||
* ignore that fd and use some other allocation mechanism, even in a production system.
|
||||
*
|
||||
* The underlying allocator implementation is chosen at compile time.
|
||||
*
|
||||
* All API Public entry points are implemented in a way that is thread safe, and the client does not need to be
|
||||
|
|
@ -61,28 +56,31 @@ extern "C" {
|
|||
*/
|
||||
|
||||
/**
|
||||
* @brief Struct for allocator type.
|
||||
* @brief Allocator type.
|
||||
*
|
||||
* Represents a private allocator structures.
|
||||
* Represents a private allocator structure.
|
||||
*/
|
||||
struct wsialloc_allocator;
|
||||
typedef struct wsialloc_allocator wsialloc_allocator;
|
||||
|
||||
typedef enum wsialloc_error
|
||||
{
|
||||
WSIALLOC_ERROR_NONE = 0,
|
||||
WSIALLOC_ERROR_INVALID = -1,
|
||||
WSIALLOC_ERROR_NOT_SUPPORTED = -2,
|
||||
WSIALLOC_ERROR_NO_RESOURCE = -3,
|
||||
} wsialloc_error;
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize a new WSI Allocator from an existing file descriptor.
|
||||
*
|
||||
* The allocator from the function is used in subsequent calls to wsialloc_alloc() to allocate new buffers.
|
||||
*
|
||||
* This function will be implemented as thread-safe. The implementer must ensure they use thread-safe functions, or use
|
||||
* appropriate locking for non-threadsafe functions/writable global data.
|
||||
* @param[out] allocator a valid allocator for use in wsialloc functions.
|
||||
*
|
||||
* @note The underlying implementation may choose to use @p external_fd or its own platform-specific allocation method.
|
||||
*
|
||||
* @param external_fd file descriptor that the WSI Allocator could use for allocating new buffers
|
||||
*
|
||||
* @return Pointer to a wsialloc_allocator struct. A NULL return value indicates an error.
|
||||
* @retval WSIALLOC_ERROR_NONE on successful allocator creation.
|
||||
* @retval WSIALLOC_ERROR_FAILED on failed allocator creation.
|
||||
*/
|
||||
wsialloc_allocator *wsialloc_new(int external_fd);
|
||||
wsialloc_error wsialloc_new(wsialloc_allocator **allocator);
|
||||
|
||||
/**
|
||||
* @brief Close down and free resources associated with a WSI Allocator
|
||||
|
|
@ -94,74 +92,103 @@ wsialloc_allocator *wsialloc_new(int external_fd);
|
|||
* @note For the implementer: there is usually no need to track this explicitly, since kernel side allocators
|
||||
* automatically defer their closing until all their allocations are also freed.
|
||||
*
|
||||
* This function will be implemented as thread-safe. The implementer must ensure they use thread-safe functions, or use
|
||||
* appropriate locking for non-threadsafe functions/writable global data.
|
||||
*
|
||||
* @post no more new allocations should be made on @p allocator even if previous allocations still exist.
|
||||
*
|
||||
* @param allocator The allocator to close down and free
|
||||
* @retval 0 on success
|
||||
* @retval non-zero on failure with errno
|
||||
* @param allocator The allocator to close down and free.
|
||||
*/
|
||||
int wsialloc_delete(wsialloc_allocator *allocator);
|
||||
void wsialloc_delete(wsialloc_allocator *allocator);
|
||||
|
||||
enum wsialloc_format_flag
|
||||
{
|
||||
/** The format requires a memory allocation with the same file descriptor for all planes. */
|
||||
WSIALLOC_FORMAT_NON_DISJOINT = 0x1,
|
||||
};
|
||||
|
||||
enum wsialloc_allocate_flag
|
||||
{
|
||||
/** Allocates the buffer in protected memory. */
|
||||
WSIALLOC_ALLOCATE_PROTECTED = 0x1,
|
||||
/** Performs allocation calculations and format selection without allocating any memory. */
|
||||
WSIALLOC_ALLOCATE_NO_MEMORY = 0x2,
|
||||
};
|
||||
|
||||
typedef struct wsialloc_format
|
||||
{
|
||||
uint32_t fourcc; /**< The DRM_FORMAT_<...> code */
|
||||
uint64_t modifier; /**< DRM modifier applied to all planes. */
|
||||
uint64_t flags; /**< Set of @r wsialloc_format_flag format flags. */
|
||||
} 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 */
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief Allocate a buffer from the WSI Allocator
|
||||
*
|
||||
* Allocate a buffer of size @p width x @p height of format @p fourcc_fmt 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.
|
||||
*
|
||||
* 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 @p fourcc_fmt and @p modifiers.
|
||||
* The allocation is made using a format from the list specified in @p info::formats . On success, @p format is set with
|
||||
* the selected format that was used for the allocation.
|
||||
*
|
||||
* Each row in the buffer may be larger than @p 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.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The client may free the buffer's planes by invoking close() on some or all of the elements of @p buffer_fds
|
||||
*
|
||||
* The same file descriptor ('fd') may be written to different elements of @p 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
|
||||
* - When the client frees the buffer, each unique fd in @p buffer_fds must only be closed once.
|
||||
*
|
||||
* Even if @p buffer_fds are all different or @p fourcc_fmt is for a single plane, then the client must inspect @p
|
||||
* offsets in case it contains non-zero values.
|
||||
* 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.
|
||||
*
|
||||
* @note The implementation might not export the file descriptors in @p buffer_fds in such a way that allows the client
|
||||
* to directly map them on the CPU as writable (PROT_WRITE).
|
||||
*
|
||||
* @p modifiers allows for a fourcc_mod_code() (as defined in drm_fourcc.h) to be passed in
|
||||
* per-plane to request that allocation account for a reordering or other modification of the data in the buffer's
|
||||
* planes (e.g. compression, change in number of planes, etc).
|
||||
* The selected @p 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 and @p offsets may have modifier-specific meaning when @p modifiers are in use.
|
||||
* @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.
|
||||
*
|
||||
* This function will be implemented as thread-safe. The implementer must ensure they use thread-safe functions, or use
|
||||
* appropriate locking for non-threadsafe functions/writable global data.
|
||||
* @p strides and @p offsets may have modifier-specific meaning when a @p 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 width >=1 && @p height >= 1
|
||||
* @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 fourcc_fmt The DRM_FORMAT_<...> code
|
||||
* @param width The number of pixel columns required in the buffer
|
||||
* @param height The number of pixel rows required in the buffer
|
||||
* @param[out] strides Per-plane number of bytes between successive rows in 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[in] modifiers Per-plane modifiers or NULL if no modifiers required
|
||||
* @retval 0 on successful buffer allocation
|
||||
* @retval Non-zero indicates some error listed below and/or a window-system/allocator specific (usually negative)
|
||||
* error
|
||||
* @retval -EINVAL is also returned for invalid parameters
|
||||
* @retval -ENOTSUP is also returned for unsupported parameters, such as a modifier or recognized format
|
||||
* not supported by the underlying window-system/allocator
|
||||
* @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.
|
||||
|
||||
* @retval WSIALLOC_ERROR_NONE on successful buffer allocation.
|
||||
* @retval WSIALLOC_ERROR_INVALID is returned for invalid parameters.
|
||||
* @retval WSIALLOC_ERROR_NOT_SUPPORTED is returned for unsupported parameters, such as a modifier or recognized
|
||||
* format not supported by the underlying window-system/allocator.
|
||||
* @retval WSIALLOC_ERROR_NO_RESOURCE is returned on failed buffer allocation due to lack of available memory or other
|
||||
* system resources.
|
||||
*/
|
||||
int wsialloc_alloc(wsialloc_allocator *allocator, uint32_t fourcc_fmt, uint32_t width, uint32_t height, int *strides, int *buffer_fds,
|
||||
uint32_t *offsets, const uint64_t *modifiers);
|
||||
|
||||
wsialloc_error wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info,
|
||||
wsialloc_format *format, int *strides, int *buffer_fds, uint32_t *offsets);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNUSED(x) ((void)(x))
|
||||
#include <string.h>
|
||||
|
||||
/** Default alignment */
|
||||
#define WSIALLOCP_MIN_ALIGN_SZ (64u)
|
||||
/** Maximum image size allowed for each dimension */
|
||||
#define MAX_IMAGE_SIZE 128000
|
||||
|
||||
struct wsialloc_allocator
|
||||
{
|
||||
|
|
@ -48,16 +50,24 @@ struct wsialloc_allocator
|
|||
int fd;
|
||||
/* Allocator heap id. */
|
||||
uint32_t alloc_heap_id;
|
||||
/* Protected allocator heap id */
|
||||
uint32_t protected_alloc_heap_id;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
|
@ -85,9 +95,7 @@ static int allocate(int fd, uint64_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)
|
||||
|
|
@ -103,150 +111,238 @@ static uint64_t round_size_up_to_align(uint64_t size)
|
|||
return (size + WSIALLOCP_MIN_ALIGN_SZ - 1) & ~(WSIALLOCP_MIN_ALIGN_SZ - 1);
|
||||
}
|
||||
|
||||
wsialloc_allocator *wsialloc_new(int external_fd)
|
||||
wsialloc_error wsialloc_new(wsialloc_allocator **allocator)
|
||||
{
|
||||
UNUSED(external_fd);
|
||||
assert(allocator != NULL);
|
||||
wsialloc_error ret = WSIALLOC_ERROR_NONE;
|
||||
|
||||
wsialloc_allocator *ion = NULL;
|
||||
ion = malloc(sizeof(*ion));
|
||||
wsialloc_allocator *ion = malloc(sizeof(wsialloc_allocator));
|
||||
if (NULL == ion)
|
||||
{
|
||||
ret = WSIALLOC_ERROR_NO_RESOURCE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ion->fd = open("/dev/ion", O_RDONLY);
|
||||
if (ion->fd < 0)
|
||||
{
|
||||
ret = WSIALLOC_ERROR_NO_RESOURCE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ion->alloc_heap_id = find_alloc_heap_id(ion->fd);
|
||||
if (ion->alloc_heap_id < 0)
|
||||
{
|
||||
ret = WSIALLOC_ERROR_NO_RESOURCE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return ion;
|
||||
ion->protected_heap_exists = false;
|
||||
*allocator = ion;
|
||||
return ret;
|
||||
fail:
|
||||
wsialloc_delete(ion);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int wsialloc_delete(wsialloc_allocator *ion)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (NULL == ion)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ion->fd != -1)
|
||||
{
|
||||
if (close(ion->fd) != 0)
|
||||
{
|
||||
ret = -errno;
|
||||
}
|
||||
}
|
||||
|
||||
free(ion);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wsiallocp_get_fmt_info(uint32_t fourcc_fmt, uint32_t *nr_planes, uint32_t *plane_bpp)
|
||||
void wsialloc_delete(wsialloc_allocator *allocator)
|
||||
{
|
||||
unsigned int fmt_idx;
|
||||
const fmt_spec *found_fmt;
|
||||
unsigned int plane_idx;
|
||||
|
||||
assert(nr_planes != NULL && plane_bpp != NULL);
|
||||
|
||||
/* Mask off any bits not necessary for allocation size */
|
||||
fourcc_fmt = fourcc_fmt & (~(uint32_t)DRM_FORMAT_BIG_ENDIAN);
|
||||
|
||||
/* Search table for the format*/
|
||||
for (fmt_idx = 0; fmt_idx < fourcc_format_table_len; ++fmt_idx)
|
||||
if (NULL == allocator)
|
||||
{
|
||||
if (fourcc_fmt == fourcc_format_table[fmt_idx].drm_format)
|
||||
{
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmt_idx >= fourcc_format_table_len)
|
||||
if (allocator->fd >= 0)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
close(allocator->fd);
|
||||
}
|
||||
|
||||
/* fmt_idx is now a correct index into the table */
|
||||
found_fmt = &fourcc_format_table[fmt_idx];
|
||||
|
||||
assert(found_fmt->nr_planes <= WSIALLOCP_MAX_PLANES);
|
||||
*nr_planes = found_fmt->nr_planes;
|
||||
|
||||
/* Only write out as many bpp as there are planes */
|
||||
for (plane_idx = 0; plane_idx < found_fmt->nr_planes; ++plane_idx)
|
||||
{
|
||||
plane_bpp[plane_idx] = (uint32_t)found_fmt->bpp[plane_idx];
|
||||
}
|
||||
|
||||
return 0;
|
||||
free(allocator);
|
||||
}
|
||||
|
||||
int wsialloc_alloc(
|
||||
wsialloc_allocator *ion,
|
||||
uint32_t fourcc,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
int *stride,
|
||||
int *new_fd,
|
||||
uint32_t *offset,
|
||||
const uint64_t *modifier)
|
||||
static wsialloc_error calculate_format_properties(const wsialloc_format_descriptor *descriptor,
|
||||
const wsialloc_allocate_info *info, int *strides, uint32_t *offsets)
|
||||
{
|
||||
assert(ion != NULL);
|
||||
assert(fourcc != 0);
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
assert(stride != NULL);
|
||||
assert(new_fd != NULL);
|
||||
assert(offset != NULL);
|
||||
assert(descriptor != NULL);
|
||||
assert(info != NULL);
|
||||
assert(strides != NULL);
|
||||
assert(offsets != NULL);
|
||||
|
||||
if (modifier != NULL && *modifier != 0)
|
||||
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 -ENOTSUP;
|
||||
return WSIALLOC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Validate format and determine per-plane bits per pixel. */
|
||||
uint32_t nr_planes, bits_per_pixel[WSIALLOCP_MAX_PLANES];
|
||||
int ret = wsiallocp_get_fmt_info(fourcc, &nr_planes, bits_per_pixel);
|
||||
if (ret != 0)
|
||||
/* No multi-plane format support */
|
||||
if (num_planes > 1)
|
||||
{
|
||||
return ret;
|
||||
return WSIALLOC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
for (uint32_t plane = 0; plane < nr_planes; plane++)
|
||||
for (size_t plane = 0; plane < num_planes; plane++)
|
||||
{
|
||||
offset[plane] = size;
|
||||
|
||||
/* 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]);
|
||||
|
||||
stride[plane] = round_size_up_to_align(width * plane_bytes_per_pixel);
|
||||
size += stride[plane] * height;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
new_fd[0] = allocate(ion->fd, size, ion->alloc_heap_id);
|
||||
if (new_fd[0] < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (uint32_t plane = 1; plane < nr_planes; plane++)
|
||||
{
|
||||
new_fd[plane] = new_fd[0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
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)
|
||||
{
|
||||
assert(allocator != NULL);
|
||||
assert(descriptor != NULL);
|
||||
assert(info != NULL);
|
||||
assert(offsets != NULL);
|
||||
assert(strides != NULL);
|
||||
assert(buffer_fds != NULL);
|
||||
|
||||
const uint64_t flags = descriptor->format.flags;
|
||||
const uint32_t num_planes = descriptor->format_spec.nr_planes;
|
||||
|
||||
/* 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 */
|
||||
if (!allocator->protected_heap_exists)
|
||||
{
|
||||
return WSIALLOC_ERROR_NO_RESOURCE;
|
||||
}
|
||||
alloc_heap_id = allocator->protected_alloc_heap_id;
|
||||
}
|
||||
|
||||
size_t total_size = offsets[0] + (strides[0] * info->height);
|
||||
|
||||
buffer_fds[0] = allocate(allocator->fd, 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 <= WSIALLOCP_MAX_PLANES);
|
||||
|
||||
return found_fmt;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool validate_parameters(const wsialloc_allocator *allocator, const wsialloc_allocate_info *info,
|
||||
const wsialloc_format *format, const int *strides, const uint32_t *offsets)
|
||||
{
|
||||
if (allocator == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!strides || !offsets)
|
||||
{
|
||||
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 wsialloc_alloc(wsialloc_allocator *allocator, const wsialloc_allocate_info *info,
|
||||
wsialloc_format *format, int *strides, int *buffer_fds, uint32_t *offsets)
|
||||
{
|
||||
assert(allocator != NULL);
|
||||
assert(info != NULL);
|
||||
assert(format != NULL);
|
||||
assert(strides != NULL);
|
||||
assert(offsets != NULL);
|
||||
|
||||
if (!validate_parameters(allocator, info, format, strides, offsets))
|
||||
{
|
||||
return WSIALLOC_ERROR_INVALID;
|
||||
}
|
||||
|
||||
int local_strides[WSIALLOCP_MAX_PLANES];
|
||||
int local_fds[WSIALLOCP_MAX_PLANES] = { -1 };
|
||||
int local_offsets[WSIALLOCP_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)
|
||||
{
|
||||
*format = selected_format_desc.format;
|
||||
*strides = local_strides[0];
|
||||
*offsets = local_offsets[0];
|
||||
if (!(info->flags & WSIALLOC_ALLOCATE_NO_MEMORY))
|
||||
{
|
||||
*buffer_fds = local_fds[0];
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -98,14 +98,9 @@ swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCal
|
|||
|
||||
swapchain::~swapchain()
|
||||
{
|
||||
int res;
|
||||
teardown();
|
||||
|
||||
res = wsialloc_delete(m_wsi_allocator);
|
||||
if (res != 0)
|
||||
{
|
||||
WSI_LOG_ERROR("error deleting the allocator: %d", res);
|
||||
}
|
||||
wsialloc_delete(m_wsi_allocator);
|
||||
m_wsi_allocator = nullptr;
|
||||
if (m_surface_queue != nullptr)
|
||||
{
|
||||
|
|
@ -179,8 +174,7 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH
|
|||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
m_wsi_allocator = wsialloc_new(-1);
|
||||
if (nullptr == m_wsi_allocator)
|
||||
if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
|
||||
{
|
||||
WSI_LOG_ERROR("Failed to create wsi allocator.");
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
|
@ -432,13 +426,30 @@ VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland
|
|||
{
|
||||
/* TODO: Handle Dedicated allocation bit. */
|
||||
const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format);
|
||||
const auto is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
|
||||
|
||||
const auto res =
|
||||
wsialloc_alloc(m_wsi_allocator, fourcc, image_create_info.extent.width, image_create_info.extent.height,
|
||||
image_data->stride, image_data->buffer_fd, image_data->offset, nullptr);
|
||||
if (res != 0)
|
||||
const uint64_t format_flags = is_disjoint ? 0 : WSIALLOC_FORMAT_NON_DISJOINT;
|
||||
wsialloc_format format = {fourcc, modifier, format_flags};
|
||||
|
||||
const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
|
||||
wsialloc_allocate_info alloc_info = {
|
||||
&format,
|
||||
1,
|
||||
image_create_info.extent.width,
|
||||
image_create_info.extent.height,
|
||||
allocation_flags
|
||||
};
|
||||
|
||||
wsialloc_format allocated_format = {0};
|
||||
const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &allocated_format, image_data->stride,
|
||||
image_data->buffer_fd, image_data->offset);
|
||||
if (res != WSIALLOC_ERROR_NONE)
|
||||
{
|
||||
WSI_LOG_ERROR("Failed allocation of DMA Buffer.");
|
||||
WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
|
||||
if(res == WSIALLOC_ERROR_NOT_SUPPORTED)
|
||||
{
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue