glasm: Implement shuffle and vote instructions on GLASM
This commit is contained in:
parent
decda4a2c7
commit
c4fd6b55bc
|
@ -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) {
|
||||
|
|
|
@ -504,11 +504,13 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
|||
info.uses_is_helper_invocation = true;
|
||||
break;
|
||||
case IR::Opcode::LaneId:
|
||||
info.uses_subgroup_invocation_id = true;
|
||||
break;
|
||||
case IR::Opcode::ShuffleIndex:
|
||||
case IR::Opcode::ShuffleUp:
|
||||
case IR::Opcode::ShuffleDown:
|
||||
case IR::Opcode::ShuffleButterfly:
|
||||
info.uses_subgroup_invocation_id = true;
|
||||
info.uses_subgroup_shuffles = true;
|
||||
break;
|
||||
case IR::Opcode::GetCbufU8:
|
||||
case IR::Opcode::GetCbufS8:
|
||||
|
|
|
@ -116,6 +116,7 @@ struct Info {
|
|||
bool uses_sample_id{};
|
||||
bool uses_is_helper_invocation{};
|
||||
bool uses_subgroup_invocation_id{};
|
||||
bool uses_subgroup_shuffles{};
|
||||
std::array<bool, 30> uses_patches{};
|
||||
|
||||
std::array<InputVarying, 32> input_generics{};
|
||||
|
|
Reference in New Issue