diff --git a/src/shader_recompiler/ir_opt/compaction_fallback_pass.cpp b/src/shader_recompiler/ir_opt/compaction_fallback_pass.cpp index f905a87d23..ca057995e5 100644 --- a/src/shader_recompiler/ir_opt/compaction_fallback_pass.cpp +++ b/src/shader_recompiler/ir_opt/compaction_fallback_pass.cpp @@ -36,15 +36,14 @@ void RewriteAtomic(IR::Block& block, IR::Inst& inst) { const IR::U32 amount{inst.Arg(2)}; const IR::U32 primitive_id{ir.GetAttributeU32(IR::Attribute::PrimitiveId)}; - const IR::U32 new_index{ir.IMul(primitive_id, amount)}; - const IR::U32 new_atomic_value{ir.IAdd(new_index, amount)}; + const IR::U1 reserves_slot{ir.INotEqual(amount, ir.Imm32(0u))}; + const IR::U32 slot_end{ir.IAdd(primitive_id, ir.Imm32(1u))}; + const IR::U32 high_water{IR::U32{ir.Select(reserves_slot, slot_end, ir.Imm32(0u))}}; - const IR::Value umax_result{&*block.PrependNewInst( - insert_point, IR::Opcode::StorageAtomicUMax32, - {inst.Arg(0), inst.Arg(1), new_atomic_value})}; - static_cast(umax_result); + block.PrependNewInst(insert_point, IR::Opcode::StorageAtomicUMax32, + {inst.Arg(0), inst.Arg(1), high_water}); - inst.ReplaceUsesWith(new_index); + inst.ReplaceUsesWith(primitive_id); } } // Anonymous namespace @@ -58,6 +57,9 @@ void CompactionFallbackPass(IR::Program& program, const HostTranslateInfo& host_ if (inst.GetOpcode() != IR::Opcode::StorageAtomicIAdd32) { continue; } + if (!inst.HasUses()) { + continue; + } if (!DependsOnSubgroupBallot(inst.Arg(2), 0)) { continue; } diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index ab78b19a44..c20e07054a 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index b9e5886945..930570fa50 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -360,19 +360,26 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, const VkDriverId driver_id{device.GetDriverID()}; const VkShaderStageFlags subgroup_stages{device.GetSubgroupSupportedStages()}; const auto subgroup_stage_bit{[subgroup_stages](VkShaderStageFlags flag, Shader::Stage stage) { - return (subgroup_stages & flag) != 0 ? (1u << static_cast(stage)) : 0u; + if ((subgroup_stages & flag) == 0) { + return 0u; + } + return 1u << static_cast(stage); }}; - const u32 supported_subgroup_stages{ + u32 supported_subgroup_stages{ subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexA) | subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexB) | subgroup_stage_bit(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, Shader::Stage::TessellationControl) | subgroup_stage_bit(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, Shader::Stage::TessellationEval) | - subgroup_stage_bit(driver_id == VK_DRIVER_ID_MESA_TURNIP ? 0 : VK_SHADER_STAGE_GEOMETRY_BIT, - Shader::Stage::Geometry) | + subgroup_stage_bit(VK_SHADER_STAGE_GEOMETRY_BIT, Shader::Stage::Geometry) | subgroup_stage_bit(VK_SHADER_STAGE_FRAGMENT_BIT, Shader::Stage::Fragment) | subgroup_stage_bit(VK_SHADER_STAGE_COMPUTE_BIT, Shader::Stage::Compute)}; + if (!device.AreSubgroupFeaturesSupported(VK_SUBGROUP_FEATURE_VOTE_BIT | + VK_SUBGROUP_FEATURE_BALLOT_BIT | + VK_SUBGROUP_FEATURE_SHUFFLE_BIT)) { + supported_subgroup_stages = 0u; + } profile = Shader::Profile{ .supported_spirv = device.SupportedSpirvVersion(), .unified_descriptor_binding = true, diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 319a7b2ec3..e51b2bf88b 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -479,6 +479,11 @@ FN_MAX_LIMIT_LIST return properties.subgroup_properties.supportedStages; } + /// Returns true if every requested subgroup operation is supported by the device. + bool AreSubgroupFeaturesSupported(VkSubgroupFeatureFlags features) const { + return (properties.subgroup_properties.supportedOperations & features) == features; + } + /// Returns the maximum number of push descriptors. u32 MaxPushDescriptors() const { return properties.push_descriptor.maxPushDescriptors;