glasm: Implement shuffle and vote instructions on GLASM
This commit is contained in:
		| @@ -25,6 +25,23 @@ EmitContext::EmitContext(IR::Program& program) { | ||||
|     if (const size_t num = program.info.storage_buffers_descriptors.size(); num > 0) { | ||||
|         Add("PARAM c[{}]={{program.local[0..{}]}};", num, num - 1); | ||||
|     } | ||||
|     switch (program.stage) { | ||||
|     case Stage::VertexA: | ||||
|     case Stage::VertexB: | ||||
|         stage_name = "vertex"; | ||||
|         break; | ||||
|     case Stage::TessellationControl: | ||||
|     case Stage::TessellationEval: | ||||
|     case Stage::Geometry: | ||||
|         stage_name = "primitive"; | ||||
|         break; | ||||
|     case Stage::Fragment: | ||||
|         stage_name = "fragment"; | ||||
|         break; | ||||
|     case Stage::Compute: | ||||
|         stage_name = "compute"; | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Backend::GLASM | ||||
|   | ||||
| @@ -45,6 +45,8 @@ public: | ||||
|  | ||||
|     std::string code; | ||||
|     RegAlloc reg_alloc{*this}; | ||||
|  | ||||
|     std::string_view stage_name = "invalid"; | ||||
| }; | ||||
|  | ||||
| } // namespace Shader::Backend::GLASM | ||||
|   | ||||
| @@ -189,6 +189,12 @@ void SetupOptions(std::string& header, Info info) { | ||||
|     if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) { | ||||
|         header += "OPTION NV_shader_atomic_fp16_vector;"; | ||||
|     } | ||||
|     if (info.uses_subgroup_invocation_id || info.uses_subgroup_mask) { | ||||
|         header += "OPTION NV_shader_thread_group;"; | ||||
|     } | ||||
|     if (info.uses_subgroup_shuffles) { | ||||
|         header += "OPTION NV_shader_thread_shuffle;"; | ||||
|     } | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
|   | ||||
| @@ -584,24 +584,24 @@ void EmitImageAtomicXor32(EmitContext& ctx, IR::Inst& inst, const IR::Value& ind | ||||
|                           ScalarU32 value); | ||||
| void EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | ||||
|                                Register coords, ScalarU32 value); | ||||
| void EmitLaneId(EmitContext& ctx); | ||||
| void EmitVoteAll(EmitContext& ctx, ScalarS32 pred); | ||||
| void EmitVoteAny(EmitContext& ctx, ScalarS32 pred); | ||||
| void EmitVoteEqual(EmitContext& ctx, ScalarS32 pred); | ||||
| void EmitSubgroupBallot(EmitContext& ctx, ScalarS32 pred); | ||||
| void EmitSubgroupEqMask(EmitContext& ctx); | ||||
| void EmitSubgroupLtMask(EmitContext& ctx); | ||||
| void EmitSubgroupLeMask(EmitContext& ctx); | ||||
| void EmitSubgroupGtMask(EmitContext& ctx); | ||||
| void EmitSubgroupGeMask(EmitContext& ctx); | ||||
| void EmitLaneId(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitVoteAll(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred); | ||||
| void EmitVoteAny(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred); | ||||
| void EmitVoteEqual(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred); | ||||
| void EmitSubgroupBallot(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred); | ||||
| void EmitSubgroupEqMask(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitSubgroupLtMask(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitSubgroupLeMask(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitSubgroupGtMask(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitSubgroupGeMask(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                       ScalarU32 clamp, ScalarU32 segmentation_mask); | ||||
|                       const IR::Value& clamp, const IR::Value& segmentation_mask); | ||||
| void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                    ScalarU32 clamp, ScalarU32 segmentation_mask); | ||||
|                    const IR::Value& clamp, const IR::Value& segmentation_mask); | ||||
| void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                      ScalarU32 clamp, ScalarU32 segmentation_mask); | ||||
|                      const IR::Value& clamp, const IR::Value& segmentation_mask); | ||||
| void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                           ScalarU32 clamp, ScalarU32 segmentation_mask); | ||||
|                           const IR::Value& clamp, const IR::Value& segmentation_mask); | ||||
| void EmitFSwizzleAdd(EmitContext& ctx, ScalarF32 op_a, ScalarF32 op_b, ScalarU32 swizzle); | ||||
| void EmitDPdxFine(EmitContext& ctx, ScalarF32 op_a); | ||||
| void EmitDPdyFine(EmitContext& ctx, ScalarF32 op_a); | ||||
|   | ||||
| @@ -21,9 +21,7 @@ void EmitPhi(EmitContext& ctx, IR::Inst& inst) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitVoid(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
| void EmitVoid(EmitContext&) {} | ||||
|  | ||||
| void EmitBranch(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| @@ -636,84 +634,4 @@ void EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst& inst, const IR::Value | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitLaneId(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitVoteAll(EmitContext& ctx, ScalarS32 pred) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitVoteAny(EmitContext& ctx, ScalarS32 pred) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitVoteEqual(EmitContext& ctx, ScalarS32 pred) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupBallot(EmitContext& ctx, ScalarS32 pred) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupEqMask(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupLtMask(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupLeMask(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupGtMask(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupGeMask(EmitContext& ctx) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                       ScalarU32 clamp, ScalarU32 segmentation_mask) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                    ScalarU32 clamp, ScalarU32 segmentation_mask) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                      ScalarU32 clamp, ScalarU32 segmentation_mask) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                           ScalarU32 clamp, ScalarU32 segmentation_mask) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitFSwizzleAdd(EmitContext& ctx, ScalarF32 op_a, ScalarF32 op_b, ScalarU32 swizzle) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitDPdxFine(EmitContext& ctx, ScalarF32 op_a) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitDPdyFine(EmitContext& ctx, ScalarF32 op_a) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitDPdxCoarse(EmitContext& ctx, ScalarF32 op_a) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| void EmitDPdyCoarse(EmitContext& ctx, ScalarF32 op_a) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Backend::GLASM | ||||
|   | ||||
| @@ -0,0 +1,118 @@ | ||||
| // Copyright 2021 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "shader_recompiler/backend/glasm/emit_context.h" | ||||
| #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" | ||||
| #include "shader_recompiler/frontend/ir/value.h" | ||||
|  | ||||
| namespace Shader::Backend::GLASM { | ||||
|  | ||||
| void EmitLaneId(EmitContext& ctx, IR::Inst& inst) { | ||||
|     ctx.Add("MOV.S {}.x,{}.threadid;", inst, ctx.stage_name); | ||||
| } | ||||
|  | ||||
| void EmitVoteAll(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) { | ||||
|     ctx.Add("TGALL.S {}.x,{};", inst, pred); | ||||
| } | ||||
|  | ||||
| void EmitVoteAny(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) { | ||||
|     ctx.Add("TGANY.S {}.x,{};", inst, pred); | ||||
| } | ||||
|  | ||||
| void EmitVoteEqual(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) { | ||||
|     ctx.Add("TGEQ.S {}.x,{};", inst, pred); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupBallot(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) { | ||||
|     ctx.Add("TGBALLOT {}.x,{};", inst, pred); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupEqMask(EmitContext& ctx, IR::Inst& inst) { | ||||
|     ctx.Add("MOV.U {},{}.threadeqmask;", inst, ctx.stage_name); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupLtMask(EmitContext& ctx, IR::Inst& inst) { | ||||
|     ctx.Add("MOV.U {},{}.threadltmask;", inst, ctx.stage_name); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupLeMask(EmitContext& ctx, IR::Inst& inst) { | ||||
|     ctx.Add("MOV.U {},{}.threadlemask;", inst, ctx.stage_name); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupGtMask(EmitContext& ctx, IR::Inst& inst) { | ||||
|     ctx.Add("MOV.U {},{}.threadgtmask;", inst, ctx.stage_name); | ||||
| } | ||||
|  | ||||
| void EmitSubgroupGeMask(EmitContext& ctx, IR::Inst& inst) { | ||||
|     ctx.Add("MOV.U {},{}.threadgemask;", inst, ctx.stage_name); | ||||
| } | ||||
|  | ||||
| static void Shuffle(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                     const IR::Value& clamp, const IR::Value& segmentation_mask, | ||||
|                     std::string_view op) { | ||||
|     std::string mask; | ||||
|     if (clamp.IsImmediate() && segmentation_mask.IsImmediate()) { | ||||
|         mask = fmt::to_string(clamp.U32() | (segmentation_mask.U32() << 8)); | ||||
|     } else { | ||||
|         mask = "RC"; | ||||
|         ctx.Add("BFI.U RC.x,{{5,8,0,0}},{},{};", | ||||
|                 ScalarU32{ctx.reg_alloc.Consume(segmentation_mask)}, | ||||
|                 ScalarU32{ctx.reg_alloc.Consume(clamp)}); | ||||
|     } | ||||
|     const Register value_ret{ctx.reg_alloc.Define(inst)}; | ||||
|     IR::Inst* const in_bounds{inst.GetAssociatedPseudoOperation(IR::Opcode::GetInBoundsFromOp)}; | ||||
|     if (in_bounds) { | ||||
|         const Register bounds_ret{ctx.reg_alloc.Define(*in_bounds)}; | ||||
|         ctx.Add("SHF{}.U {},{},{},{};" | ||||
|                 "MOV.U {}.x,{}.y;", | ||||
|                 op, bounds_ret, value, index, mask, value_ret, bounds_ret); | ||||
|         in_bounds->Invalidate(); | ||||
|     } else { | ||||
|         ctx.Add("SHF{}.U {},{},{},{};" | ||||
|                 "MOV.U {}.x,{}.y;", | ||||
|                 op, value_ret, value, index, mask, value_ret, value_ret); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                       const IR::Value& clamp, const IR::Value& segmentation_mask) { | ||||
|     Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "IDX"); | ||||
| } | ||||
|  | ||||
| void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                    const IR::Value& clamp, const IR::Value& segmentation_mask) { | ||||
|     Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "UP"); | ||||
| } | ||||
|  | ||||
| void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                      const IR::Value& clamp, const IR::Value& segmentation_mask) { | ||||
|     Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "DOWN"); | ||||
| } | ||||
|  | ||||
| void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index, | ||||
|                           const IR::Value& clamp, const IR::Value& segmentation_mask) { | ||||
|     Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "XOR"); | ||||
| } | ||||
|  | ||||
| void EmitFSwizzleAdd(EmitContext&, ScalarF32, ScalarF32, ScalarU32) { | ||||
|     throw NotImplementedException("GLASM instruction"); | ||||
| } | ||||
|  | ||||
| void EmitDPdxFine(EmitContext&, ScalarF32) { | ||||
|     throw NotImplementedException("GLASM instruction"); | ||||
| } | ||||
|  | ||||
| void EmitDPdyFine(EmitContext&, ScalarF32) { | ||||
|     throw NotImplementedException("GLASM instruction"); | ||||
| } | ||||
|  | ||||
| void EmitDPdxCoarse(EmitContext&, ScalarF32) { | ||||
|     throw NotImplementedException("GLASM instruction"); | ||||
| } | ||||
|  | ||||
| void EmitDPdyCoarse(EmitContext&, ScalarF32) { | ||||
|     throw NotImplementedException("GLASM instruction"); | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Backend::GLASM | ||||
|   | ||||
| @@ -1168,7 +1168,7 @@ void EmitContext::DefineInputs(const Info& info) { | ||||
|         subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR); | ||||
|         subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR); | ||||
|     } | ||||
|     if (info.uses_subgroup_invocation_id || | ||||
|     if (info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles || | ||||
|         (profile.warp_size_potentially_larger_than_guest && | ||||
|          (info.uses_subgroup_vote || info.uses_subgroup_mask))) { | ||||
|         subgroup_local_invocation_id = | ||||
|   | ||||
| @@ -318,7 +318,9 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | ||||
|         ctx.AddExtension("SPV_KHR_shader_draw_parameters"); | ||||
|         ctx.AddCapability(spv::Capability::DrawParameters); | ||||
|     } | ||||
|     if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id) && profile.support_vote) { | ||||
|     if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || | ||||
|          info.uses_subgroup_shuffles) && | ||||
|         profile.support_vote) { | ||||
|         ctx.AddExtension("SPV_KHR_shader_ballot"); | ||||
|         ctx.AddCapability(spv::Capability::SubgroupBallotKHR); | ||||
|         if (!profile.warp_size_potentially_larger_than_guest) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user