mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2025-12-20 08:00:12 +01:00
264 lines
5.9 KiB
C
264 lines
5.9 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) 2017, 2019, 2021 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 "format_table.h"
|
||
|
|
|
||
|
|
#include <assert.h>
|
||
|
|
#include <errno.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <ion.h>
|
||
|
|
#include <stdbool.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <sys/ioctl.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
|
||
|
|
#define UNUSED(x) ((void)(x))
|
||
|
|
|
||
|
|
/** Default alignment */
|
||
|
|
#define WSIALLOCP_MIN_ALIGN_SZ (64u)
|
||
|
|
|
||
|
|
struct ion_allocator {
|
||
|
|
/* File descriptor of /dev/ion. */
|
||
|
|
int fd;
|
||
|
|
/* Allocator heap id. */
|
||
|
|
uint32_t alloc_heap_id;
|
||
|
|
};
|
||
|
|
|
||
|
|
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,
|
||
|
|
};
|
||
|
|
|
||
|
|
int ret = ioctl(fd, ION_IOC_HEAP_QUERY, &query);
|
||
|
|
if (ret < 0)
|
||
|
|
{
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int alloc_heap_id = -1;
|
||
|
|
for (uint32_t i = 0; i < query.cnt; ++i)
|
||
|
|
{
|
||
|
|
if (ION_HEAP_TYPE_DMA == heaps[i].type)
|
||
|
|
{
|
||
|
|
alloc_heap_id = heaps[i].heap_id;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return alloc_heap_id;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int allocate(int fd, uint64_t size, uint32_t heap_id)
|
||
|
|
{
|
||
|
|
assert(size > 0);
|
||
|
|
assert(fd != -1);
|
||
|
|
|
||
|
|
struct ion_allocation_data alloc = {
|
||
|
|
.len = size,
|
||
|
|
.heap_id_mask = 1u << heap_id,
|
||
|
|
.flags = 0,
|
||
|
|
};
|
||
|
|
int ret = ioctl(fd, ION_IOC_ALLOC, &alloc);
|
||
|
|
if (ret < 0)
|
||
|
|
{
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
int wsialloc_new(int external_fd, wsialloc_allocator *allocator)
|
||
|
|
{
|
||
|
|
UNUSED(external_fd);
|
||
|
|
assert(allocator != NULL);
|
||
|
|
|
||
|
|
struct ion_allocator *ion = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
allocator->ptr = ion = malloc(sizeof(*ion));
|
||
|
|
if (NULL == ion)
|
||
|
|
{
|
||
|
|
ret = -ENOMEM;
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
ion->fd = open("/dev/ion", O_RDONLY);
|
||
|
|
if (ion->fd < 0)
|
||
|
|
{
|
||
|
|
ret = -errno;
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
ion->alloc_heap_id = find_alloc_heap_id(ion->fd);
|
||
|
|
if (ion->alloc_heap_id < 0)
|
||
|
|
{
|
||
|
|
ret = ion->alloc_heap_id;
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
fail:
|
||
|
|
wsialloc_delete(allocator);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int wsialloc_delete(wsialloc_allocator *allocator)
|
||
|
|
{
|
||
|
|
assert(allocator != NULL);
|
||
|
|
|
||
|
|
struct ion_allocator *ion = allocator->ptr;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if (NULL == ion)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ion->fd != -1)
|
||
|
|
{
|
||
|
|
if (close(ion->fd) != 0)
|
||
|
|
{
|
||
|
|
ret = -errno;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
free(ion);
|
||
|
|
allocator->ptr = NULL;
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int wsiallocp_get_fmt_info(uint32_t fourcc_fmt, uint32_t *nr_planes, uint32_t *plane_bpp)
|
||
|
|
{
|
||
|
|
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 (fourcc_fmt == fourcc_format_table[fmt_idx].drm_format)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fmt_idx >= fourcc_format_table_len)
|
||
|
|
{
|
||
|
|
return -ENOTSUP;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
int wsialloc_alloc(
|
||
|
|
wsialloc_allocator *allocator,
|
||
|
|
uint32_t fourcc,
|
||
|
|
uint32_t width,
|
||
|
|
uint32_t height,
|
||
|
|
int *stride,
|
||
|
|
int *new_fd,
|
||
|
|
uint32_t *offset,
|
||
|
|
const uint64_t *modifier)
|
||
|
|
{
|
||
|
|
assert(allocator != NULL);
|
||
|
|
assert(fourcc != 0);
|
||
|
|
assert(width > 0);
|
||
|
|
assert(height > 0);
|
||
|
|
assert(stride != NULL);
|
||
|
|
assert(new_fd != NULL);
|
||
|
|
assert(offset != NULL);
|
||
|
|
|
||
|
|
int ret = 0;
|
||
|
|
struct ion_allocator *ion = allocator->ptr;
|
||
|
|
|
||
|
|
if(modifier != NULL && *modifier != 0)
|
||
|
|
{
|
||
|
|
return -ENOTSUP;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t size = 0;
|
||
|
|
|
||
|
|
/* Validate format and determine per-plane bits per pixel. */
|
||
|
|
uint32_t nr_planes, bits_per_pixel[WSIALLOCP_MAX_PLANES];
|
||
|
|
ret = wsiallocp_get_fmt_info(fourcc, &nr_planes, bits_per_pixel);
|
||
|
|
if (ret != 0)
|
||
|
|
{
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Only single plane formats supported. */
|
||
|
|
if (nr_planes != 1)
|
||
|
|
{
|
||
|
|
return -ENOTSUP;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Assumes multiple of 8--rework otherwise. */
|
||
|
|
uint32_t plane0_bytes_per_pixel = bits_per_pixel[0] / 8;
|
||
|
|
assert(plane0_bytes_per_pixel * 8 == bits_per_pixel[0]);
|
||
|
|
|
||
|
|
*stride = round_size_up_to_align(width * plane0_bytes_per_pixel);
|
||
|
|
size = *stride * height;
|
||
|
|
|
||
|
|
*new_fd = allocate(ion->fd, size, ion->alloc_heap_id);
|
||
|
|
if (*new_fd < 0)
|
||
|
|
{
|
||
|
|
return -errno;
|
||
|
|
}
|
||
|
|
|
||
|
|
*offset = 0;
|
||
|
|
return 0;
|
||
|
|
}
|