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:
@ -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);
|
||||||
|
|
||||||
|
@ -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{};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user