Add ATOMS, LDS, POPC, RED, STS and VOTE shader instructions, start changing the way how global memory is handled
This commit is contained in:
parent
1e8bc29f32
commit
769c02235f
44 changed files with 949 additions and 242 deletions
|
@ -42,5 +42,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public const int CtaIdX = 0x2000010;
|
||||
public const int CtaIdY = 0x2000014;
|
||||
public const int CtaIdZ = 0x2000018;
|
||||
|
||||
public const int LaneId = 0x2000020;
|
||||
|
||||
public const int EqMask = 0x2000024;
|
||||
public const int GeMask = 0x2000028;
|
||||
public const int GtMask = 0x200002c;
|
||||
public const int LeMask = 0x2000030;
|
||||
public const int LtMask = 0x2000034;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,61 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
static class EmitterContextInsts
|
||||
{
|
||||
public static Operand AtomicAdd(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicAdd | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicAnd(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicAnd | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicCompareAndSwap(this EmitterContext context, Instruction mr, Operand a, Operand b, Operand c)
|
||||
{
|
||||
return context.Add(Instruction.AtomicCompareAndSwap | mr, Local(), a, b, c);
|
||||
}
|
||||
|
||||
public static Operand AtomicMaxS32(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicMaxS32 | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicMaxU32(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicMaxU32 | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicMinS32(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicMinS32 | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicMinU32(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicMinU32 | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicOr(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicOr | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicSwap(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicSwap | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand AtomicXor(this EmitterContext context, Instruction mr, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.AtomicXor | mr, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand Ballot(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.Ballot, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand BitCount(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.BitCount, Local(), a);
|
||||
|
@ -411,6 +466,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return context.Add(Instruction.LoadLocal, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand LoadShared(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.LoadShared, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand PackHalf2x16(this EmitterContext context, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.PackHalf2x16, Local(), a, b);
|
||||
|
@ -468,6 +528,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return context.Add(Instruction.StoreLocal, null, a, b);
|
||||
}
|
||||
|
||||
public static Operand StoreShared(this EmitterContext context, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.StoreShared, null, a, b);
|
||||
}
|
||||
|
||||
public static Operand UnpackHalf2x16High(this EmitterContext context, Operand a)
|
||||
{
|
||||
return UnpackHalf2x16(context, a, 1);
|
||||
|
@ -486,5 +551,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static Operand VoteAll(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.VoteAll, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand VoteAllEqual(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.VoteAllEqual, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand VoteAny(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.VoteAny, Local(), a);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -256,7 +256,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
{
|
||||
int value = operation.GetSource(0).Value;
|
||||
|
||||
value = (value >> operation.ComponentIndex * 16) & 0xffff;
|
||||
value = (value >> operation.Index * 16) & 0xffff;
|
||||
|
||||
operation.TurnIntoCopy(ConstF(HalfConversion.HalfToSingle(value)));
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
static class GlobalToStorage
|
||||
|
@ -27,7 +25,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
continue;
|
||||
}
|
||||
|
||||
if (operation.Inst == Instruction.LoadGlobal ||
|
||||
if (operation.Inst.IsAtomic() ||
|
||||
operation.Inst == Instruction.LoadGlobal ||
|
||||
operation.Inst == Instruction.StoreGlobal)
|
||||
{
|
||||
Operand source = operation.GetSource(0);
|
||||
|
@ -51,18 +50,31 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
|
||||
Operation storageOp;
|
||||
|
||||
if (operation.Inst == Instruction.LoadGlobal)
|
||||
if (operation.Inst.IsAtomic())
|
||||
{
|
||||
Operand[] sources = new Operand[operation.SourcesCount];
|
||||
|
||||
for (int index = 0; index < operation.SourcesCount; index++)
|
||||
{
|
||||
sources[index] = operation.GetSource(index);
|
||||
}
|
||||
|
||||
Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage;
|
||||
|
||||
storageOp = new Operation(inst, storageIndex, operation.Dest, sources);
|
||||
}
|
||||
else if (operation.Inst == Instruction.LoadGlobal)
|
||||
{
|
||||
Operand source = operation.GetSource(0);
|
||||
|
||||
storageOp = new Operation(Instruction.LoadStorage, operation.Dest, Const(storageIndex), source);
|
||||
storageOp = new Operation(Instruction.LoadStorage, storageIndex, operation.Dest, source);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand src1 = operation.GetSource(0);
|
||||
Operand src2 = operation.GetSource(1);
|
||||
|
||||
storageOp = new Operation(Instruction.StoreStorage, null, Const(storageIndex), src1, src2);
|
||||
storageOp = new Operation(Instruction.StoreStorage, storageIndex, null, src1, src2);
|
||||
}
|
||||
|
||||
for (int index = 0; index < operation.SourcesCount; index++)
|
||||
|
@ -114,6 +126,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
return -1;
|
||||
}
|
||||
|
||||
public static int GetStorageCbOffset(ShaderStage stage, int slot)
|
||||
{
|
||||
return GetStorageBaseCbOffset(stage) + slot * StorageDescSize;
|
||||
}
|
||||
|
||||
private static int GetStorageBaseCbOffset(ShaderStage stage)
|
||||
{
|
||||
switch (stage)
|
||||
|
|
|
@ -133,7 +133,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
|
||||
if (operation.GetSource(0) == dest)
|
||||
{
|
||||
operation.TurnIntoCopy(operation.ComponentIndex == 1 ? src1 : src0);
|
||||
operation.TurnIntoCopy(operation.Index == 1 ? src1 : src0);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
@ -251,7 +251,30 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
|
||||
private static bool IsUnused(INode node)
|
||||
{
|
||||
return DestIsLocalVar(node) && node.Dest.UseOps.Count == 0;
|
||||
return !HasSideEffects(node) && DestIsLocalVar(node) && node.Dest.UseOps.Count == 0;
|
||||
}
|
||||
|
||||
private static bool HasSideEffects(INode node)
|
||||
{
|
||||
if (node is Operation operation)
|
||||
{
|
||||
switch (operation.Inst & Instruction.Mask)
|
||||
{
|
||||
case Instruction.AtomicAdd:
|
||||
case Instruction.AtomicAnd:
|
||||
case Instruction.AtomicCompareAndSwap:
|
||||
case Instruction.AtomicMaxS32:
|
||||
case Instruction.AtomicMaxU32:
|
||||
case Instruction.AtomicMinS32:
|
||||
case Instruction.AtomicMinU32:
|
||||
case Instruction.AtomicOr:
|
||||
case Instruction.AtomicSwap:
|
||||
case Instruction.AtomicXor:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool DestIsLocalVar(INode node)
|
||||
|
|
|
@ -15,25 +15,38 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
private const int HeaderSize = 0x50;
|
||||
|
||||
public static ShaderProgram Translate(Span<byte> code, TranslationConfig translationConfig)
|
||||
public static Span<byte> ExtractCode(Span<byte> code, bool compute, out int headerSize)
|
||||
{
|
||||
return Translate(code, Span<byte>.Empty, translationConfig);
|
||||
if (compute)
|
||||
{
|
||||
headerSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
headerSize = HeaderSize;
|
||||
}
|
||||
|
||||
Block[] cfg = Decoder.Decode(code, (ulong)headerSize);
|
||||
|
||||
ulong endAddress = 0;
|
||||
|
||||
foreach (Block block in cfg)
|
||||
{
|
||||
if (endAddress < block.EndAddress)
|
||||
{
|
||||
endAddress = block.EndAddress;
|
||||
}
|
||||
}
|
||||
|
||||
return code.Slice(0, headerSize + (int)endAddress);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(Span<byte> code, Span<byte> code2, TranslationConfig translationConfig)
|
||||
public static ShaderProgram Translate(Span<byte> code, TranslationConfig translationConfig)
|
||||
{
|
||||
bool compute = (translationConfig.Flags & TranslationFlags.Compute) != 0;
|
||||
bool debugMode = (translationConfig.Flags & TranslationFlags.DebugMode) != 0;
|
||||
|
||||
Operation[] shaderOps = DecodeShader(code, compute, debugMode, out ShaderHeader header);
|
||||
|
||||
if (code2 != Span<byte>.Empty)
|
||||
{
|
||||
// Dual vertex shader.
|
||||
Operation[] shaderOpsB = DecodeShader(code2, compute, debugMode, out header);
|
||||
|
||||
shaderOps = Combine(shaderOps, shaderOpsB);
|
||||
}
|
||||
Operation[] ops = DecodeShader(code, compute, debugMode, out ShaderHeader header);
|
||||
|
||||
ShaderStage stage;
|
||||
|
||||
|
@ -63,7 +76,29 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
maxOutputVertexCount,
|
||||
outputTopology);
|
||||
|
||||
BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(shaderOps);
|
||||
return Translate(ops, config);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, TranslationConfig translationConfig)
|
||||
{
|
||||
bool debugMode = (translationConfig.Flags & TranslationFlags.DebugMode) != 0;
|
||||
|
||||
Operation[] vpAOps = DecodeShader(vpACode, compute: false, debugMode, out _);
|
||||
Operation[] vpBOps = DecodeShader(vpBCode, compute: false, debugMode, out ShaderHeader header);
|
||||
|
||||
ShaderConfig config = new ShaderConfig(
|
||||
header.Stage,
|
||||
translationConfig.Flags,
|
||||
translationConfig.MaxCBufferSize,
|
||||
header.MaxOutputVertexCount,
|
||||
header.OutputTopology);
|
||||
|
||||
return Translate(Combine(vpAOps, vpBOps), config);
|
||||
}
|
||||
|
||||
private static ShaderProgram Translate(Operation[] ops, ShaderConfig config)
|
||||
{
|
||||
BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(ops);
|
||||
|
||||
Dominance.FindDominators(irBlocks[0], irBlocks.Length);
|
||||
|
||||
|
@ -71,7 +106,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
Ssa.Rename(irBlocks);
|
||||
|
||||
Optimizer.Optimize(irBlocks, stage);
|
||||
Optimizer.Optimize(irBlocks, config.Stage);
|
||||
|
||||
StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(irBlocks, config);
|
||||
|
||||
|
@ -87,12 +122,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
string glslCode = program.Code;
|
||||
|
||||
if (translationConfig.Version != 0)
|
||||
{
|
||||
glslCode = "// " + translationConfig.Version + Environment.NewLine + glslCode;
|
||||
}
|
||||
|
||||
return new ShaderProgram(spInfo, stage, glslCode);
|
||||
return new ShaderProgram(spInfo, config.Stage, glslCode);
|
||||
}
|
||||
|
||||
private static Operation[] DecodeShader(Span<byte> code, bool compute, bool debugMode, out ShaderHeader header)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue