diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 1b301be316..cabdddebd7 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -446,8 +446,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct ctx.AddCapability(spv::Capability::GroupNonUniformVote); } } - if (info.uses_quad_shuffles && profile.support_quad_shuffles) { - ctx.AddCapability(spv::Capability::GroupNonUniformQuad); + if (info.uses_quad_shuffles) { + if (profile.support_quad_shuffles) { + ctx.AddCapability(spv::Capability::GroupNonUniformQuad); + } ctx.AddCapability(spv::Capability::GroupNonUniformShuffle); } if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index d93760995b..1690633cf6 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp @@ -224,7 +224,13 @@ Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id } Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane) { - return ctx.OpGroupNonUniformQuadBroadcast(ctx.U32[1], SubgroupScope(ctx), value, lane); + if (ctx.profile.support_quad_shuffles) { + return ctx.OpGroupNonUniformQuadBroadcast(ctx.U32[1], SubgroupScope(ctx), value, lane); + } + const Id base{ctx.OpBitwiseAnd(ctx.U32[1], GetThreadId(ctx), ctx.Const(~3u))}; + const Id local_lane{ctx.OpBitwiseAnd(ctx.U32[1], lane, ctx.Const(3u))}; + const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], base, local_lane)}; + return ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id); } Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction) { diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp index 759a74f8d3..2a19237ab2 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp @@ -36,9 +36,7 @@ enum class ShuffleMode : u64 { } } -// SHFL mask encoding for quad-constrained operations: -// bits [0:4] = clamp = 3, bits [8:12] = seg_mask = 28 (0x1C) -constexpr u32 QUAD_MASK = (28u << 8) | 3u; // 0x1C03 +constexpr u32 QUAD_MASK = (28u << 8) | 3u; void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32& mask, bool index_is_imm, u32 index_imm, bool mask_is_imm, u32 mask_imm) { @@ -50,15 +48,15 @@ void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32 BitField<48, 3, IR::Pred> pred; } const shfl{insn}; - if (mask_is_imm && mask_imm == QUAD_MASK && index_is_imm) { + const bool is_quad_candidate{mask_is_imm && mask_imm == QUAD_MASK && index_is_imm && + v.env.ShaderStage() == Stage::Fragment}; + if (is_quad_candidate) { if (shfl.mode == ShuffleMode::IDX && index_imm <= 3) { - // SHFL IDX with lane 0-3 in a quad → QuadBroadcast v.X(shfl.dest_reg, v.ir.QuadBroadcast(v.X(shfl.src_reg), v.ir.Imm32(index_imm))); v.ir.SetPred(shfl.pred, v.ir.Imm1(true)); return; } if (shfl.mode == ShuffleMode::BFLY && index_imm >= 1 && index_imm <= 3) { - // SHFL BFLY index 1/2/3 in a quad → QuadSwap direction 0/1/2 v.X(shfl.dest_reg, v.ir.QuadSwap(v.X(shfl.src_reg), v.ir.Imm32(index_imm - 1))); v.ir.SetPred(shfl.pred, v.ir.Imm1(true)); return;