aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdk <gab.dark.100@gmail.com>2019-11-08 17:29:41 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit769c02235f489f02b1791e6e76dc8b3ab18028ee (patch)
treeef0a2ffc5030360d5cef78e7c67e131e44348d50
parent1e8bc29f32cde08616175f8f87405dfa7b8c4025 (diff)
Add ATOMS, LDS, POPC, RED, STS and VOTE shader instructions, start changing the way how global memory is handled
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs34
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/RangeList.cs16
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Constants.cs7
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs70
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs10
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/GlobalMemory.glsl18
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs2
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs32
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs16
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs115
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs16
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstType.cs8
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs51
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/AtomicOp.cs15
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/IOpCodeAlu.cs5
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/IOpCodePredicate39.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeAtom.cs39
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeRed.cs32
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs8
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/OpCodeVote.cs26
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/ReductionType.cs12
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs8
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/VoteOp.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs13
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs178
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs7
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs48
-rw-r--r--Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs50
-rw-r--r--Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs6
-rw-r--r--Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj1
-rw-r--r--Ryujinx.Graphics.Shader/ShaderProgram.cs7
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/AstOperation.cs8
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs4
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs11
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs24
-rw-r--r--Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs44
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs8
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs80
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs29
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs27
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs70
44 files changed, 943 insertions, 236 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index 1431bf41..78b7bc98 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -298,23 +298,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);
_context.Renderer.Pipeline.BindUniformBuffer(index, ShaderStage.Compute, buffer);
-
- if (index == 0)
- {
- // TODO: Improve
- Span<byte> data = _context.PhysicalMemory.Read(bounds.Address + 0x310, 0x100);
-
- Span<int> words = MemoryMarshal.Cast<byte, int>(data);
-
- for (int offset = 0; offset < 0x40; offset += 4)
- {
- words[offset] &= 0x3f;
- }
-
- buffer = GetBufferRange(bounds.Address + 0x310, 0x100);
-
- buffer.Buffer.SetData(buffer.Offset, data);
- }
}
// Force rebind after doing compute work.
@@ -460,23 +443,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
_context.Renderer.Pipeline.BindUniformBuffer(index, stage, buffer);
}
-
- if (!isStorage && index == 0)
- {
- // TODO: Improve
- Span<byte> data = _context.PhysicalMemory.Read(bounds.Address + 0x110, 0x100);
-
- Span<int> words = MemoryMarshal.Cast<byte, int>(data);
-
- for (int offset = 0; offset < 0x40; offset += 4)
- {
- words[offset] &= 0x3f;
- }
-
- buffer = GetBufferRange(bounds.Address + 0x110, 0x100);
-
- buffer.Buffer.SetData(buffer.Offset, data);
- }
}
public void CopyBuffer(GpuVa srcVa, GpuVa dstVa, ulong size)
diff --git a/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs b/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs
index 7bcb011c..6d7d1ce2 100644
--- a/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/ConcurrentRangeList.cs
@@ -6,8 +6,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
private List<T> _items;
- public int Count => _items.Count;
-
public ConcurrentRangeList()
{
_items = new List<T>();
diff --git a/Ryujinx.Graphics.Gpu/Memory/RangeList.cs b/Ryujinx.Graphics.Gpu/Memory/RangeList.cs
index 072fdfe8..e3435292 100644
--- a/Ryujinx.Graphics.Gpu/Memory/RangeList.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/RangeList.cs
@@ -6,8 +6,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
private List<T> _items;
- public int Count => _items.Count;
-
public RangeList()
{
_items = new List<T>();
@@ -57,20 +55,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
return false;
}
- public bool CanExitEarly(ulong address, ulong size)
- {
- int index = BinarySearch(address, size);
-
- if (index >= 0)
- {
- T item = _items[index];
-
- return address >= item.Address && address + size <= item.Address + item.Size;
- }
-
- return false;
- }
-
public T FindFirstOverlap(T item)
{
return FindFirstOverlap(item.Address, item.Size);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Constants.cs b/Ryujinx.Graphics.Shader/CodeGen/Constants.cs
new file mode 100644
index 00000000..10c22c60
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/CodeGen/Constants.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.CodeGen
+{
+ static class Constants
+ {
+ public const int MaxShaderStorageBuffers = 16;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 6c4ba949..a8cabaaf 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -16,7 +16,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public static void Declare(CodeGenContext context, StructuredProgramInfo info)
{
context.AppendLine("#version 420 core");
+ context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable");
context.AppendLine("#extension GL_ARB_shader_ballot : enable");
+ context.AppendLine("#extension GL_ARB_shader_group_vote : enable");
context.AppendLine("#extension GL_ARB_shader_storage_buffer_object : enable");
if (context.Config.Stage == ShaderStage.Compute)
@@ -66,9 +68,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine();
- context.AppendLine($"precise float {DefaultNames.LocalMemoryName}[0x100];");
+ context.AppendLine($"uint {DefaultNames.LocalMemoryName}[0x100];");
context.AppendLine();
+ if (context.Config.Stage == ShaderStage.Compute)
+ {
+ context.AppendLine($"shared uint {DefaultNames.SharedMemoryName}[0x100];");
+ context.AppendLine();
+ }
+
if (info.CBuffers.Count != 0)
{
DeclareUniforms(context, info);
@@ -78,7 +86,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
if (info.SBuffers.Count != 0)
{
- DeclareStorage(context, info);
+ DeclareUsedStorage(context, info);
context.AppendLine();
}
@@ -168,6 +176,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";");
}
+
+ if ((info.HelperFunctionsMask & HelperFunctionsMask.GlobalMemory) != 0)
+ {
+ context.AppendLine($"ivec2 {DefaultNames.GmemOffsetName};");
+ }
}
private static string GetVarTypeName(VariableType type)
@@ -205,24 +218,59 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
}
- private static void DeclareStorage(CodeGenContext context, StructuredProgramInfo info)
+ private static void DeclareAllStorage(CodeGenContext context, StructuredProgramInfo info)
{
- foreach (int sbufSlot in info.SBuffers.OrderBy(x => x))
+ string sbName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
+
+ sbName += "_" + DefaultNames.StorageNamePrefix;
+
+ string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
+
+ context.AppendLine("layout (std430) buffer " + blockName);
+
+ context.EnterScope();
+
+ context.AppendLine("uint " + DefaultNames.DataName + "[];");
+
+ string arraySize = NumberFormatter.FormatInt(Constants.MaxShaderStorageBuffers);
+
+ context.LeaveScope($" {sbName}[{arraySize}];");
+
+ for (int sbufSlot = 0; sbufSlot < Constants.MaxShaderStorageBuffers; sbufSlot++)
{
- string sbName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
+ context.SBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{sbufSlot}]", sbufSlot));
+ }
+ }
- sbName += "_" + DefaultNames.StorageNamePrefix + sbufSlot;
+ private static void DeclareUsedStorage(CodeGenContext context, StructuredProgramInfo info)
+ {
+ string sbName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
- context.SBufferDescriptors.Add(new BufferDescriptor(sbName, sbufSlot));
+ sbName += "_" + DefaultNames.StorageNamePrefix;
- context.AppendLine("layout (std430) buffer " + sbName);
+ string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
- context.EnterScope();
+ int maxSlot = 0;
- context.AppendLine("precise float " + OperandManager.GetSbName(context.Config.Stage, sbufSlot) + "[];");
+ foreach (int sbufSlot in info.SBuffers)
+ {
+ context.SBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{sbufSlot}]", sbufSlot));
- context.LeaveScope(";");
+ if (maxSlot < sbufSlot)
+ {
+ maxSlot = sbufSlot;
+ }
}
+
+ context.AppendLine("layout (std430) buffer " + blockName);
+
+ context.EnterScope();
+
+ context.AppendLine("uint " + DefaultNames.DataName + "[];");
+
+ string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
+
+ context.LeaveScope($" {sbName}[{arraySize}];");
}
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
index a06b0cc8..f1abc949 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
@@ -11,12 +11,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public const string OAttributePrefix = "out_attr";
public const string StorageNamePrefix = "s";
- public const string StorageNameSuffix = "data";
+
+ public const string DataName = "data";
+
+ public const string BlockSuffix = "block";
public const string UniformNamePrefix = "c";
public const string UniformNameSuffix = "data";
- public const string LocalMemoryName = "local_mem";
+ public const string LocalMemoryName = "local_mem";
+ public const string SharedMemoryName = "shared_mem";
+
+ public const string GmemOffsetName = "gmemOffset";
public const string UndefinedName = "undef";
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/GlobalMemory.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/GlobalMemory.glsl
new file mode 100644
index 00000000..b8544ae2
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/GlobalMemory.glsl
@@ -0,0 +1,18 @@
+ivec2 Helper_GetStorageBuffer(uint aLow, uint aHigh)
+{
+ uint64_t address = packUint2x32(uvec2(aLow, aHigh));
+ int i;
+ for (i = 0; i < 16; i++)
+ {
+ int offset = 0x40 + i * 4;
+ uint baseLow = fp_c0_data[offset];
+ uint baseHigh = fp_c0_data[offset + 1];
+ uint size = fp_c0_data[offset + 2];
+ uint64_t baseAddr = packUint2x32(uvec2(baseLow, baseHigh));
+ if (address >= baseAddr && address < baseAddr + packUint2x32(uvec2(size, 0)))
+ {
+ return ivec2(i, int(unpackUint2x32(address - (baseAddr & ~63ul)).x) >> 2);
+ }
+ }
+ return ivec2(0);
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs
index f1540fbf..302b56ad 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/HelperFunctionNames.cs
@@ -2,6 +2,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
static class HelperFunctionNames
{
+ public static string GetStorageBuffer = "Helper_GetStorageBuffer";
+
public static string Shuffle = "Helper_Shuffle";
public static string ShuffleDown = "Helper_ShuffleDown";
public static string ShuffleUp = "Helper_ShuffleUp";
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
index 3bf31c16..b5cab54e 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
@@ -3,6 +3,7 @@ using Ryujinx.Graphics.Shader.StructuredIr;
using System;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
@@ -31,6 +32,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
if ((info.Type & InstType.Call) != 0)
{
+ bool atomic = (info.Type & InstType.Atomic) != 0;
+
int arity = (int)(info.Type & InstType.ArityMask);
string args = string.Empty;
@@ -44,10 +47,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
VariableType dstType = GetSrcVarType(inst, argIndex);
- args += GetSoureExpr(context, operation.GetSource(argIndex), dstType);
+ if (argIndex == 0 && atomic)
+ {
+ switch (inst & Instruction.MrMask)
+ {
+ // TODO: Global.
+ case Instruction.MrShared: args += LoadShared (context, operation); break;
+ case Instruction.MrStorage: args += LoadStorage(context, operation); break;
+ }
+ }
+ else
+ {
+ args += GetSoureExpr(context, operation.GetSource(argIndex), dstType);
+ }
}
- return info.OpName + "(" + args + ")";
+ if (inst == Instruction.Ballot)
+ {
+ return $"unpackUint2x32({info.OpName}({args})).x";
+ }
+ else
+ {
+ return info.OpName + "(" + args + ")";
+ }
}
else if ((info.Type & InstType.Op) != 0)
{
@@ -99,6 +121,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.LoadLocal:
return InstGenMemory.LoadLocal(context, operation);
+ case Instruction.LoadShared:
+ return InstGenMemory.LoadShared(context, operation);
+
case Instruction.LoadStorage:
return InstGenMemory.LoadStorage(context, operation);
@@ -108,6 +133,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.StoreLocal:
return InstGenMemory.StoreLocal(context, operation);
+ case Instruction.StoreShared:
+ return InstGenMemory.StoreShared(context, operation);
+
case Instruction.StoreStorage:
return InstGenMemory.StoreStorage(context, operation);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
index 2aaae71c..ec133272 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
@@ -13,8 +13,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
_infoTbl = new InstInfo[(int)Instruction.Count];
+ Add(Instruction.AtomicAdd, InstType.AtomicBinary, "atomicAdd");
+ Add(Instruction.AtomicAnd, InstType.AtomicBinary, "atomicAnd");
+ Add(Instruction.AtomicCompareAndSwap, InstType.AtomicTernary, "atomicCompSwap");
+ Add(Instruction.AtomicMaxS32, InstType.AtomicBinary, "atomicMax");
+ Add(Instruction.AtomicMaxU32, InstType.AtomicBinary, "atomicMax");
+ Add(Instruction.AtomicMinS32, InstType.AtomicBinary, "atomicMin");
+ Add(Instruction.AtomicMinU32, InstType.AtomicBinary, "atomicMin");
+ Add(Instruction.AtomicOr, InstType.AtomicBinary, "atomicOr");
+ Add(Instruction.AtomicSwap, InstType.AtomicBinary, "atomicExchange");
+ Add(Instruction.AtomicXor, InstType.AtomicBinary, "atomicXor");
Add(Instruction.Absolute, InstType.CallUnary, "abs");
Add(Instruction.Add, InstType.OpBinaryCom, "+", 2);
+ Add(Instruction.Ballot, InstType.CallUnary, "ballotARB");
Add(Instruction.BitCount, InstType.CallUnary, "bitCount");
Add(Instruction.BitfieldExtractS32, InstType.CallTernary, "bitfieldExtract");
Add(Instruction.BitfieldExtractU32, InstType.CallTernary, "bitfieldExtract");
@@ -59,6 +70,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.LoadAttribute, InstType.Special);
Add(Instruction.LoadConstant, InstType.Special);
Add(Instruction.LoadLocal, InstType.Special);
+ Add(Instruction.LoadShared, InstType.Special);
Add(Instruction.LoadStorage, InstType.Special);
Add(Instruction.LogarithmB2, InstType.CallUnary, "log2");
Add(Instruction.LogicalAnd, InstType.OpBinaryCom, "&&", 9);
@@ -87,6 +99,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.Sine, InstType.CallUnary, "sin");
Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt");
Add(Instruction.StoreLocal, InstType.Special);
+ Add(Instruction.StoreShared, InstType.Special);
Add(Instruction.StoreStorage, InstType.Special);
Add(Instruction.Subtract, InstType.OpBinary, "-", 2);
Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd);
@@ -94,6 +107,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.TextureSize, InstType.Special);
Add(Instruction.Truncate, InstType.CallUnary, "trunc");
Add(Instruction.UnpackHalf2x16, InstType.Special);
+ Add(Instruction.VoteAll, InstType.CallUnary, "allInvocationsARB");
+ Add(Instruction.VoteAllEqual, InstType.CallUnary, "allInvocationsEqualARB");
+ Add(Instruction.VoteAny, InstType.CallUnary, "anyInvocationARB");
}
private static void Add(Instruction inst, InstType flags, string opName = null, int precedence = 0)
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index 21e39fcf..c535d8fc 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -1,5 +1,6 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
+using Ryujinx.Graphics.Shader.Translation.Optimizations;
using System;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
@@ -118,27 +119,76 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return OperandManager.GetConstantBufferName(src1, offsetExpr, context.Config.Stage);
}
+ public static string LoadGlobal(CodeGenContext context, AstOperation operation)
+ {
+ IAstNode src1 = operation.GetSource(0);
+ IAstNode src2 = operation.GetSource(1);
+
+ string addrLowExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
+ string addrHighExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+
+ context.AppendLine($"{DefaultNames.GmemOffsetName} = {HelperFunctionNames.GetStorageBuffer}({addrLowExpr}, {addrHighExpr});");
+
+ return GetStorageBufferAccessor($"{DefaultNames.GmemOffsetName}.x", $"{DefaultNames.GmemOffsetName}.y", context.Config.Stage);
+ }
+
public static string LoadLocal(CodeGenContext context, AstOperation operation)
{
+ return LoadLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
+ }
+
+ public static string LoadShared(CodeGenContext context, AstOperation operation)
+ {
+ return LoadLocalOrShared(context, operation, DefaultNames.SharedMemoryName);
+ }
+
+ private static string LoadLocalOrShared(CodeGenContext context, AstOperation operation, string arrayName)
+ {
IAstNode src1 = operation.GetSource(0);
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
- return $"{DefaultNames.LocalMemoryName}[{offsetExpr}]";
+ return $"{arrayName}[{offsetExpr}]";
}
public static string LoadStorage(CodeGenContext context, AstOperation operation)
{
IAstNode src1 = operation.GetSource(0);
+
+ string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
+
+ return GetStorageBufferAccessor(operation.Index, offsetExpr, context.Config.Stage);
+ }
+
+ public static string StoreGlobal(CodeGenContext context, AstOperation operation)
+ {
+ IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
+ IAstNode src3 = operation.GetSource(2);
- string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+ string addrLowExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
+ string addrHighExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+ string valueExpr = GetSoureExpr(context, src3, GetSrcVarType(operation.Inst, 2));
- return OperandManager.GetStorageBufferName(src1, offsetExpr, context.Config.Stage);
+ context.AppendLine($"{DefaultNames.GmemOffsetName} = {HelperFunctionNames.GetStorageBuffer}({addrLowExpr}, {addrHighExpr});");
+
+ string sb = GetStorageBufferAccessor($"{DefaultNames.GmemOffsetName}.x", $"{DefaultNames.GmemOffsetName}.y", context.Config.Stage);
+
+ return $"{sb} = {valueExpr}";
}
public static string StoreLocal(CodeGenContext context, AstOperation operation)
{
+ return StoreLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
+ }
+
+ public static string StoreShared(CodeGenContext context, AstOperation operation)
+ {
+ return StoreLocalOrShared(context, operation, DefaultNames.SharedMemoryName);
+ }
+
+ private static string StoreLocalOrShared(CodeGenContext context, AstOperation operation, string arrayName)
+ {
IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
@@ -146,26 +196,25 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
VariableType srcType = OperandManager.GetNodeDestType(src2);
- string src = TypeConversion.ReinterpretCast(context, src2, srcType, VariableType.F32);
+ string src = TypeConversion.ReinterpretCast(context, src2, srcType, VariableType.U32);
- return $"{DefaultNames.LocalMemoryName}[{offsetExpr}] = {src}";
+ return $"{arrayName}[{offsetExpr}] = {src}";
}
public static string StoreStorage(CodeGenContext context, AstOperation operation)
{
IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
- IAstNode src3 = operation.GetSource(2);
- string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
+ string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
- VariableType srcType = OperandManager.GetNodeDestType(src3);
+ VariableType srcType = OperandManager.GetNodeDestType(src2);
- string src = TypeConversion.ReinterpretCast(context, src3, srcType, VariableType.F32);
+ string src = TypeConversion.ReinterpretCast(context, src2, srcType, VariableType.U32);
- string sbName = OperandManager.GetStorageBufferName(src1, offsetExpr, context.Config.Stage);
+ string sb = GetStorageBufferAccessor(operation.Index, offsetExpr, context.Config.Stage);
- return $"{sbName} = {src}";
+ return $"{sb} = {src}";
}
public static string TextureSample(CodeGenContext context, AstOperation operation)
@@ -402,7 +451,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Append(Src(VariableType.S32));
}
- texCall += ")" + (isGather || !isShadow ? GetMask(texOp.ComponentMask) : "");
+ texCall += ")" + (isGather || !isShadow ? GetMask(texOp.Index) : "");
return texCall;
}
@@ -428,22 +477,42 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
- return $"textureSize({samplerName}, {src0Expr}){GetMask(texOp.ComponentMask)}";
+ return $"textureSize({samplerName}, {src0Expr}){GetMask(texOp.Index)}";
}
- private static string GetMask(int compMask)
+ private static string GetStorageBufferAccessor(string slotExpr, string offsetExpr, ShaderStage stage)
{
- string mask = ".";
+ string sbName = OperandManager.GetShaderStagePrefix(stage);
- for (int index = 0; index < 4; index++)
- {
- if ((compMask & (1 << index)) != 0)
- {
- mask += "rgba".Substring(index, 1);
- }
- }
+ sbName += "_" + DefaultNames.StorageNamePrefix;
+
+ return $"{sbName}[{slotExpr}].{DefaultNames.DataName}[{offsetExpr}]";
+ }
+
+ private static string GetStorageBufferAccessor(int slot, string offsetExpr, ShaderStage stage)
+ {
+ string sbName = OperandManager.GetShaderStagePrefix(stage);
+
+ sbName += "_" + DefaultNames.StorageNamePrefix;
+
+ string mask = NumberFormatter.FormatUint(~(64u - 1));
- return mask;
+ // Subtract the base address of the global memory, to get the
+ // storage buffer offset. The mask is used to keep the lower bits,
+ // since the bound storage buffer must match the host alignment
+ // restrictions.
+ int ubOffset = GlobalToStorage.GetStorageCbOffset(stage, slot);
+
+ string ubName = OperandManager.GetConstantBufferName(0, ubOffset, stage);
+
+ offsetExpr = $"{offsetExpr} - int((floatBitsToUint({ubName}) & {mask}) >> 2)";
+
+ return $"{sbName}[{NumberFormatter.FormatInt(slot)}].{DefaultNames.DataName}[{offsetExpr}]";
+ }
+
+ private static string GetMask(int index)
+ {
+ return '.' + "rgba".Substring(index, 1);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs
index 4a40032c..e5167f93 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs
@@ -24,22 +24,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0));
- return $"unpackHalf2x16({srcExpr}){GetMask(operation.ComponentMask)}";
+ return $"unpackHalf2x16({srcExpr}){GetMask(operation.Index)}";
}
- private static string GetMask(int compMask)
+ private static string GetMask(int index)
{
- string mask = ".";
-
- for (int index = 0; index < 2; index++)
- {
- if ((compMask & (1 << index)) != 0)
- {
- mask += "xy".Substring(index, 1);
- }
- }
-
- return mask;
+ return '.' + "xy".Substring(index, 1);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstType.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstType.cs
index 121cd079..5836e981 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstType.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstType.cs
@@ -8,8 +8,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
OpNullary = Op | 0,
OpUnary = Op | 1,
OpBinary = Op | 2,
+ OpBinaryCom = Op | 2 | Commutative,
OpTernary = Op | 3,
- OpBinaryCom = OpBinary | Commutative,
+
+ AtomicBinary = CallBinary | Atomic,
+ AtomicTernary = CallTernary | Atomic,
CallNullary = Call | 0,
CallUnary = Call | 1,
@@ -20,7 +23,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Commutative = 1 << 8,
Op = 1 << 9,
Call = 1 << 10,
- Special = 1 << 11,
+ Atomic = 1 << 11,
+ Special = 1 << 12,
ArityMask = 0xff
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 36f76ec5..4c9d5b55 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -51,13 +51,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
// Special.
- { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
- { AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", VariableType.U32) },
- { AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", VariableType.U32) },
- { AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", VariableType.U32) },
- { AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", VariableType.U32) },
- { AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", VariableType.U32) },
- { AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", VariableType.U32) },
+ { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
+ { AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", VariableType.U32) },
+ { AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", VariableType.U32) },
+ { AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", VariableType.U32) },
+ { AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", VariableType.U32) },
+ { AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", VariableType.U32) },
+ { AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", VariableType.U32) },
+ { AttributeConsts.LaneId, new BuiltInAttribute("gl_SubGroupInvocationARB", VariableType.U32) },
+ { AttributeConsts.EqMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupEqMaskARB).x", VariableType.U32) },
+ { AttributeConsts.GeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGeMaskARB).x", VariableType.U32) },
+ { AttributeConsts.GtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGtMaskARB).x", VariableType.U32) },
+ { AttributeConsts.LeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLeMaskARB).x", VariableType.U32) },
+ { AttributeConsts.LtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLtMaskARB).x", VariableType.U32) },
};
private Dictionary<AstOperand, string> _locals;
@@ -87,7 +93,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return NumberFormatter.FormatInt(operand.Value);
case OperandType.ConstantBuffer:
- return GetConstantBufferName(operand, stage);
+ return GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, stage);
case OperandType.LocalVariable:
return _locals[operand];
@@ -99,25 +105,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
throw new ArgumentException($"Invalid operand type \"{operand.Type}\".");
}
- public static string GetConstantBufferName(AstOperand cbuf, ShaderStage stage)
+ public static string GetConstantBufferName(int slot, int offset, ShaderStage stage)
{
- string ubName = GetUbName(stage, cbuf.CbufSlot);
+ string ubName = GetUbName(stage, slot);
- ubName += "[" + (cbuf.CbufOffset >> 2) + "]";
+ ubName += "[" + (offset >> 2) + "]";
- return ubName + "." + GetSwizzleMask(cbuf.CbufOffset & 3);
- }
-
- public static string GetStorageBufferName(IAstNode slot, string offsetExpr, ShaderStage stage)
- {
- // Non-constant slots are not supported.
- // It is expected that upstream stages are never going to generate non-constant
- // slot access.
- AstOperand operand = (AstOperand)slot;
-
- string sbName = GetSbName(stage, operand.Value);
-
- return $"{sbName}[{offsetExpr}]";
+ return ubName + "." + GetSwizzleMask(offset & 3);
}
public static string GetConstantBufferName(IAstNode slot, string offsetExpr, ShaderStage stage)
@@ -205,15 +199,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0";
}
- public static string GetSbName(ShaderStage stage, int slot)
- {
- string sbName = GetShaderStagePrefix(stage);
-
- sbName += "_" + DefaultNames.StorageNamePrefix + slot;
-
- return sbName + "_" + DefaultNames.StorageNameSuffix;
- }
-
public static string GetUbName(ShaderStage stage, int slot)
{
string ubName = GetShaderStagePrefix(stage);
diff --git a/Ryujinx.Graphics.Shader/Decoders/AtomicOp.cs b/Ryujinx.Graphics.Shader/Decoders/AtomicOp.cs
new file mode 100644
index 00000000..065a57c4
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/AtomicOp.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ enum AtomicOp
+ {
+ Add = 0,
+ Minimum = 1,
+ Maximum = 2,
+ Increment = 3,
+ Decrement = 4,
+ BitwiseAnd = 5,
+ BitwiseOr = 6,
+ BitwiseExclusiveOr = 7,
+ Swap = 8
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/IOpCodeAlu.cs b/Ryujinx.Graphics.Shader/Decoders/IOpCodeAlu.cs
index d840d49d..6d1382a8 100644
--- a/Ryujinx.Graphics.Shader/Decoders/IOpCodeAlu.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/IOpCodeAlu.cs
@@ -1,10 +1,7 @@
namespace Ryujinx.Graphics.Shader.Decoders
{
- interface IOpCodeAlu : IOpCodeRd, IOpCodeRa
+ interface IOpCodeAlu : IOpCodeRd, IOpCodeRa, IOpCodePredicate39
{
- Register Predicate39 { get; }
-
- bool InvertP { get; }
bool Extended { get; }
bool SetCondCode { get; }
bool Saturate { get; }
diff --git a/Ryujinx.Graphics.Shader/Decoders/IOpCodePredicate39.cs b/Ryujinx.Graphics.Shader/Decoders/IOpCodePredicate39.cs
new file mode 100644
index 00000000..74e7aff1
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/IOpCodePredicate39.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ interface IOpCodePredicate39
+ {
+ Register Predicate39 { get; }
+
+ bool InvertP { get; }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeAtom.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeAtom.cs
new file mode 100644
index 00000000..b572703e
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeAtom.cs
@@ -0,0 +1,39 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ class OpCodeAtom : OpCode, IOpCodeRd, IOpCodeRa, IOpCodeReg
+ {
+ public Register Rd { get; }
+ public Register Ra { get; }
+ public Register Rb { get; }
+
+ public ReductionType Type { get; }
+
+ public int Offset { get; }
+
+ public bool Extended { get; }
+
+ public AtomicOp AtomicOp { get; }
+
+ public OpCodeAtom(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+ {
+ Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr);
+ Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr);
+ Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr);
+
+ Type = (ReductionType)opCode.Extract(28, 2);
+
+ if (Type == ReductionType.FP32FtzRn)
+ {
+ Type = ReductionType.S64;
+ }
+
+ Offset = opCode.Extract(30, 22);
+
+ Extended = opCode.Extract(48);
+
+ AtomicOp = (AtomicOp)opCode.Extract(52, 4);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeRed.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeRed.cs
new file mode 100644
index 00000000..8fde82a2
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeRed.cs
@@ -0,0 +1,32 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ class OpCodeRed : OpCode, IOpCodeRd, IOpCodeRa
+ {
+ public Register Rd { get; }
+ public Register Ra { get; }
+
+ public AtomicOp AtomicOp { get; }
+
+ public ReductionType Type { get; }
+
+ public int Offset { get; }
+
+ public bool Extended { get; }
+
+ public OpCodeRed(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+ {
+ Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr);
+ Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr);
+
+ Type = (ReductionType)opCode.Extract(20, 3);
+
+ AtomicOp = (AtomicOp)opCode.Extract(23, 3);
+
+ Offset = opCode.Extract(28, 20);
+
+ Extended = opCode.Extract(48);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index 7adaff61..58bd2b88 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
#region Instructions
Set("1110111111011x", InstEmit.Ald, typeof(OpCodeAttribute));
Set("1110111111110x", InstEmit.Ast, typeof(OpCodeAttribute));
+ Set("11101100xxxxxx", InstEmit.Atoms, typeof(OpCodeAtom));
Set("0100110000000x", InstEmit.Bfe, typeof(OpCodeAluCbuf));
Set("0011100x00000x", InstEmit.Bfe, typeof(OpCodeAluImm));
Set("0101110000000x", InstEmit.Bfe, typeof(OpCodeAluReg));
@@ -122,6 +123,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("1110111101000x", InstEmit.Ld, typeof(OpCodeMemory));
Set("1110111110010x", InstEmit.Ldc, typeof(OpCodeLdc));
Set("1110111011010x", InstEmit.Ldg, typeof(OpCodeMemory));
+ Set("1110111101001x", InstEmit.Lds, typeof(OpCodeMemory));
Set("0100110001000x", InstEmit.Lop, typeof(OpCodeLopCbuf));
Set("0011100001000x", InstEmit.Lop, typeof(OpCodeLopImm));
Set("000001xxxxxxxx", InstEmit.Lop, typeof(OpCodeLopImm32));
@@ -136,7 +138,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("0101000010000x", InstEmit.Mufu, typeof(OpCodeFArith));
Set("1111101111100x", InstEmit.Out, typeof(OpCode));
Set("111000101010xx", InstEmit.Pbk, typeof(OpCodeSsy));
+ Set("0100110000001x", InstEmit.Popc, typeof(OpCodeAluCbuf));
+ Set("0011100x00001x", InstEmit.Popc, typeof(OpCodeAluImm));
+ Set("0101110000001x", InstEmit.Popc, typeof(OpCodeAluReg));
Set("0101000010010x", InstEmit.Psetp, typeof(OpCodePsetp));
+ Set("1110101111111x", InstEmit.Red, typeof(OpCodeRed));
Set("0100110010010x", InstEmit.Rro, typeof(OpCodeFArithCbuf));
Set("0011100x10010x", InstEmit.Rro, typeof(OpCodeFArithImm));
Set("0101110010010x", InstEmit.Rro, typeof(OpCodeFArithReg));
@@ -154,6 +160,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("111000101001xx", InstEmit.Ssy, typeof(OpCodeSsy));
Set("1110111101010x", InstEmit.St, typeof(OpCodeMemory));
Set("1110111011011x", InstEmit.Stg, typeof(OpCodeMemory));
+ Set("1110111101011x", InstEmit.Sts, typeof(OpCodeMemory));
Set("11101011001xxx", InstEmit.Sust, typeof(OpCodeImage));
Set("1111000011111x", InstEmit.Sync, typeof(OpCodeSync));
Set("110000xxxx111x", InstEmit.Tex, typeof(OpCodeTex));
@@ -168,6 +175,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("1101111101001x", InstEmit.Txq, typeof(OpCodeTex));
Set("1101111101010x", InstEmit.TxqB, typeof(OpCodeTex));
Set("01011111xxxxxx", InstEmit.Vmad, typeof(OpCodeVideo));
+ Set("0101000011011x", InstEmit.Vote, typeof(OpCodeVote));
Set("0100111xxxxxxx", InstEmit.Xmad, typeof(OpCodeAluCbuf));
Set("0011011x00xxxx", InstEmit.Xmad, typeof(OpCodeAluImm));
Set("010100010xxxxx", InstEmit.Xmad, typeof(OpCodeAluRegCbuf));
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeVote.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeVote.cs
new file mode 100644
index 00000000..374767bd
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeVote.cs
@@ -0,0 +1,26 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ class OpCodeVote : OpCode, IOpCodeRd, IOpCodePredicate39
+ {
+ public Register Rd { get; }
+ public Register Predicate39 { get; }
+ public Register Predicate45 { get; }
+
+ public VoteOp VoteOp { get; }
+
+ public bool InvertP { get; }
+
+ public OpCodeVote(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+ {
+ Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr);
+ Predicate39 = new Register(opCode.Extract(39, 3), RegisterType.Predicate);
+ Predicate45 = new Register(opCode.Extract(45, 3), RegisterType.Predicate);
+
+ InvertP = opCode.Extract(42);
+
+ VoteOp = (VoteOp)opCode.Extract(48, 2);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/ReductionType.cs b/Ryujinx.Graphics.Shader/Decoders/ReductionType.cs
new file mode 100644
index 00000000..aaa2186e
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/ReductionType.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ enum ReductionType
+ {
+ U32 = 0,
+ S32 = 1,
+ U64 = 2,
+ FP32FtzRn = 3,
+ U128 = 4,
+ S64 = 5
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs b/Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs
index 2f3f4492..45ef3782 100644
--- a/Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs
@@ -2,6 +2,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
enum SystemRegister
{
+ LaneId = 0,
YDirection = 0x12,
ThreadId = 0x20,
ThreadIdX = 0x21,
@@ -9,6 +10,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
ThreadIdZ = 0x23,
CtaIdX = 0x25,
CtaIdY = 0x26,
- CtaIdZ = 0x27
+ CtaIdZ = 0x27,
+ EqMask = 0x38,
+ LtMask = 0x39,
+ LeMask = 0x3a,
+ GtMask = 0x3b,
+ GeMask = 0x3c
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/VoteOp.cs b/Ryujinx.Graphics.Shader/Decoders/VoteOp.cs
new file mode 100644
index 00000000..2fe937c8
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/VoteOp.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+ enum VoteOp
+ {
+ All = 0,
+ Any = 1,
+ AllEqual = 2
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
index 8d14b0cf..31375e43 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
@@ -368,6 +368,19 @@ namespace Ryujinx.Graphics.Shader.Instructions
SetZnFlags(context, dest, op.SetCondCode, op.Extended);
}
+ public static void Popc(EmitterContext context)
+ {
+ OpCodeAlu op = (OpCodeAlu)context.CurrOp;
+
+ bool invert = op.RawOpCode.Extract(40);
+
+ Operand srcB = context.BitwiseNot(GetSrcB(context), invert);
+
+ Operand res = context.BitCount(srcB);
+
+ context.Copy(GetDest(context), res);
+ }
+
public static void Psetp(EmitterContext context)
{
OpCodePsetp op = (OpCodePsetp)context.CurrOp;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
index c0a3012a..ddacc151 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
@@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static Operand GetPredicate39(EmitterContext context)
{
- IOpCodeAlu op = (IOpCodeAlu)context.CurrOp;
+ IOpCodePredicate39 op = (IOpCodePredicate39)context.CurrOp;
Operand local = Register(op.Predicate39);
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
index ee210f22..d76f44cb 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
@@ -9,6 +9,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
static partial class InstEmit
{
+ private enum MemoryRegion
+ {
+ Global,
+ Local,
+ Shared
+ }
+
public static void Ald(EmitterContext context)
{
OpCodeAttribute op = (OpCodeAttribute)context.CurrOp;
@@ -49,6 +56,21 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
+ public static void Atoms(EmitterContext context)
+ {
+ OpCodeAtom op = (OpCodeAtom)context.CurrOp;
+
+ Operand mem = context.ShiftRightU32(GetSrcA(context), Const(2));
+
+ mem = context.IAdd(mem, Const(op.Offset));
+
+ Operand value = GetSrcB(context);
+
+ Operand res = EmitAtomicOp(context, Instruction.MrShared, op.AtomicOp, op.Type, mem, value);
+
+ context.Copy(GetDest(context), res);
+ }
+
public static void Ipa(EmitterContext context)
{
OpCodeIpa op = (OpCodeIpa)context.CurrOp;
@@ -80,7 +102,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Ld(EmitterContext context)
{
- LoadLocalOrGlobal(context, isGlobal: false);
+ EmitLoad(context, MemoryRegion.Local);
}
public static void Ldc(EmitterContext context)
@@ -126,7 +148,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Ldg(EmitterContext context)
{
- LoadLocalOrGlobal(context, isGlobal: true);
+ EmitLoad(context, MemoryRegion.Global);
+ }
+
+ public static void Lds(EmitterContext context)
+ {
+ EmitLoad(context, MemoryRegion.Shared);
}
public static void Out(EmitterContext context)
@@ -152,17 +179,118 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
+ public static void Red(EmitterContext context)
+ {
+ OpCodeRed op = (OpCodeRed)context.CurrOp;
+
+ Operand offset = context.IAdd(GetSrcA(context), Const(op.Offset));
+
+ Operand mem = context.ShiftRightU32(offset, Const(2));
+
+ EmitAtomicOp(context, Instruction.MrGlobal, op.AtomicOp, op.Type, mem, GetDest(context));
+ }
+
public static void St(EmitterContext context)
{
- StoreLocalOrGlobal(context, isGlobal: false);
+ EmitStore(context, MemoryRegion.Local);
}
public static void Stg(EmitterContext context)
{
- StoreLocalOrGlobal(context, isGlobal: true);
+ EmitStore(context, MemoryRegion.Global);
+ }
+
+ public static void Sts(EmitterContext context)
+ {
+ EmitStore(context, MemoryRegion.Shared);
}
- private static void LoadLocalOrGlobal(EmitterContext context, bool isGlobal)
+ private static Operand EmitAtomicOp(
+ EmitterContext context,
+ Instruction mr,
+ AtomicOp op,
+ ReductionType type,
+ Operand mem,
+ Operand value)
+ {
+ Operand res = null;
+
+ switch (op)
+ {
+ case AtomicOp.Add:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicAdd(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.BitwiseAnd:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicAnd(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.BitwiseExclusiveOr:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicXor(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.BitwiseOr:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicOr(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.Maximum:
+ if (type == ReductionType.S32)
+ {
+ res = context.AtomicMaxS32(mr, mem, value);
+ }
+ else if (type == ReductionType.U32)
+ {
+ res = context.AtomicMaxU32(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.Minimum:
+ if (type == ReductionType.S32)
+ {
+ res = context.AtomicMinS32(mr, mem, value);
+ }
+ else if (type == ReductionType.U32)
+ {
+ res = context.AtomicMinU32(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ }
+
+ return res;
+ }
+
+ private static void EmitLoad(EmitterContext context, MemoryRegion region)
{
OpCodeMemory op = (OpCodeMemory)context.CurrOp;
@@ -199,9 +327,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
Operand offset = context.IAdd(wordOffset, Const(index));
- Operand value = isGlobal
- ? context.LoadGlobal(offset)
- : context.LoadLocal (offset);
+ Operand value = null;
+
+ switch (region)
+ {
+ case MemoryRegion.Global: value = context.LoadGlobal(offset); break;
+ case MemoryRegion.Local: value = context.LoadLocal (offset); break;
+ case MemoryRegion.Shared: value = context.LoadShared(offset); break;
+ }
if (isSmallInt)
{
@@ -212,7 +345,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
- private static void StoreLocalOrGlobal(EmitterContext context, bool isGlobal)
+ private static void EmitStore(EmitterContext context, MemoryRegion region)
{
OpCodeMemory op = (OpCodeMemory)context.CurrOp;
@@ -241,31 +374,34 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
Register rd = new Register(op.Rd.Index + index, RegisterType.Gpr);
- if (rd.IsRZ)
- {
- break;
- }
-
Operand value = Register(rd);
Operand offset = context.IAdd(wordOffset, Const(index));
if (isSmallInt)
{
- Operand word = isGlobal
- ? context.LoadGlobal(offset)
- : context.LoadLocal (offset);
+ Operand word = null;
+
+ switch (region)
+ {
+ case MemoryRegion.Global: word = context.LoadGlobal(offset); break;
+ case MemoryRegion.Local: word = context.LoadLocal (offset); break;
+ case MemoryRegion.Shared: word = context.LoadShared(offset); break;
+ }
value = InsertSmallInt(context, op.Size, bitOffset, word, value);
}
- if (isGlobal)
+ switch (region)
{
- context.StoreGlobal(offset, value);
+ case MemoryRegion.Global: context.StoreGlobal(offset, value); break;
+ case MemoryRegion.Local: context.StoreLocal (offset, value); break;
+ case MemoryRegion.Shared: context.StoreShared(offset, value); break;
}
- else
+
+ if (rd.IsRZ)
{
- context.StoreLocal(offset, value);
+ break;
}
}
}
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
index f0792245..5833d879 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
@@ -27,6 +27,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (sysReg)
{
+ case SystemRegister.LaneId: src = Attribute(AttributeConsts.LaneId); break;
+
// TODO: Use value from Y direction GPU register.
case SystemRegister.YDirection: src = ConstF(1); break;
@@ -50,6 +52,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
case SystemRegister.CtaIdX: src = Attribute(AttributeConsts.CtaIdX); break;
case SystemRegister.CtaIdY: src = Attribute(AttributeConsts.CtaIdY); break;
case SystemRegister.CtaIdZ: src = Attribute(AttributeConsts.CtaIdZ); break;
+ case SystemRegister.EqMask: src = Attribute(AttributeConsts.EqMask); break;
+ case SystemRegister.LtMask: src = Attribute(AttributeConsts.LtMask); break;
+ case SystemRegister.LeMask: src = Attribute(AttributeConsts.LeMask); break;
+ case SystemRegister.GtMask: src = Attribute(AttributeConsts.GtMask); break;
+ case SystemRegister.GeMask: src = Attribute(AttributeConsts.GeMask); break;
default: src = Const(0); break;
}
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
new file mode 100644
index 00000000..9c4d5f1a
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
@@ -0,0 +1,48 @@
+using Ryujinx.Graphics.Shader.Decoders;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.Translation;
+
+using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
+using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
+
+namespace Ryujinx.Graphics.Shader.Instructions
+{
+ static partial class InstEmit
+ {
+ public static void Vote(EmitterContext context)
+ {
+ OpCodeVote op = (OpCodeVote)context.CurrOp;
+
+ Operand pred = GetPredicate39(context);
+
+ Operand res = null;
+
+ switch (op.VoteOp)
+ {
+ case VoteOp.All:
+ res = context.VoteAll(pred);
+ break;
+ case VoteOp.Any:
+ res = context.VoteAny(pred);
+ break;
+ case VoteOp.AllEqual:
+ res = context.VoteAllEqual(pred);
+ break;
+ }
+
+ if (res != null)
+ {
+ context.Copy(Register(op.Predicate45), res);
+ }
+ else
+ {
+ // Invalid.
+ }
+
+ if (!op.Rd.IsRZ)
+ {
+ context.Copy(Register(op.Rd), context.Ballot(pred));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
index 46c6b57f..d99e3f2b 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
@@ -7,6 +7,17 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
Absolute = 1,
Add,
+ AtomicAdd,
+ AtomicAnd,
+ AtomicCompareAndSwap,
+ AtomicMinS32,
+ AtomicMinU32,
+ AtomicMaxS32,
+ AtomicMaxU32,
+ AtomicOr,
+ AtomicSwap,
+ AtomicXor,
+ Ballot,
BitCount,
BitfieldExtractS32,
BitfieldExtractU32,
@@ -57,6 +68,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
LoadConstant,
LoadGlobal,
LoadLocal,
+ LoadShared,
LoadStorage,
LogarithmB2,
LogicalAnd,
@@ -88,6 +100,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
SquareRoot,
StoreGlobal,
StoreLocal,
+ StoreShared,
StoreStorage,
Subtract,
SwizzleAdd,
@@ -96,9 +109,44 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Truncate,
UnpackDouble2x32,
UnpackHalf2x16,
+ VoteAll,
+ VoteAllEqual,
+ VoteAny,
Count,
- FP = 1 << 16,
+
+ FP = 1 << 16,
+
+ MrShift = 17,
+
+ MrGlobal = 0 << MrShift,
+ MrShared = 1 << MrShift,
+ MrStorage = 2 << MrShift,
+ MrMask = 3 << MrShift,
+
Mask = 0xffff
}
+
+ static class InstructionExtensions
+ {
+ public static bool IsAtomic(this Instruction inst)
+ {
+ switch (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;
+ }
+ }
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
index 0d7379a8..6b7fb82f 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public int SourcesCount => _sources.Length;
- public int ComponentIndex { get; }
+ public int Index { get; }
public Operation(Instruction inst, Operand dest, params Operand[] sources)
{
@@ -39,11 +39,11 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public Operation(
Instruction inst,
- int compIndex,
+ int index,
Operand dest,
params Operand[] sources) : this(inst, dest, sources)
{
- ComponentIndex = compIndex;
+ Index = index;
}
private Operand AssignDest(Operand dest)
diff --git a/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj b/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj
index e10d1eda..a046c2f9 100644
--- a/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj
+++ b/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
+ <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\GlobalMemory.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\Shuffle.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleDown.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleUp.glsl" />
diff --git a/Ryujinx.Graphics.Shader/ShaderProgram.cs b/Ryujinx.Graphics.Shader/ShaderProgram.cs
index 52c2d55b..5d04f2cf 100644
--- a/Ryujinx.Graphics.Shader/ShaderProgram.cs
+++ b/Ryujinx.Graphics.Shader/ShaderProgram.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace Ryujinx.Graphics.Shader
{
public class ShaderProgram
@@ -15,6 +17,11 @@ namespace Ryujinx.Graphics.Shader
Code = code;
}
+ public void Prepend(string line)
+ {
+ Code = line + Environment.NewLine + Code;
+ }
+
public void Replace(string name, string value)
{
Code = Code.Replace(name, value);
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstOperation.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstOperation.cs
index 1607ffec..76eee71e 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/AstOperation.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/AstOperation.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{
public Instruction Inst { get; }
- public int ComponentMask { get; }
+ public int Index { get; }
private IAstNode[] _sources;
@@ -24,12 +24,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
AddUse(source, this);
}
- ComponentMask = 1;
+ Index = 0;
}
- public AstOperation(Instruction inst, int compMask, params IAstNode[] sources) : this(inst, sources)
+ public AstOperation(Instruction inst, int index, params IAstNode[] sources) : this(inst, sources)
{
- ComponentMask = compMask;
+ Index = index;
}
public IAstNode GetSource(int index)
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
index d6d40732..5473978e 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
@@ -16,8 +16,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
TextureFlags flags,
int handle,
int arraySize,
- int compMask,
- params IAstNode[] sources) : base(inst, compMask, sources)
+ int index,
+ params IAstNode[] sources) : base(inst, index, sources)
{
Type = type;
Flags = flags;
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs b/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs
index e2eee78d..b262e6bc 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/HelperFunctionsMask.cs
@@ -5,10 +5,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
[Flags]
enum HelperFunctionsMask
{
- Shuffle = 1 << 0,
- ShuffleDown = 1 << 1,
- ShuffleUp = 1 << 2,
- ShuffleXor = 1 << 3,
- SwizzleAdd = 1 << 4
+ GlobalMemory = 1 << 0,
+ Shuffle = 1 << 1,
+ ShuffleDown = 1 << 2,
+ ShuffleUp = 1 << 3,
+ ShuffleXor = 1 << 4,
+ SwizzleAdd = 1 << 5
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
index 381cf292..4f4ebb99 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
@@ -25,8 +25,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
_infoTbl = new InstInfo[(int)Instruction.Count];
// Inst Destination type Source 1 type Source 2 type Source 3 type Source 4 type
+ Add(Instruction.AtomicAdd, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicAnd, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicCompareAndSwap, VariableType.U32, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicMaxS32, VariableType.S32, VariableType.S32, VariableType.S32);
+ Add(Instruction.AtomicMaxU32, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicMinS32, VariableType.S32, VariableType.S32, VariableType.S32);
+ Add(Instruction.AtomicMinU32, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicOr, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicSwap, VariableType.U32, VariableType.U32, VariableType.U32);
+ Add(Instruction.AtomicXor, VariableType.U32, VariableType.U32, VariableType.U32);
Add(Instruction.Absolute, VariableType.Scalar, VariableType.Scalar);
Add(Instruction.Add, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
+ Add(Instruction.Ballot, VariableType.U32, VariableType.Bool);
Add(Instruction.BitCount, VariableType.Int, VariableType.Int);
Add(Instruction.BitfieldExtractS32, VariableType.S32, VariableType.S32, VariableType.S32, VariableType.S32);
Add(Instruction.BitfieldExtractU32, VariableType.U32, VariableType.U32, VariableType.S32, VariableType.S32);
@@ -69,9 +80,10 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.IsNan, VariableType.Bool, VariableType.F32);
Add(Instruction.LoadAttribute, VariableType.F32, VariableType.S32, VariableType.S32);
Add(Instruction.LoadConstant, VariableType.F32, VariableType.S32, VariableType.S32);
- Add(Instruction.LoadGlobal, VariableType.F32, VariableType.S32, VariableType.S32);
+ Add(Instruction.LoadGlobal, VariableType.U32, VariableType.S32, VariableType.S32);
Add(Instruction.LoadLocal, VariableType.F32, VariableType.S32);
- Add(Instruction.LoadStorage, VariableType.F32, VariableType.S32, VariableType.S32);
+ Add(Instruction.LoadShared, VariableType.U32, VariableType.S32);
+ Add(Instruction.LoadStorage, VariableType.U32, VariableType.S32);
Add(Instruction.LogarithmB2, VariableType.Scalar, VariableType.Scalar);
Add(Instruction.LogicalAnd, VariableType.Bool, VariableType.Bool, VariableType.Bool);
Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool);
@@ -95,15 +107,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.Round, VariableType.F32, VariableType.F32);
Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar);
Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar);
- Add(Instruction.StoreGlobal, VariableType.None, VariableType.S32, VariableType.S32, VariableType.F32);
+ Add(Instruction.StoreGlobal, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32);
Add(Instruction.StoreLocal, VariableType.None, VariableType.S32, VariableType.F32);
- Add(Instruction.StoreStorage, VariableType.None, VariableType.S32, VariableType.S32, VariableType.F32);
+ Add(Instruction.StoreShared, VariableType.None, VariableType.S32, VariableType.U32);
+ Add(Instruction.StoreStorage, VariableType.None, VariableType.S32, VariableType.U32);
Add(Instruction.Subtract, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
Add(Instruction.SwizzleAdd, VariableType.F32, VariableType.F32, VariableType.F32, VariableType.S32);
Add(Instruction.TextureSample, VariableType.F32);
Add(Instruction.TextureSize, VariableType.S32, VariableType.S32, VariableType.S32);
Add(Instruction.Truncate, VariableType.F32, VariableType.F32);
Add(Instruction.UnpackHalf2x16, VariableType.F32, VariableType.U32);
+ Add(Instruction.VoteAll, VariableType.Bool, VariableType.Bool);
+ Add(Instruction.VoteAllEqual, VariableType.Bool, VariableType.Bool);
+ Add(Instruction.VoteAny, VariableType.Bool, VariableType.Bool);
}
private static void Add(Instruction inst, VariableType destType, params VariableType[] srcTypes)
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
index ef8443ab..a81b3d12 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
@@ -51,8 +51,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
sources[index] = context.GetOperandUse(operation.GetSource(index));
}
- int componentMask = 1 << operation.ComponentIndex;
-
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
{
return new AstTextureOperation(
@@ -61,7 +59,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
texOp.Flags,
texOp.Handle,
4, // TODO: Non-hardcoded array size.
- componentMask,
+ texOp.Index,
sources);
}
@@ -80,16 +78,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
context.Info.CBuffers.Add(slot.Value);
}
- else if (inst == Instruction.LoadStorage)
+ else if (UsesStorage(inst))
{
- Operand slot = operation.GetSource(0);
-
- if (slot.Type != OperandType.Constant)
- {
- throw new InvalidOperationException("Found load or store with non-constant storage buffer slot.");
- }
-
- context.Info.SBuffers.Add(slot.Value);
+ context.Info.SBuffers.Add(operation.Index);
}
AstAssignment assignment;
@@ -141,7 +132,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
}
else if (!isCopy)
{
- source = new AstOperation(inst, componentMask, sources);
+ source = new AstOperation(inst, operation.Index, sources);
}
else
{
@@ -166,19 +157,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
}
else
{
- if (inst == Instruction.StoreStorage)
+ if (UsesStorage(inst))
{
- Operand slot = operation.GetSource(0);
-
- if (slot.Type != OperandType.Constant)
- {
- throw new InvalidOperationException("Found load or store with non-constant storage buffer slot.");
- }
-
- context.Info.SBuffers.Add(slot.Value);
+ context.Info.SBuffers.Add(operation.Index);
}
- context.AddNode(new AstOperation(inst, sources));
+ context.AddNode(new AstOperation(inst, operation.Index, sources));
}
// Those instructions needs to be emulated by using helper functions,
@@ -186,6 +170,10 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
// decide which helper functions are needed on the final generated code.
switch (operation.Inst)
{
+ case Instruction.LoadGlobal:
+ case Instruction.StoreGlobal:
+ context.Info.HelperFunctionsMask |= HelperFunctionsMask.GlobalMemory;
+ break;
case Instruction.Shuffle:
context.Info.HelperFunctionsMask |= HelperFunctionsMask.Shuffle;
break;
@@ -320,5 +308,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
throw new ArgumentException($"Unexpected instruction \"{inst}\".");
}
+
+ private static bool UsesStorage(Instruction inst)
+ {
+ if (inst == Instruction.LoadStorage || inst == Instruction.StoreStorage)
+ {
+ return true;
+ }
+
+ return inst.IsAtomic() && (inst & Instruction.MrMask) == Instruction.MrStorage;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
index 08aac1ca..8ff37429 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
@@ -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;
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
index 58a37b52..e94d4d2d 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
@@ -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);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
index 97852ac1..b6958929 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
@@ -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)));
}
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
index 3d89faf6..2fafa5ad 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
@@ -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)
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index 6ee27884..93d86541 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -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)
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index aaf618e9..b7a5bffa 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -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)