diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index ce6080851..e67f32c1c 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -404,7 +404,15 @@ bool Drawer::Draw(const Texture *fogTexture, const Texture *paletteTexture) static const float scopeColor[4] = { 0.75f, 0.75f, 0.75f, 1.0f }; CommandBufferDebugScope _(cmdBuffer, "Draw", scopeColor); - setFirstProvokingVertex(pvrrc); + if (VulkanContext::Instance()->hasProvokingVertex()) + { + // Pipelines are using VK_EXT_provoking_vertex, no need to + // re-order vertices + } + else + { + setFirstProvokingVertex(pvrrc); + } // Upload vertex and index buffers VertexShaderUniforms vtxUniforms; diff --git a/core/rend/vulkan/oit/oit_drawer.cpp b/core/rend/vulkan/oit/oit_drawer.cpp index f4ed5b3c8..2695ad3eb 100644 --- a/core/rend/vulkan/oit/oit_drawer.cpp +++ b/core/rend/vulkan/oit/oit_drawer.cpp @@ -341,7 +341,15 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture) bool firstFrameAfterInit = oitBuffers->isFirstFrameAfterInit(); oitBuffers->OnNewFrame(cmdBuffer); - setFirstProvokingVertex(pvrrc); + if (VulkanContext::Instance()->hasProvokingVertex()) + { + // Pipelines are using VK_EXT_provoking_vertex, no need to + // re-order vertices + } + else + { + setFirstProvokingVertex(pvrrc); + } // Upload vertex and index buffers UploadMainBuffer(vtxUniforms, fragUniforms); diff --git a/core/rend/vulkan/oit/oit_pipeline.cpp b/core/rend/vulkan/oit/oit_pipeline.cpp index cb0ecd2cc..b6d3d31db 100644 --- a/core/rend/vulkan/oit/oit_pipeline.cpp +++ b/core/rend/vulkan/oit/oit_pipeline.cpp @@ -49,6 +49,17 @@ void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyP 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil @@ -211,6 +222,17 @@ void OITPipelineManager::CreateFinalPipeline(bool dithering) 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil @@ -295,6 +317,17 @@ void OITPipelineManager::CreateClearPipeline() 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil @@ -377,6 +410,17 @@ void OITPipelineManager::CreateModVolPipeline(ModVolMode mode, int cullMode, boo 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil @@ -489,6 +533,17 @@ void OITPipelineManager::CreateTrModVolPipeline(ModVolMode mode, int cullMode, b 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil diff --git a/core/rend/vulkan/pipeline.cpp b/core/rend/vulkan/pipeline.cpp index 37bf1f198..fa2e45a8b 100644 --- a/core/rend/vulkan/pipeline.cpp +++ b/core/rend/vulkan/pipeline.cpp @@ -67,6 +67,17 @@ void PipelineManager::CreateModVolPipeline(ModVolMode mode, int cullMode, bool n 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil @@ -189,6 +200,17 @@ void PipelineManager::CreateDepthPassPipeline(int cullMode, bool naomi2) 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil @@ -295,6 +317,17 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); + + // Dreamcast uses the last vertex as the provoking vertex, but Vulkan uses the first. + // Utilize VK_EXT_provoking_vertex when available to set the provoking vertex to be the + // last vertex + vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexInfo{}; + if (GetContext()->hasProvokingVertex()) + { + provokingVertexInfo.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex; + pipelineRasterizationStateCreateInfo.pNext = &provokingVertexInfo; + } + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil diff --git a/core/rend/vulkan/vk_context_lr.cpp b/core/rend/vulkan/vk_context_lr.cpp index 5f0db5c72..a49eeeebb 100644 --- a/core/rend/vulkan/vk_context_lr.cpp +++ b/core/rend/vulkan/vk_context_lr.cpp @@ -71,6 +71,9 @@ bool VkCreateDevice(retro_vulkan_context* context, VkInstance instance, VkPhysic physicalDevice = vkinstance.enumeratePhysicalDevices().front(); } context->gpu = (VkPhysicalDevice)physicalDevice; + + const vk::PhysicalDeviceProperties physicalDeviceProperties = physicalDevice.getProperties(); + std::vector queueFamilyProperties = physicalDevice.getQueueFamilyProperties(); // get the first index into queueFamilyProperties which supports graphics and compute @@ -124,54 +127,119 @@ bool VkCreateDevice(retro_vulkan_context* context, VkInstance instance, VkPhysic DEBUG_LOG(RENDERER, "Using distinct Graphics and Present queue families"); } - vk::PhysicalDeviceFeatures supportedFeatures; - physicalDevice.getFeatures(&supportedFeatures); - VulkanContext::Instance()->fragmentStoresAndAtomics = supportedFeatures.fragmentStoresAndAtomics; - VulkanContext::Instance()->samplerAnisotropy = supportedFeatures.samplerAnisotropy; - // Enable VK_KHR_dedicated_allocation if available - bool getMemReq2Supported = false; - VulkanContext::Instance()->dedicatedAllocationSupported = false; - std::vector deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; - for (unsigned i = 0; i < num_required_device_extensions; i++) - deviceExtensions.push_back(required_device_extensions[i]); - for (const auto& property : physicalDevice.enumerateDeviceExtensionProperties()) + std::set supportedExtensions; + + const auto deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties(); + for (const auto& property : deviceExtensionProperties) { - if (!strcmp(property.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) + supportedExtensions.insert(property.extensionName); + } + + std::vector enabledExtensions; + + const auto tryAddDeviceExtension = [&supportedExtensions = std::as_const(supportedExtensions), &enabledExtensions] + (std::string_view extensionName) -> bool { - deviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - getMemReq2Supported = true; - } - else if (!strcmp(property.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME)) + if (supportedExtensions.count(extensionName.data())) + { + enabledExtensions.push_back(extensionName.data()); + NOTICE_LOG(RENDERER, "Device extension enabled: %s", extensionName.data()); + return true; + } + NOTICE_LOG(RENDERER, "Device extension unavailable: %s", extensionName.data()); + return false; + }; + + // Required swapchain extension + tryAddDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + // Enable VK_KHR_dedicated_allocation if available + if (physicalDeviceProperties.apiVersion >= VK_API_VERSION_1_1) + { + // Core in Vulkan 1.1 + VulkanContext::Instance()->dedicatedAllocationSupported = true; + } + else + { + const bool getMemReq2Supported = tryAddDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + if (getMemReq2Supported) { - deviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - VulkanContext::Instance()->dedicatedAllocationSupported = true; + VulkanContext::Instance()->dedicatedAllocationSupported = tryAddDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); } } - VulkanContext::Instance()->dedicatedAllocationSupported &= getMemReq2Supported; + + // Check for VK_KHR_get_physical_device_properties2 + // Core as of Vulkan 1.1 + const bool getPhysicalDeviceProperties2Supported = + (physicalDeviceProperties.apiVersion >= VK_API_VERSION_1_1) + ? true : tryAddDeviceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + if (getPhysicalDeviceProperties2Supported) + { + // Enable VK_EXT_provoking_vertex if available + VulkanContext::Instance()->provokingVertexSupported = tryAddDeviceExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME); + } + + // Get device features + + vk::PhysicalDeviceFeatures2 featuresChain{}; + vk::PhysicalDeviceFeatures& features = featuresChain.features; + + vk::PhysicalDeviceProvokingVertexFeaturesEXT provokingVertexFeatures{}; + if (VulkanContext::Instance()->provokingVertexSupported) + { + featuresChain.pNext = &provokingVertexFeatures; + } + + // Get the physical device's features + if (getPhysicalDeviceProperties2Supported && featuresChain.pNext) + { + physicalDevice.getFeatures2(&featuresChain); + } + else + { + physicalDevice.getFeatures(&features); + } + + if (VulkanContext::Instance()->provokingVertexSupported) + { + VulkanContext::Instance()->provokingVertexSupported &= provokingVertexFeatures.provokingVertexLast; + } + + VulkanContext::Instance()->samplerAnisotropy = features.samplerAnisotropy; + VulkanContext::Instance()->fragmentStoresAndAtomics = features.fragmentStoresAndAtomics; // create a Device float queuePriority = 1.0f; - vk::DeviceQueueCreateInfo deviceQueueCreateInfos[] = { + vk::DeviceQueueCreateInfo deviceQueueCreateInfo[] = { vk::DeviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), context->queue_family_index, 1, &queuePriority), vk::DeviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), context->presentation_queue_family_index, 1, &queuePriority), }; - vk::PhysicalDeviceFeatures features(*required_features); - if (VulkanContext::Instance()->fragmentStoresAndAtomics) - features.fragmentStoresAndAtomics = true; - if (VulkanContext::Instance()->samplerAnisotropy) - features.samplerAnisotropy = true; - vk::Device device = physicalDevice.createDevice(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), - context->queue_family_index == context->presentation_queue_family_index ? 1 : 2, deviceQueueCreateInfos, - num_required_device_layers, required_device_layers, deviceExtensions.size(), &deviceExtensions[0], &features)); - context->device = (VkDevice)device; + + + vk::Device newDevice{}; + if (getPhysicalDeviceProperties2Supported) + { + vk::DeviceCreateInfo deviceCreateInfo(vk::DeviceCreateFlags(), deviceQueueCreateInfo, + nullptr, enabledExtensions); + deviceCreateInfo.pNext = &featuresChain; + newDevice = physicalDevice.createDevice(deviceCreateInfo); + } + else + { + newDevice = physicalDevice.createDevice(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), deviceQueueCreateInfo, + nullptr, enabledExtensions, &features)); + } + + context->device = (VkDevice)newDevice; #if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 VULKAN_HPP_DEFAULT_DISPATCHER.init(context->device); #endif // Queues - context->queue = (VkQueue)device.getQueue(context->queue_family_index, 0); - context->presentation_queue = (VkQueue)device.getQueue(context->presentation_queue_family_index, 0); + context->queue = (VkQueue)newDevice.getQueue(context->queue_family_index, 0); + context->presentation_queue = (VkQueue)newDevice.getQueue(context->presentation_queue_family_index, 0); return true; } diff --git a/core/rend/vulkan/vk_context_lr.h b/core/rend/vulkan/vk_context_lr.h index 4d49c345a..c97f489bc 100644 --- a/core/rend/vulkan/vk_context_lr.h +++ b/core/rend/vulkan/vk_context_lr.h @@ -92,6 +92,7 @@ class VulkanContext : public GraphicsContext, public FlightManager bool SupportsSamplerAnisotropy() const { return samplerAnisotropy; } bool SupportsDedicatedAllocation() const { return dedicatedAllocationSupported; } bool hasPerPixel() override { return fragmentStoresAndAtomics; } + bool hasProvokingVertex() { return provokingVertexSupported; } const VMAllocator& GetAllocator() const { return allocator; } vk::DeviceSize GetMaxMemoryAllocationSize() const { return maxMemoryAllocationSize; } f32 GetMaxSamplerAnisotropy() const { return samplerAnisotropy ? maxSamplerAnisotropy : 1.f; } @@ -129,10 +130,11 @@ class VulkanContext : public GraphicsContext, public FlightManager bool optimalTilingSupported1555 = false; bool optimalTilingSupported4444 = false; public: + bool fragmentStoresAndAtomics = false; bool samplerAnisotropy = false; f32 maxSamplerAnisotropy = 0.f; bool dedicatedAllocationSupported = false; - bool fragmentStoresAndAtomics = false; + bool provokingVertexSupported = false; private: u32 vendorID = 0; diff --git a/core/rend/vulkan/vmallocator.cpp b/core/rend/vulkan/vmallocator.cpp index b284a4c6a..abe592a5f 100644 --- a/core/rend/vulkan/vmallocator.cpp +++ b/core/rend/vulkan/vmallocator.cpp @@ -55,6 +55,8 @@ void VMAllocator::Init(vk::PhysicalDevice physicalDevice, vk::Device device, vk: allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; allocatorInfo.physicalDevice = (VkPhysicalDevice)physicalDevice; + // Top-out at vulkan 1.1 + allocatorInfo.vulkanApiVersion = (physicalDevice.getProperties().apiVersion >= VK_API_VERSION_1_1) ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0; allocatorInfo.device = (VkDevice)device; allocatorInfo.instance = (VkInstance)instance; #if !defined(NDEBUG) || defined(DEBUGFAST) diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index 8439a2d37..304bd0c0b 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -158,10 +158,9 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co bool vulkan11 = false; if (VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceVersion != nullptr) { - u32 apiVersion = vk::enumerateInstanceVersion(); + const u32 apiVersion = vk::enumerateInstanceVersion(); - vulkan11 = VK_API_VERSION_MAJOR(apiVersion) > 1 - || (VK_API_VERSION_MAJOR(apiVersion) == 1 && VK_API_VERSION_MINOR(apiVersion) >= 1); + vulkan11 = (apiVersion >= VK_API_VERSION_1_1); } vk::ApplicationInfo applicationInfo("Flycast", 1, "Flycast", 1, vulkan11 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0); @@ -290,11 +289,6 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co optimalTilingSupported4444 = true; else NOTICE_LOG(RENDERER, "eR4G4B4A4UnormPack16 not supported for optimal tiling"); - const auto features = physicalDevice.getFeatures(); - fragmentStoresAndAtomics = !!features.fragmentStoresAndAtomics; - samplerAnisotropy = !!features.samplerAnisotropy; - if (!fragmentStoresAndAtomics) - NOTICE_LOG(RENDERER, "Fragment stores & atomic not supported: no per-pixel sorting"); ShaderCompiler::Init(); @@ -358,6 +352,8 @@ bool VulkanContext::InitDevice() return false; try { + const vk::PhysicalDeviceProperties physicalDeviceProperties = physicalDevice.getProperties(); + std::vector queueFamilyProperties = physicalDevice.getQueueFamilyProperties(); #ifdef VK_DEBUG std::for_each(queueFamilyProperties.begin(), queueFamilyProperties.end(), @@ -434,11 +430,6 @@ bool VulkanContext::InitDevice() // Required swapchain extension tryAddDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - // Enable VK_KHR_dedicated_allocation if available - const bool getMemReq2Supported = tryAddDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - dedicatedAllocationSupported = tryAddDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - dedicatedAllocationSupported &= getMemReq2Supported; - #ifdef VK_ENABLE_BETA_EXTENSIONS tryAddDeviceExtension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); #endif @@ -449,16 +440,80 @@ bool VulkanContext::InitDevice() tryAddDeviceExtension(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); #endif + // Enable VK_KHR_dedicated_allocation if available + if (physicalDeviceProperties.apiVersion >= VK_API_VERSION_1_1) + { + // Core in Vulkan 1.1 + dedicatedAllocationSupported = true; + } + else + { + const bool getMemReq2Supported = tryAddDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + if (getMemReq2Supported) + { + dedicatedAllocationSupported = tryAddDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + } + } + + // Check for VK_KHR_get_physical_device_properties2 + // Core as of Vulkan 1.1 + const bool getPhysicalDeviceProperties2Supported = + (physicalDeviceProperties.apiVersion >= VK_API_VERSION_1_1) + ? true : tryAddDeviceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + if (getPhysicalDeviceProperties2Supported) + { + // Enable VK_EXT_provoking_vertex if available + provokingVertexSupported = tryAddDeviceExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME); + } + + // Get device features + + vk::PhysicalDeviceFeatures2 featuresChain{}; + vk::PhysicalDeviceFeatures& features = featuresChain.features; + + vk::PhysicalDeviceProvokingVertexFeaturesEXT provokingVertexFeatures{}; + if (provokingVertexSupported) + { + featuresChain.pNext = &provokingVertexFeatures; + } + + // Get the physical device's features + if (getPhysicalDeviceProperties2Supported && featuresChain.pNext) + { + physicalDevice.getFeatures2(&featuresChain); + } + else + { + physicalDevice.getFeatures(&features); + } + + if (provokingVertexSupported) + { + provokingVertexSupported &= provokingVertexFeatures.provokingVertexLast; + } + + samplerAnisotropy = features.samplerAnisotropy; + fragmentStoresAndAtomics = features.fragmentStoresAndAtomics; + if (!fragmentStoresAndAtomics) + NOTICE_LOG(RENDERER, "Fragment stores & atomic not supported: no per-pixel sorting"); + // create a UniqueDevice float queuePriority = 1.0f; vk::DeviceQueueCreateInfo deviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), graphicsQueueIndex, 1, &queuePriority); - vk::PhysicalDeviceFeatures features; - if (fragmentStoresAndAtomics) - features.fragmentStoresAndAtomics = true; - if (samplerAnisotropy) - features.samplerAnisotropy = true; - device = physicalDevice.createDeviceUnique(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), deviceQueueCreateInfo, + + if (getPhysicalDeviceProperties2Supported) + { + vk::DeviceCreateInfo deviceCreateInfo(vk::DeviceCreateFlags(), deviceQueueCreateInfo, + nullptr, enabledExtensions); + deviceCreateInfo.pNext = &featuresChain; + device = physicalDevice.createDeviceUnique(deviceCreateInfo); + } + else + { + device = physicalDevice.createDeviceUnique(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), deviceQueueCreateInfo, nullptr, enabledExtensions, &features)); + } #if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 VULKAN_HPP_DEFAULT_DISPATCHER.init(*device); diff --git a/core/rend/vulkan/vulkan_context.h b/core/rend/vulkan/vulkan_context.h index 3baf5f2e7..8001905c2 100644 --- a/core/rend/vulkan/vulkan_context.h +++ b/core/rend/vulkan/vulkan_context.h @@ -167,6 +167,7 @@ class VulkanContext : public GraphicsContext, public FlightManager vk::SubmitInfo(nullptr, nullptr, buffers), fence); } bool hasPerPixel() override { return fragmentStoresAndAtomics; } + bool hasProvokingVertex() { return provokingVertexSupported; } bool recreateSwapChainIfNeeded(); void addToFlight(Deletable *object) override { inFlightObjects[GetCurrentImageIndex()].emplace_back(object); @@ -229,6 +230,7 @@ class VulkanContext : public GraphicsContext, public FlightManager bool samplerAnisotropy = false; float maxSamplerAnisotropy = 0.f; bool dedicatedAllocationSupported = false; + bool provokingVertexSupported = false; u32 vendorID = 0; int swapInterval = 1; vk::UniqueDevice device;