1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018 |
- /*
- Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely.
- */
- #include <SDL3/SDL.h>
- #include <SDL3/SDL_vulkan.h>
- #include "testffmpeg_vulkan.h"
- #ifdef FFMPEG_VULKAN_SUPPORT
- #define VULKAN_FUNCTIONS() \
- VULKAN_GLOBAL_FUNCTION(vkCreateInstance) \
- VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties) \
- VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties) \
- VULKAN_INSTANCE_FUNCTION(vkCreateDevice) \
- VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) \
- VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR) \
- VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties) \
- VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices) \
- VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr) \
- VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures2) \
- VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) \
- VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) \
- VULKAN_INSTANCE_FUNCTION(vkQueueWaitIdle) \
- VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers) \
- VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer) \
- VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier2) \
- VULKAN_DEVICE_FUNCTION(vkCreateCommandPool) \
- VULKAN_DEVICE_FUNCTION(vkCreateSemaphore) \
- VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool) \
- VULKAN_DEVICE_FUNCTION(vkDestroyDevice) \
- VULKAN_DEVICE_FUNCTION(vkDestroySemaphore) \
- VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle) \
- VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer) \
- VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers) \
- VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue) \
- VULKAN_DEVICE_FUNCTION(vkQueueSubmit) \
- \
- VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceVideoFormatPropertiesKHR) \
- typedef struct
- {
- VkPhysicalDeviceFeatures2 device_features;
- VkPhysicalDeviceVulkan11Features device_features_1_1;
- VkPhysicalDeviceVulkan12Features device_features_1_2;
- VkPhysicalDeviceVulkan13Features device_features_1_3;
- VkPhysicalDeviceDescriptorBufferFeaturesEXT desc_buf_features;
- VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_features;
- VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_matrix_features;
- } VulkanDeviceFeatures;
- struct VulkanVideoContext
- {
- VkInstance instance;
- VkSurfaceKHR surface;
- VkPhysicalDevice physicalDevice;
- int presentQueueFamilyIndex;
- int presentQueueCount;
- int graphicsQueueFamilyIndex;
- int graphicsQueueCount;
- int transferQueueFamilyIndex;
- int transferQueueCount;
- int computeQueueFamilyIndex;
- int computeQueueCount;
- int decodeQueueFamilyIndex;
- int decodeQueueCount;
- VkDevice device;
- VkQueue graphicsQueue;
- VkCommandPool commandPool;
- VkCommandBuffer *commandBuffers;
- uint32_t commandBufferCount;
- uint32_t commandBufferIndex;
- VkSemaphore *waitSemaphores;
- uint32_t waitSemaphoreCount;
- VkSemaphore *signalSemaphores;
- uint32_t signalSemaphoreCount;
- const char **instanceExtensions;
- int instanceExtensionsCount;
- const char **deviceExtensions;
- int deviceExtensionsCount;
- VulkanDeviceFeatures features;
- PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
- #define VULKAN_GLOBAL_FUNCTION(name) PFN_##name name;
- #define VULKAN_INSTANCE_FUNCTION(name) PFN_##name name;
- #define VULKAN_DEVICE_FUNCTION(name) PFN_##name name;
- VULKAN_FUNCTIONS()
- #undef VULKAN_GLOBAL_FUNCTION
- #undef VULKAN_INSTANCE_FUNCTION
- #undef VULKAN_DEVICE_FUNCTION
- };
- static int loadGlobalFunctions(VulkanVideoContext *context)
- {
- context->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
- if (!context->vkGetInstanceProcAddr) {
- return -1;
- }
- #define VULKAN_GLOBAL_FUNCTION(name) \
- context->name = (PFN_##name)context->vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \
- if (!context->name) { \
- return SDL_SetError("vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \
- }
- #define VULKAN_INSTANCE_FUNCTION(name)
- #define VULKAN_DEVICE_FUNCTION(name)
- VULKAN_FUNCTIONS()
- #undef VULKAN_GLOBAL_FUNCTION
- #undef VULKAN_INSTANCE_FUNCTION
- #undef VULKAN_DEVICE_FUNCTION
- return 0;
- }
- static int loadInstanceFunctions(VulkanVideoContext *context)
- {
- #define VULKAN_GLOBAL_FUNCTION(name)
- #define VULKAN_INSTANCE_FUNCTION(name) \
- context->name = (PFN_##name)context->vkGetInstanceProcAddr(context->instance, #name); \
- if (!context->name) { \
- return SDL_SetError("vkGetInstanceProcAddr(instance, \"" #name "\") failed"); \
- }
- #define VULKAN_DEVICE_FUNCTION(name)
- VULKAN_FUNCTIONS()
- #undef VULKAN_GLOBAL_FUNCTION
- #undef VULKAN_INSTANCE_FUNCTION
- #undef VULKAN_DEVICE_FUNCTION
- return 0;
- }
- static int loadDeviceFunctions(VulkanVideoContext *context)
- {
- #define VULKAN_GLOBAL_FUNCTION(name)
- #define VULKAN_INSTANCE_FUNCTION(name)
- #define VULKAN_DEVICE_FUNCTION(name) \
- context->name = (PFN_##name)context->vkGetDeviceProcAddr(context->device, #name); \
- if (!context->name) { \
- return SDL_SetError("vkGetDeviceProcAddr(device, \"" #name "\") failed"); \
- }
- VULKAN_FUNCTIONS()
- #undef VULKAN_GLOBAL_FUNCTION
- #undef VULKAN_INSTANCE_FUNCTION
- #undef VULKAN_DEVICE_FUNCTION
- return 0;
- }
- #undef VULKAN_FUNCTIONS
- static const char *getVulkanResultString(VkResult result)
- {
- switch ((int)result) {
- #define RESULT_CASE(x) \
- case x: \
- return #x
- RESULT_CASE(VK_SUCCESS);
- RESULT_CASE(VK_NOT_READY);
- RESULT_CASE(VK_TIMEOUT);
- RESULT_CASE(VK_EVENT_SET);
- RESULT_CASE(VK_EVENT_RESET);
- RESULT_CASE(VK_INCOMPLETE);
- RESULT_CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
- RESULT_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
- RESULT_CASE(VK_ERROR_INITIALIZATION_FAILED);
- RESULT_CASE(VK_ERROR_DEVICE_LOST);
- RESULT_CASE(VK_ERROR_MEMORY_MAP_FAILED);
- RESULT_CASE(VK_ERROR_LAYER_NOT_PRESENT);
- RESULT_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
- RESULT_CASE(VK_ERROR_FEATURE_NOT_PRESENT);
- RESULT_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
- RESULT_CASE(VK_ERROR_TOO_MANY_OBJECTS);
- RESULT_CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
- RESULT_CASE(VK_ERROR_FRAGMENTED_POOL);
- RESULT_CASE(VK_ERROR_SURFACE_LOST_KHR);
- RESULT_CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
- RESULT_CASE(VK_SUBOPTIMAL_KHR);
- RESULT_CASE(VK_ERROR_OUT_OF_DATE_KHR);
- RESULT_CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
- RESULT_CASE(VK_ERROR_VALIDATION_FAILED_EXT);
- RESULT_CASE(VK_ERROR_OUT_OF_POOL_MEMORY_KHR);
- RESULT_CASE(VK_ERROR_INVALID_SHADER_NV);
- #undef RESULT_CASE
- default:
- break;
- }
- return (result < 0) ? "VK_ERROR_<Unknown>" : "VK_<Unknown>";
- }
- static int createInstance(VulkanVideoContext *context)
- {
- static const char *optional_extensions[] = {
- VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
- VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
- };
- VkApplicationInfo appInfo = { 0 };
- VkInstanceCreateInfo instanceCreateInfo = { 0 };
- VkResult result;
- char const *const *instanceExtensions = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount);
- appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- appInfo.apiVersion = VK_API_VERSION_1_3;
- instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- instanceCreateInfo.pApplicationInfo = &appInfo;
- const char **instanceExtensionsCopy = SDL_calloc(instanceCreateInfo.enabledExtensionCount + SDL_arraysize(optional_extensions), sizeof(const char *));
- for (uint32_t i = 0; i < instanceCreateInfo.enabledExtensionCount; i++) {
- instanceExtensionsCopy[i] = instanceExtensions[i];
- }
- // Get the rest of the optional extensions
- {
- uint32_t extensionCount;
- if (context->vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL) == VK_SUCCESS && extensionCount > 0) {
- VkExtensionProperties *extensionProperties = SDL_calloc(extensionCount, sizeof(VkExtensionProperties));
- if (context->vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionProperties) == VK_SUCCESS) {
- for (uint32_t i = 0; i < SDL_arraysize(optional_extensions); ++i) {
- for (uint32_t j = 0; j < extensionCount; ++j) {
- if (SDL_strcmp(extensionProperties[j].extensionName, optional_extensions[i]) == 0) {
- instanceExtensionsCopy[instanceCreateInfo.enabledExtensionCount++] = optional_extensions[i];
- break;
- }
- }
- }
- }
- SDL_free(extensionProperties);
- }
- }
- instanceCreateInfo.ppEnabledExtensionNames = instanceExtensionsCopy;
- context->instanceExtensions = instanceExtensionsCopy;
- context->instanceExtensionsCount = instanceCreateInfo.enabledExtensionCount;
- result = context->vkCreateInstance(&instanceCreateInfo, NULL, &context->instance);
- if (result != VK_SUCCESS) {
- context->instance = VK_NULL_HANDLE;
- return SDL_SetError("vkCreateInstance(): %s", getVulkanResultString(result));
- }
- if (loadInstanceFunctions(context) < 0) {
- return -1;
- }
- return 0;
- }
- static int createSurface(VulkanVideoContext *context, SDL_Window *window)
- {
- if (!SDL_Vulkan_CreateSurface(window, context->instance, NULL, &context->surface)) {
- context->surface = VK_NULL_HANDLE;
- return -1;
- }
- return 0;
- }
- // Use the same queue scoring algorithm as ffmpeg to make sure we get the same device configuration
- static int selectQueueFamily(VkQueueFamilyProperties *queueFamiliesProperties, uint32_t queueFamiliesCount, VkQueueFlagBits flags, int *queueCount)
- {
- uint32_t queueFamilyIndex;
- uint32_t selectedQueueFamilyIndex = queueFamiliesCount;
- uint32_t min_score = ~0u;
- for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; ++queueFamilyIndex) {
- VkQueueFlagBits current_flags = queueFamiliesProperties[queueFamilyIndex].queueFlags;
- if (current_flags & flags) {
- uint32_t score = av_popcount(current_flags) + queueFamiliesProperties[queueFamilyIndex].timestampValidBits;
- if (score < min_score) {
- selectedQueueFamilyIndex = queueFamilyIndex;
- min_score = score;
- }
- }
- }
- if (selectedQueueFamilyIndex != queueFamiliesCount) {
- VkQueueFamilyProperties *selectedQueueFamily = &queueFamiliesProperties[selectedQueueFamilyIndex];
- *queueCount = (int)selectedQueueFamily->queueCount;
- ++selectedQueueFamily->timestampValidBits;
- return (int)selectedQueueFamilyIndex;
- } else {
- *queueCount = 0;
- return -1;
- }
- }
- static int findPhysicalDevice(VulkanVideoContext *context)
- {
- uint32_t physicalDeviceCount = 0;
- VkPhysicalDevice *physicalDevices;
- VkQueueFamilyProperties *queueFamiliesProperties = NULL;
- uint32_t queueFamiliesPropertiesAllocatedSize = 0;
- VkExtensionProperties *deviceExtensions = NULL;
- uint32_t deviceExtensionsAllocatedSize = 0;
- uint32_t physicalDeviceIndex;
- VkResult result;
- result = context->vkEnumeratePhysicalDevices(context->instance, &physicalDeviceCount, NULL);
- if (result != VK_SUCCESS) {
- return SDL_SetError("vkEnumeratePhysicalDevices(): %s", getVulkanResultString(result));
- }
- if (physicalDeviceCount == 0) {
- return SDL_SetError("vkEnumeratePhysicalDevices(): no physical devices");
- }
- physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
- if (!physicalDevices) {
- return -1;
- }
- result = context->vkEnumeratePhysicalDevices(context->instance, &physicalDeviceCount, physicalDevices);
- if (result != VK_SUCCESS) {
- SDL_free(physicalDevices);
- return SDL_SetError("vkEnumeratePhysicalDevices(): %s", getVulkanResultString(result));
- }
- context->physicalDevice = NULL;
- for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) {
- uint32_t queueFamiliesCount = 0;
- uint32_t queueFamilyIndex;
- uint32_t deviceExtensionCount = 0;
- bool hasSwapchainExtension = false;
- uint32_t i;
- VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex];
- context->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL);
- if (queueFamiliesCount == 0) {
- continue;
- }
- if (queueFamiliesPropertiesAllocatedSize < queueFamiliesCount) {
- SDL_free(queueFamiliesProperties);
- queueFamiliesPropertiesAllocatedSize = queueFamiliesCount;
- queueFamiliesProperties = (VkQueueFamilyProperties *)SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize);
- if (!queueFamiliesProperties) {
- SDL_free(physicalDevices);
- SDL_free(deviceExtensions);
- return -1;
- }
- }
- context->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, queueFamiliesProperties);
- // Initialize timestampValidBits for scoring in selectQueueFamily
- for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; queueFamilyIndex++) {
- queueFamiliesProperties[queueFamilyIndex].timestampValidBits = 0;
- }
- context->presentQueueFamilyIndex = -1;
- context->graphicsQueueFamilyIndex = -1;
- for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; queueFamilyIndex++) {
- VkBool32 supported = 0;
- if (queueFamiliesProperties[queueFamilyIndex].queueCount == 0) {
- continue;
- }
- if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
- context->graphicsQueueFamilyIndex = queueFamilyIndex;
- }
- result = context->vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, context->surface, &supported);
- if (result == VK_SUCCESS) {
- if (supported) {
- context->presentQueueFamilyIndex = queueFamilyIndex;
- if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
- break; // use this queue because it can present and do graphics
- }
- }
- }
- }
- if (context->presentQueueFamilyIndex < 0 || context->graphicsQueueFamilyIndex < 0) {
- // We can't render and present on this device
- continue;
- }
- context->presentQueueCount = queueFamiliesProperties[context->presentQueueFamilyIndex].queueCount;
- ++queueFamiliesProperties[context->presentQueueFamilyIndex].timestampValidBits;
- context->graphicsQueueCount = queueFamiliesProperties[context->graphicsQueueFamilyIndex].queueCount;
- ++queueFamiliesProperties[context->graphicsQueueFamilyIndex].timestampValidBits;
- context->transferQueueFamilyIndex = selectQueueFamily(queueFamiliesProperties, queueFamiliesCount, VK_QUEUE_TRANSFER_BIT, &context->transferQueueCount);
- context->computeQueueFamilyIndex = selectQueueFamily(queueFamiliesProperties, queueFamiliesCount, VK_QUEUE_COMPUTE_BIT, &context->computeQueueCount);
- context->decodeQueueFamilyIndex = selectQueueFamily(queueFamiliesProperties, queueFamiliesCount, VK_QUEUE_VIDEO_DECODE_BIT_KHR, &context->decodeQueueCount);
- if (context->transferQueueFamilyIndex < 0) {
- // ffmpeg can fall back to the compute or graphics queues for this
- context->transferQueueFamilyIndex = selectQueueFamily(queueFamiliesProperties, queueFamiliesCount, VK_QUEUE_COMPUTE_BIT, &context->transferQueueCount);
- if (context->transferQueueFamilyIndex < 0) {
- context->transferQueueFamilyIndex = selectQueueFamily(queueFamiliesProperties, queueFamiliesCount, VK_QUEUE_GRAPHICS_BIT, &context->transferQueueCount);
- }
- }
- if (context->transferQueueFamilyIndex < 0 ||
- context->computeQueueFamilyIndex < 0) {
- // This device doesn't have the queues we need for video decoding
- continue;
- }
- result = context->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL);
- if (result != VK_SUCCESS) {
- SDL_free(physicalDevices);
- SDL_free(queueFamiliesProperties);
- SDL_free(deviceExtensions);
- return SDL_SetError("vkEnumerateDeviceExtensionProperties(): %s", getVulkanResultString(result));
- }
- if (deviceExtensionCount == 0) {
- continue;
- }
- if (deviceExtensionsAllocatedSize < deviceExtensionCount) {
- SDL_free(deviceExtensions);
- deviceExtensionsAllocatedSize = deviceExtensionCount;
- deviceExtensions = SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize);
- if (!deviceExtensions) {
- SDL_free(physicalDevices);
- SDL_free(queueFamiliesProperties);
- return -1;
- }
- }
- result = context->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, deviceExtensions);
- if (result != VK_SUCCESS) {
- SDL_free(physicalDevices);
- SDL_free(queueFamiliesProperties);
- SDL_free(deviceExtensions);
- return SDL_SetError("vkEnumerateDeviceExtensionProperties(): %s", getVulkanResultString(result));
- }
- for (i = 0; i < deviceExtensionCount; i++) {
- if (SDL_strcmp(deviceExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
- hasSwapchainExtension = true;
- break;
- }
- }
- if (!hasSwapchainExtension) {
- continue;
- }
- context->physicalDevice = physicalDevice;
- break;
- }
- SDL_free(physicalDevices);
- SDL_free(queueFamiliesProperties);
- SDL_free(deviceExtensions);
- if (!context->physicalDevice) {
- return SDL_SetError("Vulkan: no viable physical devices found");
- }
- return 0;
- }
- static void initDeviceFeatures(VulkanDeviceFeatures *features)
- {
- features->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- features->device_features.pNext = &features->device_features_1_1;
- features->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
- features->device_features_1_1.pNext = &features->device_features_1_2;
- features->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
- features->device_features_1_2.pNext = &features->device_features_1_3;
- features->device_features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
- features->device_features_1_3.pNext = &features->desc_buf_features;
- features->desc_buf_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT;
- features->desc_buf_features.pNext = &features->atomic_float_features;
- features->atomic_float_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT;
- features->atomic_float_features.pNext = &features->coop_matrix_features;
- features->coop_matrix_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR;
- features->coop_matrix_features.pNext = NULL;
- }
- static void copyDeviceFeatures(VulkanDeviceFeatures *supported_features, VulkanDeviceFeatures *requested_features)
- {
- #define COPY_OPTIONAL_FEATURE(X) requested_features->X = supported_features->X
- COPY_OPTIONAL_FEATURE(device_features.features.shaderImageGatherExtended);
- COPY_OPTIONAL_FEATURE(device_features.features.shaderStorageImageReadWithoutFormat);
- COPY_OPTIONAL_FEATURE(device_features.features.shaderStorageImageWriteWithoutFormat);
- COPY_OPTIONAL_FEATURE(device_features.features.fragmentStoresAndAtomics);
- COPY_OPTIONAL_FEATURE(device_features.features.vertexPipelineStoresAndAtomics);
- COPY_OPTIONAL_FEATURE(device_features.features.shaderInt64);
- COPY_OPTIONAL_FEATURE(device_features.features.shaderInt16);
- COPY_OPTIONAL_FEATURE(device_features.features.shaderFloat64);
- COPY_OPTIONAL_FEATURE(device_features_1_1.samplerYcbcrConversion);
- COPY_OPTIONAL_FEATURE(device_features_1_1.storagePushConstant16);
- COPY_OPTIONAL_FEATURE(device_features_1_2.bufferDeviceAddress);
- COPY_OPTIONAL_FEATURE(device_features_1_2.hostQueryReset);
- COPY_OPTIONAL_FEATURE(device_features_1_2.storagePushConstant8);
- COPY_OPTIONAL_FEATURE(device_features_1_2.shaderInt8);
- COPY_OPTIONAL_FEATURE(device_features_1_2.storageBuffer8BitAccess);
- COPY_OPTIONAL_FEATURE(device_features_1_2.uniformAndStorageBuffer8BitAccess);
- COPY_OPTIONAL_FEATURE(device_features_1_2.shaderFloat16);
- COPY_OPTIONAL_FEATURE(device_features_1_2.shaderSharedInt64Atomics);
- COPY_OPTIONAL_FEATURE(device_features_1_2.vulkanMemoryModel);
- COPY_OPTIONAL_FEATURE(device_features_1_2.vulkanMemoryModelDeviceScope);
- COPY_OPTIONAL_FEATURE(device_features_1_2.hostQueryReset);
- COPY_OPTIONAL_FEATURE(device_features_1_3.dynamicRendering);
- COPY_OPTIONAL_FEATURE(device_features_1_3.maintenance4);
- COPY_OPTIONAL_FEATURE(device_features_1_3.synchronization2);
- COPY_OPTIONAL_FEATURE(device_features_1_3.computeFullSubgroups);
- COPY_OPTIONAL_FEATURE(device_features_1_3.shaderZeroInitializeWorkgroupMemory);
- COPY_OPTIONAL_FEATURE(desc_buf_features.descriptorBuffer);
- COPY_OPTIONAL_FEATURE(desc_buf_features.descriptorBufferPushDescriptors);
- COPY_OPTIONAL_FEATURE(atomic_float_features.shaderBufferFloat32Atomics);
- COPY_OPTIONAL_FEATURE(atomic_float_features.shaderBufferFloat32AtomicAdd);
- COPY_OPTIONAL_FEATURE(coop_matrix_features.cooperativeMatrix);
- #undef COPY_OPTIONAL_FEATURE
- // timeline semaphores is required by ffmpeg
- requested_features->device_features_1_2.timelineSemaphore = 1;
- }
- static int addQueueFamily(VkDeviceQueueCreateInfo **pQueueCreateInfos, uint32_t *pQueueCreateInfoCount, uint32_t queueFamilyIndex, uint32_t queueCount)
- {
- VkDeviceQueueCreateInfo *queueCreateInfo;
- VkDeviceQueueCreateInfo *queueCreateInfos = *pQueueCreateInfos;
- uint32_t queueCreateInfoCount = *pQueueCreateInfoCount;
- float *queuePriorities;
- if (queueCount == 0) {
- return 0;
- }
- for (uint32_t i = 0; i < queueCreateInfoCount; ++i) {
- if (queueCreateInfos[i].queueFamilyIndex == queueFamilyIndex) {
- return 0;
- }
- }
- queueCreateInfos = (VkDeviceQueueCreateInfo *)SDL_realloc(queueCreateInfos, (queueCreateInfoCount + 1) * sizeof(*queueCreateInfos));
- if (!queueCreateInfos) {
- return -1;
- }
- queuePriorities = (float *)SDL_malloc(queueCount * sizeof(*queuePriorities));
- if (!queuePriorities) {
- return -1;
- }
- for (uint32_t i = 0; i < queueCount; ++i) {
- queuePriorities[i] = 1.0f / queueCount;
- }
- queueCreateInfo = &queueCreateInfos[queueCreateInfoCount++];
- SDL_zerop(queueCreateInfo);
- queueCreateInfo->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queueCreateInfo->queueFamilyIndex = queueFamilyIndex;
- queueCreateInfo->queueCount = queueCount;
- queueCreateInfo->pQueuePriorities = queuePriorities;
- *pQueueCreateInfos = queueCreateInfos;
- *pQueueCreateInfoCount = queueCreateInfoCount;
- return 0;
- }
- static int createDevice(VulkanVideoContext *context)
- {
- static const char *const deviceExtensionNames[] = {
- VK_KHR_SWAPCHAIN_EXTENSION_NAME,
- VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
- VK_KHR_MAINTENANCE1_EXTENSION_NAME,
- VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
- VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
- };
- static const char *optional_extensions[] = {
- VK_KHR_VIDEO_QUEUE_EXTENSION_NAME,
- VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
- VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
- VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
- VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME
- };
- VkDeviceCreateInfo deviceCreateInfo = { 0 };
- VkDeviceQueueCreateInfo *queueCreateInfos = NULL;
- uint32_t queueCreateInfoCount = 0;
- VulkanDeviceFeatures supported_features;
- VkResult result = VK_ERROR_UNKNOWN;
- if (addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->presentQueueFamilyIndex, context->presentQueueCount) < 0 ||
- addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->graphicsQueueFamilyIndex, context->graphicsQueueCount) < 0 ||
- addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->transferQueueFamilyIndex, context->transferQueueCount) < 0 ||
- addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->computeQueueFamilyIndex, context->computeQueueCount) < 0 ||
- addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->decodeQueueFamilyIndex, context->decodeQueueCount) < 0) {
- goto done;
- }
- initDeviceFeatures(&supported_features);
- initDeviceFeatures(&context->features);
- context->vkGetPhysicalDeviceFeatures2(context->physicalDevice, &supported_features.device_features);
- copyDeviceFeatures(&supported_features, &context->features);
- deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- deviceCreateInfo.queueCreateInfoCount = queueCreateInfoCount;
- deviceCreateInfo.pQueueCreateInfos = queueCreateInfos;
- deviceCreateInfo.pEnabledFeatures = NULL;
- deviceCreateInfo.enabledExtensionCount = SDL_arraysize(deviceExtensionNames);
- deviceCreateInfo.pNext = &context->features.device_features;
- const char **deviceExtensionsCopy = SDL_calloc(deviceCreateInfo.enabledExtensionCount + SDL_arraysize(optional_extensions), sizeof(const char *));
- for (uint32_t i = 0; i < deviceCreateInfo.enabledExtensionCount; i++) {
- deviceExtensionsCopy[i] = deviceExtensionNames[i];
- }
- // Get the rest of the optional extensions
- {
- uint32_t extensionCount;
- if (context->vkEnumerateDeviceExtensionProperties(context->physicalDevice, NULL, &extensionCount, NULL) == VK_SUCCESS && extensionCount > 0) {
- VkExtensionProperties *extensionProperties = SDL_calloc(extensionCount, sizeof(VkExtensionProperties));
- if (context->vkEnumerateDeviceExtensionProperties(context->physicalDevice, NULL, &extensionCount, extensionProperties) == VK_SUCCESS) {
- for (uint32_t i = 0; i < SDL_arraysize(optional_extensions); ++i) {
- for (uint32_t j = 0; j < extensionCount; ++j) {
- if (SDL_strcmp(extensionProperties[j].extensionName, optional_extensions[i]) == 0) {
- deviceExtensionsCopy[deviceCreateInfo.enabledExtensionCount++] = optional_extensions[i];
- break;
- }
- }
- }
- }
- SDL_free(extensionProperties);
- }
- }
- deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionsCopy;
- context->deviceExtensions = deviceExtensionsCopy;
- context->deviceExtensionsCount = deviceCreateInfo.enabledExtensionCount;
- result = context->vkCreateDevice(context->physicalDevice, &deviceCreateInfo, NULL, &context->device);
- if (result != VK_SUCCESS) {
- SDL_SetError("vkCreateDevice(): %s", getVulkanResultString(result));
- goto done;
- }
- if (loadDeviceFunctions(context) < 0) {
- result = VK_ERROR_UNKNOWN;
- context->device = VK_NULL_HANDLE;
- goto done;
- }
- // Get the graphics queue that SDL will use
- context->vkGetDeviceQueue(context->device, context->graphicsQueueFamilyIndex, 0, &context->graphicsQueue);
- // Create a command pool
- VkCommandPoolCreateInfo commandPoolCreateInfo = { 0 };
- commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- commandPoolCreateInfo.queueFamilyIndex = context->graphicsQueueFamilyIndex;
- result = context->vkCreateCommandPool(context->device, &commandPoolCreateInfo, NULL, &context->commandPool);
- if (result != VK_SUCCESS) {
- SDL_SetError("vkCreateCommandPool(): %s", getVulkanResultString(result));
- goto done;
- }
- done:
- for (uint32_t i = 0; i < queueCreateInfoCount; ++i) {
- SDL_free((void *)queueCreateInfos[i].pQueuePriorities);
- }
- SDL_free(queueCreateInfos);
- if (result != VK_SUCCESS) {
- return -1;
- }
- return 0;
- }
- VulkanVideoContext *CreateVulkanVideoContext(SDL_Window *window)
- {
- VulkanVideoContext *context = SDL_calloc(1, sizeof(*context));
- if (!context) {
- return NULL;
- }
- if (loadGlobalFunctions(context) < 0 ||
- createInstance(context) < 0 ||
- createSurface(context, window) < 0 ||
- findPhysicalDevice(context) < 0 ||
- createDevice(context) < 0) {
- DestroyVulkanVideoContext(context);
- return NULL;
- }
- return context;
- }
- void SetupVulkanRenderProperties(VulkanVideoContext *context, SDL_PropertiesID props)
- {
- SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER, context->instance);
- SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER, (Sint64)context->surface);
- SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER, context->physicalDevice);
- SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_DEVICE_POINTER, context->device);
- SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER, context->presentQueueFamilyIndex);
- SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER, context->graphicsQueueFamilyIndex);
- }
- #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(59, 34, 100)
- static void AddQueueFamily(AVVulkanDeviceContext *ctx, int idx, int num, VkQueueFlagBits flags)
- {
- AVVulkanDeviceQueueFamily *entry = &ctx->qf[ctx->nb_qf++];
- entry->idx = idx;
- entry->num = num;
- entry->flags = flags;
- }
- #endif /* LIBAVUTIL_VERSION_INT */
- void SetupVulkanDeviceContextData(VulkanVideoContext *context, AVVulkanDeviceContext *ctx)
- {
- ctx->get_proc_addr = context->vkGetInstanceProcAddr;
- ctx->inst = context->instance;
- ctx->phys_dev = context->physicalDevice;
- ctx->act_dev = context->device;
- ctx->device_features = context->features.device_features;
- ctx->enabled_inst_extensions = context->instanceExtensions;
- ctx->nb_enabled_inst_extensions = context->instanceExtensionsCount;
- ctx->enabled_dev_extensions = context->deviceExtensions;
- ctx->nb_enabled_dev_extensions = context->deviceExtensionsCount;
- #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(59, 34, 100)
- AddQueueFamily(ctx, context->graphicsQueueFamilyIndex, context->graphicsQueueCount, VK_QUEUE_GRAPHICS_BIT);
- AddQueueFamily(ctx, context->transferQueueFamilyIndex, context->transferQueueCount, VK_QUEUE_TRANSFER_BIT);
- AddQueueFamily(ctx, context->computeQueueFamilyIndex, context->computeQueueCount, VK_QUEUE_COMPUTE_BIT);
- AddQueueFamily(ctx, context->decodeQueueFamilyIndex, context->decodeQueueCount, VK_QUEUE_VIDEO_DECODE_BIT_KHR);
- #else
- ctx->queue_family_index = context->graphicsQueueFamilyIndex;
- ctx->nb_graphics_queues = context->graphicsQueueCount;
- ctx->queue_family_tx_index = context->transferQueueFamilyIndex;
- ctx->nb_tx_queues = context->transferQueueCount;
- ctx->queue_family_comp_index = context->computeQueueFamilyIndex;
- ctx->nb_comp_queues = context->computeQueueCount;
- ctx->queue_family_encode_index = -1;
- ctx->nb_encode_queues = 0;
- ctx->queue_family_decode_index = context->decodeQueueFamilyIndex;
- ctx->nb_decode_queues = context->decodeQueueCount;
- #endif /* LIBAVUTIL_VERSION_INT */
- }
- static int CreateCommandBuffers(VulkanVideoContext *context, SDL_Renderer *renderer)
- {
- uint32_t commandBufferCount = (uint32_t)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VULKAN_SWAPCHAIN_IMAGE_COUNT_NUMBER, 1);
- if (commandBufferCount > context->waitSemaphoreCount) {
- VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(context->waitSemaphores, commandBufferCount * sizeof(*semaphores));
- if (!semaphores) {
- return -1;
- }
- context->waitSemaphores = semaphores;
- VkSemaphoreCreateInfo semaphoreCreateInfo = { 0 };
- semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- while (context->waitSemaphoreCount < commandBufferCount) {
- VkResult result = context->vkCreateSemaphore(context->device, &semaphoreCreateInfo, NULL, &context->waitSemaphores[context->waitSemaphoreCount]);
- if (result != VK_SUCCESS) {
- SDL_SetError("vkCreateSemaphore(): %s", getVulkanResultString(result));
- return -1;
- }
- ++context->waitSemaphoreCount;
- }
- }
- if (commandBufferCount > context->signalSemaphoreCount) {
- VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(context->signalSemaphores, commandBufferCount * sizeof(*semaphores));
- if (!semaphores) {
- return -1;
- }
- context->signalSemaphores = semaphores;
- VkSemaphoreCreateInfo semaphoreCreateInfo = { 0 };
- semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- while (context->signalSemaphoreCount < commandBufferCount) {
- VkResult result = context->vkCreateSemaphore(context->device, &semaphoreCreateInfo, NULL, &context->signalSemaphores[context->signalSemaphoreCount]);
- if (result != VK_SUCCESS) {
- SDL_SetError("vkCreateSemaphore(): %s", getVulkanResultString(result));
- return -1;
- }
- ++context->signalSemaphoreCount;
- }
- }
- if (commandBufferCount > context->commandBufferCount) {
- uint32_t needed = (commandBufferCount - context->commandBufferCount);
- VkCommandBuffer *commandBuffers = (VkCommandBuffer *)SDL_realloc(context->commandBuffers, commandBufferCount * sizeof(*commandBuffers));
- if (!commandBuffers) {
- return -1;
- }
- context->commandBuffers = commandBuffers;
- VkCommandBufferAllocateInfo commandBufferAllocateInfo = { 0 };
- commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- commandBufferAllocateInfo.commandPool = context->commandPool;
- commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- commandBufferAllocateInfo.commandBufferCount = needed;
- VkResult result = context->vkAllocateCommandBuffers(context->device, &commandBufferAllocateInfo, &context->commandBuffers[context->commandBufferCount]);
- if (result != VK_SUCCESS) {
- SDL_SetError("vkAllocateCommandBuffers(): %s", getVulkanResultString(result));
- return -1;
- }
- context->commandBufferCount = commandBufferCount;
- }
- return 0;
- }
- int BeginVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_Renderer *renderer)
- {
- AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
- AVVulkanFramesContext *vk = (AVVulkanFramesContext *)(frames->hwctx);
- AVVkFrame *pVkFrame = (AVVkFrame *)frame->data[0];
- if (CreateCommandBuffers(context, renderer) < 0) {
- return -1;
- }
- vk->lock_frame(frames, pVkFrame);
- VkTimelineSemaphoreSubmitInfo timeline = { 0 };
- timeline.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
- timeline.waitSemaphoreValueCount = 1;
- timeline.pWaitSemaphoreValues = pVkFrame->sem_value;
- VkPipelineStageFlags pipelineStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- VkSubmitInfo submitInfo = { 0 };
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pWaitSemaphores = pVkFrame->sem;
- submitInfo.pWaitDstStageMask = &pipelineStageMask;
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = &context->waitSemaphores[context->commandBufferIndex];
- submitInfo.pNext = &timeline;
- if (pVkFrame->layout[0] != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
- VkCommandBuffer commandBuffer = context->commandBuffers[context->commandBufferIndex];
- VkCommandBufferBeginInfo beginInfo = { 0 };
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = 0;
- context->vkBeginCommandBuffer(commandBuffer, &beginInfo);
- VkImageMemoryBarrier2 barrier = { 0 };
- barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
- barrier.srcAccessMask = VK_ACCESS_2_NONE;
- barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
- barrier.oldLayout = pVkFrame->layout[0];
- barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- barrier.image = pVkFrame->img[0];
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- barrier.subresourceRange.levelCount = 1;
- barrier.subresourceRange.layerCount = 1;
- barrier.srcQueueFamilyIndex = pVkFrame->queue_family[0];
- barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- barrier.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- barrier.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- VkDependencyInfo dep = { 0 };
- dep.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
- dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
- dep.imageMemoryBarrierCount = 1;
- dep.pImageMemoryBarriers = &barrier;
- context->vkCmdPipelineBarrier2(commandBuffer, &dep);
- context->vkEndCommandBuffer(commandBuffer);
- // Add the image barrier to the submit info
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &context->commandBuffers[context->commandBufferIndex];
- pVkFrame->layout[0] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- pVkFrame->queue_family[0] = VK_QUEUE_FAMILY_IGNORED;
- }
- VkResult result = context->vkQueueSubmit(context->graphicsQueue, 1, &submitInfo, 0);
- if (result != VK_SUCCESS) {
- // Don't return an error here, we need to complete the frame operation
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION , "vkQueueSubmit(): %s", getVulkanResultString(result));
- }
- SDL_AddVulkanRenderSemaphores(renderer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (Sint64)context->waitSemaphores[context->commandBufferIndex], (Sint64)context->signalSemaphores[context->commandBufferIndex]);
- return 0;
- }
- int FinishVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_Renderer *renderer)
- {
- AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
- AVVulkanFramesContext *vk = (AVVulkanFramesContext *)(frames->hwctx);
- AVVkFrame *pVkFrame = (AVVkFrame *)frame->data[0];
- // Transition the frame back to ffmpeg
- ++pVkFrame->sem_value[0];
- VkTimelineSemaphoreSubmitInfo timeline = { 0 };
- timeline.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
- timeline.signalSemaphoreValueCount = 1;
- timeline.pSignalSemaphoreValues = pVkFrame->sem_value;
- VkPipelineStageFlags pipelineStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- VkSubmitInfo submitInfo = { 0 };
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pWaitSemaphores = &context->signalSemaphores[context->commandBufferIndex];
- submitInfo.pWaitDstStageMask = &pipelineStageMask;
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = pVkFrame->sem;
- submitInfo.pNext = &timeline;
- VkResult result = context->vkQueueSubmit(context->graphicsQueue, 1, &submitInfo, 0);
- if (result != VK_SUCCESS) {
- // Don't return an error here, we need to complete the frame operation
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkQueueSubmit(): %s", getVulkanResultString(result));
- }
- vk->unlock_frame(frames, pVkFrame);
- context->commandBufferIndex = (context->commandBufferIndex + 1) % context->commandBufferCount;
- return 0;
- }
- SDL_Texture *CreateVulkanVideoTexture(VulkanVideoContext *context, AVFrame *frame, SDL_Renderer *renderer, SDL_PropertiesID props)
- {
- AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
- AVVulkanFramesContext *vk = (AVVulkanFramesContext *)(frames->hwctx);
- AVVkFrame *pVkFrame = (AVVkFrame *)frame->data[0];
- Uint32 format;
- switch (vk->format[0]) {
- case VK_FORMAT_G8B8G8R8_422_UNORM:
- format = SDL_PIXELFORMAT_YUY2;
- break;
- case VK_FORMAT_B8G8R8G8_422_UNORM:
- format = SDL_PIXELFORMAT_UYVY;
- break;
- case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
- format = SDL_PIXELFORMAT_IYUV;
- break;
- case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
- format = SDL_PIXELFORMAT_NV12;
- break;
- case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
- format = SDL_PIXELFORMAT_P010;
- break;
- default:
- format = SDL_PIXELFORMAT_UNKNOWN;
- break;
- }
- SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, format);
- SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER, (Sint64)pVkFrame->img[0]);
- return SDL_CreateTextureWithProperties(renderer, props);
- }
- void DestroyVulkanVideoContext(VulkanVideoContext *context)
- {
- if (context) {
- if (context->device) {
- context->vkDeviceWaitIdle(context->device);
- }
- if (context->instanceExtensions) {
- SDL_free(context->instanceExtensions);
- }
- if (context->deviceExtensions) {
- SDL_free(context->deviceExtensions);
- }
- if (context->waitSemaphores) {
- for (uint32_t i = 0; i < context->waitSemaphoreCount; ++i) {
- context->vkDestroySemaphore(context->device, context->waitSemaphores[i], NULL);
- }
- SDL_free(context->waitSemaphores);
- context->waitSemaphores = NULL;
- }
- if (context->signalSemaphores) {
- for (uint32_t i = 0; i < context->signalSemaphoreCount; ++i) {
- context->vkDestroySemaphore(context->device, context->signalSemaphores[i], NULL);
- }
- SDL_free(context->signalSemaphores);
- context->signalSemaphores = NULL;
- }
- if (context->commandBuffers) {
- context->vkFreeCommandBuffers(context->device, context->commandPool, context->commandBufferCount, context->commandBuffers);
- SDL_free(context->commandBuffers);
- context->commandBuffers = NULL;
- }
- if (context->commandPool) {
- context->vkDestroyCommandPool(context->device, context->commandPool, NULL);
- context->commandPool = VK_NULL_HANDLE;
- }
- if (context->device) {
- context->vkDestroyDevice(context->device, NULL);
- }
- if (context->surface) {
- context->vkDestroySurfaceKHR(context->instance, context->surface, NULL);
- }
- if (context->instance) {
- context->vkDestroyInstance(context->instance, NULL);
- }
- SDL_free(context);
- }
- }
- #else
- VulkanVideoContext *CreateVulkanVideoContext(SDL_Window *window)
- {
- SDL_SetError("testffmpeg not built with Vulkan support");
- return NULL;
- }
- void SetupVulkanRenderProperties(VulkanVideoContext *context, SDL_PropertiesID props)
- {
- }
- void SetupVulkanDeviceContextData(VulkanVideoContext *context, AVVulkanDeviceContext *ctx)
- {
- }
- SDL_Texture *CreateVulkanVideoTexture(VulkanVideoContext *context, AVFrame *frame, SDL_Renderer *renderer, SDL_PropertiesID props)
- {
- return NULL;
- }
- int BeginVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_Renderer *renderer)
- {
- return -1;
- }
- int FinishVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_Renderer *renderer)
- {
- return -1;
- }
- void DestroyVulkanVideoContext(VulkanVideoContext *context)
- {
- }
- #endif /* FFMPEG_VULKAN_SUPPORT */
|