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.
#include <span>
#include <boost/container/small_vector.hpp>
#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<vk::PhysicalDeviceProperties2,
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
// 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<const char*, 10> enabled_extensions;
std::array<const char*, 12> 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<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(),
#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<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
triangle_fan_supported = portability_features.triangleFans;
#define PROP_GET(structName, prop, property) property = properties_chain.get<structName>().prop;
const vk::StructureChain portability_properties_chain =
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
const vk::PhysicalDevicePortabilitySubsetPropertiesKHR portability_properties =
portability_properties_chain.get<vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
min_vertex_stride_alignment = portability_properties.minVertexInputBindingStrideAlignment;
#define FEAT_SET(structName, feature, property) \
if (feature_chain.get<structName>().feature) { \
property = true; \
device_chain.get<structName>().feature = true; \
} else { \
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 {
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>();
}
if (!extended_dynamic_state) {
if (has_extended_dynamic_state) {
FEAT_SET(vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT, extendedDynamicState,
extended_dynamic_state)
} else {
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>();
}
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>();
}
#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);

View File

@ -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{};

View File

@ -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;
}