12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001 |
- /*
- Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
- 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\n"); \
- }
- 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\n", 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);
- }
- 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;
- 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;
- }
- 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
|