diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/engines/maxwell_dma.cpp | 1 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_device.cpp | 43 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 10 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 12 | ||||
-rw-r--r-- | src/video_core/shader_cache.cpp | 5 | ||||
-rw-r--r-- | src/video_core/shader_cache.h | 2 | ||||
-rw-r--r-- | src/video_core/shader_environment.cpp | 31 | ||||
-rw-r--r-- | src/video_core/shader_environment.h | 6 | ||||
-rw-r--r-- | src/video_core/vulkan_common/vulkan_device.cpp | 181 | ||||
-rw-r--r-- | src/video_core/vulkan_common/vulkan_device.h | 13 |
10 files changed, 201 insertions, 103 deletions
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index cd8e24b0b..da8eab7ee 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/core.h" #include "core/memory.h" diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index ee140c9c2..94258ccd0 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -106,6 +106,43 @@ bool IsASTCSupported() { return true; } +static bool HasSlowSoftwareAstc(std::string_view vendor_name, std::string_view renderer) { +// ifdef for Unix reduces string comparisons for non-Windows drivers, and Intel +#ifdef YUZU_UNIX + // Sorted vaguely by how likely a vendor is to appear + if (vendor_name == "AMD") { + // RadeonSI + return true; + } + if (vendor_name == "Intel") { + // Must be inside YUZU_UNIX ifdef as the Windows driver uses the same vendor string + // iris, crocus + const bool is_intel_dg = (renderer.find("DG") != std::string_view::npos); + return is_intel_dg; + } + if (vendor_name == "nouveau") { + return true; + } + if (vendor_name == "X.Org") { + // R600 + return true; + } +#endif + if (vendor_name == "Collabora Ltd") { + // Zink + return true; + } + if (vendor_name == "Microsoft Corporation") { + // d3d12 + return true; + } + if (vendor_name == "Mesa/X.org") { + // llvmpipe, softpipe, virgl + return true; + } + return false; +} + [[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) { const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); return nsight || HasExtension(extensions, "GL_EXT_debug_tool") || @@ -120,12 +157,16 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { } vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION)); + const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); const std::vector extensions = GetExtensions(); const bool is_nvidia = vendor_name == "NVIDIA Corporation"; const bool is_amd = vendor_name == "ATI Technologies Inc."; const bool is_intel = vendor_name == "Intel"; + const bool has_slow_software_astc = + !is_nvidia && !is_amd && HasSlowSoftwareAstc(vendor_name, renderer); + #ifdef __unix__ constexpr bool is_linux = true; #else @@ -152,7 +193,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted"); has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod"); - has_astc = IsASTCSupported(); + has_astc = !has_slow_software_astc && IsASTCSupported(); has_variable_aoffi = TestVariableAoffi(); has_component_indexing_bug = is_amd; has_precise_bug = TestPreciseBug(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 618cb6354..2888e0238 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -445,7 +445,8 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key, std::span<Shader::Environment* const> envs, bool use_shader_workers, bool force_context_flush) try { - LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash()); + auto hash = key.Hash(); + LOG_INFO(Render_OpenGL, "0x{:016x}", hash); size_t env_index{}; u32 total_storage_buffers{}; std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; @@ -474,7 +475,7 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); if (Settings::values.dump_shaders) { - env.Dump(key.unique_hashes[index]); + env.Dump(hash, key.unique_hashes[index]); } if (!uses_vertex_a || index != 1) { @@ -566,12 +567,13 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( ShaderContext::ShaderPools& pools, const ComputePipelineKey& key, Shader::Environment& env, bool force_context_flush) try { - LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash()); + auto hash = key.Hash(); + LOG_INFO(Render_OpenGL, "0x{:016x}", hash); Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; if (Settings::values.dump_shaders) { - env.Dump(key.Hash()); + env.Dump(hash, key.unique_hash); } auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4f84d8497..c1314ca99 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -584,7 +584,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( ShaderPools& pools, const GraphicsPipelineCacheKey& key, std::span<Shader::Environment* const> envs, PipelineStatistics* statistics, bool build_in_parallel) try { - LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); + auto hash = key.Hash(); + LOG_INFO(Render_Vulkan, "0x{:016x}", hash); size_t env_index{0}; std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; const bool uses_vertex_a{key.unique_hashes[0] != 0}; @@ -611,7 +612,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); if (Settings::values.dump_shaders) { - env.Dump(key.unique_hashes[index]); + env.Dump(hash, key.unique_hashes[index]); } if (!uses_vertex_a || index != 1) { // Normal path @@ -712,18 +713,19 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, PipelineStatistics* statistics, bool build_in_parallel) try { + auto hash = key.Hash(); if (device.HasBrokenCompute()) { - LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); + LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", hash); return nullptr; } - LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); + LOG_INFO(Render_Vulkan, "0x{:016x}", hash); Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; // Dump it before error. if (Settings::values.dump_shaders) { - env.Dump(key.Hash()); + env.Dump(hash, key.unique_hash); } auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp index 01701201d..e81cd031b 100644 --- a/src/video_core/shader_cache.cpp +++ b/src/video_core/shader_cache.cpp @@ -51,6 +51,11 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) { } const auto& shader_config{maxwell3d->regs.pipelines[index]}; const auto program{static_cast<Tegra::Engines::Maxwell3D::Regs::ShaderType>(index)}; + if (program == Tegra::Engines::Maxwell3D::Regs::ShaderType::Pixel && + !maxwell3d->regs.rasterize_enable) { + unique_hashes[index] = 0; + continue; + } const GPUVAddr shader_addr{base_addr + shader_config.offset}; const std::optional<VAddr> cpu_shader_addr{gpu_memory->GpuToCpuAddress(shader_addr)}; if (!cpu_shader_addr) { diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h index de8e08002..a76896620 100644 --- a/src/video_core/shader_cache.h +++ b/src/video_core/shader_cache.h @@ -70,7 +70,7 @@ public: protected: struct GraphicsEnvironments { std::array<GraphicsEnvironment, NUM_PROGRAMS> envs; - std::array<Shader::Environment*, NUM_PROGRAMS> env_ptrs; + std::array<Shader::Environment*, NUM_PROGRAMS> env_ptrs{}; std::span<Shader::Environment* const> Span() const noexcept { return std::span(env_ptrs.begin(), std::ranges::find(env_ptrs, nullptr)); diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index c7cb56243..4edbe5700 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -102,7 +102,8 @@ static std::string_view StageToPrefix(Shader::Stage stage) { } } -static void DumpImpl(u64 hash, const u64* code, u32 read_highest, u32 read_lowest, +static void DumpImpl(u64 pipeline_hash, u64 shader_hash, std::span<const u64> code, + [[maybe_unused]] u32 read_highest, [[maybe_unused]] u32 read_lowest, u32 initial_offset, Shader::Stage stage) { const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)}; const auto base_dir{shader_dir / "shaders"}; @@ -111,13 +112,18 @@ static void DumpImpl(u64 hash, const u64* code, u32 read_highest, u32 read_lowes return; } const auto prefix = StageToPrefix(stage); - const auto name{base_dir / fmt::format("{}{:016x}.ash", prefix, hash)}; - const size_t real_size = read_highest - read_lowest + initial_offset; - const size_t padding_needed = ((32 - (real_size % 32)) % 32); + const auto name{base_dir / + fmt::format("{:016x}_{}_{:016x}.ash", pipeline_hash, prefix, shader_hash)}; std::fstream shader_file(name, std::ios::out | std::ios::binary); + ASSERT(initial_offset % sizeof(u64) == 0); const size_t jump_index = initial_offset / sizeof(u64); - shader_file.write(reinterpret_cast<const char*>(code + jump_index), real_size); - for (size_t i = 0; i < padding_needed; i++) { + const size_t code_size = code.size_bytes() - initial_offset; + shader_file.write(reinterpret_cast<const char*>(&code[jump_index]), code_size); + + // + 1 instruction, due to the fact that we skip the final self branch instruction in the code, + // but we need to consider it for padding, otherwise nvdisasm rages. + const size_t padding_needed = (32 - ((code_size + INST_SIZE) % 32)) % 32; + for (size_t i = 0; i < INST_SIZE + padding_needed; i++) { shader_file.put(0); } } @@ -197,8 +203,8 @@ u64 GenericEnvironment::CalculateHash() const { return Common::CityHash64(data.get(), size); } -void GenericEnvironment::Dump(u64 hash) { - DumpImpl(hash, code.data(), read_highest, read_lowest, initial_offset, stage); +void GenericEnvironment::Dump(u64 pipeline_hash, u64 shader_hash) { + DumpImpl(pipeline_hash, shader_hash, code, read_highest, read_lowest, initial_offset, stage); } void GenericEnvironment::Serialize(std::ofstream& file) const { @@ -282,6 +288,7 @@ std::optional<u64> GenericEnvironment::TryFindSize() { Tegra::Texture::TICEntry GenericEnvironment::ReadTextureInfo(GPUVAddr tic_addr, u32 tic_limit, bool via_header_index, u32 raw) { const auto handle{Tegra::Texture::TexturePair(raw, via_header_index)}; + ASSERT(handle.first <= tic_limit); const GPUVAddr descriptor_addr{tic_addr + handle.first * sizeof(Tegra::Texture::TICEntry)}; Tegra::Texture::TICEntry entry; gpu_memory->ReadBlock(descriptor_addr, &entry, sizeof(entry)); @@ -465,8 +472,8 @@ void FileEnvironment::Deserialize(std::ifstream& file) { .read(reinterpret_cast<char*>(&read_highest), sizeof(read_highest)) .read(reinterpret_cast<char*>(&viewport_transform_state), sizeof(viewport_transform_state)) .read(reinterpret_cast<char*>(&stage), sizeof(stage)); - code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64))); - file.read(reinterpret_cast<char*>(code.get()), code_size); + code.resize(Common::DivCeil(code_size, sizeof(u64))); + file.read(reinterpret_cast<char*>(code.data()), code_size); for (size_t i = 0; i < num_texture_types; ++i) { u32 key; Shader::TextureType type; @@ -509,8 +516,8 @@ void FileEnvironment::Deserialize(std::ifstream& file) { is_propietary_driver = texture_bound == 2; } -void FileEnvironment::Dump(u64 hash) { - DumpImpl(hash, code.get(), read_highest, read_lowest, initial_offset, stage); +void FileEnvironment::Dump(u64 pipeline_hash, u64 shader_hash) { + DumpImpl(pipeline_hash, shader_hash, code, read_highest, read_lowest, initial_offset, stage); } u64 FileEnvironment::ReadInstruction(u32 address) { diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index a0f61cbda..b90f3d44e 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h @@ -58,7 +58,7 @@ public: [[nodiscard]] u64 CalculateHash() const; - void Dump(u64 hash) override; + void Dump(u64 pipeline_hash, u64 shader_hash) override; void Serialize(std::ofstream& file) const; @@ -188,10 +188,10 @@ public: return cbuf_replacements.size() != 0; } - void Dump(u64 hash) override; + void Dump(u64 pipeline_hash, u64 shader_hash) override; private: - std::unique_ptr<u64[]> code; + std::vector<u64> code; std::unordered_map<u32, Shader::TextureType> texture_types; std::unordered_map<u32, Shader::TexturePixelFormat> texture_pixel_formats; std::unordered_map<u64, u32> cbuf_values; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index bd67e27ed..adde96aa5 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -326,6 +326,43 @@ std::vector<const char*> ExtensionListForVulkan( } // Anonymous namespace +void Device::RemoveExtension(bool& extension, const std::string& extension_name) { + extension = false; + loaded_extensions.erase(extension_name); +} + +void Device::RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name) { + if (loaded_extensions.contains(extension_name) && !is_suitable) { + LOG_WARNING(Render_Vulkan, "Removing unsuitable extension {}", extension_name); + this->RemoveExtension(is_suitable, extension_name); + } +} + +template <typename Feature> +void Device::RemoveExtensionFeature(bool& extension, Feature& feature, + const std::string& extension_name) { + // Unload extension. + this->RemoveExtension(extension, extension_name); + + // Save sType and pNext for chain. + VkStructureType sType = feature.sType; + void* pNext = feature.pNext; + + // Clear feature struct and restore chain. + feature = {}; + feature.sType = sType; + feature.pNext = pNext; +} + +template <typename Feature> +void Device::RemoveExtensionFeatureIfUnsuitable(bool is_suitable, Feature& feature, + const std::string& extension_name) { + if (loaded_extensions.contains(extension_name) && !is_suitable) { + LOG_WARNING(Render_Vulkan, "Removing features for unsuitable extension {}", extension_name); + this->RemoveExtensionFeature(is_suitable, feature, extension_name); + } +} + Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) : instance{instance_}, dld{dld_}, physical{physical_}, @@ -397,21 +434,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (is_qualcomm || is_turnip) { LOG_WARNING(Render_Vulkan, "Qualcomm and Turnip drivers have broken VK_EXT_custom_border_color"); - extensions.custom_border_color = false; - loaded_extensions.erase(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); + RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color, + VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); } if (is_qualcomm) { must_emulate_scaled_formats = true; LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken VK_EXT_extended_dynamic_state"); - extensions.extended_dynamic_state = false; - loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); LOG_WARNING(Render_Vulkan, "Qualcomm drivers have a slow VK_KHR_push_descriptor implementation"); - extensions.push_descriptor = false; - loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); + RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); #if defined(ANDROID) && defined(ARCHITECTURE_arm64) // Patch the driver to enable BCn textures. @@ -440,15 +476,12 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR must_emulate_scaled_formats = true; LOG_WARNING(Render_Vulkan, "ARM drivers have broken VK_EXT_extended_dynamic_state"); - extensions.extended_dynamic_state = false; - loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); LOG_WARNING(Render_Vulkan, "ARM drivers have broken VK_EXT_extended_dynamic_state2"); - features.extended_dynamic_state2.extendedDynamicState2 = false; - features.extended_dynamic_state2.extendedDynamicState2LogicOp = false; - features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false; - extensions.extended_dynamic_state2 = false; - loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); } if (is_nvidia) { @@ -464,8 +497,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR case NvidiaArchitecture::VoltaOrOlder: if (nv_major_version < 527) { LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor"); - extensions.push_descriptor = false; - loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); + RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); } break; } @@ -480,8 +512,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (version < VK_MAKE_API_VERSION(0, 21, 2, 0)) { LOG_WARNING(Render_Vulkan, "RADV versions older than 21.2 have broken VK_EXT_extended_dynamic_state"); - extensions.extended_dynamic_state = false; - loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state, + features.extended_dynamic_state, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); } } if (extensions.extended_dynamic_state2 && is_radv) { @@ -490,11 +523,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR LOG_WARNING( Render_Vulkan, "RADV versions older than 22.3.1 have broken VK_EXT_extended_dynamic_state2"); - features.extended_dynamic_state2.extendedDynamicState2 = false; - features.extended_dynamic_state2.extendedDynamicState2LogicOp = false; - features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false; - extensions.extended_dynamic_state2 = false; - loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state2, + features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); } } if (extensions.extended_dynamic_state2 && is_qualcomm) { @@ -504,11 +535,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR // 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"); - features.extended_dynamic_state2.extendedDynamicState2 = false; - features.extended_dynamic_state2.extendedDynamicState2LogicOp = false; - features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false; - extensions.extended_dynamic_state2 = false; - loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state2, + features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); } } if (extensions.extended_dynamic_state3 && is_radv) { @@ -540,9 +569,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (is_rdna2) { LOG_WARNING(Render_Vulkan, "RADV has broken VK_EXT_vertex_input_dynamic_state on RDNA2 hardware"); - features.vertex_input_dynamic_state.vertexInputDynamicState = false; - extensions.vertex_input_dynamic_state = false; - loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); } } if (extensions.vertex_input_dynamic_state && is_qualcomm) { @@ -553,9 +582,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR LOG_WARNING( Render_Vulkan, "Qualcomm Adreno 7xx drivers have broken VK_EXT_vertex_input_dynamic_state"); - features.vertex_input_dynamic_state.vertexInputDynamicState = false; - extensions.vertex_input_dynamic_state = false; - loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); } } @@ -575,8 +604,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (!features.shader_float16_int8.shaderFloat16) { LOG_WARNING(Render_Vulkan, "AMD GCN4 and earlier have broken VK_EXT_sampler_filter_minmax"); - extensions.sampler_filter_minmax = false; - loaded_extensions.erase(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME); + RemoveExtension(extensions.sampler_filter_minmax, + VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME); } } @@ -584,8 +613,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const u32 version = (properties.properties.driverVersion << 3) >> 3; if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) { LOG_WARNING(Render_Vulkan, "Intel has broken VK_EXT_vertex_input_dynamic_state"); - extensions.vertex_input_dynamic_state = false; - loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); } } if (features.shader_float16_int8.shaderFloat16 && is_intel_windows) { @@ -612,8 +642,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR // mesa/mesa/-/commit/ff91c5ca42bc80aa411cb3fd8f550aa6fdd16bdc LOG_WARNING(Render_Vulkan, "ANV drivers 22.3.0 to 23.1.0 have broken VK_KHR_push_descriptor"); - extensions.push_descriptor = false; - loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); + RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); } } if (is_mvk) { @@ -963,7 +992,7 @@ bool Device::GetSuitability(bool requires_swapchain) { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR; SetNext(next, properties.push_descriptor); } - if (extensions.subgroup_size_control) { + if (extensions.subgroup_size_control || features.subgroup_size_control.subgroupSizeControl) { properties.subgroup_size_control.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES; SetNext(next, properties.subgroup_size_control); @@ -1007,34 +1036,29 @@ bool Device::GetSuitability(bool requires_swapchain) { return suitable; } -void Device::RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name) { - if (loaded_extensions.contains(extension_name) && !is_suitable) { - LOG_WARNING(Render_Vulkan, "Removing unsuitable extension {}", extension_name); - loaded_extensions.erase(extension_name); - } -} - void Device::RemoveUnsuitableExtensions() { // VK_EXT_custom_border_color extensions.custom_border_color = features.custom_border_color.customBorderColors && features.custom_border_color.customBorderColorWithoutFormat; - RemoveExtensionIfUnsuitable(extensions.custom_border_color, - VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color, + VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); // VK_EXT_depth_clip_control extensions.depth_clip_control = features.depth_clip_control.depthClipControl; - RemoveExtensionIfUnsuitable(extensions.depth_clip_control, - VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control, + VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); // VK_EXT_extended_dynamic_state extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState; - RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state, - VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state, + features.extended_dynamic_state, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); // VK_EXT_extended_dynamic_state2 extensions.extended_dynamic_state2 = features.extended_dynamic_state2.extendedDynamicState2; - RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state2, - VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state2, + features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); // VK_EXT_extended_dynamic_state3 dynamic_state3_blending = @@ -1048,35 +1072,38 @@ void Device::RemoveUnsuitableExtensions() { 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; - RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state3, - VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state3, + features.extended_dynamic_state3, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); // VK_EXT_provoking_vertex extensions.provoking_vertex = features.provoking_vertex.provokingVertexLast && features.provoking_vertex.transformFeedbackPreservesProvokingVertex; - RemoveExtensionIfUnsuitable(extensions.provoking_vertex, - VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.provoking_vertex, features.provoking_vertex, + VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME); // VK_KHR_shader_atomic_int64 extensions.shader_atomic_int64 = features.shader_atomic_int64.shaderBufferInt64Atomics && features.shader_atomic_int64.shaderSharedInt64Atomics; - RemoveExtensionIfUnsuitable(extensions.shader_atomic_int64, - VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.shader_atomic_int64, features.shader_atomic_int64, + VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME); // VK_EXT_shader_demote_to_helper_invocation extensions.shader_demote_to_helper_invocation = features.shader_demote_to_helper_invocation.shaderDemoteToHelperInvocation; - RemoveExtensionIfUnsuitable(extensions.shader_demote_to_helper_invocation, - VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.shader_demote_to_helper_invocation, + features.shader_demote_to_helper_invocation, + VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME); // VK_EXT_subgroup_size_control extensions.subgroup_size_control = features.subgroup_size_control.subgroupSizeControl && properties.subgroup_size_control.minSubgroupSize <= GuestWarpSize && properties.subgroup_size_control.maxSubgroupSize >= GuestWarpSize; - RemoveExtensionIfUnsuitable(extensions.subgroup_size_control, - VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.subgroup_size_control, + features.subgroup_size_control, + VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME); // VK_EXT_transform_feedback extensions.transform_feedback = @@ -1086,24 +1113,27 @@ void Device::RemoveUnsuitableExtensions() { properties.transform_feedback.maxTransformFeedbackBuffers > 0 && properties.transform_feedback.transformFeedbackQueries && properties.transform_feedback.transformFeedbackDraw; - RemoveExtensionIfUnsuitable(extensions.transform_feedback, - VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.transform_feedback, features.transform_feedback, + VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); // VK_EXT_vertex_input_dynamic_state extensions.vertex_input_dynamic_state = features.vertex_input_dynamic_state.vertexInputDynamicState; - RemoveExtensionIfUnsuitable(extensions.vertex_input_dynamic_state, - VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); // VK_KHR_pipeline_executable_properties if (Settings::values.renderer_shader_feedback.GetValue()) { extensions.pipeline_executable_properties = features.pipeline_executable_properties.pipelineExecutableInfo; - RemoveExtensionIfUnsuitable(extensions.pipeline_executable_properties, - VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.pipeline_executable_properties, + features.pipeline_executable_properties, + VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); } else { - extensions.pipeline_executable_properties = false; - loaded_extensions.erase(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); + RemoveExtensionFeature(extensions.pipeline_executable_properties, + features.pipeline_executable_properties, + VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); } // VK_KHR_workgroup_memory_explicit_layout @@ -1113,8 +1143,9 @@ void Device::RemoveUnsuitableExtensions() { features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout8BitAccess && features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout16BitAccess && features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayoutScalarBlockLayout; - RemoveExtensionIfUnsuitable(extensions.workgroup_memory_explicit_layout, - VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME); + RemoveExtensionFeatureIfUnsuitable(extensions.workgroup_memory_explicit_layout, + features.workgroup_memory_explicit_layout, + VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_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 be3ed45ff..488fdd313 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -20,7 +20,6 @@ VK_DEFINE_HANDLE(VmaAllocator) // Vulkan version in the macro describes the minimum version required for feature availability. // If the Vulkan version is lower than the required version, the named extension is required. #define FOR_EACH_VK_FEATURE_1_1(FEATURE) \ - FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \ FEATURE(KHR, 16BitStorage, 16BIT_STORAGE, bit16_storage) \ FEATURE(KHR, ShaderAtomicInt64, SHADER_ATOMIC_INT64, shader_atomic_int64) \ FEATURE(KHR, ShaderDrawParameters, SHADER_DRAW_PARAMETERS, shader_draw_parameters) \ @@ -36,7 +35,8 @@ VK_DEFINE_HANDLE(VmaAllocator) #define FOR_EACH_VK_FEATURE_1_3(FEATURE) \ FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \ - shader_demote_to_helper_invocation) + shader_demote_to_helper_invocation) \ + FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) // Define all features which may be used by the implementation and require an extension here. #define FOR_EACH_VK_FEATURE_EXT(FEATURE) \ @@ -639,8 +639,17 @@ private: // Remove extensions which have incomplete feature support. void RemoveUnsuitableExtensions(); + + void RemoveExtension(bool& extension, const std::string& extension_name); void RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name); + template <typename Feature> + void RemoveExtensionFeature(bool& extension, Feature& feature, + const std::string& extension_name); + template <typename Feature> + void RemoveExtensionFeatureIfUnsuitable(bool is_suitable, Feature& feature, + const std::string& extension_name); + /// Sets up queue families. void SetupFamilies(VkSurfaceKHR surface); |