From 48d3093fc8715443a3de99a0dbd13b714f7d5f33 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Wed, 25 Jan 2023 09:30:52 +0200 Subject: [PATCH] vk_instance: Rework feature management * Use a helper macro to always check for features. Previously it was assumed extension availability was also feature availability but this isn't the case. This is inspired by skyline's trait_manager --- .../renderer_vulkan/vk_instance.cpp | 125 +++++++++++------- src/video_core/renderer_vulkan/vk_instance.h | 32 +++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 18 +-- 3 files changed, 122 insertions(+), 53 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 85561f7d1..1c2da4654 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "common/assert.h" #include "common/settings.h" #include "core/frontend/emu_window.h" @@ -525,9 +526,14 @@ bool Instance::CreateDevice() { const vk::StructureChain feature_chain = physical_device.getFeatures2< vk::PhysicalDeviceFeatures2, vk::PhysicalDevicePortabilitySubsetFeaturesKHR, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT, + vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT, + vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT, vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR, vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT, vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>(); + const vk::StructureChain properties_chain = + physical_device.getProperties2(); // Not having geometry shaders will cause issues with accelerated rendering. features = feature_chain.get().features; @@ -542,11 +548,9 @@ bool Instance::CreateDevice() { return false; } - // Helper lambda for adding extensions - std::array enabled_extensions; + std::array enabled_extensions; u32 enabled_extension_count = 0; - - auto AddExtension = [&](std::string_view extension) -> bool { + const auto AddExtension = [&](std::string_view extension) -> bool { auto result = std::find_if(available_extensions.begin(), available_extensions.end(), [&](const std::string& name) { return name == extension; }); @@ -561,16 +565,15 @@ bool Instance::CreateDevice() { }; AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); -#ifdef __APPLE__ - bool portability_subset = AddExtension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); -#endif timeline_semaphores = AddExtension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME); - extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); - push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); - custom_border_color = AddExtension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); - index_type_uint8 = AddExtension(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME); image_format_list = AddExtension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME); - pipeline_creation_cache_control = + bool has_portability_subset = AddExtension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + bool has_extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + bool has_extended_dynamic_state2 = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + bool has_extended_dynamic_state3 = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + bool has_custom_border_color = AddExtension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); + bool has_index_type_uint8 = AddExtension(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME); + bool has_pipeline_creation_cache_control = AddExtension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME); // Search queue families for graphics and present queues @@ -643,60 +646,93 @@ bool Instance::CreateDevice() { .shaderClipDistance = features.shaderClipDistance, }, }, -#ifdef __APPLE__ - feature_chain.get(), -#endif + vk::PhysicalDevicePortabilitySubsetFeaturesKHR{}, +#ifndef ANDROID ///< Android uses the extension layer. Avoid enabling the feature because it messes + ///< with the pNext chain vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR{ .timelineSemaphore = true, }, - vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT{ - .extendedDynamicState = true, - }, - vk::PhysicalDeviceCustomBorderColorFeaturesEXT{ - .customBorderColors = true, - .customBorderColorWithoutFormat = true, - }, - vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{ - .indexTypeUint8 = true, - }, - vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT{ - .pipelineCreationCacheControl = true, - }, +#endif + vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT{}, + vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT{}, + vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{}, + vk::PhysicalDeviceCustomBorderColorFeaturesEXT{}, + vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{}, + vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT{}, }; -#ifdef __APPLE__ - if (portability_subset) { - const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features = - feature_chain.get(); - triangle_fan_supported = portability_features.triangleFans; +#define PROP_GET(structName, prop, property) property = properties_chain.get().prop; - const vk::StructureChain portability_properties_chain = - physical_device.getProperties2(); - const vk::PhysicalDevicePortabilitySubsetPropertiesKHR portability_properties = - portability_properties_chain.get(); - min_vertex_stride_alignment = portability_properties.minVertexInputBindingStrideAlignment; +#define FEAT_SET(structName, feature, property) \ + if (feature_chain.get().feature) { \ + property = true; \ + device_chain.get().feature = true; \ + } else { \ + property = false; \ + device_chain.get().feature = false; \ + } + + if (has_portability_subset) { + FEAT_SET(vk::PhysicalDevicePortabilitySubsetFeaturesKHR, triangleFans, + triangle_fan_supported) + PROP_GET(vk::PhysicalDevicePortabilitySubsetPropertiesKHR, + minVertexInputBindingStrideAlignment, min_vertex_stride_alignment) } else { device_chain.unlink(); } -#endif - if (!index_type_uint8) { + if (has_index_type_uint8) { + FEAT_SET(vk::PhysicalDeviceIndexTypeUint8FeaturesEXT, indexTypeUint8, index_type_uint8) + } else { device_chain.unlink(); } - if (!extended_dynamic_state) { + if (has_extended_dynamic_state) { + FEAT_SET(vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT, extendedDynamicState, + extended_dynamic_state) + } else { device_chain.unlink(); } - if (!custom_border_color) { + if (has_extended_dynamic_state2) { + FEAT_SET(vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT, extendedDynamicState2LogicOp, + extended_dynamic_state2) + } else { + device_chain.unlink(); + } + + if (has_extended_dynamic_state3) { + FEAT_SET(vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT, + extendedDynamicState3LogicOpEnable, extended_dynamic_state3_logicop_enable) + FEAT_SET(vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT, + extendedDynamicState3ColorBlendEnable, extended_dynamic_state3_color_blend_enable) + FEAT_SET(vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT, + extendedDynamicState3ColorBlendEquation, extended_dynamic_state3_color_blend_eq) + FEAT_SET(vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT, + extendedDynamicState3ColorWriteMask, extended_dynamic_state3_color_write_mask) + } else { + device_chain.unlink(); + } + + if (has_custom_border_color) { + FEAT_SET(vk::PhysicalDeviceCustomBorderColorFeaturesEXT, customBorderColors, + custom_border_color) + FEAT_SET(vk::PhysicalDeviceCustomBorderColorFeaturesEXT, customBorderColorWithoutFormat, + custom_border_color) + } else { device_chain.unlink(); } - if (!pipeline_creation_cache_control) { + if (has_pipeline_creation_cache_control) { + FEAT_SET(vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT, + pipelineCreationCacheControl, pipeline_creation_cache_control) + } else { device_chain.unlink(); } +#undef PROP_GET +#undef FEAT_SET + try { device = physical_device.createDevice(device_chain.get()); } catch (vk::ExtensionNotPresentError& err) { @@ -706,7 +742,6 @@ bool Instance::CreateDevice() { VULKAN_HPP_DEFAULT_DISPATCHER.init(device); - // Grab the graphics and present queues. graphics_queue = device.getQueue(graphics_queue_family_index, 0); present_queue = device.getQueue(present_queue_family_index, 0); diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 1add82724..fcc55516c 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -121,6 +121,33 @@ public: return extended_dynamic_state; } + /// Returns true when VK_EXT_extended_dynamic_state2 is supported + bool IsExtendedDynamicState2Supported() const { + return extended_dynamic_state2; + } + + /// Returns true when the logicOpEnable feature of VK_EXT_extended_dynamic_state3 is supported + bool IsExtendedDynamicState3LogicOpSupported() const { + return extended_dynamic_state3_logicop_enable; + } + + /// Returns true when the colorBlendEnable feature of VK_EXT_extended_dynamic_state3 is + /// supported + bool IsExtendedDynamicState3BlendEnableSupported() const { + return extended_dynamic_state3_color_blend_enable; + } + + /// Returns true when the colorBlendEquation feature of VK_EXT_extended_dynamic_state3 is + /// supported + bool IsExtendedDynamicState3BlendEqSupported() const { + return extended_dynamic_state3_color_blend_eq; + } + + /// Returns true when the colorWriteMask feature of VK_EXT_extended_dynamic_state3 is supported + bool IsExtendedDynamicState3ColorMaskSupported() const { + return extended_dynamic_state3_color_write_mask; + } + /// Returns true when VK_KHR_push_descriptors is supported bool IsPushDescriptorsSupported() const { return push_descriptors; @@ -262,6 +289,11 @@ private: u32 min_vertex_stride_alignment{1}; bool timeline_semaphores{}; bool extended_dynamic_state{}; + bool extended_dynamic_state2{}; + bool extended_dynamic_state3_logicop_enable{}; + bool extended_dynamic_state3_color_blend_enable{}; + bool extended_dynamic_state3_color_blend_eq{}; + bool extended_dynamic_state3_color_write_mask{}; bool push_descriptors{}; bool custom_border_color{}; bool index_type_uint8{}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index bd34f8bd6..a4dfe8561 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -617,11 +617,8 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info, bool is_dirty) { return; } - scheduler.Record([this, is_dirty, current_dynamic = current_info.dynamic, - current_rasterization = current_info.rasterization, - current_depth_stencil = current_info.depth_stencil, dynamic = info.dynamic, - rasterization = info.rasterization, - depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) { + scheduler.Record([is_dirty, current_dynamic = current_info.dynamic, + dynamic = info.dynamic](vk::CommandBuffer cmdbuf) { if (dynamic.stencil_compare_mask != current_dynamic.stencil_compare_mask || is_dirty) { cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, dynamic.stencil_compare_mask); @@ -641,8 +638,13 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info, bool is_dirty) { const Common::Vec4f color = PicaToVK::ColorRGBA8(dynamic.blend_color); cmdbuf.setBlendConstants(color.AsArray()); } + }); - if (instance.IsExtendedDynamicStateSupported()) { + if (instance.IsExtendedDynamicStateSupported()) { + scheduler.Record([is_dirty, current_rasterization = current_info.rasterization, + current_depth_stencil = current_info.depth_stencil, + rasterization = info.rasterization, + depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) { if (rasterization.cull_mode != current_rasterization.cull_mode || is_dirty) { cmdbuf.setCullModeEXT(PicaToVK::CullMode(rasterization.cull_mode)); cmdbuf.setFrontFaceEXT(PicaToVK::FrontFace(rasterization.cull_mode)); @@ -684,8 +686,8 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info, bool is_dirty) { PicaToVK::StencilOp(depth_stencil.stencil_depth_fail_op), PicaToVK::CompareFunc(depth_stencil.stencil_compare_op)); } - } - }); + }); + } current_info = info; }