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