2023-08-31 00:19:12 +02:00
|
|
|
/* Spa */
|
|
|
|
|
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
|
|
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
|
2019-08-19 16:32:22 +02:00
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <string.h>
|
2022-07-07 16:23:51 -04:00
|
|
|
#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
|
2019-08-19 16:32:22 +02:00
|
|
|
#include <alloca.h>
|
2020-03-27 19:20:21 +00:00
|
|
|
#endif
|
2019-08-19 16:32:22 +02:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
2019-08-19 18:16:32 +02:00
|
|
|
#include <spa/utils/result.h>
|
2022-05-31 18:00:24 +02:00
|
|
|
#include <spa/utils/string.h>
|
2023-02-21 16:29:17 +01:00
|
|
|
#include <spa/param/video/format.h>
|
2019-08-19 18:16:32 +02:00
|
|
|
#include <spa/support/log.h>
|
2019-08-19 16:32:22 +02:00
|
|
|
#include <spa/debug/mem.h>
|
|
|
|
|
|
|
|
|
|
#include "vulkan-utils.h"
|
|
|
|
|
|
2022-06-01 10:54:15 +02:00
|
|
|
//#define ENABLE_VALIDATION
|
|
|
|
|
|
2019-08-19 16:32:22 +02:00
|
|
|
static int vkresult_to_errno(VkResult result)
|
|
|
|
|
{
|
|
|
|
|
switch (result) {
|
|
|
|
|
case VK_SUCCESS:
|
|
|
|
|
case VK_EVENT_SET:
|
|
|
|
|
case VK_EVENT_RESET:
|
|
|
|
|
return 0;
|
|
|
|
|
case VK_NOT_READY:
|
|
|
|
|
case VK_INCOMPLETE:
|
|
|
|
|
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
|
|
|
|
return EBUSY;
|
|
|
|
|
case VK_TIMEOUT:
|
|
|
|
|
return ETIMEDOUT;
|
|
|
|
|
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
|
|
|
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
|
|
|
|
case VK_ERROR_MEMORY_MAP_FAILED:
|
|
|
|
|
case VK_ERROR_OUT_OF_POOL_MEMORY:
|
|
|
|
|
case VK_ERROR_FRAGMENTED_POOL:
|
2019-09-27 10:53:36 +02:00
|
|
|
#ifdef VK_ERROR_FRAGMENTATION_EXT
|
|
|
|
|
case VK_ERROR_FRAGMENTATION_EXT:
|
|
|
|
|
#endif
|
2019-08-19 16:32:22 +02:00
|
|
|
return ENOMEM;
|
|
|
|
|
case VK_ERROR_INITIALIZATION_FAILED:
|
|
|
|
|
return EIO;
|
|
|
|
|
case VK_ERROR_DEVICE_LOST:
|
|
|
|
|
case VK_ERROR_SURFACE_LOST_KHR:
|
2019-09-27 10:53:36 +02:00
|
|
|
#ifdef VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT
|
2019-08-19 16:32:22 +02:00
|
|
|
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
|
2019-09-27 10:53:36 +02:00
|
|
|
#endif
|
2019-08-19 16:32:22 +02:00
|
|
|
return ENODEV;
|
|
|
|
|
case VK_ERROR_LAYER_NOT_PRESENT:
|
|
|
|
|
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
|
|
|
|
case VK_ERROR_FEATURE_NOT_PRESENT:
|
|
|
|
|
return ENOENT;
|
|
|
|
|
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
|
|
|
|
case VK_ERROR_FORMAT_NOT_SUPPORTED:
|
|
|
|
|
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
|
|
|
|
|
return ENOTSUP;
|
|
|
|
|
case VK_ERROR_TOO_MANY_OBJECTS:
|
|
|
|
|
return ENFILE;
|
|
|
|
|
case VK_SUBOPTIMAL_KHR:
|
|
|
|
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
|
|
|
|
return EIO;
|
|
|
|
|
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
|
|
|
|
|
case VK_ERROR_INVALID_SHADER_NV:
|
2019-09-27 10:53:36 +02:00
|
|
|
#ifdef VK_ERROR_VALIDATION_FAILED_EXT
|
|
|
|
|
case VK_ERROR_VALIDATION_FAILED_EXT:
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT
|
2019-08-19 16:32:22 +02:00
|
|
|
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
|
2019-09-27 10:53:36 +02:00
|
|
|
#endif
|
|
|
|
|
#ifdef VK_ERROR_INVALID_DEVICE_ADDRESS_EXT
|
2019-08-19 16:32:22 +02:00
|
|
|
case VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
|
2019-09-27 10:53:36 +02:00
|
|
|
#endif
|
2019-08-19 16:32:22 +02:00
|
|
|
return EINVAL;
|
2019-09-27 10:53:36 +02:00
|
|
|
#ifdef VK_ERROR_NOT_PERMITTED_EXT
|
2019-08-19 16:32:22 +02:00
|
|
|
case VK_ERROR_NOT_PERMITTED_EXT:
|
|
|
|
|
return EPERM;
|
2019-09-27 10:53:36 +02:00
|
|
|
#endif
|
2019-08-19 16:32:22 +02:00
|
|
|
default:
|
|
|
|
|
return EIO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-21 16:29:17 +01:00
|
|
|
static struct {
|
|
|
|
|
VkFormat format;
|
|
|
|
|
uint32_t id;
|
|
|
|
|
} vk_video_format_convs[] = {
|
|
|
|
|
{ VK_FORMAT_R32G32B32A32_SFLOAT, SPA_VIDEO_FORMAT_RGBA_F32 },
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
static int createInstance(struct vulkan_base *s)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
2021-06-27 17:47:13 +02:00
|
|
|
static const VkApplicationInfo applicationInfo = {
|
2019-08-19 16:32:22 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
2019-08-19 16:47:02 +02:00
|
|
|
.pApplicationName = "PipeWire",
|
2019-08-19 16:32:22 +02:00
|
|
|
.applicationVersion = 0,
|
2019-08-19 16:47:02 +02:00
|
|
|
.pEngineName = "PipeWire Vulkan Engine",
|
2019-08-19 16:32:22 +02:00
|
|
|
.engineVersion = 0,
|
|
|
|
|
.apiVersion = VK_API_VERSION_1_1
|
|
|
|
|
};
|
2021-06-27 17:47:13 +02:00
|
|
|
static const char * const extensions[] = {
|
2019-08-19 16:32:22 +02:00
|
|
|
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME
|
|
|
|
|
};
|
2022-05-31 18:00:24 +02:00
|
|
|
static const char * const checkLayers[] = {
|
|
|
|
|
#ifdef ENABLE_VALIDATION
|
2022-05-31 09:53:08 +02:00
|
|
|
"VK_LAYER_KHRONOS_validation",
|
2022-05-31 18:00:24 +02:00
|
|
|
#endif
|
|
|
|
|
NULL
|
2022-05-31 09:53:08 +02:00
|
|
|
};
|
2022-05-31 18:00:24 +02:00
|
|
|
uint32_t i, j, layerCount, n_layers = 0;
|
|
|
|
|
const char *layers[1];
|
2022-05-31 09:53:08 +02:00
|
|
|
vkEnumerateInstanceLayerProperties(&layerCount, NULL);
|
|
|
|
|
|
|
|
|
|
VkLayerProperties availableLayers[layerCount];
|
|
|
|
|
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers);
|
|
|
|
|
|
2022-05-31 18:00:24 +02:00
|
|
|
for (i = 0; i < layerCount; i++) {
|
|
|
|
|
for (j = 0; j < SPA_N_ELEMENTS(checkLayers); j++) {
|
|
|
|
|
if (spa_streq(availableLayers[i].layerName, checkLayers[j]))
|
|
|
|
|
layers[n_layers++] = checkLayers[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-27 17:47:13 +02:00
|
|
|
|
|
|
|
|
const VkInstanceCreateInfo createInfo = {
|
2019-08-19 16:32:22 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
|
|
|
.pApplicationInfo = &applicationInfo,
|
|
|
|
|
.enabledExtensionCount = 1,
|
|
|
|
|
.ppEnabledExtensionNames = extensions,
|
2022-05-31 18:00:24 +02:00
|
|
|
.enabledLayerCount = n_layers,
|
2022-05-31 09:53:08 +02:00
|
|
|
.ppEnabledLayerNames = layers,
|
2019-08-19 16:32:22 +02:00
|
|
|
};
|
|
|
|
|
|
2019-08-19 18:16:32 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateInstance(&createInfo, NULL, &s->instance));
|
2019-08-19 16:32:22 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
static int findPhysicalDevice(struct vulkan_base *s)
|
|
|
|
|
{
|
|
|
|
|
uint32_t deviceCount;
|
|
|
|
|
VkPhysicalDevice *devices;
|
|
|
|
|
|
|
|
|
|
vkEnumeratePhysicalDevices(s->instance, &deviceCount, NULL);
|
|
|
|
|
if (deviceCount == 0)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
devices = alloca(deviceCount * sizeof(VkPhysicalDevice));
|
|
|
|
|
vkEnumeratePhysicalDevices(s->instance, &deviceCount, devices);
|
|
|
|
|
|
|
|
|
|
s->physicalDevice = devices[0];
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int getComputeQueueFamilyIndex(struct vulkan_base *s, uint32_t queueFlags, uint32_t *queueFamilyIndex)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
|
|
|
|
uint32_t i, queueFamilyCount;
|
|
|
|
|
VkQueueFamilyProperties *queueFamilies;
|
|
|
|
|
|
2019-08-19 18:16:32 +02:00
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(s->physicalDevice, &queueFamilyCount, NULL);
|
2019-08-19 16:32:22 +02:00
|
|
|
|
|
|
|
|
queueFamilies = alloca(queueFamilyCount * sizeof(VkQueueFamilyProperties));
|
2019-08-19 18:16:32 +02:00
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(s->physicalDevice, &queueFamilyCount, queueFamilies);
|
2019-08-19 16:32:22 +02:00
|
|
|
|
|
|
|
|
for (i = 0; i < queueFamilyCount; i++) {
|
|
|
|
|
VkQueueFamilyProperties props = queueFamilies[i];
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
if (props.queueCount > 0 && ((props.queueFlags & queueFlags) == queueFlags))
|
2019-08-19 16:32:22 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (i == queueFamilyCount)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
*queueFamilyIndex = i;
|
2019-08-19 16:32:22 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
static int createDevice(struct vulkan_base *s, struct vulkan_base_info *info)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
2021-06-27 17:47:13 +02:00
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
CHECK(getComputeQueueFamilyIndex(s, info->queueFlags, &s->queueFamilyIndex));
|
|
|
|
|
|
2021-06-27 17:47:13 +02:00
|
|
|
const VkDeviceQueueCreateInfo queueCreateInfo = {
|
2019-08-19 16:32:22 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
2019-08-19 18:16:32 +02:00
|
|
|
.queueFamilyIndex = s->queueFamilyIndex,
|
2019-08-19 16:32:22 +02:00
|
|
|
.queueCount = 1,
|
|
|
|
|
.pQueuePriorities = (const float[]) { 1.0f }
|
|
|
|
|
};
|
2021-06-27 17:47:13 +02:00
|
|
|
static const char * const extensions[] = {
|
2019-08-19 16:32:22 +02:00
|
|
|
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
|
|
|
|
|
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME
|
|
|
|
|
};
|
2021-06-27 17:47:13 +02:00
|
|
|
const VkDeviceCreateInfo deviceCreateInfo = {
|
2019-08-19 16:32:22 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
|
|
|
.queueCreateInfoCount = 1,
|
|
|
|
|
.pQueueCreateInfos = &queueCreateInfo,
|
|
|
|
|
.enabledExtensionCount = 2,
|
|
|
|
|
.ppEnabledExtensionNames = extensions,
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-19 18:16:32 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateDevice(s->physicalDevice, &deviceCreateInfo, NULL, &s->device));
|
2019-08-19 16:32:22 +02:00
|
|
|
|
2019-08-19 18:16:32 +02:00
|
|
|
vkGetDeviceQueue(s->device, s->queueFamilyIndex, 0, &s->queue);
|
2019-08-19 16:32:22 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
int vulkan_commandPool_create(struct vulkan_base *s, VkCommandPool *commandPool)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
2021-06-27 17:47:13 +02:00
|
|
|
const VkCommandPoolCreateInfo commandPoolCreateInfo = {
|
2019-08-19 16:32:22 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
|
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
2019-08-19 18:16:32 +02:00
|
|
|
.queueFamilyIndex = s->queueFamilyIndex,
|
2019-08-19 16:32:22 +02:00
|
|
|
};
|
2019-08-19 18:16:32 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateCommandPool(s->device,
|
2019-08-19 16:32:22 +02:00
|
|
|
&commandPoolCreateInfo, NULL,
|
2023-08-27 00:24:04 +02:00
|
|
|
commandPool));
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-08-19 16:32:22 +02:00
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
int vulkan_commandBuffer_create(struct vulkan_base *s, VkCommandPool commandPool, VkCommandBuffer *commandBuffer)
|
|
|
|
|
{
|
2021-06-27 17:47:13 +02:00
|
|
|
const VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
|
2019-08-19 16:32:22 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
2023-08-27 00:24:04 +02:00
|
|
|
.commandPool = commandPool,
|
2019-08-19 16:32:22 +02:00
|
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
|
};
|
2019-08-19 18:16:32 +02:00
|
|
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(s->device,
|
2019-08-19 16:32:22 +02:00
|
|
|
&commandBufferAllocateInfo,
|
2023-08-27 00:24:04 +02:00
|
|
|
commandBuffer));
|
2019-08-19 16:32:22 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
uint32_t vulkan_memoryType_find(struct vulkan_base *s,
|
|
|
|
|
uint32_t memoryTypeBits, VkMemoryPropertyFlags properties)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
|
|
|
|
uint32_t i;
|
2023-08-27 00:24:04 +02:00
|
|
|
VkPhysicalDeviceMemoryProperties memoryProperties;
|
2019-08-19 16:32:22 +02:00
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
vkGetPhysicalDeviceMemoryProperties(s->physicalDevice, &memoryProperties);
|
2022-05-30 18:34:31 +02:00
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
for (i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
|
|
|
|
if ((memoryTypeBits & (1 << i)) &&
|
|
|
|
|
((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties))
|
|
|
|
|
return i;
|
2019-08-19 16:32:22 +02:00
|
|
|
}
|
2023-08-27 00:24:04 +02:00
|
|
|
return -1;
|
2019-08-19 16:32:22 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
void vulkan_buffer_clear(struct vulkan_base *s, struct vulkan_buffer *buffer)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
2023-08-27 00:24:04 +02:00
|
|
|
if (buffer->fd != -1)
|
|
|
|
|
close(buffer->fd);
|
|
|
|
|
vkFreeMemory(s->device, buffer->memory, NULL);
|
|
|
|
|
vkDestroyImage(s->device, buffer->image, NULL);
|
|
|
|
|
vkDestroyImageView(s->device, buffer->view, NULL);
|
2019-08-19 16:32:22 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
int vulkan_stream_init(struct vulkan_stream *stream, enum spa_direction direction,
|
|
|
|
|
struct spa_dict *props)
|
2022-05-30 18:34:31 +02:00
|
|
|
{
|
|
|
|
|
spa_zero(*stream);
|
|
|
|
|
stream->direction = direction;
|
|
|
|
|
stream->current_buffer_id = SPA_ID_INVALID;
|
|
|
|
|
stream->busy_buffer_id = SPA_ID_INVALID;
|
|
|
|
|
stream->ready_buffer_id = SPA_ID_INVALID;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-21 16:29:17 +01:00
|
|
|
uint32_t vulkan_vkformat_to_id(VkFormat format)
|
|
|
|
|
{
|
|
|
|
|
SPA_FOR_EACH_ELEMENT_VAR(vk_video_format_convs, f) {
|
|
|
|
|
if (f->format == format)
|
|
|
|
|
return f->id;
|
|
|
|
|
}
|
|
|
|
|
return SPA_VIDEO_FORMAT_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkFormat vulkan_id_to_vkformat(uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
SPA_FOR_EACH_ELEMENT_VAR(vk_video_format_convs, f) {
|
|
|
|
|
if (f->id == id)
|
|
|
|
|
return f->format;
|
|
|
|
|
}
|
|
|
|
|
return VK_FORMAT_UNDEFINED;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
int vulkan_vkresult_to_errno(VkResult result)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
2023-08-27 00:24:04 +02:00
|
|
|
return vkresult_to_errno(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int vulkan_base_init(struct vulkan_base *s, struct vulkan_base_info *info)
|
|
|
|
|
{
|
|
|
|
|
if (!s->initialized) {
|
2022-05-31 11:33:51 +02:00
|
|
|
CHECK(createInstance(s));
|
|
|
|
|
CHECK(findPhysicalDevice(s));
|
2023-08-27 00:24:04 +02:00
|
|
|
CHECK(createDevice(s, info));
|
|
|
|
|
s->initialized = true;
|
2019-08-19 16:32:22 +02:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 00:24:04 +02:00
|
|
|
void vulkan_base_deinit(struct vulkan_base *s)
|
2019-08-19 16:32:22 +02:00
|
|
|
{
|
2023-08-27 00:24:04 +02:00
|
|
|
if (s->initialized) {
|
2019-08-19 16:32:22 +02:00
|
|
|
vkDestroyDevice(s->device, NULL);
|
|
|
|
|
vkDestroyInstance(s->instance, NULL);
|
2023-08-27 00:24:04 +02:00
|
|
|
s->initialized = false;
|
2022-05-30 18:34:31 +02:00
|
|
|
}
|
2019-08-19 16:32:22 +02:00
|
|
|
}
|