diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index 6572db86dc..51db349f8c 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h @@ -665,6 +665,8 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU3 const IR::Value& clamp, const IR::Value& segmentation_mask); void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, const IR::Value& clamp, const IR::Value& segmentation_mask); +void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 lane); +void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 direction); void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b, ScalarU32 swizzle); void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a); diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp index fb6a597d4e..80ba7556de 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp @@ -97,6 +97,26 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, Sca Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "XOR"); } +void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 lane) { + // QuadBroadcast: src = (thread_id & ~3) | (lane & 3) — SHFLIDX with quad mask 0x1C03 + const Register ret{ctx.reg_alloc.Define(inst)}; + ctx.Add("AND.U RC.x,{}.threadid,~3;" + "AND.U RC.y,{},3;" + "OR.U RC.x,RC.x,RC.y;" + "SHFLIDX.U {},{},RC.x,0x1C03;" + "MOV.U {}.x,{}.x;", + ctx.stage_name, lane, ret, value, ret, ret); +} + +void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 direction) { + // QuadSwap: XOR thread_id with (direction+1) within quad — SHFLXOR with quad mask 0x1C03 + const Register ret{ctx.reg_alloc.Define(inst)}; + ctx.Add("ADD.U RC.x,{},1;" + "SHFLXOR.U {},{},RC.x,0x1C03;" + "MOV.U {}.x,{}.x;", + direction, ret, value, ret, ret); +} + void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b, ScalarU32 swizzle) { const auto ret{ctx.reg_alloc.Define(inst)}; diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index d508b84cec..433e626228 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h @@ -743,6 +743,10 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value, void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index, std::string_view clamp, std::string_view segmentation_mask); +void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, std::string_view value, + std::string_view lane); +void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, std::string_view value, + std::string_view direction); void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b, std::string_view swizzle); void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, std::string_view op_a); diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp index f9be5de1c0..854a1cf08e 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp @@ -200,6 +200,20 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view val ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value); } +void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, std::string_view value, + std::string_view lane) { + // QuadBroadcast: read from (thread_id & ~3) | (lane & 3) within the subgroup + const auto src_thread_id{fmt::format("(({}&~3)|({}& 3))", THREAD_ID, lane)}; + ctx.AddU32("{}=readInvocationARB({},{});", inst, value, src_thread_id); +} + +void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, std::string_view value, + std::string_view direction) { + // QuadSwap: XOR thread_id with (direction+1) — maps directions 0/1/2 to XOR 1/2/3 + const auto src_thread_id{fmt::format("({}^({}+1))", THREAD_ID, direction)}; + ctx.AddU32("{}=readInvocationARB({},{});", inst, value, src_thread_id); +} + void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b, std::string_view swizzle) { const auto mask{fmt::format("({}>>((gl_SubGroupInvocationARB&3)<<1))&3", swizzle)};