Compare commits
25 Commits
3096/hle/b
...
flatopsfix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e80396ee0 | ||
|
|
672011f302 | ||
|
|
bb1d1e484d | ||
|
|
5a03ef7fba | ||
|
|
88555a17be | ||
|
|
9600f99b1a | ||
|
|
7bed3bb947 | ||
|
|
380112bcb4 | ||
|
|
2685f832e5 | ||
|
|
d65afcda81 | ||
|
|
1cb88492a8 | ||
|
|
1b06fa6658 | ||
|
|
af1b610fbb | ||
|
|
9a266e60b6 | ||
|
|
1fc9c3f6ff | ||
|
|
a0f08704f1 | ||
|
|
c6c3edc95c | ||
|
|
76c5de0443 | ||
|
|
9ffead7e7a | ||
|
|
22bb942947 | ||
|
|
3af7aafc25 | ||
|
|
3a8677597f | ||
|
|
16ae756da3 | ||
|
|
004264d2a6 | ||
|
|
4bbde3e5ec |
@@ -10,6 +10,8 @@
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "common/android/multiplayer/multiplayer.h"
|
||||
#include <network/network.h>
|
||||
#include "common/settings.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
|
||||
static JavaVM *s_java_vm;
|
||||
@@ -524,6 +526,13 @@ namespace Common::Android {
|
||||
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
||||
env->DeleteLocalRef(patch_class);
|
||||
|
||||
// Prefer hardware decoding on Android by default, forcing this setting will
|
||||
// make the native side attempt GPU decoding first. If the platform lacks a usable
|
||||
// FFmpeg HW device, FFmpeg will fall back to CPU automatically.
|
||||
Settings::values.nvdec_emulation.SetValue(Settings::NvdecEmulation::Gpu);
|
||||
LOG_INFO(HW_GPU, "Android JNI_OnLoad: forced nvdec_emulation = GPU");
|
||||
|
||||
|
||||
const jclass double_class = env->FindClass("java/lang/Double");
|
||||
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
||||
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
||||
|
||||
@@ -349,7 +349,9 @@ struct Values {
|
||||
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
||||
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
|
||||
#ifdef ANDROID
|
||||
AstcDecodeMode::Cpu,
|
||||
// Most modern Android devices have native ASTC support
|
||||
// and benefit from GPU decoding. Default to GPU there.
|
||||
AstcDecodeMode::Gpu,
|
||||
#else
|
||||
AstcDecodeMode::Gpu,
|
||||
#endif
|
||||
|
||||
@@ -77,7 +77,12 @@ VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wra
|
||||
ASSERT(false);
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
if (device.IsKhrSamplerMirrorClampToEdgeSupported()) {
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
}
|
||||
// Fallback when the sampler mirror clamp extension isn't present.
|
||||
// Use CLAMP_TO_EDGE as the safest approximation.
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::MirrorOnceBorder:
|
||||
UNIMPLEMENTED();
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
|
||||
@@ -31,6 +31,10 @@ namespace Vulkan {
|
||||
struct GraphicsPipelineCacheKey {
|
||||
std::array<u64, 6> unique_hashes;
|
||||
FixedPipelineState state;
|
||||
// Per-pipeline float control choices (selected at pipeline key time).
|
||||
// 0 = disabled, 1 = enabled
|
||||
uint8_t use_ftz_f32{};
|
||||
uint8_t use_ftz_f16{};
|
||||
|
||||
size_t Hash() const noexcept;
|
||||
|
||||
@@ -41,12 +45,12 @@ struct GraphicsPipelineCacheKey {
|
||||
}
|
||||
|
||||
size_t Size() const noexcept {
|
||||
return sizeof(unique_hashes) + state.Size();
|
||||
return sizeof(unique_hashes) + state.Size() + sizeof(use_ftz_f32) + sizeof(use_ftz_f16);
|
||||
}
|
||||
};
|
||||
static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>);
|
||||
// The key is compared/hashed using a custom Size() and memcmp over the
|
||||
// meaningful bytes. Ensure it's trivially copyable so memcmp/hash are safe.
|
||||
static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>);
|
||||
static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
|
||||
@@ -327,20 +327,28 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.support_int64 = device.IsShaderInt64Supported(),
|
||||
.support_vertex_instance_id = false,
|
||||
.support_float_controls = device.IsKhrShaderFloatControlsSupported(),
|
||||
.support_separate_denorm_behavior =
|
||||
float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
|
||||
.support_separate_rounding_mode =
|
||||
float_control.roundingModeIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
|
||||
.support_fp16_denorm_preserve = float_control.shaderDenormPreserveFloat16 != VK_FALSE,
|
||||
.support_fp32_denorm_preserve = float_control.shaderDenormPreserveFloat32 != VK_FALSE,
|
||||
.support_fp16_denorm_flush = float_control.shaderDenormFlushToZeroFloat16 != VK_FALSE,
|
||||
.support_fp32_denorm_flush = float_control.shaderDenormFlushToZeroFloat32 != VK_FALSE,
|
||||
.support_fp16_signed_zero_nan_preserve =
|
||||
float_control.shaderSignedZeroInfNanPreserveFloat16 != VK_FALSE,
|
||||
.support_fp32_signed_zero_nan_preserve =
|
||||
float_control.shaderSignedZeroInfNanPreserveFloat32 != VK_FALSE,
|
||||
.support_fp64_signed_zero_nan_preserve =
|
||||
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
|
||||
// Only enable per-size float control capabilities when the KHR_shader_float_controls
|
||||
// extension is actually enabled on the device and the driver reports explicit support
|
||||
// for the individual properties. This avoids enabling functionality when the extension
|
||||
// was removed due to driver workarounds.
|
||||
.support_separate_denorm_behavior = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL),
|
||||
.support_separate_rounding_mode = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.roundingModeIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL),
|
||||
.support_fp16_denorm_preserve = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderDenormPreserveFloat16 == VK_TRUE),
|
||||
.support_fp32_denorm_preserve = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderDenormPreserveFloat32 == VK_TRUE),
|
||||
.support_fp16_denorm_flush = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderDenormFlushToZeroFloat16 == VK_TRUE),
|
||||
.support_fp32_denorm_flush = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderDenormFlushToZeroFloat32 == VK_TRUE),
|
||||
.support_fp16_signed_zero_nan_preserve = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderSignedZeroInfNanPreserveFloat16 == VK_TRUE),
|
||||
.support_fp32_signed_zero_nan_preserve = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderSignedZeroInfNanPreserveFloat32 == VK_TRUE),
|
||||
.support_fp64_signed_zero_nan_preserve = device.IsKhrShaderFloatControlsSupported() &&
|
||||
(float_control.shaderSignedZeroInfNanPreserveFloat64 == VK_TRUE),
|
||||
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
|
||||
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
||||
.support_viewport_index_layer_non_geometry =
|
||||
@@ -368,13 +376,13 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA,
|
||||
|
||||
.has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS,
|
||||
.has_broken_spirv_position_input = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
|
||||
.has_broken_spirv_position_input = device.IsQualcomm(),
|
||||
.has_broken_unsigned_image_offsets = false,
|
||||
.has_broken_signed_operations = false,
|
||||
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
|
||||
.ignore_nan_fp_comparisons = false,
|
||||
.has_broken_spirv_subgroup_mask_vector_extract_dynamic =
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
|
||||
device.IsQualcomm(),
|
||||
.has_broken_robust =
|
||||
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
|
||||
.min_ssbo_alignment = device.GetStorageBufferAlignment(),
|
||||
@@ -438,6 +446,21 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
|
||||
}
|
||||
graphics_key.state.Refresh(*maxwell3d, dynamic_features);
|
||||
|
||||
// Decide per-pipeline FTZ (flush-to-zero) usage based on device float-controls
|
||||
// properties and vendor-specific workarounds, going initially for Qualcomm drivers
|
||||
const bool force_extensions = Settings::values.force_unsupported_extensions.GetValue();
|
||||
const bool is_qualcomm = device.IsQualcomm();
|
||||
const auto& float_control = device.FloatControlProperties();
|
||||
const bool has_khr_float_controls = device.IsKhrShaderFloatControlsSupported();
|
||||
const bool denorm_indep_all = float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL;
|
||||
const bool denorm_indep_32 = denorm_indep_all || float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY;
|
||||
|
||||
// Allow FTZ when device reports support the device is a Qualcomm driver
|
||||
// (we allow Qualcomm to opt-in automatically to work around driver reporting differences).
|
||||
const bool allow_ftz_override = force_extensions || is_qualcomm;
|
||||
graphics_key.use_ftz_f32 = (has_khr_float_controls && (float_control.shaderDenormFlushToZeroFloat32 == VK_TRUE) && denorm_indep_32 && allow_ftz_override) ? 1 : 0;
|
||||
graphics_key.use_ftz_f16 = (has_khr_float_controls && (float_control.shaderDenormFlushToZeroFloat16 == VK_TRUE) && denorm_indep_all && allow_ftz_override) ? 1 : 0;
|
||||
|
||||
if (current_pipeline) {
|
||||
GraphicsPipeline* const next{current_pipeline->Next(graphics_key)};
|
||||
if (next) {
|
||||
@@ -682,7 +705,24 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
|
||||
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output)};
|
||||
// Forward a pipeline-specific profile to the SPIR-V emitter so it can
|
||||
// enable/disable fast-math (FTZ) optimizations per-pipeline. We use the
|
||||
// GraphicsPipelineCacheKey's FTZ choice to decide whether to allow
|
||||
// fast-math. When fast-math is enabled we keep need_fastmath_off=false
|
||||
// (allow optimizations); otherwise we set it to true to prevent unsafe
|
||||
// transformations.
|
||||
Shader::Profile emit_profile = profile;
|
||||
// Per-pipeline override: control fast-math (FTZ) for FP32 via the pipeline key.
|
||||
emit_profile.need_fastmath_off = (key.use_ftz_f32 == 0);
|
||||
// Per-pipeline FP16 FTZ selection is stored in the pipeline key but was not
|
||||
// previously propagated to the SPIR-V emitter. Some drivers (notably certain
|
||||
// Qualcomm builds) report FP16 float-control support incorrectly. Respect the
|
||||
// pipeline's FP16 FTZ choice here and disable emitting FP16 DenormFlush when
|
||||
// the pipeline explicitly disables it.
|
||||
if (key.use_ftz_f16 == 0) {
|
||||
emit_profile.support_fp16_denorm_flush = false;
|
||||
}
|
||||
const std::vector<u32> code{EmitSPIRV(emit_profile, runtime_info, program, binding, this->optimize_spirv_output)};
|
||||
device.SaveShader(code);
|
||||
modules[stage_index] = BuildShader(device, code);
|
||||
if (device.HasDebuggingToolAttached()) {
|
||||
|
||||
@@ -222,7 +222,13 @@ template <typename Key, typename Envs>
|
||||
void SerializePipeline(const Key& key, const Envs& envs, const std::filesystem::path& filename,
|
||||
u32 cache_version) {
|
||||
static_assert(std::is_trivially_copyable_v<Key>);
|
||||
static_assert(std::has_unique_object_representations_v<Key>);
|
||||
// Note: we relax the unique object representation requirement because some
|
||||
// pipeline/key types (e.g. GraphicsPipelineCacheKey) contain unions or
|
||||
// bitfield-backed types that do not guarantee "unique object
|
||||
// representations" across compilers/platforms. We still require
|
||||
// trivially-copyable so the raw byte serialization is well-defined for a
|
||||
// given build. Be aware that serialized blobs may not be portable across
|
||||
// builds with different compilers or packing rules.
|
||||
SerializePipeline(std::span(reinterpret_cast<const char*>(&key), sizeof(key)),
|
||||
std::span(envs.data(), envs.size()), filename, cache_version);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,34 @@
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#ifndef VK_KHR_MAINTENANCE_1_EXTENSION_NAME
|
||||
# define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1"
|
||||
#endif
|
||||
#ifndef VK_KHR_MAINTENANCE_2_EXTENSION_NAME
|
||||
# define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2"
|
||||
#endif
|
||||
#ifndef VK_KHR_MAINTENANCE_3_EXTENSION_NAME
|
||||
# define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3"
|
||||
#endif
|
||||
#ifndef VK_KHR_MAINTENANCE_4_EXTENSION_NAME
|
||||
# define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4"
|
||||
#endif
|
||||
#ifndef VK_KHR_MAINTENANCE_5_EXTENSION_NAME
|
||||
# define VK_KHR_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5"
|
||||
#endif
|
||||
#ifndef VK_KHR_MAINTENANCE_6_EXTENSION_NAME
|
||||
# define VK_KHR_MAINTENANCE_6_EXTENSION_NAME "VK_KHR_maintenance6"
|
||||
#endif
|
||||
#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
|
||||
|
||||
@@ -501,24 +501,38 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
}
|
||||
|
||||
if ((is_qualcomm || is_turnip) && !force_extensions) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Qualcomm and Turnip drivers have broken VK_EXT_custom_border_color");
|
||||
RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color,
|
||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||
// Some Qualcomm/Turnip drivers have a broken implementation of
|
||||
// VK_EXT_custom_border_color, but on certain devices the driver may
|
||||
// still implement a subset of the extension's functions. If the
|
||||
// driver reports any of the useful custom border color features, allow
|
||||
// them; otherwise remove the extension to avoid crashes.
|
||||
const bool has_custom_border_colors =
|
||||
features.custom_border_color.customBorderColors ||
|
||||
features.custom_border_color.customBorderColorWithoutFormat;
|
||||
if (!has_custom_border_colors) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Qualcomm and Turnip drivers have broken VK_EXT_custom_border_color");
|
||||
RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color,
|
||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||
} else {
|
||||
LOG_INFO(Render_Vulkan,
|
||||
"Partial VK_EXT_custom_border_color support detected on driver '{}'; enabling available features",
|
||||
properties.driver.driverName);
|
||||
// Keep extensions.custom_border_color set based on RemoveUnsuitableExtensions later.
|
||||
}
|
||||
}
|
||||
|
||||
if (is_qualcomm) {
|
||||
if (is_qualcomm || is_arm) {
|
||||
if (!force_extensions) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Qualcomm drivers have a slow VK_KHR_push_descriptor implementation");
|
||||
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
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);
|
||||
RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64,
|
||||
VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Disabling 64-bit integer features on Qualcomm and ARM Mali proprietary drivers");
|
||||
RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64,
|
||||
VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
|
||||
features.shader_atomic_int64.shaderBufferInt64Atomics = false;
|
||||
features.shader_atomic_int64.shaderSharedInt64Atomics = false;
|
||||
features.features.shaderInt64 = false;
|
||||
@@ -585,13 +599,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
if (extensions.extended_dynamic_state2 && is_qualcomm) {
|
||||
if (extensions.extended_dynamic_state2 && (is_qualcomm || is_arm)) {
|
||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||
if (version >= VK_MAKE_API_VERSION(0, 0, 676, 0) &&
|
||||
version < VK_MAKE_API_VERSION(0, 0, 680, 0) && !force_extensions) {
|
||||
// Arm Mali Inmortalis drivers have broken extendedDynamicState2LogicOp.
|
||||
// Qualcomm Adreno 7xx drivers do not properly support extended_dynamic_state2.
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Qualcomm Adreno 7xx drivers have broken VK_EXT_extended_dynamic_state2");
|
||||
"Qualcomm Adreno 7xx and Arm Mali Inmortalis drivers have broken VK_EXT_extended_dynamic_state2");
|
||||
RemoveExtensionFeature(extensions.extended_dynamic_state2,
|
||||
features.extended_dynamic_state2,
|
||||
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||
@@ -700,10 +715,24 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
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 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) {
|
||||
// Qualcomm driver version where VK_KHR_maintenance5 and A1B5G5R5 become reliable
|
||||
constexpr uint32_t QUALCOMM_FIXED_DRIVER_VERSION = VK_MAKE_VERSION(512, 800, 1);
|
||||
// Check if VK_KHR_maintenance5 is supported
|
||||
if (extensions.maintenance5 && properties.properties.driverVersion >= QUALCOMM_FIXED_DRIVER_VERSION) {
|
||||
LOG_INFO(Render_Vulkan, "Qualcomm driver supports VK_KHR_maintenance5, disabling BGR emulation");
|
||||
must_emulate_bgr565 = false;
|
||||
} else {
|
||||
LOG_WARNING(Render_Vulkan, "Qualcomm driver doesn't support native BGR, emulating formats");
|
||||
must_emulate_bgr565 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (extensions.push_descriptor && is_intel_anv) {
|
||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||
if (version >= VK_MAKE_API_VERSION(0, 22, 3, 0) &&
|
||||
@@ -1040,13 +1069,13 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
// Some extensions are mandatory. Check those.
|
||||
#define CHECK_EXTENSION(extension_name) \
|
||||
if (!loaded_extensions.contains(extension_name)) { \
|
||||
LOG_ERROR(Render_Vulkan, "Missing required extension {}", extension_name); \
|
||||
suitable = false; \
|
||||
LOG_ERROR(Render_Vulkan, "Missing required extension " extension_name); \
|
||||
suitable = false; \
|
||||
}
|
||||
|
||||
#define LOG_EXTENSION(extension_name) \
|
||||
if (!loaded_extensions.contains(extension_name)) { \
|
||||
LOG_INFO(Render_Vulkan, "Device doesn't support extension {}", extension_name); \
|
||||
LOG_INFO(Render_Vulkan, "Device doesn't support extension " extension_name); \
|
||||
}
|
||||
|
||||
FOR_EACH_VK_RECOMMENDED_EXTENSION(LOG_EXTENSION);
|
||||
@@ -1178,9 +1207,55 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
// Store base properties
|
||||
properties.properties = properties2.properties;
|
||||
|
||||
// Diagnostic logging for shader float controls on Qualcomm/ARM drivers.
|
||||
// Print the reported per-float-size properties so we can debug denorm/flush issues.
|
||||
{
|
||||
const auto driver_id = properties.driver.driverID;
|
||||
if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_ARM_PROPRIETARY) {
|
||||
const auto& fc = properties.float_controls;
|
||||
LOG_INFO(Render_Vulkan,
|
||||
"Driver '{}' id={} reports VK_KHR_shader_float_controls extension present={} -- "
|
||||
"denormPreserveF16={} denormPreserveF32={} flushToZeroF16={} flushToZeroF32={} "
|
||||
"denormBehaviorIndependence={} roundingModeIndependence={}",
|
||||
properties.driver.driverName, driver_id, extensions.shader_float_controls,
|
||||
(fc.shaderDenormPreserveFloat16 == VK_TRUE), (fc.shaderDenormPreserveFloat32 == VK_TRUE),
|
||||
(fc.shaderDenormFlushToZeroFloat16 == VK_TRUE), (fc.shaderDenormFlushToZeroFloat32 == VK_TRUE),
|
||||
fc.denormBehaviorIndependence, fc.roundingModeIndependence);
|
||||
}
|
||||
}
|
||||
|
||||
// Some drivers (notably Qualcomm and certain ARM drivers) misreport the
|
||||
// VK_KHR_shader_float_controls capabilities. Disable the extension and
|
||||
// clear the reported properties unless the user explicitly forces
|
||||
// unsupported extensions via settings.
|
||||
{
|
||||
const auto driver_id = properties.driver.driverID;
|
||||
const bool force_extensions = Settings::values.force_unsupported_extensions.GetValue();
|
||||
if ((driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY) &&
|
||||
!force_extensions) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Disabling VK_KHR_shader_float_controls for driver '{}' id={} due to unreliable float-control reporting",
|
||||
properties.driver.driverName, driver_id);
|
||||
extensions.shader_float_controls = false;
|
||||
// Zero-out the structure to avoid accidental use of reported values.
|
||||
properties.float_controls = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Unload extensions if feature support is insufficient.
|
||||
RemoveUnsuitableExtensions();
|
||||
|
||||
// Log final state of shader float controls extension on Qualcomm/ARM for diagnostics.
|
||||
{
|
||||
const auto driver_id = properties.driver.driverID;
|
||||
if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_ARM_PROPRIETARY) {
|
||||
LOG_INFO(Render_Vulkan,
|
||||
"Final shader float controls extension enabled={} after suitability checks for driver '{}' id={}",
|
||||
extensions.shader_float_controls, properties.driver.driverName, driver_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Check limits.
|
||||
struct Limit {
|
||||
u32 minimum;
|
||||
@@ -1208,9 +1283,30 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
}
|
||||
|
||||
void Device::RemoveUnsuitableExtensions() {
|
||||
// Restrict NV-specific extensions to NVIDIA drivers only.
|
||||
if (!IsNvidia()) {
|
||||
RemoveExtension(extensions.device_diagnostics_config,
|
||||
VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME);
|
||||
RemoveExtension(extensions.geometry_shader_passthrough,
|
||||
VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME);
|
||||
RemoveExtension(extensions.viewport_array2, VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME);
|
||||
RemoveExtension(extensions.viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
// VK_EXT_custom_border_color
|
||||
extensions.custom_border_color = features.custom_border_color.customBorderColors &&
|
||||
features.custom_border_color.customBorderColorWithoutFormat;
|
||||
// On most drivers we require both customBorderColors and
|
||||
// customBorderColorWithoutFormat. However, some Qualcomm drivers expose a
|
||||
// subset of the functionality; when running on Qualcomm, enable the
|
||||
// extension if the driver reports any useful feature.
|
||||
if (IsQualcomm()) {
|
||||
extensions.custom_border_color =
|
||||
features.custom_border_color.customBorderColors ||
|
||||
features.custom_border_color.customBorderColorWithoutFormat;
|
||||
} else {
|
||||
extensions.custom_border_color =
|
||||
features.custom_border_color.customBorderColors &&
|
||||
features.custom_border_color.customBorderColorWithoutFormat;
|
||||
}
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||
|
||||
@@ -1226,6 +1322,14 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,
|
||||
VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
|
||||
|
||||
// VK_EXT_robustness2
|
||||
// Enable the extension only if at least one of the useful robustness2 features is present.
|
||||
extensions.robustness2 = features.robustness2.nullDescriptor ||
|
||||
features.robustness2.robustBufferAccess2 ||
|
||||
features.robustness2.robustImageAccess2;
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.robustness2, features.robustness2,
|
||||
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
|
||||
|
||||
// VK_EXT_extended_dynamic_state
|
||||
extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
|
||||
|
||||
@@ -90,7 +90,16 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle) \
|
||||
EXTENSION(EXT, DESCRIPTOR_INDEXING, descriptor_indexing) \
|
||||
EXTENSION(EXT, FILTER_CUBIC, filter_cubic) \
|
||||
EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights)
|
||||
EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights) \
|
||||
EXTENSION(KHR, MAINTENANCE_1, maintenance1) \
|
||||
EXTENSION(KHR, MAINTENANCE_2, maintenance2) \
|
||||
EXTENSION(KHR, MAINTENANCE_3, maintenance3) \
|
||||
EXTENSION(KHR, MAINTENANCE_4, maintenance4) \
|
||||
EXTENSION(KHR, MAINTENANCE_5, maintenance5) \
|
||||
EXTENSION(KHR, MAINTENANCE_6, maintenance6) \
|
||||
EXTENSION(KHR, MAINTENANCE_7, maintenance7) \
|
||||
EXTENSION(KHR, MAINTENANCE_8, maintenance8) \
|
||||
EXTENSION(KHR, MAINTENANCE_9, maintenance9) \
|
||||
|
||||
// Define extensions which must be supported.
|
||||
#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
|
||||
@@ -445,6 +454,56 @@ public:
|
||||
return extensions.shader_float_controls;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance1 is enabled.
|
||||
bool IsKhrMaintenance1Supported() const {
|
||||
return extensions.maintenance1;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance2 is enabled.
|
||||
bool IsKhrMaintenance2Supported() const {
|
||||
return extensions.maintenance2;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance3 is enabled.
|
||||
bool IsKhrMaintenance3Supported() const {
|
||||
return extensions.maintenance3;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance4 is enabled.
|
||||
bool IsKhrMaintenance4Supported() const {
|
||||
return extensions.maintenance4;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance5 is enabled.
|
||||
bool IsKhrMaintenance5Supported() const {
|
||||
return extensions.maintenance5;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance6 is enabled.
|
||||
bool IsKhrMaintenance6Supported() const {
|
||||
return extensions.maintenance6;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance7 is enabled.
|
||||
bool IsKhrMaintenance7Supported() const {
|
||||
return extensions.maintenance7;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance8 is enabled.
|
||||
bool IsKhrMaintenance8Supported() const {
|
||||
return extensions.maintenance8;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_maintenance9 is enabled.
|
||||
bool IsKhrMaintenance9Supported() const {
|
||||
return extensions.maintenance9;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_sampler_mirror_clamp_to_edge is enabled.
|
||||
bool IsKhrSamplerMirrorClampToEdgeSupported() const {
|
||||
return extensions.sampler_mirror_clamp_to_edge;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
|
||||
bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
|
||||
return extensions.workgroup_memory_explicit_layout;
|
||||
@@ -727,6 +786,10 @@ public:
|
||||
return properties.driver.driverID == VK_DRIVER_ID_MOLTENVK;
|
||||
}
|
||||
|
||||
bool IsQualcomm() const noexcept {
|
||||
return properties.driver.driverID == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
||||
}
|
||||
|
||||
NvidiaArchitecture GetNvidiaArch() const noexcept {
|
||||
return nvidia_arch;
|
||||
}
|
||||
@@ -783,11 +846,11 @@ private:
|
||||
#define EXTENSION(prefix, macro_name, var_name) bool var_name{};
|
||||
#define FEATURE(prefix, struct_name, macro_name, var_name) bool var_name{};
|
||||
|
||||
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_EXT(FEATURE);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
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_EXT(FEATURE);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
|
||||
#undef EXTENSION
|
||||
#undef FEATURE
|
||||
|
||||
Reference in New Issue
Block a user