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
This commit is contained in:
GPUCode
2023-01-25 09:30:52 +02:00
parent f77491196c
commit 48d3093fc8
3 changed files with 122 additions and 53 deletions

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <span> #include <span>
#include <boost/container/small_vector.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
@ -525,9 +526,14 @@ bool Instance::CreateDevice() {
const vk::StructureChain feature_chain = physical_device.getFeatures2< const vk::StructureChain feature_chain = physical_device.getFeatures2<
vk::PhysicalDeviceFeatures2, vk::PhysicalDevicePortabilitySubsetFeaturesKHR, vk::PhysicalDeviceFeatures2, vk::PhysicalDevicePortabilitySubsetFeaturesKHR,
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT,
vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT,
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT,
vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR, vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR,
vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT, vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT,
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>(); vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>();
const vk::StructureChain properties_chain =
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
// Not having geometry shaders will cause issues with accelerated rendering. // Not having geometry shaders will cause issues with accelerated rendering.
features = feature_chain.get().features; features = feature_chain.get().features;
@ -542,11 +548,9 @@ bool Instance::CreateDevice() {
return false; return false;
} }
// Helper lambda for adding extensions std::array<const char*, 12> enabled_extensions;
std::array<const char*, 10> enabled_extensions;
u32 enabled_extension_count = 0; u32 enabled_extension_count = 0;
const auto AddExtension = [&](std::string_view extension) -> bool {
auto AddExtension = [&](std::string_view extension) -> bool {
auto result = std::find_if(available_extensions.begin(), available_extensions.end(), auto result = std::find_if(available_extensions.begin(), available_extensions.end(),
[&](const std::string& name) { return name == extension; }); [&](const std::string& name) { return name == extension; });
@ -561,16 +565,15 @@ bool Instance::CreateDevice() {
}; };
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 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); 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); 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); AddExtension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME);
// Search queue families for graphics and present queues // Search queue families for graphics and present queues
@ -643,60 +646,93 @@ bool Instance::CreateDevice() {
.shaderClipDistance = features.shaderClipDistance, .shaderClipDistance = features.shaderClipDistance,
}, },
}, },
#ifdef __APPLE__ vk::PhysicalDevicePortabilitySubsetFeaturesKHR{},
feature_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(), #ifndef ANDROID ///< Android uses the extension layer. Avoid enabling the feature because it messes
#endif ///< with the pNext chain
vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR{ vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR{
.timelineSemaphore = true, .timelineSemaphore = true,
}, },
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT{ #endif
.extendedDynamicState = true, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT{},
}, vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT{},
vk::PhysicalDeviceCustomBorderColorFeaturesEXT{ vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{},
.customBorderColors = true, vk::PhysicalDeviceCustomBorderColorFeaturesEXT{},
.customBorderColorWithoutFormat = true, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{},
}, vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT{},
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{
.indexTypeUint8 = true,
},
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT{
.pipelineCreationCacheControl = true,
},
}; };
#ifdef __APPLE__ #define PROP_GET(structName, prop, property) property = properties_chain.get<structName>().prop;
if (portability_subset) {
const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features =
feature_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
triangle_fan_supported = portability_features.triangleFans;
const vk::StructureChain portability_properties_chain = #define FEAT_SET(structName, feature, property) \
physical_device.getProperties2<vk::PhysicalDeviceProperties2, if (feature_chain.get<structName>().feature) { \
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>(); property = true; \
const vk::PhysicalDevicePortabilitySubsetPropertiesKHR portability_properties = device_chain.get<structName>().feature = true; \
portability_properties_chain.get<vk::PhysicalDevicePortabilitySubsetPropertiesKHR>(); } else { \
min_vertex_stride_alignment = portability_properties.minVertexInputBindingStrideAlignment; property = false; \
device_chain.get<structName>().feature = false; \
}
if (has_portability_subset) {
FEAT_SET(vk::PhysicalDevicePortabilitySubsetFeaturesKHR, triangleFans,
triangle_fan_supported)
PROP_GET(vk::PhysicalDevicePortabilitySubsetPropertiesKHR,
minVertexInputBindingStrideAlignment, min_vertex_stride_alignment)
} else { } else {
device_chain.unlink<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(); device_chain.unlink<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
} }
#endif
if (!index_type_uint8) { if (has_index_type_uint8) {
FEAT_SET(vk::PhysicalDeviceIndexTypeUint8FeaturesEXT, indexTypeUint8, index_type_uint8)
} else {
device_chain.unlink<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(); device_chain.unlink<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>();
} }
if (!extended_dynamic_state) { if (has_extended_dynamic_state) {
FEAT_SET(vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT, extendedDynamicState,
extended_dynamic_state)
} else {
device_chain.unlink<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(); device_chain.unlink<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
} }
if (!custom_border_color) { if (has_extended_dynamic_state2) {
FEAT_SET(vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT, extendedDynamicState2LogicOp,
extended_dynamic_state2)
} else {
device_chain.unlink<vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT>();
}
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<vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT>();
}
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<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>(); device_chain.unlink<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>();
} }
if (!pipeline_creation_cache_control) { if (has_pipeline_creation_cache_control) {
FEAT_SET(vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT,
pipelineCreationCacheControl, pipeline_creation_cache_control)
} else {
device_chain.unlink<vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>(); device_chain.unlink<vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>();
} }
#undef PROP_GET
#undef FEAT_SET
try { try {
device = physical_device.createDevice(device_chain.get()); device = physical_device.createDevice(device_chain.get());
} catch (vk::ExtensionNotPresentError& err) { } catch (vk::ExtensionNotPresentError& err) {
@ -706,7 +742,6 @@ bool Instance::CreateDevice() {
VULKAN_HPP_DEFAULT_DISPATCHER.init(device); VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
// Grab the graphics and present queues.
graphics_queue = device.getQueue(graphics_queue_family_index, 0); graphics_queue = device.getQueue(graphics_queue_family_index, 0);
present_queue = device.getQueue(present_queue_family_index, 0); present_queue = device.getQueue(present_queue_family_index, 0);

View File

@ -121,6 +121,33 @@ public:
return extended_dynamic_state; 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 /// Returns true when VK_KHR_push_descriptors is supported
bool IsPushDescriptorsSupported() const { bool IsPushDescriptorsSupported() const {
return push_descriptors; return push_descriptors;
@ -262,6 +289,11 @@ private:
u32 min_vertex_stride_alignment{1}; u32 min_vertex_stride_alignment{1};
bool timeline_semaphores{}; bool timeline_semaphores{};
bool extended_dynamic_state{}; 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 push_descriptors{};
bool custom_border_color{}; bool custom_border_color{};
bool index_type_uint8{}; bool index_type_uint8{};

View File

@ -617,11 +617,8 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info, bool is_dirty) {
return; return;
} }
scheduler.Record([this, is_dirty, current_dynamic = current_info.dynamic, scheduler.Record([is_dirty, current_dynamic = current_info.dynamic,
current_rasterization = current_info.rasterization, dynamic = info.dynamic](vk::CommandBuffer cmdbuf) {
current_depth_stencil = current_info.depth_stencil, dynamic = info.dynamic,
rasterization = info.rasterization,
depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) {
if (dynamic.stencil_compare_mask != current_dynamic.stencil_compare_mask || is_dirty) { if (dynamic.stencil_compare_mask != current_dynamic.stencil_compare_mask || is_dirty) {
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
dynamic.stencil_compare_mask); 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); const Common::Vec4f color = PicaToVK::ColorRGBA8(dynamic.blend_color);
cmdbuf.setBlendConstants(color.AsArray()); 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) { if (rasterization.cull_mode != current_rasterization.cull_mode || is_dirty) {
cmdbuf.setCullModeEXT(PicaToVK::CullMode(rasterization.cull_mode)); cmdbuf.setCullModeEXT(PicaToVK::CullMode(rasterization.cull_mode));
cmdbuf.setFrontFaceEXT(PicaToVK::FrontFace(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::StencilOp(depth_stencil.stencil_depth_fail_op),
PicaToVK::CompareFunc(depth_stencil.stencil_compare_op)); PicaToVK::CompareFunc(depth_stencil.stencil_compare_op));
} }
} });
}); }
current_info = info; current_info = info;
} }