diff options
Diffstat (limited to 'src/video_core/vulkan_common')
| -rw-r--r-- | src/video_core/vulkan_common/vulkan.h | 11 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.cpp | 402 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.h | 202 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.h | 25 |
5 files changed, 553 insertions, 91 deletions
diff --git a/src/video_core/vulkan_common/vulkan.h b/src/video_core/vulkan_common/vulkan.h index 13f679ff54..8d2e8e2a37 100644 --- a/src/video_core/vulkan_common/vulkan.h +++ b/src/video_core/vulkan_common/vulkan.h @@ -22,6 +22,17 @@ #include <vulkan/vulkan.h> +// Define maintenance 7-9 extension names (not yet in official Vulkan headers) +#ifndef VK_KHR_MAINTENANCE_7_EXTENSION_NAME +#define VK_KHR_MAINTENANCE_7_EXTENSION_NAME "VK_KHR_maintenance7" +#endif +#ifndef VK_KHR_MAINTENANCE_8_EXTENSION_NAME +#define VK_KHR_MAINTENANCE_8_EXTENSION_NAME "VK_KHR_maintenance8" +#endif +#ifndef VK_KHR_MAINTENANCE_9_EXTENSION_NAME +#define VK_KHR_MAINTENANCE_9_EXTENSION_NAME "VK_KHR_maintenance9" +#endif + // Sanitize macros #undef CreateEvent #undef CreateSemaphore diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 3fc56d35d6..d68cc4b9a4 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -294,9 +294,10 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica #if defined(ANDROID) && defined(ARCHITECTURE_arm64) void OverrideBcnFormats(std::unordered_map<VkFormat, VkFormatProperties>& format_properties) { // These properties are extracted from Adreno driver 512.687.0 - constexpr VkFormatFeatureFlags tiling_features{ - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT | - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + constexpr VkFormatFeatureFlags tiling_features{VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_BLIT_SRC_BIT | + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT}; constexpr VkFormatFeatureFlags buffer_features{VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT}; @@ -418,7 +419,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_suitable = GetSuitability(surface != nullptr); const VkDriverId driver_id = properties.driver.driverID; - const auto device_id = properties.properties.deviceID; const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; const bool is_amd_driver = @@ -432,8 +432,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK; const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY; const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP; - const bool is_s8gen2 = device_id == 0x43050a01; - //const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; + const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; if (!is_suitable) LOG_WARNING(Render_Vulkan, "Unsuitable driver - continuing anyways"); @@ -487,8 +486,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR is_non_gpu = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER || properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU; - const bool is_intel_igpu = is_integrated && (is_intel_anv || is_intel_windows); - supports_d24_depth = IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal); @@ -499,6 +496,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR CollectToolingInfo(); if (is_qualcomm) { + // Qualcomm Adreno GPUs doesn't handle scaled vertex attributes; keep emulation enabled + must_emulate_scaled_formats = true; + LOG_WARNING(Render_Vulkan, + "Qualcomm drivers require scaled vertex format emulation; forcing fallback"); + LOG_WARNING(Render_Vulkan, "Disabling shader float controls and 64-bit integer features on Qualcomm proprietary drivers"); RemoveExtension(extensions.shader_float_controls, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); @@ -561,35 +563,31 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR } if (nv_major_version >= 510) { - LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits"); + LOG_WARNING(Render_Vulkan, + "NVIDIA Drivers >= 510 do not support MSAA->MSAA image blits. " + "MSAA scaling will use 3D helpers. MSAA resolves work normally."); cant_blit_msaa = true; } - } - if (extensions.extended_dynamic_state3 && is_radv) { - LOG_WARNING(Render_Vulkan, "RADV has broken extendedDynamicState3ColorBlendEquation"); - features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false; - features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false; - dynamic_state3_blending = false; - - const u32 version = (properties.properties.driverVersion << 3) >> 3; - if (version < VK_MAKE_API_VERSION(0, 23, 1, 0)) { - LOG_WARNING(Render_Vulkan, - "RADV versions older than 23.1.0 have broken depth clamp dynamic state"); - features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable = false; - dynamic_state3_enables = false; + // Mali/ NVIDIA proprietary drivers: Shader stencil export not supported + // Use hardware depth/stencil blits instead when available + if (!extensions.shader_stencil_export) { + LOG_INFO(Render_Vulkan, + "NVIDIA: VK_EXT_shader_stencil_export not supported, using hardware blits " + "for depth/stencil operations"); + LOG_INFO(Render_Vulkan, " D24S8 hardware blit support: {}", + is_blit_depth24_stencil8_supported); + LOG_INFO(Render_Vulkan, " D32S8 hardware blit support: {}", + is_blit_depth32_stencil8_supported); + + if (!is_blit_depth24_stencil8_supported && !is_blit_depth32_stencil8_supported) { + LOG_WARNING(Render_Vulkan, + "NVIDIA: Neither shader export nor hardware blits available for " + "depth/stencil. Performance may be degraded."); + } } } - if (extensions.extended_dynamic_state3 && (is_amd_driver || driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY)) { - // AMD and Samsung drivers have broken extendedDynamicState3ColorBlendEquation - LOG_WARNING(Render_Vulkan, - "AMD and Samsung drivers have broken extendedDynamicState3ColorBlendEquation"); - features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false; - features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false; - dynamic_state3_blending = false; - } - sets_per_pool = 64; if (is_amd_driver) { // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2. @@ -626,15 +624,27 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR } if (is_intel_windows) { - LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); + LOG_WARNING(Render_Vulkan, + "Intel proprietary drivers do not support MSAA->MSAA image blits. " + "MSAA scaling will use 3D helpers. MSAA resolves work normally."); cant_blit_msaa = true; } has_broken_compute = CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) && !Settings::values.enable_compute_pipelines.GetValue(); - if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { - LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); + must_emulate_bgr565 = false; // Default: assume emulation isn't required + + if (is_intel_anv) { + LOG_WARNING(Render_Vulkan, "Intel ANV driver does not support native BGR format"); + must_emulate_bgr565 = true; + } else if (is_qualcomm) { + LOG_WARNING(Render_Vulkan, + "Qualcomm driver mishandles BGR5 formats even with VK_KHR_maintenance5, forcing emulation"); + must_emulate_bgr565 = true; + } else if (is_arm) { + LOG_WARNING(Render_Vulkan, + "ARM Mali driver mishandles BGR5 formats even with VK_KHR_maintenance5, forcing emulation"); must_emulate_bgr565 = true; } @@ -647,53 +657,57 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR (std::min)(properties.properties.limits.maxVertexInputBindings, 16U); } - if (is_turnip) { - LOG_WARNING(Render_Vulkan, "Turnip requires higher-than-reported binding limits"); + if (is_turnip || is_qualcomm) { + LOG_WARNING(Render_Vulkan, "Driver requires higher-than-reported binding limits"); properties.properties.limits.maxVertexInputBindings = 32; } - if (!extensions.extended_dynamic_state && extensions.extended_dynamic_state2) { - LOG_INFO(Render_Vulkan, - "Removing extendedDynamicState2 due to missing extendedDynamicState"); - RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, - VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); - } + const auto dyna_state = Settings::values.dyna_state.GetValue(); + + // Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp + // This slider controls EXTENDED dynamic states with accumulative levels per Vulkan specs: + // Level 0 = Core Dynamic States only (Vulkan 1.0) + // Level 1 = Core + VK_EXT_extended_dynamic_state + // Level 2 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2 + // Level 3 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2 + VK_EXT_extended_dynamic_state3 - if (!extensions.extended_dynamic_state2 && extensions.extended_dynamic_state3) { - LOG_INFO(Render_Vulkan, - "Removing extendedDynamicState3 due to missing extendedDynamicState2"); + switch (dyna_state) { + case Settings::ExtendedDynamicState::Disabled: + // Level 0: Disable all extended dynamic state extensions + RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, - VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); dynamic_state3_blending = false; dynamic_state3_enables = false; - } - - const auto dyna_state = u32(Settings::values.dyna_state.GetValue()); - - // Mesa Intel drivers on UHD 620 have broken EDS causing extreme flickering - unknown if it affects other iGPUs - // ALSO affects ALL versions of UHD drivers on Windows 10+, seems to cause even worse issues like straight up crashing - // So... Yeah, UHD drivers fucking suck -- maybe one day we can work past this, maybe; some driver hacking? - // And then we can rest in peace by doing `< VK_MAKE_API_VERSION(26, 0, 0)` for our beloved mesa drivers... one day - if ((is_mvk || is_intel_igpu) && dyna_state != 0) { - LOG_WARNING(Render_Vulkan, "Driver has broken dynamic state, forcing to 0 to prevent graphical issues"); - Settings::values.dyna_state.SetValue(Settings::ExtendedDynamicState::Disabled); - } - - switch (dyna_state) { - case 0: - RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); - [[fallthrough]]; - case 1: - RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); - [[fallthrough]]; - case 2: - RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + break; + case Settings::ExtendedDynamicState::EDS1: + // Level 1: Enable EDS1, disable EDS2 and EDS3 + RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + dynamic_state3_blending = false; + dynamic_state3_enables = false; + break; + case Settings::ExtendedDynamicState::EDS2: + // Level 2: Enable EDS1 + EDS2, disable EDS3 + RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); dynamic_state3_blending = false; dynamic_state3_enables = false; break; + case Settings::ExtendedDynamicState::EDS3: + default: + // Level 3: Enable all (EDS1 + EDS2 + EDS3) + break; } - if (!Settings::values.vertex_input_dynamic_state.GetValue() || !extensions.extended_dynamic_state) { + // VK_EXT_vertex_input_dynamic_state is independent from EDS + // It can be enabled even without extended_dynamic_state + if (!Settings::values.vertex_input_dynamic_state.GetValue()) { RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); } @@ -781,8 +795,8 @@ void Device::SaveShader(std::span<const u32> spirv) const { } bool Device::ComputeIsOptimalAstcSupported() const { - // Disable for now to avoid converting ASTC twice. - static constexpr std::array astc_formats = { + // Verify hardware supports all ASTC formats with optimal tiling to avoid software conversion + static constexpr std::array<VkFormat, 28> astc_formats = { VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_ASTC_5x4_SRGB_BLOCK, VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_ASTC_5x5_SRGB_BLOCK, @@ -801,9 +815,10 @@ bool Device::ComputeIsOptimalAstcSupported() const { if (!features.features.textureCompressionASTC_LDR) { return false; } - const auto format_feature_usage{ - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT | - VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + const auto format_feature_usage{VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_BLIT_SRC_BIT | + VK_FORMAT_FEATURE_BLIT_DST_BIT | + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT}; for (const auto format : astc_formats) { const auto physical_format_properties{physical.GetFormatProperties(format)}; @@ -1000,7 +1015,7 @@ bool Device::GetSuitability(bool requires_swapchain) { // Set next pointer. void** next = &features2.pNext; - // Vulkan 1.2, 1.3 and 1.4 features + // Vulkan 1.2 and 1.3 features if (instance_version >= VK_API_VERSION_1_2) { features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; @@ -1106,6 +1121,16 @@ bool Device::GetSuitability(bool requires_swapchain) { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT; SetNext(next, properties.transform_feedback); } + if (extensions.maintenance5) { + properties.maintenance5.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR; + SetNext(next, properties.maintenance5); + } + if (extensions.multi_draw) { + properties.multi_draw.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT; + SetNext(next, properties.multi_draw); + } // Perform the property fetch. physical.GetProperties2(properties2); @@ -1138,14 +1163,70 @@ bool Device::GetSuitability(bool requires_swapchain) { } } + // VK_DYNAMIC_STATE + + // Driver detection variables for workarounds in GetSuitability + const VkDriverId driver_id = properties.driver.driverID; + const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS; + + // VK_EXT_extended_dynamic_state2 below this will appear drivers that need workarounds. + + // VK_EXT_extended_dynamic_state3 below this will appear drivers that need workarounds. + + // Samsung: Broken extendedDynamicState3ColorBlendEquation + // Disable blend equation dynamic state, force static pipeline state + if (extensions.extended_dynamic_state3 && + (driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY)) { + LOG_WARNING(Render_Vulkan, + "Samsung: Disabling broken extendedDynamicState3ColorBlendEquation"); + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false; + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false; + } + + // Intel Windows < 27.20.100.0: Broken VertexInputDynamicState + // Disable VertexInputDynamicState on old Intel Windows drivers + if (extensions.vertex_input_dynamic_state && is_intel_windows) { + const u32 version = (properties.properties.driverVersion << 3) >> 3; + if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) { + LOG_WARNING(Render_Vulkan, + "Intel Windows < 27.20.100.0: Disabling broken VK_EXT_vertex_input_dynamic_state"); + RemoveExtensionFeature(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + } + } + + if (u32(Settings::values.dyna_state.GetValue()) == 0) { + LOG_INFO(Render_Vulkan, "Extended Dynamic State disabled by user setting, clearing all EDS features"); + features.custom_border_color.customBorderColors = false; + features.custom_border_color.customBorderColorWithoutFormat = false; + features.extended_dynamic_state.extendedDynamicState = false; + features.extended_dynamic_state2.extendedDynamicState2 = false; + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false; + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false; + features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask = false; + features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable = false; + features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false; + } + // Return whether we were suitable. return suitable; } void Device::RemoveUnsuitableExtensions() { // VK_EXT_custom_border_color - extensions.custom_border_color = features.custom_border_color.customBorderColors && - features.custom_border_color.customBorderColorWithoutFormat; + // Enable extension if driver supports it, then check individual features + // - customBorderColors: Required to use VK_BORDER_COLOR_FLOAT_CUSTOM_EXT + // - customBorderColorWithoutFormat: Optional, allows VK_FORMAT_UNDEFINED + // If only customBorderColors is available, we must provide a specific format + if (extensions.custom_border_color) { + // Verify that at least customBorderColors is available + if (!features.custom_border_color.customBorderColors) { + LOG_WARNING(Render_Vulkan, + "VK_EXT_custom_border_color reported but customBorderColors feature not available, disabling"); + extensions.custom_border_color = false; + } + } RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); @@ -1174,21 +1255,79 @@ void Device::RemoveUnsuitableExtensions() { VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); // VK_EXT_extended_dynamic_state3 - dynamic_state3_blending = - features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable && - features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation && + const bool supports_color_blend_enable = + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable; + const bool supports_color_blend_equation = + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation; + const bool supports_color_write_mask = features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask; - dynamic_state3_enables = - features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable && + dynamic_state3_blending = supports_color_blend_enable && supports_color_blend_equation && + supports_color_write_mask; + + const bool supports_depth_clamp_enable = + features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable; + const bool supports_logic_op_enable = features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable; + const bool supports_line_raster_mode = + features.extended_dynamic_state3.extendedDynamicState3LineRasterizationMode && + extensions.line_rasterization && features.line_rasterization.rectangularLines; + const bool supports_conservative_raster_mode = + features.extended_dynamic_state3.extendedDynamicState3ConservativeRasterizationMode && + extensions.conservative_rasterization; + const bool supports_line_stipple_enable = + features.extended_dynamic_state3.extendedDynamicState3LineStippleEnable && + extensions.line_rasterization && features.line_rasterization.stippledRectangularLines; + const bool supports_alpha_to_coverage = + features.extended_dynamic_state3.extendedDynamicState3AlphaToCoverageEnable; + const bool supports_alpha_to_one = + features.extended_dynamic_state3.extendedDynamicState3AlphaToOneEnable && + features.features.alphaToOne; + + dynamic_state3_depth_clamp_enable = supports_depth_clamp_enable; + dynamic_state3_logic_op_enable = supports_logic_op_enable; + dynamic_state3_line_raster_mode = supports_line_raster_mode; + dynamic_state3_conservative_raster_mode = supports_conservative_raster_mode; + dynamic_state3_line_stipple_enable = supports_line_stipple_enable; + dynamic_state3_alpha_to_coverage = supports_alpha_to_coverage; + dynamic_state3_alpha_to_one = supports_alpha_to_one; + + dynamic_state3_enables = dynamic_state3_depth_clamp_enable || dynamic_state3_logic_op_enable || + dynamic_state3_line_raster_mode || + dynamic_state3_conservative_raster_mode || + dynamic_state3_line_stipple_enable || + dynamic_state3_alpha_to_coverage || dynamic_state3_alpha_to_one; extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables; - dynamic_state3_blending = dynamic_state3_blending && extensions.extended_dynamic_state3; - dynamic_state3_enables = dynamic_state3_enables && extensions.extended_dynamic_state3; + if (!extensions.extended_dynamic_state3) { + dynamic_state3_blending = false; + dynamic_state3_enables = false; + dynamic_state3_depth_clamp_enable = false; + dynamic_state3_logic_op_enable = false; + dynamic_state3_line_raster_mode = false; + dynamic_state3_conservative_raster_mode = false; + dynamic_state3_line_stipple_enable = false; + dynamic_state3_alpha_to_coverage = false; + dynamic_state3_alpha_to_one = false; + } RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + // VK_EXT_robustness2 + // Enable if at least one robustness2 feature is available + extensions.robustness_2 = features.robustness2.robustBufferAccess2 || + features.robustness2.robustImageAccess2 || + features.robustness2.nullDescriptor; + + RemoveExtensionFeatureIfUnsuitable(extensions.robustness_2, features.robustness2, + VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); + + // VK_EXT_image_robustness + // Enable if robustImageAccess is available + extensions.image_robustness = features.image_robustness.robustImageAccess; + RemoveExtensionFeatureIfUnsuitable(extensions.image_robustness, features.image_robustness, + VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME); + // VK_EXT_provoking_vertex if (Settings::values.provoking_vertex.GetValue()) { extensions.provoking_vertex = features.provoking_vertex.provokingVertexLast @@ -1226,15 +1365,21 @@ void Device::RemoveUnsuitableExtensions() { VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME); // VK_EXT_transform_feedback + // We only require the basic transformFeedback feature and at least + // one transform feedback buffer. We keep transformFeedbackQueries as it's used by + // the streaming byte count implementation. GeometryStreams and multiple streams + // are not strictly required since we currently support only stream 0. extensions.transform_feedback = features.transform_feedback.transformFeedback && - features.transform_feedback.geometryStreams && - properties.transform_feedback.maxTransformFeedbackStreams >= 4 && properties.transform_feedback.maxTransformFeedbackBuffers > 0 && - properties.transform_feedback.transformFeedbackQueries && - properties.transform_feedback.transformFeedbackDraw; + properties.transform_feedback.transformFeedbackQueries; RemoveExtensionFeatureIfUnsuitable(extensions.transform_feedback, features.transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); + if (extensions.transform_feedback) { + LOG_INFO(Render_Vulkan, "VK_EXT_transform_feedback enabled (buffers={}, queries={})", + properties.transform_feedback.maxTransformFeedbackBuffers, + properties.transform_feedback.transformFeedbackQueries); + } // VK_EXT_vertex_input_dynamic_state extensions.vertex_input_dynamic_state = @@ -1243,6 +1388,17 @@ void Device::RemoveUnsuitableExtensions() { features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + // VK_EXT_multi_draw + extensions.multi_draw = features.multi_draw.multiDraw; + + if (extensions.multi_draw) { + LOG_INFO(Render_Vulkan, "VK_EXT_multi_draw: maxMultiDrawCount={}", + properties.multi_draw.maxMultiDrawCount); + } + + RemoveExtensionFeatureIfUnsuitable(extensions.multi_draw, features.multi_draw, + VK_EXT_MULTI_DRAW_EXTENSION_NAME); + // VK_KHR_pipeline_executable_properties if (Settings::values.renderer_shader_feedback.GetValue()) { extensions.pipeline_executable_properties = @@ -1266,6 +1422,76 @@ void Device::RemoveUnsuitableExtensions() { RemoveExtensionFeatureIfUnsuitable(extensions.workgroup_memory_explicit_layout, features.workgroup_memory_explicit_layout, VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME); + + // VK_EXT_swapchain_maintenance1 (extension only, has features) + // Requires VK_EXT_surface_maintenance1 instance extension + extensions.swapchain_maintenance1 = features.swapchain_maintenance1.swapchainMaintenance1; + if (extensions.swapchain_maintenance1) { + // Check if VK_EXT_surface_maintenance1 instance extension is available + const auto instance_extensions = vk::EnumerateInstanceExtensionProperties(dld); + const bool has_surface_maintenance1 = instance_extensions && std::ranges::any_of(*instance_extensions, + [](const VkExtensionProperties& prop) { + return std::strcmp(prop.extensionName, VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) == 0; + }); + if (!has_surface_maintenance1) { + LOG_WARNING(Render_Vulkan, + "VK_EXT_swapchain_maintenance1 requires VK_EXT_surface_maintenance1, disabling"); + extensions.swapchain_maintenance1 = false; + features.swapchain_maintenance1.swapchainMaintenance1 = false; + } + } + RemoveExtensionFeatureIfUnsuitable(extensions.swapchain_maintenance1, features.swapchain_maintenance1, + VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); + + // VK_KHR_maintenance1 (core in Vulkan 1.1, no features) + extensions.maintenance1 = loaded_extensions.contains(VK_KHR_MAINTENANCE_1_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.maintenance1, VK_KHR_MAINTENANCE_1_EXTENSION_NAME); + + // VK_KHR_maintenance2 (core in Vulkan 1.1, no features) + extensions.maintenance2 = loaded_extensions.contains(VK_KHR_MAINTENANCE_2_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.maintenance2, VK_KHR_MAINTENANCE_2_EXTENSION_NAME); + + // VK_KHR_maintenance3 (core in Vulkan 1.1, no features) + extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME); + + // VK_KHR_maintenance4 + extensions.maintenance4 = features.maintenance4.maintenance4; + RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4, + VK_KHR_MAINTENANCE_4_EXTENSION_NAME); + + // VK_KHR_maintenance5 + extensions.maintenance5 = features.maintenance5.maintenance5; + + if (extensions.maintenance5) { + LOG_INFO(Render_Vulkan, "VK_KHR_maintenance5 properties: polygonModePointSize={} " + "depthStencilSwizzleOne={} earlyFragmentTests={} nonStrictWideLines={}", + properties.maintenance5.polygonModePointSize, + properties.maintenance5.depthStencilSwizzleOneSupport, + properties.maintenance5.earlyFragmentMultisampleCoverageAfterSampleCounting && + properties.maintenance5.earlyFragmentSampleMaskTestBeforeSampleCounting, + properties.maintenance5.nonStrictWideLinesUseParallelogram); + } + + RemoveExtensionFeatureIfUnsuitable(extensions.maintenance5, features.maintenance5, + VK_KHR_MAINTENANCE_5_EXTENSION_NAME); + + // VK_KHR_maintenance6 + extensions.maintenance6 = features.maintenance6.maintenance6; + RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6, + VK_KHR_MAINTENANCE_6_EXTENSION_NAME); + + // VK_KHR_maintenance7 (proposed for Vulkan 1.4, no features) + extensions.maintenance7 = loaded_extensions.contains(VK_KHR_MAINTENANCE_7_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.maintenance7, VK_KHR_MAINTENANCE_7_EXTENSION_NAME); + + // VK_KHR_maintenance8 (proposed for Vulkan 1.4, no features) + extensions.maintenance8 = loaded_extensions.contains(VK_KHR_MAINTENANCE_8_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.maintenance8, VK_KHR_MAINTENANCE_8_EXTENSION_NAME); + + // VK_KHR_maintenance9 (proposed for Vulkan 1.4, no features) + extensions.maintenance9 = loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME); } void Device::SetupFamilies(VkSurfaceKHR surface) { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index cb13f28523..6c67cc44f8 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -37,9 +37,13 @@ VK_DEFINE_HANDLE(VmaAllocator) FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore) #define FOR_EACH_VK_FEATURE_1_3(FEATURE) \ + FEATURE(EXT, ImageRobustness, IMAGE_ROBUSTNESS, image_robustness) \ FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \ shader_demote_to_helper_invocation) \ - FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) + FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \ + FEATURE(KHR, Maintenance4, MAINTENANCE_4, maintenance4) + +#define FOR_EACH_VK_FEATURE_1_4(FEATURE) // Define all features which may be used by the implementation and require an extension here. #define FOR_EACH_VK_FEATURE_EXT(FEATURE) \ @@ -52,12 +56,16 @@ VK_DEFINE_HANDLE(VmaAllocator) FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \ FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \ FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \ + FEATURE(EXT, MultiDraw, MULTI_DRAW, multi_draw) \ FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \ primitive_topology_list_restart) \ FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \ FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \ FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback) \ FEATURE(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state) \ + FEATURE(EXT, SwapchainMaintenance1, SWAPCHAIN_MAINTENANCE_1, swapchain_maintenance1) \ + FEATURE(KHR, Maintenance5, MAINTENANCE_5, maintenance5) \ + FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \ FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \ pipeline_executable_properties) \ FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \ @@ -84,6 +92,12 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION(KHR, SWAPCHAIN, swapchain) \ EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \ EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \ + EXTENSION(KHR, MAINTENANCE_1, maintenance1) \ + EXTENSION(KHR, MAINTENANCE_2, maintenance2) \ + EXTENSION(KHR, MAINTENANCE_3, maintenance3) \ + EXTENSION(KHR, MAINTENANCE_7, maintenance7) \ + EXTENSION(KHR, MAINTENANCE_8, maintenance8) \ + EXTENSION(KHR, MAINTENANCE_9, maintenance9) \ EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \ EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \ EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \ @@ -110,6 +124,7 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_4444_FORMATS_EXTENSION_NAME) \ + EXTENSION_NAME(VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \ @@ -161,6 +176,7 @@ VK_DEFINE_HANDLE(VmaAllocator) FEATURE_NAME(depth_bias_control, depthBiasExact) \ FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \ FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \ + FEATURE_NAME(image_robustness, robustImageAccess) \ FEATURE_NAME(index_type_uint8, indexTypeUint8) \ FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \ FEATURE_NAME(provoking_vertex, provokingVertexLast) \ @@ -440,6 +456,11 @@ public: return extensions.swapchain_mutable_format; } + /// Returns true if VK_EXT_swapchain_maintenance1 is enabled. + bool IsExtSwapchainMaintenance1Enabled() const { + return extensions.swapchain_maintenance1; + } + /// Returns true if VK_KHR_shader_float_controls is enabled. bool IsKhrShaderFloatControlsSupported() const { return extensions.shader_float_controls; @@ -476,10 +497,18 @@ public: } /// Returns true if the device supports VK_EXT_shader_stencil_export. + /// Note: Most Mali/NVIDIA drivers don't support this. Use hardware blits as fallback. bool IsExtShaderStencilExportSupported() const { return extensions.shader_stencil_export; } + /// Returns true if depth/stencil operations can be performed efficiently. + /// Either through shader export or hardware blits. + bool CanPerformDepthStencilOperations() const { + return extensions.shader_stencil_export || is_blit_depth24_stencil8_supported || + is_blit_depth32_stencil8_supported; + } + /// Returns true if the device supports VK_EXT_depth_range_unrestricted. bool IsExtDepthRangeUnrestrictedSupported() const { return extensions.depth_range_unrestricted; @@ -520,6 +549,46 @@ public: return extensions.custom_border_color; } + /// Returns true if the device supports VK_EXT_image_robustness. + bool IsExtImageRobustnessSupported() const { + return extensions.image_robustness; + } + + /// Returns true if robustImageAccess is supported. + bool IsRobustImageAccessSupported() const { + return features.image_robustness.robustImageAccess; + } + + /// Returns true if the device supports VK_EXT_robustness2. + bool IsExtRobustness2Supported() const { + return extensions.robustness_2; + } + + /// Returns true if robustBufferAccess2 is supported. + bool IsRobustBufferAccess2Supported() const { + return features.robustness2.robustBufferAccess2; + } + + /// Returns true if robustImageAccess2 is supported. + bool IsRobustImageAccess2Supported() const { + return features.robustness2.robustImageAccess2; + } + + /// Returns true if nullDescriptor is supported. + bool IsNullDescriptorSupported() const { + return features.robustness2.nullDescriptor; + } + + /// Returns true if customBorderColors feature is available. + bool IsCustomBorderColorsSupported() const { + return features.custom_border_color.customBorderColors; + } + + /// Returns true if customBorderColorWithoutFormat feature is available. + bool IsCustomBorderColorWithoutFormatSupported() const { + return features.custom_border_color.customBorderColorWithoutFormat; + } + /// Returns true if the device supports VK_EXT_extended_dynamic_state. bool IsExtExtendedDynamicStateSupported() const { return extensions.extended_dynamic_state; @@ -569,6 +638,55 @@ public: return extensions.line_rasterization; } + bool SupportsRectangularLines() const { + return features.line_rasterization.rectangularLines != VK_FALSE; + } + + bool SupportsSmoothLines() const { + return features.line_rasterization.smoothLines != VK_FALSE; + } + + bool SupportsStippledRectangularLines() const { + return features.line_rasterization.stippledRectangularLines != VK_FALSE; + } + + bool SupportsAlphaToOne() const { + return features.features.alphaToOne != VK_FALSE; + } + + bool SupportsDynamicState3DepthClampEnable() const { + return dynamic_state3_depth_clamp_enable; + } + + bool SupportsDynamicState3LogicOpEnable() const { + return dynamic_state3_logic_op_enable; + } + + bool SupportsDynamicState3LineRasterizationMode() const { + return dynamic_state3_line_raster_mode; + } + + bool SupportsDynamicState3ConservativeRasterizationMode() const { + return dynamic_state3_conservative_raster_mode; + } + + bool SupportsDynamicState3LineStippleEnable() const { + return dynamic_state3_line_stipple_enable; + } + + bool SupportsDynamicState3AlphaToCoverageEnable() const { + return dynamic_state3_alpha_to_coverage; + } + + bool SupportsDynamicState3AlphaToOneEnable() const { + return dynamic_state3_alpha_to_one; + } + + /// Returns true when the user enabled extended core dynamic states (level > 0). + bool UsesAdvancedCoreDynamicState() const { + return u32(Settings::values.dyna_state.GetValue()) > 0; + } + /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state. bool IsExtVertexInputDynamicStateSupported() const { return extensions.vertex_input_dynamic_state; @@ -703,6 +821,73 @@ public: return features2.features.multiViewport; } + /// Returns true if the device supports VK_KHR_maintenance1. + bool IsKhrMaintenance1Supported() const { + return extensions.maintenance1; + } + + /// Returns true if the device supports VK_KHR_maintenance2. + bool IsKhrMaintenance2Supported() const { + return extensions.maintenance2; + } + + /// Returns true if the device supports VK_KHR_maintenance3. + bool IsKhrMaintenance3Supported() const { + return extensions.maintenance3; + } + + /// Returns true if the device supports VK_KHR_maintenance4. + bool IsKhrMaintenance4Supported() const { + return extensions.maintenance4; + } + + /// Returns true if the device supports VK_KHR_maintenance5. + bool IsKhrMaintenance5Supported() const { + return extensions.maintenance5; + } + + /// Returns true if polygon mode POINT supports gl_PointSize. + bool SupportsPolygonModePointSize() const { + return extensions.maintenance5 && properties.maintenance5.polygonModePointSize; + } + + /// Returns true if depth/stencil swizzle ONE is supported. + bool SupportsDepthStencilSwizzleOne() const { + return extensions.maintenance5 && properties.maintenance5.depthStencilSwizzleOneSupport; + } + + /// Returns true if early fragment tests optimizations are available. + bool SupportsEarlyFragmentTests() const { + return extensions.maintenance5 && + properties.maintenance5.earlyFragmentMultisampleCoverageAfterSampleCounting && + properties.maintenance5.earlyFragmentSampleMaskTestBeforeSampleCounting; + } + + /// Returns true if the device supports VK_KHR_maintenance6. + bool IsKhrMaintenance6Supported() const { + return extensions.maintenance6; + } + + /// Returns true if the device supports VK_EXT_multi_draw. + bool IsExtMultiDrawSupported() const { + return extensions.multi_draw; + } + + /// Returns true if the device supports VK_KHR_maintenance7. + bool IsKhrMaintenance7Supported() const { + return extensions.maintenance7; + } + + /// Returns true if the device supports VK_KHR_maintenance8. + bool IsKhrMaintenance8Supported() const { + return extensions.maintenance8; + } + + /// Returns true if the device supports VK_KHR_maintenance9. + bool IsKhrMaintenance9Supported() const { + return extensions.maintenance9; + } + [[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id, u32 driver_version) { if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { @@ -786,6 +971,7 @@ private: FOR_EACH_VK_FEATURE_1_1(FEATURE); FOR_EACH_VK_FEATURE_1_2(FEATURE); FOR_EACH_VK_FEATURE_1_3(FEATURE); + FOR_EACH_VK_FEATURE_1_4(FEATURE); FOR_EACH_VK_FEATURE_EXT(FEATURE); FOR_EACH_VK_EXTENSION(EXTENSION); @@ -802,6 +988,7 @@ private: FOR_EACH_VK_FEATURE_1_1(FEATURE_CORE); FOR_EACH_VK_FEATURE_1_2(FEATURE_CORE); FOR_EACH_VK_FEATURE_1_3(FEATURE_CORE); + FOR_EACH_VK_FEATURE_1_4(FEATURE_CORE); FOR_EACH_VK_FEATURE_EXT(FEATURE_EXT); #undef FEATURE_CORE @@ -817,6 +1004,8 @@ private: VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{}; + VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{}; + VkPhysicalDeviceMultiDrawPropertiesEXT multi_draw{}; VkPhysicalDeviceProperties properties{}; }; @@ -846,8 +1035,15 @@ private: bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format. - bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3. - bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3. + bool dynamic_state3_blending{}; ///< Has blending features of dynamic_state3. + bool dynamic_state3_enables{}; ///< Has at least one enable feature of dynamic_state3. + bool dynamic_state3_depth_clamp_enable{}; + bool dynamic_state3_logic_op_enable{}; + bool dynamic_state3_line_raster_mode{}; + bool dynamic_state3_conservative_raster_mode{}; + bool dynamic_state3_line_stipple_enable{}; + bool dynamic_state3_alpha_to_coverage{}; + bool dynamic_state3_alpha_to_one{}; bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. u64 device_access_memory{}; ///< Total size of device local memory in bytes. u32 sets_per_pool{}; ///< Sets per Description Pool diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index b77d01711a..9ee93653d9 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -116,6 +116,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkCmdDrawIndirectCount); X(vkCmdDrawIndexedIndirectCount); X(vkCmdDrawIndirectByteCountEXT); + X(vkCmdDrawMultiEXT); + X(vkCmdDrawMultiIndexedEXT); X(vkCmdEndConditionalRenderingEXT); X(vkCmdEndQuery); X(vkCmdEndRenderPass); @@ -145,6 +147,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkCmdSetDepthWriteEnableEXT); X(vkCmdSetPrimitiveRestartEnableEXT); X(vkCmdSetRasterizerDiscardEnableEXT); + X(vkCmdSetAlphaToCoverageEnableEXT); + X(vkCmdSetAlphaToOneEnableEXT); X(vkCmdSetConservativeRasterizationModeEXT); X(vkCmdSetLineRasterizationModeEXT); X(vkCmdSetLineStippleEnableEXT); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 39396b3279..39717affa1 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -216,6 +216,8 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount{}; PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount{}; PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT{}; + PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT{}; + PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT{}; PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT{}; PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; PFN_vkCmdEndQuery vkCmdEndQuery{}; @@ -238,6 +240,8 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{}; PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{}; PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{}; + PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT{}; + PFN_vkCmdSetAlphaToOneEnableEXT vkCmdSetAlphaToOneEnableEXT{}; PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT{}; PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT{}; PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT{}; @@ -1239,6 +1243,19 @@ public: counter_buffer_offset, counter_offset, stride); } + void DrawMultiEXT(u32 draw_count, const VkMultiDrawInfoEXT* vertex_info, + u32 instance_count, u32 first_instance, u32 stride) const noexcept { + dld->vkCmdDrawMultiEXT(handle, draw_count, vertex_info, instance_count, first_instance, + stride); + } + + void DrawMultiIndexedEXT(u32 draw_count, const VkMultiDrawIndexedInfoEXT* index_info, + u32 instance_count, u32 first_instance, u32 stride, + const int32_t* vertex_offset) const noexcept { + dld->vkCmdDrawMultiIndexedEXT(handle, draw_count, index_info, instance_count, + first_instance, stride, vertex_offset); + } + void ClearAttachments(Span<VkClearAttachment> attachments, Span<VkClearRect> rects) const noexcept { dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), @@ -1471,6 +1488,14 @@ public: dld->vkCmdSetLogicOpEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); } + void SetAlphaToCoverageEnableEXT(bool enable) const noexcept { + dld->vkCmdSetAlphaToCoverageEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void SetAlphaToOneEnableEXT(bool enable) const noexcept { + dld->vkCmdSetAlphaToOneEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + void SetDepthClampEnableEXT(bool enable) const noexcept { dld->vkCmdSetDepthClampEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); } |
