Add support for fragment shader interlock (#2768)

* Support coherent images

* Add support for fragment shader interlock

* Change to tree based match approach

* Refactor + check for branch targets and external registers

* Make detection more robust

* Use Intel fragment shader ordering if interlock is not available, use nothing if both are not available

* Remove unused field
This commit is contained in:
gdkchan 2021-10-28 19:53:12 -03:00 committed by GitHub
parent a7a40a77f2
commit 99445dd0a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1309 additions and 179 deletions

View file

@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.GAL
public bool HasVectorIndexingBug { get; }
public bool SupportsAstcCompression { get; }
public bool SupportsFragmentShaderInterlock { get; }
public bool SupportsFragmentShaderOrderingIntel { get; }
public bool SupportsImageLoadFormatted { get; }
public bool SupportsMismatchingViewFormat { get; }
public bool SupportsNonConstantTextureOffset { get; }
@ -22,6 +24,8 @@ namespace Ryujinx.Graphics.GAL
bool hasFrontFacingBug,
bool hasVectorIndexingBug,
bool supportsAstcCompression,
bool supportsFragmentShaderInterlock,
bool supportsFragmentShaderOrderingIntel,
bool supportsImageLoadFormatted,
bool supportsMismatchingViewFormat,
bool supportsNonConstantTextureOffset,
@ -36,6 +40,8 @@ namespace Ryujinx.Graphics.GAL
HasFrontFacingBug = hasFrontFacingBug;
HasVectorIndexingBug = hasVectorIndexingBug;
SupportsAstcCompression = supportsAstcCompression;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
SupportsImageLoadFormatted = supportsImageLoadFormatted;
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;

View file

@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
private const ulong ShaderCodeGenVersion = 2741;
private const ulong ShaderCodeGenVersion = 2768;
// Progress reporting helpers
private volatile int _shaderCount;

View file

@ -36,6 +36,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>Host storage buffer alignment in bytes</returns>
public int QueryHostStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
/// <summary>
/// Queries host support for fragment shader ordering critical sections on the shader code.
/// </summary>
/// <returns>True if fragment shader interlock is supported, false otherwise</returns>
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
/// <summary>
/// Queries host support for fragment shader ordering scoped critical sections on the shader code.
/// </summary>
/// <returns>True if fragment shader ordering is supported, false otherwise</returns>
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
/// <summary>
/// Queries host support for readable images without a explicit format declaration on the shader.
/// </summary>

View file

@ -6,7 +6,10 @@ namespace Ryujinx.Graphics.OpenGL
static class HwCapabilities
{
private static readonly Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
private static readonly Lazy<bool> _supportsFragmentShaderInterlock = new Lazy<bool>(() => HasExtension("GL_ARB_fragment_shader_interlock"));
private static readonly Lazy<bool> _supportsFragmentShaderOrdering = new Lazy<bool>(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
private static readonly Lazy<bool> _supportsImageLoadFormatted = new Lazy<bool>(() => HasExtension("GL_EXT_shader_image_load_formatted"));
private static readonly Lazy<bool> _supportsIndirectParameters = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
private static readonly Lazy<bool> _supportsParallelShaderCompile = new Lazy<bool>(() => HasExtension("GL_ARB_parallel_shader_compile"));
private static readonly Lazy<bool> _supportsPolygonOffsetClamp = new Lazy<bool>(() => HasExtension("GL_EXT_polygon_offset_clamp"));
private static readonly Lazy<bool> _supportsQuads = new Lazy<bool>(SupportsQuadsCheck);
@ -14,7 +17,6 @@ namespace Ryujinx.Graphics.OpenGL
private static readonly Lazy<bool> _supportsShaderBallot = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
private static readonly Lazy<bool> _supportsTextureShadowLod = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
private static readonly Lazy<bool> _supportsViewportSwizzle = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));
private static readonly Lazy<bool> _supportsIndirectParameters = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
private static readonly Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
@ -41,7 +43,10 @@ namespace Ryujinx.Graphics.OpenGL
public static bool UsePersistentBufferForFlush => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
public static bool SupportsQuads => _supportsQuads.Value;
@ -49,7 +54,6 @@ namespace Ryujinx.Graphics.OpenGL
public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;

View file

@ -104,6 +104,8 @@ namespace Ryujinx.Graphics.OpenGL
HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
HwCapabilities.SupportsAstcCompression,
HwCapabilities.SupportsFragmentShaderInterlock,
HwCapabilities.SupportsFragmentShaderOrdering,
HwCapabilities.SupportsImageLoadFormatted,
HwCapabilities.SupportsMismatchingViewFormat,
HwCapabilities.SupportsNonConstantTextureOffset,

View file

@ -32,6 +32,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
context.AppendLine("#extension GL_ARB_compute_shader : enable");
}
else if (context.Config.Stage == ShaderStage.Fragment)
{
if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
{
context.AppendLine("#extension GL_ARB_fragment_shader_interlock : enable");
}
else if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel())
{
context.AppendLine("#extension GL_INTEL_fragment_shader_ordering : enable");
}
}
if (context.Config.GpPassthrough)
{
@ -431,6 +442,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string imageTypeName = descriptor.Type.ToGlslImageType(descriptor.Format.GetComponentType());
if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
{
imageTypeName = "coherent " + imageTypeName;
}
string layout = descriptor.Format.ToGlslFormat();
if (!string.IsNullOrEmpty(layout))

View file

@ -117,7 +117,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
if (node is AstOperation operation)
{
context.AppendLine(InstGen.GetExpression(context, operation) + ";");
string expr = InstGen.GetExpression(context, operation);
if (expr != null)
{
context.AppendLine(expr + ";");
}
}
else if (node is AstAssignment assignment)
{

View file

@ -4,6 +4,7 @@ using System;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenBallot;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenCall;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenFSI;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenPacking;
@ -144,6 +145,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.Call:
return Call(context, operation);
case Instruction.FSIBegin:
return FSIBegin(context);
case Instruction.FSIEnd:
return FSIEnd(context);
case Instruction.ImageLoad:
case Instruction.ImageStore:
case Instruction.ImageAtomic:

View file

@ -0,0 +1,29 @@
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
static class InstGenFSI
{
public static string FSIBegin(CodeGenContext context)
{
if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
{
return "beginInvocationInterlockARB()";
}
else if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel())
{
return "beginFragmentShaderOrderingINTEL()";
}
return null;
}
public static string FSIEnd(CodeGenContext context)
{
if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
{
return "endInvocationInterlockARB()";
}
return null;
}
}
}

View file

@ -65,6 +65,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.EmitVertex, InstType.CallNullary, "EmitVertex");
Add(Instruction.EndPrimitive, InstType.CallNullary, "EndPrimitive");
Add(Instruction.ExponentB2, InstType.CallUnary, "exp2");
Add(Instruction.FSIBegin, InstType.Special);
Add(Instruction.FSIEnd, InstType.Special);
Add(Instruction.FindFirstSetS32, InstType.CallUnary, "findMSB");
Add(Instruction.FindFirstSetU32, InstType.CallUnary, "findMSB");
Add(Instruction.Floor, InstType.CallUnary, "floor");

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.Decoders
{
class DecodedFunction
{
private readonly HashSet<DecodedFunction> _callers;
public bool IsCompilerGenerated => Type != FunctionType.User;
public FunctionType Type { get; set; }
public int Id { get; set; }
public ulong Address { get; }
public Block[] Blocks { get; private set; }
public DecodedFunction(ulong address)
{
Address = address;
_callers = new HashSet<DecodedFunction>();
Type = FunctionType.User;
Id = -1;
}
public void SetBlocks(Block[] blocks)
{
if (Blocks != null)
{
throw new InvalidOperationException("Blocks have already been set.");
}
Blocks = blocks;
}
public void AddCaller(DecodedFunction caller)
{
_callers.Add(caller);
}
public void RemoveCaller(DecodedFunction caller)
{
if (_callers.Remove(caller) && _callers.Count == 0)
{
Type = FunctionType.Unused;
}
}
}
}

View file

@ -0,0 +1,57 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.Decoders
{
struct DecodedProgram : IEnumerable<DecodedFunction>
{
public DecodedFunction MainFunction { get; }
private readonly IReadOnlyDictionary<ulong, DecodedFunction> _functions;
private readonly List<DecodedFunction> _functionsWithId;
public int FunctionsWithIdCount => _functionsWithId.Count;
public DecodedProgram(DecodedFunction mainFunction, IReadOnlyDictionary<ulong, DecodedFunction> functions)
{
MainFunction = mainFunction;
_functions = functions;
_functionsWithId = new List<DecodedFunction>();
}
public DecodedFunction GetFunctionByAddress(ulong address)
{
if (_functions.TryGetValue(address, out DecodedFunction function))
{
return function;
}
return null;
}
public DecodedFunction GetFunctionById(int id)
{
if ((uint)id >= (uint)_functionsWithId.Count)
{
throw new ArgumentOutOfRangeException(nameof(id));
}
return _functionsWithId[id];
}
public void AddFunctionAndSetId(DecodedFunction function)
{
function.Id = _functionsWithId.Count;
_functionsWithId.Add(function);
}
public IEnumerator<DecodedFunction> GetEnumerator()
{
return _functions.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View file

@ -10,24 +10,25 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
static class Decoder
{
public static Block[][] Decode(ShaderConfig config, ulong startAddress)
public static DecodedProgram Decode(ShaderConfig config, ulong startAddress)
{
List<Block[]> funcs = new List<Block[]>();
Queue<DecodedFunction> functionsQueue = new Queue<DecodedFunction>();
Dictionary<ulong, DecodedFunction> functionsVisited = new Dictionary<ulong, DecodedFunction>();
Queue<ulong> funcQueue = new Queue<ulong>();
HashSet<ulong> funcVisited = new HashSet<ulong>();
void EnqueueFunction(ulong funcAddress)
DecodedFunction EnqueueFunction(ulong address)
{
if (funcVisited.Add(funcAddress))
if (!functionsVisited.TryGetValue(address, out DecodedFunction function))
{
funcQueue.Enqueue(funcAddress);
functionsVisited.Add(address, function = new DecodedFunction(address));
functionsQueue.Enqueue(function);
}
return function;
}
funcQueue.Enqueue(0);
DecodedFunction mainFunction = EnqueueFunction(0);
while (funcQueue.TryDequeue(out ulong funcAddress))
while (functionsQueue.TryDequeue(out DecodedFunction currentFunction))
{
List<Block> blocks = new List<Block>();
Queue<Block> workQueue = new Queue<Block>();
@ -46,7 +47,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
return block;
}
GetBlock(funcAddress);
GetBlock(currentFunction.Address);
bool hasNewTarget;
@ -108,7 +109,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
if (lastOp.Name == InstName.Cal)
{
EnqueueFunction(lastOp.GetAbsoluteAddress());
EnqueueFunction(lastOp.GetAbsoluteAddress()).AddCaller(currentFunction);
}
else if (lastOp.Name == InstName.Bra)
{
@ -157,10 +158,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
}
while (hasNewTarget);
funcs.Add(blocks.ToArray());
currentFunction.SetBlocks(blocks.ToArray());
}
return funcs.ToArray();
return new DecodedProgram(mainFunction, functionsVisited);
}
private static bool BinarySearch(List<Block> blocks, ulong address, out int index)

View file

@ -0,0 +1,10 @@
namespace Ryujinx.Graphics.Shader.Decoders
{
enum FunctionType : byte
{
User,
Unused,
BuiltInFSIBegin,
BuiltInFSIEnd
}
}

View file

@ -404,13 +404,22 @@ namespace Ryujinx.Graphics.Shader.Decoders
Attr = 3,
}
enum CacheOp
enum CacheOpLd
{
Ca = 0,
Cg = 1,
Ci = 2,
Cv = 3,
}
enum CacheOpSt
{
Wb = 0,
Cg = 1,
Ci = 2,
Wt = 3,
}
enum LsSize
{
U8 = 0,
@ -1163,19 +1172,19 @@ namespace Ryujinx.Graphics.Shader.Decoders
public CctltOp CctltOp => (CctltOp)((_opcode >> 0) & 0x3);
}
struct InstContUnsup
struct InstCont
{
private ulong _opcode;
public InstContUnsup(ulong opcode) => _opcode = opcode;
public InstCont(ulong opcode) => _opcode = opcode;
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
public Ccc Ccc => (Ccc)((_opcode >> 0) & 0x1F);
}
struct InstCsetUnsup
struct InstCset
{
private ulong _opcode;
public InstCsetUnsup(ulong opcode) => _opcode = opcode;
public InstCset(ulong opcode) => _opcode = opcode;
public int Dest => (int)((_opcode >> 0) & 0xFF);
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
@ -3507,7 +3516,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
public int SrcPred => (int)((_opcode >> 58) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 56) & 0x3);
public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 56) & 0x3);
public LsSize LsSize => (LsSize)((_opcode >> 53) & 0x7);
public bool E => (_opcode & 0x10000000000000) != 0;
public int Imm32 => (int)(_opcode >> 20);
@ -3536,7 +3545,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
public LsSize LsSize => (LsSize)((_opcode >> 48) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 46) & 0x3);
public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 46) & 0x3);
public bool E => (_opcode & 0x200000000000) != 0;
public int Imm24 => (int)((_opcode >> 20) & 0xFFFFFF);
}
@ -4502,7 +4511,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
public int SrcPred => (int)((_opcode >> 58) & 0x7);
public CacheOp Cop => (CacheOp)((_opcode >> 56) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 56) & 0x3);
public LsSize LsSize => (LsSize)((_opcode >> 53) & 0x7);
public bool E => (_opcode & 0x10000000000000) != 0;
public int Imm32 => (int)(_opcode >> 20);
@ -4517,7 +4526,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
public LsSize2 LsSize => (LsSize2)((_opcode >> 48) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 46) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 46) & 0x3);
public bool E => (_opcode & 0x200000000000) != 0;
public int Imm24 => (int)((_opcode >> 20) & 0xFFFFFF);
}
@ -4531,7 +4540,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int Pred => (int)((_opcode >> 16) & 0x7);
public bool PredInv => (_opcode & 0x80000) != 0;
public LsSize2 LsSize => (LsSize2)((_opcode >> 48) & 0x7);
public CacheOp2 CacheOp => (CacheOp2)((_opcode >> 44) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 44) & 0x3);
public int Imm24 => (int)((_opcode >> 20) & 0xFFFFFF);
}
@ -4653,7 +4662,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public int DestPred2 => (int)((_opcode >> 30) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
public bool Ba => (_opcode & 0x800000) != 0;
public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
}
@ -4670,7 +4679,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int TidB => (int)((_opcode >> 36) & 0x1FFF);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public int DestPred2 => (int)((_opcode >> 30) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
public bool Ba => (_opcode & 0x800000) != 0;
public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
}
@ -4687,7 +4696,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public int DestPred2 => (int)((_opcode >> 30) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
}
@ -4703,7 +4712,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int TidB => (int)((_opcode >> 36) & 0x1FFF);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public int DestPred2 => (int)((_opcode >> 30) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
}
@ -4750,7 +4759,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public bool PredInv => (_opcode & 0x80000) != 0;
public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
public bool Ba => (_opcode & 0x800000) != 0;
public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
}
@ -4766,7 +4775,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
public int TidB => (int)((_opcode >> 36) & 0x1FFF);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
public bool Ba => (_opcode & 0x800000) != 0;
public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
}
@ -4782,7 +4791,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public bool PredInv => (_opcode & 0x80000) != 0;
public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
}
@ -4797,7 +4806,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
public int TidB => (int)((_opcode >> 36) & 0x1FFF);
public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
}

View file

@ -7,14 +7,22 @@ namespace Ryujinx.Graphics.Shader.Decoders
Rd2 = 1 << 1,
Ra = 1 << 2,
Rb = 1 << 3,
Ib = 1 << 4,
Rc = 1 << 5,
Pd = 1 << 6,
Pd2 = 1 << 7,
Pdn = 1 << 8,
Tex = 1 << 9,
TexB = 1 << 10,
Bra = 1 << 11,
NoPred = 1 << 12
Rb2 = 1 << 4,
Ib = 1 << 5,
Rc = 1 << 6,
Pd = 1 << 7,
LPd = 2 << 7,
SPd = 3 << 7,
TPd = 4 << 7,
VPd = 5 << 7,
PdMask = 7 << 7,
Pdn = 1 << 10,
Ps = 1 << 11,
Tex = 1 << 12,
TexB = 1 << 13,
Bra = 1 << 14,
NoPred = 1 << 15
}
}

View file

@ -32,13 +32,13 @@ namespace Ryujinx.Graphics.Shader.Decoders
#region Instructions
Add("1110111110100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Al2p, InstEmit.Al2p, InstProps.Rd | InstProps.Ra);
Add("1110111111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ald, InstEmit.Ald, InstProps.Rd | InstProps.Ra);
Add("1110111111110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ast, InstEmit.Ast, InstProps.Ra | InstProps.Rc);
Add("1110111111110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ast, InstEmit.Ast, InstProps.Ra | InstProps.Rb2 | InstProps.Rc);
Add("11101101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Atom, InstEmit.Atom, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("111011101111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.AtomCas, InstEmit.AtomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("11101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Atoms, InstEmit.Atoms, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("111011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.AtomsCas, InstEmit.AtomsCas, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("1111000010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.B2r, InstEmit.B2r, InstProps.Rd | InstProps.Ra);
Add("1111000010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bar, InstEmit.Bar, InstProps.Ra);
Add("1111000010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.B2r, InstEmit.B2r, InstProps.Rd | InstProps.Ra | InstProps.VPd);
Add("1111000010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bar, InstEmit.Bar, InstProps.Ra | InstProps.Ps);
Add("0101110000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bfe, InstEmit.BfeR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x00000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bfe, InstEmit.BfeI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bfe, InstEmit.BfeC, InstProps.Rd | InstProps.Ra);
@ -56,8 +56,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("1110101111110xx0000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cctlt, InstEmit.Cctlt);
Add("1110101111101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cctlt, InstEmit.Cctlt, InstProps.Rc);
Add("111000110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cont, InstEmit.Cont);
Add("0101000010011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cset, InstEmit.Cset, InstProps.Rd);
Add("0101000010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Csetp, InstEmit.Csetp, InstProps.Pd | InstProps.Pdn);
Add("0101000010011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cset, InstEmit.Cset, InstProps.Rd | InstProps.Ps);
Add("0101000010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Csetp, InstEmit.Csetp, InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0101000011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cs2r, InstEmit.Cs2r, InstProps.Rd);
Add("0101110001110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dadd, InstEmit.DaddR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x01110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dadd, InstEmit.DaddI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
@ -67,18 +67,18 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("0011011x0111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dfma, InstEmit.DfmaI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Rc);
Add("010010110111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dfma, InstEmit.DfmaC, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("010100110111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dfma, InstEmit.DfmaRc, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("0101110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx, InstEmit.DmnmxR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x01010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx, InstEmit.DmnmxI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx, InstEmit.DmnmxC, InstProps.Rd | InstProps.Ra);
Add("0101110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx, InstEmit.DmnmxR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011100x01010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx, InstEmit.DmnmxI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("0100110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx, InstEmit.DmnmxC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("0101110010000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmul, InstEmit.DmulR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x10000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmul, InstEmit.DmulI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110010000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmul, InstEmit.DmulC, InstProps.Rd | InstProps.Ra);
Add("010110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset, InstEmit.DsetR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011001x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset, InstEmit.DsetI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("010010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset, InstEmit.DsetC, InstProps.Rd | InstProps.Ra);
Add("010110111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp, InstEmit.DsetpR, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn);
Add("0011011x1000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp, InstEmit.DsetpI, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn);
Add("010010111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp, InstEmit.DsetpC, InstProps.Ra | InstProps.Pd | InstProps.Pdn);
Add("010110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset, InstEmit.DsetR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011001x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset, InstEmit.DsetI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("010010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset, InstEmit.DsetC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("010110111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp, InstEmit.DsetpR, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0011011x1000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp, InstEmit.DsetpI, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("010010111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp, InstEmit.DsetpC, InstProps.Ra | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("111000110000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Exit, InstEmit.Exit, InstProps.Bra);
Add("0101110010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.F2f, InstEmit.F2fR, InstProps.Rd | InstProps.Rb);
Add("0011100x10101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.F2f, InstEmit.F2fI, InstProps.Rd | InstProps.Ib);
@ -105,19 +105,19 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("0101110000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Flo, InstEmit.FloR, InstProps.Rd | InstProps.Rb);
Add("0011100x00110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Flo, InstEmit.FloI, InstProps.Rd | InstProps.Ib);
Add("0100110000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Flo, InstEmit.FloC, InstProps.Rd);
Add("0101110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx, InstEmit.FmnmxR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x01100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx, InstEmit.FmnmxI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx, InstEmit.FmnmxC, InstProps.Rd | InstProps.Ra);
Add("0101110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx, InstEmit.FmnmxR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011100x01100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx, InstEmit.FmnmxI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("0100110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx, InstEmit.FmnmxC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("0101110001101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul, InstEmit.FmulR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x01101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul, InstEmit.FmulI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110001101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul, InstEmit.FmulC, InstProps.Rd | InstProps.Ra);
Add("00011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul32i, InstEmit.Fmul32i, InstProps.Rd | InstProps.Ra);
Add("01011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset, InstEmit.FsetR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset, InstEmit.FsetI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("01001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset, InstEmit.FsetC, InstProps.Rd | InstProps.Ra);
Add("010110111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp, InstEmit.FsetpR, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn);
Add("0011011x1011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp, InstEmit.FsetpI, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn);
Add("010010111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp, InstEmit.FsetpC, InstProps.Ra | InstProps.Pd | InstProps.Pdn);
Add("01011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset, InstEmit.FsetR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset, InstEmit.FsetI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("01001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset, InstEmit.FsetC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("010110111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp, InstEmit.FsetpR, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0011011x1011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp, InstEmit.FsetpI, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("010010111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp, InstEmit.FsetpC, InstProps.Ra | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0101000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fswzadd, InstEmit.Fswzadd, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("111000101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Getcrsptr, InstEmit.Getcrsptr, InstProps.Rd | InstProps.NoPred);
Add("111000101101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Getlmembase, InstEmit.Getlmembase, InstProps.Rd | InstProps.NoPred);
@ -133,12 +133,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("0111100x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hmul2, InstEmit.Hmul2I, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0111100x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hmul2, InstEmit.Hmul2C, InstProps.Rd | InstProps.Ra);
Add("0010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hmul232i, InstEmit.Hmul232i, InstProps.Rd | InstProps.Ra);
Add("0101110100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2, InstEmit.Hset2R, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0111110x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2, InstEmit.Hset2I, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0111110x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2, InstEmit.Hset2C, InstProps.Rd | InstProps.Ra);
Add("0101110100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2, InstEmit.Hsetp2R, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn);
Add("0111111x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2, InstEmit.Hsetp2I, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn);
Add("0111111x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2, InstEmit.Hsetp2C, InstProps.Ra | InstProps.Pd | InstProps.Pdn);
Add("0101110100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2, InstEmit.Hset2R, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0111110x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2, InstEmit.Hset2I, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("0111110x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2, InstEmit.Hset2C, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("0101110100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2, InstEmit.Hsetp2R, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0111111x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2, InstEmit.Hsetp2I, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0111111x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2, InstEmit.Hsetp2C, InstProps.Ra | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0101110010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.I2f, InstEmit.I2fR, InstProps.Rd | InstProps.Rb);
Add("0011100x10111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.I2f, InstEmit.I2fI, InstProps.Rd | InstProps.Ib);
Add("0100110010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.I2f, InstEmit.I2fC, InstProps.Rd);
@ -168,9 +168,9 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("0011010x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imadsp, InstEmit.ImadspI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Rc);
Add("010010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imadsp, InstEmit.ImadspC, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("010100101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imadsp, InstEmit.ImadspRc, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("0101110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx, InstEmit.ImnmxR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x00100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx, InstEmit.ImnmxI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx, InstEmit.ImnmxC, InstProps.Rd | InstProps.Ra);
Add("0101110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx, InstEmit.ImnmxR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011100x00100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx, InstEmit.ImnmxI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("0100110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx, InstEmit.ImnmxC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("0101110000111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imul, InstEmit.ImulR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x00111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imul, InstEmit.ImulI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110000111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imul, InstEmit.ImulC, InstProps.Rd | InstProps.Ra);
@ -181,12 +181,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("0011100x00011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iscadd, InstEmit.IscaddI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110000011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iscadd, InstEmit.IscaddC, InstProps.Rd | InstProps.Ra);
Add("000101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iscadd32i, InstEmit.Iscadd32i, InstProps.Rd | InstProps.Ra);
Add("010110110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset, InstEmit.IsetR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011011x0101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset, InstEmit.IsetI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("010010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset, InstEmit.IsetC, InstProps.Rd | InstProps.Ra);
Add("010110110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp, InstEmit.IsetpR, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn);
Add("0011011x0110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp, InstEmit.IsetpI, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn);
Add("010010110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp, InstEmit.IsetpC, InstProps.Ra | InstProps.Pd | InstProps.Pdn);
Add("010110110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset, InstEmit.IsetR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011011x0101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset, InstEmit.IsetI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("010010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset, InstEmit.IsetC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("010110110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp, InstEmit.IsetpR, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("0011011x0110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp, InstEmit.IsetpI, InstProps.Ra | InstProps.Ib | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("010010110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp, InstEmit.IsetpC, InstProps.Ra | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("111000100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Jcal, InstEmit.Jcal, InstProps.Bra);
Add("111000100001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Jmp, InstEmit.Jmp, InstProps.Ra | InstProps.Bra);
Add("111000100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Jmx, InstEmit.Jmx, InstProps.Ra | InstProps.Bra);
@ -196,17 +196,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("1110111011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldg, InstEmit.Ldg, InstProps.Rd | InstProps.Ra);
Add("1110111101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldl, InstEmit.Ldl, InstProps.Rd | InstProps.Ra);
Add("1110111101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lds, InstEmit.Lds, InstProps.Rd | InstProps.Ra);
Add("0101101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea, InstEmit.LeaR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd);
Add("0011011x11010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea, InstEmit.LeaI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Pd);
Add("0100101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea, InstEmit.LeaC, InstProps.Rd | InstProps.Ra | InstProps.Pd);
Add("0101101111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi, InstEmit.LeaHiR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.Pd);
Add("000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi, InstEmit.LeaHiC, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.Pd);
Add("0101101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea, InstEmit.LeaR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.LPd);
Add("0011011x11010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea, InstEmit.LeaI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.LPd);
Add("0100101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea, InstEmit.LeaC, InstProps.Rd | InstProps.Ra | InstProps.LPd);
Add("0101101111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi, InstEmit.LeaHiR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.LPd);
Add("000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi, InstEmit.LeaHiC, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.LPd);
Add("0101000011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lepc, InstEmit.Lepc);
Add("111000110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Longjmp, InstEmit.Longjmp, InstProps.Bra);
Add("0101110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop, InstEmit.LopR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd);
Add("0011100x01000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop, InstEmit.LopI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Pd);
Add("0100110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop, InstEmit.LopC, InstProps.Rd | InstProps.Ra | InstProps.Pd);
Add("0101101111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3, InstEmit.Lop3R, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.Pd);
Add("0101110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop, InstEmit.LopR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.LPd);
Add("0011100x01000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop, InstEmit.LopI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.LPd);
Add("0100110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop, InstEmit.LopC, InstProps.Rd | InstProps.Ra | InstProps.LPd);
Add("0101101111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3, InstEmit.Lop3R, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.LPd);
Add("001111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3, InstEmit.Lop3I, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Rc);
Add("0000001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3, InstEmit.Lop3C, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("000001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop32i, InstEmit.Lop32i, InstProps.Rd | InstProps.Ra);
@ -226,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("111000101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pbk, InstEmit.Pbk, InstProps.NoPred);
Add("111000101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pcnt, InstEmit.Pcnt, InstProps.NoPred);
Add("111000100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pexit, InstEmit.Pexit);
Add("1110111111101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pixld, InstEmit.Pixld, InstProps.Rd | InstProps.Ra);
Add("1110111111101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pixld, InstEmit.Pixld, InstProps.Rd | InstProps.Ra | InstProps.VPd);
Add("111000101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Plongjmp, InstEmit.Plongjmp, InstProps.Bra | InstProps.NoPred);
Add("0101110000001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Popc, InstEmit.PopcR, InstProps.Rd | InstProps.Rb);
Add("0011100x00001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Popc, InstEmit.PopcI, InstProps.Rd | InstProps.Ib);
@ -236,14 +236,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("0011011x1100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Prmt, InstEmit.PrmtI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Rc);
Add("010010111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Prmt, InstEmit.PrmtC, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("010100111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Prmt, InstEmit.PrmtRc, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("0101000010001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pset, InstEmit.Pset, InstProps.Rd);
Add("0101000010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Psetp, InstEmit.Psetp, InstProps.Pd | InstProps.Pdn);
Add("0101000010001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pset, InstEmit.Pset, InstProps.Rd | InstProps.Ps);
Add("0101000010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Psetp, InstEmit.Psetp, InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("1111000011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2b, InstEmit.R2b, InstProps.Rb);
Add("0101110011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2p, InstEmit.R2pR, InstProps.Ra | InstProps.Rb);
Add("0011100x11110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2p, InstEmit.R2pI, InstProps.Ra | InstProps.Ib);
Add("0100110011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2p, InstEmit.R2pC, InstProps.Ra);
Add("111000111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ram, InstEmit.Ram, InstProps.NoPred);
Add("1110101111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Red, InstEmit.Red, InstProps.Ra);
Add("1110101111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Red, InstEmit.Red, InstProps.Ra | InstProps.Rb2);
Add("111000110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ret, InstEmit.Ret, InstProps.Bra);
Add("0101110010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Rro, InstEmit.RroR, InstProps.Rd | InstProps.Rb);
Add("0011100x10010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Rro, InstEmit.RroI, InstProps.Rd | InstProps.Ib);
@ -251,16 +251,16 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("111000110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Rtt, InstEmit.Rtt, InstProps.NoPred);
Add("1111000011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.S2r, InstEmit.S2r, InstProps.Rd);
Add("111000110111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sam, InstEmit.Sam, InstProps.NoPred);
Add("0101110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel, InstEmit.SelR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x10100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel, InstEmit.SelI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel, InstEmit.SelC, InstProps.Rd | InstProps.Ra);
Add("0101110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel, InstEmit.SelR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Ps);
Add("0011100x10100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel, InstEmit.SelI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Ps);
Add("0100110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel, InstEmit.SelC, InstProps.Rd | InstProps.Ra | InstProps.Ps);
Add("111000101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Setcrsptr, InstEmit.Setcrsptr, InstProps.Ra | InstProps.NoPred);
Add("111000101111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Setlmembase, InstEmit.Setlmembase, InstProps.Ra | InstProps.NoPred);
Add("0101101111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf, InstEmit.ShfLR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("0101110011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf, InstEmit.ShfRR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("0011011x11111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf, InstEmit.ShfLI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Rc);
Add("0011100x11111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf, InstEmit.ShfRI, InstProps.Rd | InstProps.Ra | InstProps.Ib | InstProps.Rc);
Add("1110111100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shfl, InstEmit.Shfl, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.Pd);
Add("1110111100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shfl, InstEmit.Shfl, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.LPd);
Add("0101110001001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shl, InstEmit.ShlR, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("0011100x01001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shl, InstEmit.ShlI, InstProps.Rd | InstProps.Ra | InstProps.Ib);
Add("0100110001001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shl, InstEmit.ShlC, InstProps.Rd | InstProps.Ra);
@ -276,12 +276,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("1110101001110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB, InstEmit.SuatomB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("11101010x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suatom, InstEmit.Suatom, InstProps.Rd | InstProps.Ra | InstProps.Rb);
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.Pd2);
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd2);
Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.Pd2 | InstProps.TexB);
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.Pd2 | InstProps.Tex);
Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.Pd2 | InstProps.TexB);
Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.Pd2 | InstProps.Tex);
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.SPd);
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.SPd);
Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
Add("111010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra);
Add("111010110011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
@ -289,23 +289,23 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("11101011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
Add("11101011001x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra);
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Tex);
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.TexB);
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
Add("1101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Texs, InstEmit.Texs, InstProps.Rd | InstProps.Rd2 | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("1101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexsF16, InstEmit.TexsF16, InstProps.Rd | InstProps.Rd2 | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("11011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld, InstEmit.Tld, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Tex);
Add("11011101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TldB, InstEmit.TldB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.TexB);
Add("11011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld, InstEmit.Tld, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
Add("11011101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TldB, InstEmit.TldB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
Add("1101101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tlds, InstEmit.Tlds, InstProps.Rd | InstProps.Rd2 | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("1101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TldsF16, InstEmit.TldsF16, InstProps.Rd | InstProps.Rd2 | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4, InstEmit.Tld4, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Tex);
Add("1101111011xxxxxxxxxxxxx0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4B, InstEmit.Tld4B, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.TexB);
Add("110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4, InstEmit.Tld4, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
Add("1101111011xxxxxxxxxxxxx0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4B, InstEmit.Tld4B, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
Add("1101111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4s, InstEmit.Tld4s, InstProps.Rd | InstProps.Rd2 | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("1101111110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4sF16, InstEmit.Tld4sF16, InstProps.Rd | InstProps.Rd2 | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("1101111101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tmml, InstEmit.Tmml, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Tex);
Add("1101111101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TmmlB, InstEmit.TmmlB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TexB);
Add("1101111101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txa, InstEmit.Txa, InstProps.Rd | InstProps.Ra | InstProps.Tex);
Add("110111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txd, InstEmit.Txd, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Tex);
Add("1101111001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TxdB, InstEmit.TxdB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.TexB);
Add("110111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txd, InstEmit.Txd, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
Add("1101111001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TxdB, InstEmit.TxdB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
Add("1101111101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txq, InstEmit.Txq, InstProps.Rd | InstProps.Ra | InstProps.Tex);
Add("1101111101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TxqB, InstEmit.TxqB, InstProps.Rd | InstProps.Ra | InstProps.TexB);
Add("01010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vabsdiff, InstEmit.Vabsdiff, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
@ -313,10 +313,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
Add("001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vadd, InstEmit.Vadd, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("01011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vmad, InstEmit.Vmad, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("0011101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vmnmx, InstEmit.Vmnmx, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("0101000011011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vote, InstEmit.Vote, InstProps.Rd);
Add("0101000011011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vote, InstEmit.Vote, InstProps.Rd | InstProps.VPd | InstProps.Ps);
Add("0101000011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Votevtg, InstEmit.Votevtg);
Add("0100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vset, InstEmit.Vset, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("0101000011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vsetp, InstEmit.Vsetp, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn);
Add("0101000011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vsetp, InstEmit.Vsetp, InstProps.Ra | InstProps.Rb | InstProps.Pd | InstProps.Pdn | InstProps.Ps);
Add("01010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vshl, InstEmit.Vshl, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("01010110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vshr, InstEmit.Vshr, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
Add("0101101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Xmad, InstEmit.XmadR, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);

View file

@ -61,6 +61,16 @@ namespace Ryujinx.Graphics.Shader
return 16;
}
bool QueryHostSupportsFragmentShaderInterlock()
{
return true;
}
bool QueryHostSupportsFragmentShaderOrderingIntel()
{
return false;
}
bool QueryHostSupportsImageLoadFormatted()
{
return true;

View file

@ -56,14 +56,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Cont(EmitterContext context)
{
InstContUnsup op = context.GetOp<InstContUnsup>();
InstCont op = context.GetOp<InstCont>();
context.Config.GpuAccessor.Log("Shader instruction ContUnsup is not implemented.");
}
public static void Cset(EmitterContext context)
{
InstCsetUnsup op = context.GetOp<InstCsetUnsup>();
InstCset op = context.GetOp<InstCset>();
context.Config.GpuAccessor.Log("Shader instruction CsetUnsup is not implemented.");
}

View file

@ -67,7 +67,24 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
InstCal op = context.GetOp<InstCal>();
context.Call(context.GetFunctionId(context.CurrOp.GetAbsoluteAddress()), false);
DecodedFunction function = context.Program.GetFunctionByAddress(context.CurrOp.GetAbsoluteAddress());
if (function.IsCompilerGenerated)
{
switch (function.Type)
{
case FunctionType.BuiltInFSIBegin:
context.FSIBegin();
break;
case FunctionType.BuiltInFSIEnd:
context.FSIEnd();
break;
}
}
else
{
context.Call(function.Id, false);
}
}
public static void Exit(EmitterContext context)

View file

@ -109,28 +109,28 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
InstSuldDB op = context.GetOp<InstSuldDB>();
EmitSuld(context, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
EmitSuld(context, op.CacheOp, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
}
public static void SuldD(EmitterContext context)
{
InstSuldD op = context.GetOp<InstSuldD>();
EmitSuld(context, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
EmitSuld(context, op.CacheOp, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
}
public static void SuldB(EmitterContext context)
{
InstSuldB op = context.GetOp<InstSuldB>();
EmitSuld(context, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
}
public static void Suld(EmitterContext context)
{
InstSuld op = context.GetOp<InstSuld>();
EmitSuld(context, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
EmitSuld(context, op.CacheOp, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
}
public static void SuredB(EmitterContext context)
@ -151,28 +151,28 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
InstSustDB op = context.GetOp<InstSustDB>();
EmitSust(context, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
EmitSust(context, op.CacheOp, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
}
public static void SustD(EmitterContext context)
{
InstSustD op = context.GetOp<InstSustD>();
EmitSust(context, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
EmitSust(context, op.CacheOp, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
}
public static void SustB(EmitterContext context)
{
InstSustB op = context.GetOp<InstSustB>();
EmitSust(context, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
EmitSust(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
}
public static void Sust(EmitterContext context)
{
InstSust op = context.GetOp<InstSust>();
EmitSust(context, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
EmitSust(context, op.CacheOp, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
}
private static void EmitSuatom(
@ -299,6 +299,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
private static void EmitSuld(
EmitterContext context,
CacheOpLd cacheOp,
SuDim dimensions,
SuSize size,
int imm,
@ -363,6 +364,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
if (cacheOp == CacheOpLd.Cg)
{
flags |= TextureFlags.Coherent;
}
if (useComponents)
{
for (int compMask = (int)componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
@ -546,6 +552,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
private static void EmitSust(
EmitterContext context,
CacheOpSt cacheOp,
SuDim dimensions,
SuSize size,
int imm,
@ -654,6 +661,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
if (cacheOp == CacheOpSt.Cg)
{
flags |= TextureFlags.Coherent;
}
TextureOperation operation = context.CreateTextureOperation(
Instruction.ImageStore,
type,

View file

@ -62,6 +62,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
EmitVertex,
EndPrimitive,
ExponentB2,
FSIBegin,
FSIEnd,
FindFirstSetS32,
FindFirstSetU32,
Floor,

View file

@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
LodLevel = 1 << 5,
Offset = 1 << 6,
Offsets = 1 << 7,
Coherent = 1 << 8,
AtomicMask = 15 << 16,

View file

@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{
return type switch
{
OperandType.Argument => VariableType.S32,
OperandType.Attribute => VariableType.F32,
OperandType.AttributePerPatch => VariableType.F32,
OperandType.Constant => VariableType.S32,

View file

@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Shader
// Integer sampled textures must be noted for resolution scaling.
ResScaleUnsupported = 1 << 0,
NeedsScaleValue = 1 << 1,
ImageStore = 1 << 2
ImageStore = 1 << 2,
ImageCoherent = 1 << 3
}
}

View file

@ -10,24 +10,24 @@ namespace Ryujinx.Graphics.Shader.Translation
{
class EmitterContext
{
public Block CurrBlock { get; set; }
public InstOp CurrOp { get; set; }
public DecodedProgram Program { get; }
public ShaderConfig Config { get; }
public bool IsNonMain { get; }
public Block CurrBlock { get; set; }
public InstOp CurrOp { get; set; }
public int OperationsCount => _operations.Count;
private readonly IReadOnlyDictionary<ulong, int> _funcs;
private readonly List<Operation> _operations;
private readonly Dictionary<ulong, Operand> _labels;
public EmitterContext(ShaderConfig config, bool isNonMain, IReadOnlyDictionary<ulong, int> funcs)
public EmitterContext(DecodedProgram program, ShaderConfig config, bool isNonMain)
{
Program = program;
Config = config;
IsNonMain = isNonMain;
_funcs = funcs;
_operations = new List<Operation>();
_labels = new Dictionary<ulong, Operand>();
}
@ -154,11 +154,6 @@ namespace Ryujinx.Graphics.Shader.Translation
return label;
}
public int GetFunctionId(ulong address)
{
return _funcs[address];
}
public void PrepareForReturn()
{
if (!IsNonMain && Config.Stage == ShaderStage.Fragment)
@ -195,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation
Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);
Operand lblIsBgra = Label();
Operand lblEnd = Label();
Operand lblEnd = Label();
this.BranchIfTrue(lblIsBgra, isBgra);

View file

@ -361,6 +361,16 @@ namespace Ryujinx.Graphics.Shader.Translation
return context.Add(Instruction.SwizzleAdd, Local(), a, b, Const(mask));
}
public static void FSIBegin(this EmitterContext context)
{
context.Add(Instruction.FSIBegin);
}
public static void FSIEnd(this EmitterContext context)
{
context.Add(Instruction.FSIEnd);
}
public static Operand GroupMemoryBarrier(this EmitterContext context)
{
return context.Add(Instruction.GroupMemoryBarrier);

View file

@ -0,0 +1,866 @@
using Ryujinx.Graphics.Shader.Decoders;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Shader.Translation
{
static class FunctionMatch
{
private static IPatternTreeNode[] _fsiGetAddressTree = PatternTrees.GetFsiGetAddress();
private static IPatternTreeNode[] _fsiGetAddressV2Tree = PatternTrees.GetFsiGetAddressV2();
private static IPatternTreeNode[] _fsiIsLastWarpThreadPatternTree = PatternTrees.GetFsiIsLastWarpThread();
private static IPatternTreeNode[] _fsiBeginPatternTree = PatternTrees.GetFsiBeginPattern();
private static IPatternTreeNode[] _fsiEndPatternTree = PatternTrees.GetFsiEndPattern();
public static void RunPass(DecodedProgram program)
{
byte[] externalRegs = new byte[4];
bool hasGetAddress = false;
foreach (DecodedFunction function in program)
{
if (function == program.MainFunction)
{
continue;
}
int externalReg4 = 0;
TreeNode[] functionTree = BuildTree(function.Blocks);
if (Matches(_fsiGetAddressTree, functionTree))
{
externalRegs[1] = functionTree[0].GetRd();
externalRegs[2] = functionTree[2].GetRd();
externalRegs[3] = functionTree[1].GetRd();
externalReg4 = functionTree[3].GetRd();
}
else if (Matches(_fsiGetAddressV2Tree, functionTree))
{
externalRegs[1] = functionTree[2].GetRd();
externalRegs[2] = functionTree[1].GetRd();
externalRegs[3] = functionTree[0].GetRd();
externalReg4 = functionTree[3].GetRd();
}
// Ensure the register allocation is valid.
// If so, then we have a match.
if (externalRegs[1] != externalRegs[2] &&
externalRegs[2] != externalRegs[3] &&
externalRegs[1] != externalRegs[3] &&
externalRegs[1] + 1 != externalRegs[2] &&
externalRegs[1] + 1 != externalRegs[3] &&
externalRegs[1] + 1 == externalReg4 &&
externalRegs[2] != RegisterConsts.RegisterZeroIndex &&
externalRegs[3] != RegisterConsts.RegisterZeroIndex &&
externalReg4 != RegisterConsts.RegisterZeroIndex)
{
hasGetAddress = true;
function.Type = FunctionType.Unused;
break;
}
}
foreach (DecodedFunction function in program)
{
if (function.IsCompilerGenerated || function == program.MainFunction)
{
continue;
}
if (hasGetAddress)
{
TreeNode[] functionTree = BuildTree(function.Blocks);
if (MatchesFsi(_fsiBeginPatternTree, program, function, functionTree, externalRegs))
{
function.Type = FunctionType.BuiltInFSIBegin;
continue;
}
else if (MatchesFsi(_fsiEndPatternTree, program, function, functionTree, externalRegs))
{
function.Type = FunctionType.BuiltInFSIEnd;
continue;
}
}
}
}
private struct TreeNodeUse
{
public TreeNode Node { get; }
public int Index { get; }
public bool Inverted { get; }
private TreeNodeUse(int index, bool inverted, TreeNode node)
{
Index = index;
Inverted = inverted;
Node = node;
}
public TreeNodeUse(int index, TreeNode node) : this(index, false, node)
{
}
public TreeNodeUse Flip()
{
return new TreeNodeUse(Index, !Inverted, Node);
}
}
private enum TreeNodeType : byte
{
Op,
Label
}
private class TreeNode
{
public readonly InstOp Op;
public readonly List<TreeNodeUse> Uses;
public TreeNodeType Type { get; }
public byte Order { get; }
public TreeNode(byte order)
{
Type = TreeNodeType.Label;
Order = order;
}
public TreeNode(InstOp op, byte order)
{
Op = op;
Uses = new List<TreeNodeUse>();
Type = TreeNodeType.Op;
Order = order;
}
public byte GetPd()
{
return (byte)((Op.RawOpCode >> 3) & 7);
}
public byte GetRd()
{
return (byte)Op.RawOpCode;
}
}
private static TreeNode[] BuildTree(Block[] blocks)
{
List<TreeNode> nodes = new List<TreeNode>();
Dictionary<ulong, TreeNode> labels = new Dictionary<ulong, TreeNode>();
TreeNodeUse[] predDefs = new TreeNodeUse[RegisterConsts.PredsCount];
TreeNodeUse[] gprDefs = new TreeNodeUse[RegisterConsts.GprsCount];
void DefPred(byte predIndex, int index, TreeNode node)
{
if (predIndex != RegisterConsts.PredicateTrueIndex)
{
predDefs[predIndex] = new TreeNodeUse(index, node);
}
}
void DefGpr(byte regIndex, int index, TreeNode node)
{
if (regIndex != RegisterConsts.RegisterZeroIndex)
{
gprDefs[regIndex] = new TreeNodeUse(index, node);
}
}
TreeNodeUse UsePred(byte predIndex, bool predInv)
{
if (predIndex != RegisterConsts.PredicateTrueIndex)
{
TreeNodeUse use = predDefs[predIndex];
if (use.Node != null)
{
nodes.Remove(use.Node);
}
else
{
use = new TreeNodeUse(-(predIndex + 2), null);
}
return predInv ? use.Flip() : use;
}
return new TreeNodeUse(-1, null);
}
TreeNodeUse UseGpr(byte regIndex)
{
if (regIndex != RegisterConsts.RegisterZeroIndex)
{
TreeNodeUse use = gprDefs[regIndex];
if (use.Node != null)
{
nodes.Remove(use.Node);
}
else
{
use = new TreeNodeUse(-(regIndex + 2), null);
}
return use;
}
return new TreeNodeUse(-1, null);
}
byte order = 0;
for (int index = 0; index < blocks.Length; index++)
{
Block block = blocks[index];
if (block.Predecessors.Count > 1)
{
TreeNode label = new TreeNode(order++);
nodes.Add(label);
labels.Add(block.Address, label);
}
for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++)
{
InstOp op = block.OpCodes[opIndex];
TreeNode node = new TreeNode(op, IsOrderDependant(op.Name) ? order : (byte)0);
// Add uses.
if (!op.Props.HasFlag(InstProps.NoPred))
{
byte predIndex = (byte)((op.RawOpCode >> 16) & 7);
bool predInv = (op.RawOpCode & 0x80000) != 0;
node.Uses.Add(UsePred(predIndex, predInv));
}
if (op.Props.HasFlag(InstProps.Ps))
{
byte predIndex = (byte)((op.RawOpCode >> 39) & 7);
bool predInv = (op.RawOpCode & 0x40000000000) != 0;
node.Uses.Add(UsePred(predIndex, predInv));
}
if (op.Props.HasFlag(InstProps.Ra))
{
byte ra = (byte)(op.RawOpCode >> 8);
node.Uses.Add(UseGpr(ra));
}
if ((op.Props & (InstProps.Rb | InstProps.Rb2)) != 0)
{
byte rb = op.Props.HasFlag(InstProps.Rb2) ? (byte)op.RawOpCode : (byte)(op.RawOpCode >> 20);
node.Uses.Add(UseGpr(rb));
}
if (op.Props.HasFlag(InstProps.Rc))
{
byte rc = (byte)(op.RawOpCode >> 39);
node.Uses.Add(UseGpr(rc));
}
if (op.Name == InstName.Bra && labels.TryGetValue(op.GetAbsoluteAddress(), out TreeNode label))
{
node.Uses.Add(new TreeNodeUse(0, label));
}
// Make definitions.
int defIndex = 0;
InstProps pdType = op.Props & InstProps.PdMask;
if (pdType != 0)
{
int bit = pdType switch
{
InstProps.Pd => 3,
InstProps.LPd => 48,
InstProps.SPd => 30,
InstProps.TPd => 51,
InstProps.VPd => 45,
_ => throw new InvalidOperationException($"Table has unknown predicate destination {pdType}.")
};
byte predIndex = (byte)((op.RawOpCode >> bit) & 7);
DefPred(predIndex, defIndex++, node);
}
if (op.Props.HasFlag(InstProps.Rd))
{
byte rd = (byte)op.RawOpCode;
DefGpr(rd, defIndex++, node);
}
nodes.Add(node);
}
}
return nodes.ToArray();
}
private static bool IsOrderDependant(InstName name)
{
switch (name)
{
case InstName.Atom:
case InstName.AtomCas:
case InstName.Atoms:
case InstName.AtomsCas:
case InstName.Ld:
case InstName.Ldg:
case InstName.Ldl:
case InstName.Lds:
case InstName.Suatom:
case InstName.SuatomB:
case InstName.SuatomB2:
case InstName.SuatomCas:
case InstName.SuatomCasB:
case InstName.Suld:
case InstName.SuldB:
case InstName.SuldD:
case InstName.SuldDB:
return true;
}
return false;
}
private interface IPatternTreeNode
{
List<PatternTreeNodeUse> Uses { get; }
InstName Name { get; }
TreeNodeType Type { get; }
byte Order { get; }
bool IsImm { get; }
bool Matches(in InstOp opInfo);
}
private struct PatternTreeNodeUse
{
public IPatternTreeNode Node { get; }
public int Index { get; }
public bool Inverted { get; }
public PatternTreeNodeUse Inv => new PatternTreeNodeUse(Index, !Inverted, Node);
private PatternTreeNodeUse(int index, bool inverted, IPatternTreeNode node)
{
Index = index;
Inverted = inverted;
Node = node;
}
public PatternTreeNodeUse(int index, IPatternTreeNode node) : this(index, false, node)
{
}
}
private class PatternTreeNode<T> : IPatternTreeNode
{
public List<PatternTreeNodeUse> Uses { get; }
private readonly Func<T, bool> _match;
public InstName Name { get; }
public TreeNodeType Type { get; }
public byte Order { get; }
public bool IsImm { get; }
public PatternTreeNodeUse Out => new PatternTreeNodeUse(0, this);
public PatternTreeNode(InstName name, Func<T, bool> match, TreeNodeType type = TreeNodeType.Op, byte order = 0, bool isImm = false)
{
Name = name;
_match = match;
Type = type;
Order = order;
IsImm = isImm;
Uses = new List<PatternTreeNodeUse>();
}
public PatternTreeNode<T> Use(PatternTreeNodeUse use)
{
Uses.Add(use);
return this;
}
public PatternTreeNodeUse OutAt(int index)
{
return new PatternTreeNodeUse(index, this);
}
public bool Matches(in InstOp opInfo)
{
if (opInfo.Name != Name)
{
return false;
}
ulong rawOp = opInfo.RawOpCode;
T op = Unsafe.As<ulong, T>(ref rawOp);
if (!_match(op))
{
return false;
}
return true;
}
}
private static bool MatchesFsi(
IPatternTreeNode[] pattern,
DecodedProgram program,
DecodedFunction function,
TreeNode[] functionTree,
byte[] externalRegs)
{
if (function.Blocks.Length == 0)
{
return false;
}
InstOp callOp = function.Blocks[0].GetLastOp();
if (callOp.Name != InstName.Cal)
{
return false;
}
DecodedFunction callTarget = program.GetFunctionByAddress(callOp.GetAbsoluteAddress());
TreeNode[] callTargetTree = null;
if (callTarget == null || !Matches(_fsiIsLastWarpThreadPatternTree, callTargetTree = BuildTree(callTarget.Blocks)))
{
return false;
}
externalRegs[0] = callTargetTree[0].GetPd();
if (Matches(pattern, functionTree, externalRegs))
{
callTarget.RemoveCaller(function);
return true;
}
return false;
}
private static bool Matches(IPatternTreeNode[] pTree, TreeNode[] cTree, byte[] externalRegs = null)
{
if (pTree.Length != cTree.Length)
{
return false;
}
for (int index = 0; index < pTree.Length; index++)
{
if (!Matches(pTree[index], cTree[index], externalRegs))
{
return false;
}
}
return true;
}
private static bool Matches(IPatternTreeNode pTreeNode, TreeNode cTreeNode, byte[] externalRegs)
{
if (!pTreeNode.Matches(in cTreeNode.Op) ||
pTreeNode.Type != cTreeNode.Type ||
pTreeNode.Order != cTreeNode.Order ||
pTreeNode.IsImm != cTreeNode.Op.Props.HasFlag(InstProps.Ib))
{
return false;
}
if (pTreeNode.Type == TreeNodeType.Op)
{
if (pTreeNode.Uses.Count != cTreeNode.Uses.Count)
{
return false;
}
for (int index = 0; index < pTreeNode.Uses.Count; index++)
{
var pUse = pTreeNode.Uses[index];
var cUse = cTreeNode.Uses[index];
if (pUse.Index <= -2)
{
if (externalRegs[-pUse.Index - 2] != (-cUse.Index - 2))
{
return false;
}
}
else if (pUse.Index != cUse.Index)
{
return false;
}
if (pUse.Inverted != cUse.Inverted || (pUse.Node == null) != (cUse.Node == null))
{
return false;
}
if (pUse.Node != null && !Matches(pUse.Node, cUse.Node, externalRegs))
{
return false;
}
}
}
return true;
}
private static class PatternTrees
{
public static IPatternTreeNode[] GetFsiGetAddress()
{
var affinityValue = S2r(SReg.Affinity).Use(PT).Out;
var orderingTicketValue = S2r(SReg.OrderingTicket).Use(PT).Out;
return new IPatternTreeNode[]
{
Iscadd(cc: true, 2, 0, 404)
.Use(PT)
.Use(Iscadd(cc: false, 8)
.Use(PT)
.Use(Lop32i(LogicOp.And, 0xff)
.Use(PT)
.Use(affinityValue).Out)
.Use(Lop32i(LogicOp.And, 0xff)
.Use(PT)
.Use(orderingTicketValue).Out).Out),
ShrU32W(16)
.Use(PT)
.Use(orderingTicketValue),
Iadd32i(0x200)
.Use(PT)
.Use(Lop32i(LogicOp.And, 0xfe00)
.Use(PT)
.Use(orderingTicketValue).Out),
Iadd(x: true, 0, 405).Use(PT).Use(RZ),
Ret().Use(PT)
};
}
public static IPatternTreeNode[] GetFsiGetAddressV2()
{
var affinityValue = S2r(SReg.Affinity).Use(PT).Out;
var orderingTicketValue = S2r(SReg.OrderingTicket).Use(PT).Out;
return new IPatternTreeNode[]
{
ShrU32W(16)
.Use(PT)
.Use(orderingTicketValue),
Iadd32i(0x200)
.Use(PT)
.Use(Lop32i(LogicOp.And, 0xfe00)
.Use(PT)
.Use(orderingTicketValue).Out),
Iscadd(cc: true, 2, 0, 404)
.Use(PT)
.Use(Bfi(0x808)
.Use(PT)
.Use(affinityValue)
.Use(Lop32i(LogicOp.And, 0xff)
.Use(PT)
.Use(orderingTicketValue).Out).Out),
Iadd(x: true, 0, 405).Use(PT).Use(RZ),
Ret().Use(PT)
};
}
public static IPatternTreeNode[] GetFsiIsLastWarpThread()
{
var threadKillValue = S2r(SReg.ThreadKill).Use(PT).Out;
var laneIdValue = S2r(SReg.LaneId).Use(PT).Out;
return new IPatternTreeNode[]
{
IsetpU32(IComp.Eq)
.Use(PT)
.Use(PT)
.Use(FloU32()
.Use(PT)
.Use(Vote(VoteMode.Any)
.Use(PT)
.Use(IsetpU32(IComp.Ne)
.Use(PT)
.Use(PT)
.Use(Lop(negB: true, LogicOp.PassB)
.Use(PT)
.Use(RZ)
.Use(threadKillValue).OutAt(1))
.Use(RZ).Out).OutAt(1)).Out)
.Use(laneIdValue),
Ret().Use(PT)
};
}
public static IPatternTreeNode[] GetFsiBeginPattern()
{
var addressLowValue = CallArg(1);
static PatternTreeNodeUse HighU16Equals(PatternTreeNodeUse x)
{
var expectedValue = CallArg(3);
return IsetpU32(IComp.Eq)
.Use(PT)
.Use(PT)
.Use(ShrU32W(16).Use(PT).Use(x).Out)
.Use(expectedValue).Out;
}
PatternTreeNode<byte> label;
return new IPatternTreeNode[]
{
Cal(),
Ret().Use(CallArg(0).Inv),
Ret()
.Use(HighU16Equals(LdgE(CacheOpLd.Cg, LsSize.B32)
.Use(PT)
.Use(addressLowValue).Out)),
label = Label(),
Bra()
.Use(HighU16Equals(LdgE(CacheOpLd.Cg, LsSize.B32, 1)
.Use(PT)
.Use(addressLowValue).Out).Inv)
.Use(label.Out),
Ret().Use(PT)
};
}
public static IPatternTreeNode[] GetFsiEndPattern()
{
var voteResult = Vote(VoteMode.All).Use(PT).Use(PT).OutAt(1);
var popcResult = Popc().Use(PT).Use(voteResult).Out;
var threadKillValue = S2r(SReg.ThreadKill).Use(PT).Out;
var laneIdValue = S2r(SReg.LaneId).Use(PT).Out;
var addressLowValue = CallArg(1);
var incrementValue = CallArg(2);
return new IPatternTreeNode[]
{
Cal(),
Ret().Use(CallArg(0).Inv),
Membar(Decoders.Membar.Vc).Use(PT),
Ret().Use(IsetpU32(IComp.Ne)
.Use(PT)
.Use(PT)
.Use(threadKillValue)
.Use(RZ).Out),
RedE(RedOp.Add, AtomSize.U32)
.Use(IsetpU32(IComp.Eq)
.Use(PT)
.Use(PT)
.Use(FloU32()
.Use(PT)
.Use(voteResult).Out)
.Use(laneIdValue).Out)
.Use(addressLowValue)
.Use(Xmad(XmadCop.Cbcc, psl: true, hiloA: true, hiloB: true)
.Use(PT)
.Use(incrementValue)
.Use(Xmad(XmadCop.Cfull, mrg: true, hiloB: true)
.Use(PT)
.Use(incrementValue)
.Use(popcResult)
.Use(RZ).Out)
.Use(Xmad(XmadCop.Cfull)
.Use(PT)
.Use(incrementValue)
.Use(popcResult)
.Use(RZ).Out).Out),
Ret().Use(PT)
};
}
private static PatternTreeNode<InstBfiI> Bfi(int imm)
{
return new(InstName.Bfi, (op) => !op.WriteCC && op.Imm20 == imm, isImm: true);
}
private static PatternTreeNode<InstBra> Bra()
{
return new(InstName.Bra, (op) => op.Ccc == Ccc.T && !op.Ca);
}
private static PatternTreeNode<InstCal> Cal()
{
return new(InstName.Cal, (op) => !op.Ca && op.Inc);
}
private static PatternTreeNode<InstFloR> FloU32()
{
return new(InstName.Flo, (op) => !op.Signed && !op.Sh && !op.NegB && !op.WriteCC);
}
private static PatternTreeNode<InstIaddC> Iadd(bool x, int cbufSlot, int cbufOffset)
{
return new(InstName.Iadd, (op) =>
!op.Sat &&
!op.WriteCC &&
op.X == x &&
op.AvgMode == AvgMode.NoNeg &&
op.CbufSlot == cbufSlot &&
op.CbufOffset == cbufOffset);
}
private static PatternTreeNode<InstIadd32i> Iadd32i(int imm)
{
return new(InstName.Iadd32i, (op) => !op.Sat && !op.WriteCC && !op.X && op.AvgMode == AvgMode.NoNeg && op.Imm32 == imm);
}
private static PatternTreeNode<InstIscaddR> Iscadd(bool cc, int imm)
{
return new(InstName.Iscadd, (op) => op.WriteCC == cc && op.AvgMode == AvgMode.NoNeg && op.Imm5 == imm);
}
private static PatternTreeNode<InstIscaddC> Iscadd(bool cc, int imm, int cbufSlot, int cbufOffset)
{
return new(InstName.Iscadd, (op) =>
op.WriteCC == cc &&
op.AvgMode == AvgMode.NoNeg &&
op.Imm5 == imm &&
op.CbufSlot == cbufSlot &&
op.CbufOffset == cbufOffset);
}
private static PatternTreeNode<InstIsetpR> IsetpU32(IComp comp)
{
return new(InstName.Isetp, (op) => !op.Signed && op.IComp == comp && op.Bop == BoolOp.And);
}
private static PatternTreeNode<byte> Label()
{
return new(InstName.Invalid, (op) => true, type: TreeNodeType.Label);
}
private static PatternTreeNode<InstLopR> Lop(bool negB, LogicOp logicOp)
{
return new(InstName.Lop, (op) => !op.NegA && op.NegB == negB && !op.WriteCC && !op.X && op.Lop == logicOp && op.PredicateOp == PredicateOp.F);
}
private static PatternTreeNode<InstLop32i> Lop32i(LogicOp logicOp, int imm)
{
return new(InstName.Lop32i, (op) => !op.NegA && !op.NegB && !op.X && !op.WriteCC && op.LogicOp == logicOp && op.Imm32 == imm);
}
private static PatternTreeNode<InstMembar> Membar(Membar membar)
{
return new(InstName.Membar, (op) => op.Membar == membar);
}
private static PatternTreeNode<InstPopcR> Popc()
{
return new(InstName.Popc, (op) => !op.NegB);
}
private static PatternTreeNode<InstRet> Ret()
{
return new(InstName.Ret, (op) => op.Ccc == Ccc.T);
}
private static PatternTreeNode<InstS2r> S2r(SReg reg)
{
return new(InstName.S2r, (op) => op.SReg == reg);
}
private static PatternTreeNode<InstShrI> ShrU32W(int imm)
{
return new(InstName.Shr, (op) => !op.Signed && !op.Brev && op.M && op.XMode == 0 && op.Imm20 == imm, isImm: true);
}
private static PatternTreeNode<InstLdg> LdgE(CacheOpLd cacheOp, LsSize size, byte order = 0)
{
return new(InstName.Ldg, (op) => op.E && op.CacheOp == cacheOp && op.LsSize == size, order: order);
}
private static PatternTreeNode<InstRed> RedE(RedOp redOp, AtomSize size, byte order = 0)
{
return new(InstName.Red, (op) => op.E && op.RedOp == redOp && op.RedSize == size, order: order);
}
private static PatternTreeNode<InstVote> Vote(VoteMode mode)
{
return new(InstName.Vote, (op) => op.VoteMode == mode);
}
private static PatternTreeNode<InstXmadR> Xmad(XmadCop cop, bool psl = false, bool mrg = false, bool hiloA = false, bool hiloB = false)
{
return new(InstName.Xmad, (op) => op.XmadCop == cop && op.Psl == psl && op.Mrg == mrg && op.HiloA == hiloA && op.HiloB == hiloB);
}
private static PatternTreeNodeUse PT => PTOrRZ();
private static PatternTreeNodeUse RZ => PTOrRZ();
private static PatternTreeNodeUse Undef => new PatternTreeNodeUse(0, null);
private static PatternTreeNodeUse CallArg(int index)
{
return new PatternTreeNodeUse(-(index + 2), null);
}
private static PatternTreeNodeUse PTOrRZ()
{
return new PatternTreeNodeUse(-1, null);
}
}
private static void PrintTreeNode(TreeNode node, string indentation)
{
Console.WriteLine($" {node.Op.Name}");
for (int i = 0; i < node.Uses.Count; i++)
{
TreeNodeUse use = node.Uses[i];
bool last = i == node.Uses.Count - 1;
char separator = last ? '`' : '|';
if (use.Node != null)
{
Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
}
else
{
Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
}
}
}
private static void PrintTreeNode(IPatternTreeNode node, string indentation)
{
Console.WriteLine($" {node.Name}");
for (int i = 0; i < node.Uses.Count; i++)
{
PatternTreeNodeUse use = node.Uses[i];
bool last = i == node.Uses.Count - 1;
char separator = last ? '`' : '|';
if (use.Node != null)
{
Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
}
else
{
Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
}
}
}
}
}

View file

@ -315,15 +315,16 @@ namespace Ryujinx.Graphics.Shader.Translation
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
bool accurateType = inst != Instruction.Lod;
bool coherent = flags.HasFlag(TextureFlags.Coherent);
if (isImage)
{
SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false);
SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false, coherent);
}
else
{
bool intCoords = flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize;
SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType);
SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType, coherent);
}
}
@ -335,7 +336,8 @@ namespace Ryujinx.Graphics.Shader.Translation
TextureFormat format,
bool intCoords,
bool write,
bool accurateType)
bool accurateType,
bool coherent)
{
var dimensions = type.GetDimensions();
var isIndexed = type.HasFlag(SamplerType.Indexed);
@ -361,6 +363,11 @@ namespace Ryujinx.Graphics.Shader.Translation
usageFlags |= TextureUsageFlags.ImageStore;
}
if (coherent)
{
usageFlags |= TextureUsageFlags.ImageCoherent;
}
int arraySize = isIndexed ? SamplerArraySize : 1;
for (int layer = 0; layer < arraySize; layer++)

View file

@ -4,7 +4,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation.Optimizations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@ -33,9 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
counts ??= new TranslationCounts();
Block[][] cfg = DecodeShader(address, gpuAccessor, options, counts, out ShaderConfig config);
return new TranslatorContext(address, cfg, config);
return DecodeShader(address, gpuAccessor, options, counts);
}
internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo)
@ -112,35 +110,29 @@ namespace Ryujinx.Graphics.Shader.Translation
return program;
}
private static Block[][] DecodeShader(
ulong address,
IGpuAccessor gpuAccessor,
TranslationOptions options,
TranslationCounts counts,
out ShaderConfig config)
private static TranslatorContext DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationOptions options, TranslationCounts counts)
{
Block[][] cfg;
ShaderConfig config;
DecodedProgram program;
ulong maxEndAddress = 0;
if ((options.Flags & TranslationFlags.Compute) != 0)
{
config = new ShaderConfig(gpuAccessor, options, counts);
cfg = Decoder.Decode(config, address);
program = Decoder.Decode(config, address);
}
else
{
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, options, counts);
cfg = Decoder.Decode(config, address + HeaderSize);
program = Decoder.Decode(config, address + HeaderSize);
}
for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
foreach (DecodedFunction function in program)
{
for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
foreach (Block block in function.Blocks)
{
Block block = cfg[funcIndex][blkIndex];
if (maxEndAddress < block.EndAddress)
{
maxEndAddress = block.EndAddress;
@ -164,36 +156,36 @@ namespace Ryujinx.Graphics.Shader.Translation
config.SizeAdd((int)maxEndAddress + (options.Flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize));
return cfg;
return new TranslatorContext(address, program, config);
}
internal static FunctionCode[] EmitShader(Block[][] cfg, ShaderConfig config, bool initializeOutputs, out int initializationOperations)
internal static FunctionCode[] EmitShader(DecodedProgram program, ShaderConfig config, bool initializeOutputs, out int initializationOperations)
{
initializationOperations = 0;
Dictionary<ulong, int> funcIds = new Dictionary<ulong, int>();
FunctionMatch.RunPass(program);
for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
foreach (DecodedFunction function in program.OrderBy(x => x.Address).Where(x => !x.IsCompilerGenerated))
{
funcIds.Add(cfg[funcIndex][0].Address, funcIndex);
program.AddFunctionAndSetId(function);
}
List<FunctionCode> funcs = new List<FunctionCode>();
FunctionCode[] functions = new FunctionCode[program.FunctionsWithIdCount];
for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
for (int index = 0; index < functions.Length; index++)
{
EmitterContext context = new EmitterContext(config, funcIndex != 0, funcIds);
EmitterContext context = new EmitterContext(program, config, index != 0);
if (initializeOutputs && funcIndex == 0)
if (initializeOutputs && index == 0)
{
EmitOutputsInitialization(context, config);
initializationOperations = context.OperationsCount;
}
for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
{
Block block = cfg[funcIndex][blkIndex];
DecodedFunction function = program.GetFunctionById(index);
foreach (Block block in function.Blocks)
{
context.CurrBlock = block;
context.MarkLabel(context.GetLabel(block.Address));
@ -201,10 +193,10 @@ namespace Ryujinx.Graphics.Shader.Translation
EmitOps(context, block);
}
funcs.Add(new FunctionCode(context.GetOperations()));
functions[index] = new FunctionCode(context.GetOperations());
}
return funcs.ToArray();
return functions;
}
private static void EmitOutputsInitialization(EmitterContext context, ShaderConfig config)

View file

@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
public class TranslatorContext
{
private readonly Block[][] _cfg;
private readonly DecodedProgram _program;
private ShaderConfig _config;
public ulong Address { get; }
@ -23,11 +23,11 @@ namespace Ryujinx.Graphics.Shader.Translation
public IGpuAccessor GpuAccessor => _config.GpuAccessor;
internal TranslatorContext(ulong address, Block[][] cfg, ShaderConfig config)
internal TranslatorContext(ulong address, DecodedProgram program, ShaderConfig config)
{
Address = address;
_program = program;
_config = config;
_cfg = cfg;
}
private static bool IsUserAttribute(Operand operand)
@ -141,13 +141,13 @@ namespace Ryujinx.Graphics.Shader.Translation
nextStage._config.UsedInputAttributesPerPatch);
}
FunctionCode[] code = EmitShader(_cfg, _config, initializeOutputs: other == null, out _);
FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
if (other != null)
{
other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, 0);
FunctionCode[] otherCode = EmitShader(other._cfg, other._config, initializeOutputs: true, out int aStart);
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
code = Combine(otherCode, code, aStart);