Refactor shader GPU state and memory access (#1203)
* Refactor shader GPU state and memory access * Fix NVDEC project build * Address PR feedback and add missing XML comments
This commit is contained in:
parent
7f500e7cae
commit
b8eb6abecc
35 changed files with 633 additions and 684 deletions
|
@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
string inPrimitive = ((InputTopology)context.Config.QueryInfo(QueryInfoName.PrimitiveTopology)).ToGlslString();
|
||||
string inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology().ToGlslString();
|
||||
|
||||
context.AppendLine($"layout ({inPrimitive}) in;");
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
|
||||
if (context.Config.Stage == ShaderStage.Compute)
|
||||
{
|
||||
int localMemorySize = BitUtils.DivRoundUp(context.Config.QueryInfo(QueryInfoName.ComputeLocalMemorySize), 4);
|
||||
int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
|
||||
|
||||
if (localMemorySize != 0)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
context.AppendLine();
|
||||
}
|
||||
|
||||
int sharedMemorySize = BitUtils.DivRoundUp(context.Config.QueryInfo(QueryInfoName.ComputeSharedMemorySize), 4);
|
||||
int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4);
|
||||
|
||||
if (sharedMemorySize != 0)
|
||||
{
|
||||
|
@ -124,9 +124,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
}
|
||||
else
|
||||
{
|
||||
string localSizeX = NumberFormatter.FormatInt(context.Config.QueryInfo(QueryInfoName.ComputeLocalSizeX));
|
||||
string localSizeY = NumberFormatter.FormatInt(context.Config.QueryInfo(QueryInfoName.ComputeLocalSizeY));
|
||||
string localSizeZ = NumberFormatter.FormatInt(context.Config.QueryInfo(QueryInfoName.ComputeLocalSizeZ));
|
||||
string localSizeX = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeX());
|
||||
string localSizeY = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeY());
|
||||
string localSizeZ = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeZ());
|
||||
|
||||
context.AppendLine(
|
||||
"layout (" +
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Ryujinx.Graphics.Shader.Instructions;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -10,7 +9,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
{
|
||||
static class Decoder
|
||||
{
|
||||
public static Block[] Decode(ReadOnlySpan<byte> code, ulong headerSize)
|
||||
public static Block[] Decode(IGpuAccessor gpuAccessor, ulong startAddress)
|
||||
{
|
||||
List<Block> blocks = new List<Block>();
|
||||
|
||||
|
@ -18,8 +17,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
|
||||
Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
|
||||
|
||||
ulong maxAddress = (ulong)code.Length - headerSize;
|
||||
|
||||
Block GetBlock(ulong blkAddress)
|
||||
{
|
||||
if (!visited.TryGetValue(blkAddress, out Block block))
|
||||
|
@ -56,7 +53,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
}
|
||||
|
||||
// If we have a block after the current one, set the limit address.
|
||||
ulong limitAddress = maxAddress;
|
||||
ulong limitAddress = ulong.MaxValue;
|
||||
|
||||
if (nBlkIndex != blocks.Count)
|
||||
{
|
||||
|
@ -74,7 +71,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
}
|
||||
}
|
||||
|
||||
FillBlock(code, currBlock, limitAddress, headerSize);
|
||||
FillBlock(gpuAccessor, currBlock, limitAddress, startAddress);
|
||||
|
||||
if (currBlock.OpCodes.Count != 0)
|
||||
{
|
||||
|
@ -82,11 +79,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
// including those from SSY/PBK instructions.
|
||||
foreach (OpCodePush pushOp in currBlock.PushOpCodes)
|
||||
{
|
||||
if (pushOp.GetAbsoluteAddress() >= maxAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
GetBlock(pushOp.GetAbsoluteAddress());
|
||||
}
|
||||
|
||||
|
@ -98,11 +90,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
|
||||
if (lastOp is OpCodeBranch opBr)
|
||||
{
|
||||
if (opBr.GetAbsoluteAddress() >= maxAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
currBlock.Branch = GetBlock(opBr.GetAbsoluteAddress());
|
||||
}
|
||||
else if (lastOp is OpCodeBranchIndir opBrIndir)
|
||||
|
@ -141,7 +128,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
}
|
||||
|
||||
// Do we have a block after the current one?
|
||||
if (!IsExit(currBlock.GetLastOp()) && currBlock.BrIndir != null && currBlock.EndAddress < maxAddress)
|
||||
if (!IsExit(currBlock.GetLastOp()) && currBlock.BrIndir != null)
|
||||
{
|
||||
bool targetVisited = visited.ContainsKey(currBlock.EndAddress);
|
||||
|
||||
|
@ -203,10 +190,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
}
|
||||
|
||||
private static void FillBlock(
|
||||
ReadOnlySpan<byte> code,
|
||||
Block block,
|
||||
ulong limitAddress,
|
||||
ulong startAddress)
|
||||
IGpuAccessor gpuAccessor,
|
||||
Block block,
|
||||
ulong limitAddress,
|
||||
ulong startAddress)
|
||||
{
|
||||
ulong address = block.Address;
|
||||
|
||||
|
@ -225,14 +212,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
continue;
|
||||
}
|
||||
|
||||
uint word0 = BinaryPrimitives.ReadUInt32LittleEndian(code.Slice((int)(startAddress + address)));
|
||||
uint word1 = BinaryPrimitives.ReadUInt32LittleEndian(code.Slice((int)(startAddress + address + 4)));
|
||||
|
||||
ulong opAddress = address;
|
||||
|
||||
address += 8;
|
||||
|
||||
long opCode = word0 | (long)word1 << 32;
|
||||
long opCode = gpuAccessor.MemoryRead<long>(startAddress + opAddress);
|
||||
|
||||
(InstEmitter emitter, OpCodeTable.OpActivator opActivator) = OpCodeTable.GetEmitter(opCode);
|
||||
|
||||
|
|
67
Ryujinx.Graphics.Shader/IGpuAccessor.cs
Normal file
67
Ryujinx.Graphics.Shader/IGpuAccessor.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public interface IGpuAccessor
|
||||
{
|
||||
public void Log(string message)
|
||||
{
|
||||
// No default log output.
|
||||
}
|
||||
|
||||
T MemoryRead<T>(ulong address) where T : unmanaged;
|
||||
|
||||
public int QueryComputeLocalSizeX()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalSizeY()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalSizeZ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int QueryComputeLocalMemorySize()
|
||||
{
|
||||
return 0x1000;
|
||||
}
|
||||
|
||||
public int QueryComputeSharedMemorySize()
|
||||
{
|
||||
return 0xc000;
|
||||
}
|
||||
|
||||
public bool QueryIsTextureBuffer(int handle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool QueryIsTextureRectangle(int handle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public InputTopology QueryPrimitiveTopology()
|
||||
{
|
||||
return InputTopology.Points;
|
||||
}
|
||||
|
||||
public int QueryStorageBufferOffsetAlignment()
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
public bool QuerySupportsNonConstantTextureOffset()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public TextureFormat QueryTextureFormat(int handle)
|
||||
{
|
||||
return TextureFormat.R8G8B8A8Unorm;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (intType == IntegerType.U64)
|
||||
{
|
||||
context.Config.PrintLog("Unimplemented 64-bits F2I.");
|
||||
context.Config.GpuAccessor.Log("Unimplemented 64-bits F2I.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (srcType == IntegerType.U64 || dstType == IntegerType.U64)
|
||||
{
|
||||
context.Config.PrintLog("Invalid I2I encoding.");
|
||||
context.Config.GpuAccessor.Log("Invalid I2I encoding.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (scale.AsFloat() == 1)
|
||||
{
|
||||
context.Config.PrintLog($"Invalid FP multiply scale \"{op.Scale}\".");
|
||||
context.Config.GpuAccessor.Log($"Invalid FP multiply scale \"{op.Scale}\".");
|
||||
}
|
||||
|
||||
if (isFP64)
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid barrier mode: {op.Mode}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid barrier mode: {op.Mode}.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (op.Size > IntegerSize.B64)
|
||||
{
|
||||
context.Config.PrintLog($"Invalid LDC size: {op.Size}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid LDC size: {op.Size}.");
|
||||
}
|
||||
|
||||
bool isSmallInt = op.Size < IntegerSize.B32;
|
||||
|
@ -209,7 +209,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (!(emit || cut))
|
||||
{
|
||||
context.Config.PrintLog("Invalid OUT encoding.");
|
||||
context.Config.GpuAccessor.Log("Invalid OUT encoding.");
|
||||
}
|
||||
|
||||
if (emit)
|
||||
|
@ -274,7 +274,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
|
||||
}
|
||||
break;
|
||||
case AtomicOp.BitwiseAnd:
|
||||
|
@ -284,7 +284,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
|
||||
}
|
||||
break;
|
||||
case AtomicOp.BitwiseExclusiveOr:
|
||||
|
@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
|
||||
}
|
||||
break;
|
||||
case AtomicOp.BitwiseOr:
|
||||
|
@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
|
||||
}
|
||||
break;
|
||||
case AtomicOp.Maximum:
|
||||
|
@ -318,7 +318,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
|
||||
}
|
||||
break;
|
||||
case AtomicOp.Minimum:
|
||||
|
@ -332,7 +332,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid reduction type: {type}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid reduction type: {type}.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (op.Size > IntegerSize.B128)
|
||||
{
|
||||
context.Config.PrintLog($"Invalid load size: {op.Size}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid load size: {op.Size}.");
|
||||
}
|
||||
|
||||
bool isSmallInt = op.Size < IntegerSize.B32;
|
||||
|
@ -432,7 +432,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (op.Size > IntegerSize.B128)
|
||||
{
|
||||
context.Config.PrintLog($"Invalid store size: {op.Size}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid store size: {op.Size}.");
|
||||
}
|
||||
|
||||
bool isSmallInt = op.Size < IntegerSize.B32;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
if (isCC)
|
||||
{
|
||||
// TODO: Support Register to condition code flags copy.
|
||||
context.Config.PrintLog("R2P.CC not implemented.");
|
||||
context.Config.GpuAccessor.Log("R2P.CC not implemented.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (type == SamplerType.None)
|
||||
{
|
||||
context.Config.PrintLog("Invalid image store sampler type.");
|
||||
context.Config.GpuAccessor.Log("Invalid image store sampler type.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (type == SamplerType.None)
|
||||
{
|
||||
context.Config.PrintLog("Invalid image store sampler type.");
|
||||
context.Config.GpuAccessor.Log("Invalid image store sampler type.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (type == SamplerType.None)
|
||||
{
|
||||
context.Config.PrintLog("Invalid texture sampler type.");
|
||||
context.Config.GpuAccessor.Log("Invalid texture sampler type.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -423,14 +423,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (type == SamplerType.None)
|
||||
{
|
||||
context.Config.PrintLog("Invalid texel fetch sampler type.");
|
||||
context.Config.GpuAccessor.Log("Invalid texel fetch sampler type.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
flags = ConvertTextureFlags(tldsOp.Target) | TextureFlags.IntCoords;
|
||||
|
||||
if (tldsOp.Target == TexelLoadTarget.Texture1DLodZero && context.Config.QueryInfoBool(QueryInfoName.IsTextureBuffer, tldsOp.Immediate))
|
||||
if (tldsOp.Target == TexelLoadTarget.Texture1DLodZero && context.Config.GpuAccessor.QueryIsTextureBuffer(tldsOp.Immediate))
|
||||
{
|
||||
type = SamplerType.TextureBuffer;
|
||||
flags &= ~TextureFlags.LodLevel;
|
||||
|
@ -1020,7 +1020,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
if (type == SamplerType.Texture1D && flags == TextureFlags.IntCoords && !isBindless)
|
||||
{
|
||||
bool isTypeBuffer = context.Config.QueryInfoBool(QueryInfoName.IsTextureBuffer, op.Immediate);
|
||||
bool isTypeBuffer = context.Config.GpuAccessor.QueryIsTextureBuffer(op.Immediate);
|
||||
|
||||
if (isTypeBuffer)
|
||||
{
|
||||
|
@ -1093,11 +1093,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
private static TextureFormat GetTextureFormat(EmitterContext context, int handle)
|
||||
{
|
||||
var format = (TextureFormat)context.Config.QueryInfo(QueryInfoName.TextureFormat, handle);
|
||||
var format = context.Config.GpuAccessor.QueryTextureFormat(handle);
|
||||
|
||||
if (format == TextureFormat.Unknown)
|
||||
{
|
||||
context.Config.PrintLog($"Unknown format for texture {handle}.");
|
||||
context.Config.GpuAccessor.Log($"Unknown format for texture {handle}.");
|
||||
|
||||
format = TextureFormat.R8G8B8A8Unorm;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Config.PrintLog($"Invalid vote operation: {op.VoteOp}.");
|
||||
context.Config.GpuAccessor.Log($"Invalid vote operation: {op.VoteOp}.");
|
||||
}
|
||||
|
||||
if (!op.Rd.IsRZ)
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public enum QueryInfoName
|
||||
{
|
||||
ComputeLocalSizeX,
|
||||
ComputeLocalSizeY,
|
||||
ComputeLocalSizeZ,
|
||||
ComputeLocalMemorySize,
|
||||
ComputeSharedMemorySize,
|
||||
IsTextureBuffer,
|
||||
IsTextureRectangle,
|
||||
PrimitiveTopology,
|
||||
StorageBufferOffsetAlignment,
|
||||
SupportsNonConstantTextureOffset,
|
||||
TextureFormat
|
||||
}
|
||||
}
|
|
@ -10,13 +10,15 @@ namespace Ryujinx.Graphics.Shader
|
|||
|
||||
public string Code { get; private set; }
|
||||
|
||||
public int SizeA { get; }
|
||||
public int Size { get; }
|
||||
|
||||
internal ShaderProgram(ShaderProgramInfo info, ShaderStage stage, string code, int size)
|
||||
internal ShaderProgram(ShaderProgramInfo info, ShaderStage stage, string code, int size, int sizeA)
|
||||
{
|
||||
Info = info;
|
||||
Stage = stage;
|
||||
Code = code;
|
||||
SizeA = sizeA;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot);
|
||||
}
|
||||
|
||||
Operand alignMask = Const(-config.QueryInfo(QueryInfoName.StorageBufferOffsetAlignment));
|
||||
Operand alignMask = Const(-config.GpuAccessor.QueryStorageBufferOffsetAlignment());
|
||||
|
||||
Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask);
|
||||
Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc);
|
||||
|
@ -131,9 +131,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0;
|
||||
bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0;
|
||||
|
||||
bool hasInvalidOffset = (hasOffset || hasOffsets) && !config.QueryInfoBool(QueryInfoName.SupportsNonConstantTextureOffset);
|
||||
bool hasInvalidOffset = (hasOffset || hasOffsets) && !config.GpuAccessor.QuerySupportsNonConstantTextureOffset();
|
||||
|
||||
bool isRect = config.QueryInfoBool(QueryInfoName.IsTextureRectangle, texOp.Handle);
|
||||
bool isRect = config.GpuAccessor.QueryIsTextureRectangle(texOp.Handle);
|
||||
|
||||
if (!(hasInvalidOffset || isRect))
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
|
||||
Operand baseAddrTrunc = Local();
|
||||
|
||||
Operand alignMask = Const(-config.QueryInfo(QueryInfoName.StorageBufferOffsetAlignment));
|
||||
Operand alignMask = Const(-config.GpuAccessor.QueryStorageBufferOffsetAlignment());
|
||||
|
||||
Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask);
|
||||
|
||||
|
@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
|
||||
Operand baseAddrTrunc = Local();
|
||||
|
||||
Operand alignMask = Const(-config.QueryInfo(QueryInfoName.StorageBufferOffsetAlignment));
|
||||
Operand alignMask = Const(-config.GpuAccessor.QueryStorageBufferOffsetAlignment());
|
||||
|
||||
Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask);
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
|
||||
public IGpuAccessor GpuAccessor { get; }
|
||||
|
||||
public TranslationFlags Flags { get; }
|
||||
|
||||
private TranslatorCallbacks _callbacks;
|
||||
|
||||
public ShaderConfig(TranslationFlags flags, TranslatorCallbacks callbacks)
|
||||
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
{
|
||||
Stage = ShaderStage.Compute;
|
||||
OutputTopology = OutputTopology.PointList;
|
||||
|
@ -32,11 +32,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
OmapTargets = null;
|
||||
OmapSampleMask = false;
|
||||
OmapDepth = false;
|
||||
GpuAccessor = gpuAccessor;
|
||||
Flags = flags;
|
||||
_callbacks = callbacks;
|
||||
}
|
||||
|
||||
public ShaderConfig(ShaderHeader header, TranslationFlags flags, TranslatorCallbacks callbacks)
|
||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
{
|
||||
Stage = header.Stage;
|
||||
OutputTopology = header.OutputTopology;
|
||||
|
@ -46,8 +46,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
OmapTargets = header.OmapTargets;
|
||||
OmapSampleMask = header.OmapSampleMask;
|
||||
OmapDepth = header.OmapDepth;
|
||||
GpuAccessor = gpuAccessor;
|
||||
Flags = flags;
|
||||
_callbacks = callbacks;
|
||||
}
|
||||
|
||||
public int GetDepthRegister()
|
||||
|
@ -68,51 +68,5 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
// The depth register is always two registers after the last color output.
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
public bool QueryInfoBool(QueryInfoName info, int index = 0)
|
||||
{
|
||||
return Convert.ToBoolean(QueryInfo(info, index));
|
||||
}
|
||||
|
||||
public int QueryInfo(QueryInfoName info, int index = 0)
|
||||
{
|
||||
if (_callbacks.QueryInfo != null)
|
||||
{
|
||||
return _callbacks.QueryInfo(info, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (info)
|
||||
{
|
||||
case QueryInfoName.ComputeLocalSizeX:
|
||||
case QueryInfoName.ComputeLocalSizeY:
|
||||
case QueryInfoName.ComputeLocalSizeZ:
|
||||
return 1;
|
||||
case QueryInfoName.ComputeLocalMemorySize:
|
||||
return 0x1000;
|
||||
case QueryInfoName.ComputeSharedMemorySize:
|
||||
return 0xc000;
|
||||
case QueryInfoName.IsTextureBuffer:
|
||||
return Convert.ToInt32(false);
|
||||
case QueryInfoName.IsTextureRectangle:
|
||||
return Convert.ToInt32(false);
|
||||
case QueryInfoName.PrimitiveTopology:
|
||||
return (int)InputTopology.Points;
|
||||
case QueryInfoName.StorageBufferOffsetAlignment:
|
||||
return 16;
|
||||
case QueryInfoName.SupportsNonConstantTextureOffset:
|
||||
return Convert.ToInt32(true);
|
||||
case QueryInfoName.TextureFormat:
|
||||
return (int)TextureFormat.R8G8B8A8Unorm;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void PrintLog(string message)
|
||||
{
|
||||
_callbacks.PrintLog?.Invoke(message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
|
@ -110,15 +109,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
|
||||
public ShaderHeader(ReadOnlySpan<byte> code)
|
||||
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
|
||||
{
|
||||
ReadOnlySpan<int> header = MemoryMarshal.Cast<byte, int>(code);
|
||||
|
||||
int commonWord0 = header[0];
|
||||
int commonWord1 = header[1];
|
||||
int commonWord2 = header[2];
|
||||
int commonWord3 = header[3];
|
||||
int commonWord4 = header[4];
|
||||
int commonWord0 = gpuAccessor.MemoryRead<int>(address + 0);
|
||||
int commonWord1 = gpuAccessor.MemoryRead<int>(address + 4);
|
||||
int commonWord2 = gpuAccessor.MemoryRead<int>(address + 8);
|
||||
int commonWord3 = gpuAccessor.MemoryRead<int>(address + 12);
|
||||
int commonWord4 = gpuAccessor.MemoryRead<int>(address + 16);
|
||||
|
||||
SphType = commonWord0.Extract(0, 5);
|
||||
Version = commonWord0.Extract(5, 5);
|
||||
|
@ -163,22 +160,19 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
ImapTypes = new ImapPixelType[32];
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (ulong i = 0; i < 32; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
byte imap = (byte)(header[6 + i] >> (j * 8));
|
||||
byte imap = gpuAccessor.MemoryRead<byte>(address + 0x18 + i);
|
||||
|
||||
ImapTypes[i * 4 + j] = new ImapPixelType(
|
||||
(PixelImap)((imap >> 0) & 3),
|
||||
(PixelImap)((imap >> 2) & 3),
|
||||
(PixelImap)((imap >> 4) & 3),
|
||||
(PixelImap)((imap >> 6) & 3));
|
||||
}
|
||||
ImapTypes[i] = new ImapPixelType(
|
||||
(PixelImap)((imap >> 0) & 3),
|
||||
(PixelImap)((imap >> 2) & 3),
|
||||
(PixelImap)((imap >> 4) & 3),
|
||||
(PixelImap)((imap >> 6) & 3));
|
||||
}
|
||||
|
||||
int type2OmapTarget = header[18];
|
||||
int type2Omap = header[19];
|
||||
int type2OmapTarget = gpuAccessor.MemoryRead<int>(address + 0x48);
|
||||
int type2Omap = gpuAccessor.MemoryRead<int>(address + 0x4c);
|
||||
|
||||
OmapTargets = new OmapTarget[8];
|
||||
|
||||
|
|
|
@ -14,46 +14,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
private const int HeaderSize = 0x50;
|
||||
|
||||
public static ReadOnlySpan<byte> ExtractCode(ReadOnlySpan<byte> code, bool compute, out int headerSize)
|
||||
public static ShaderProgram Translate(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
{
|
||||
headerSize = compute ? 0 : HeaderSize;
|
||||
|
||||
Block[] cfg = Decoder.Decode(code, (ulong)headerSize);
|
||||
|
||||
if (cfg == null)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
ulong endAddress = 0;
|
||||
|
||||
foreach (Block block in cfg)
|
||||
{
|
||||
if (endAddress < block.EndAddress)
|
||||
{
|
||||
endAddress = block.EndAddress;
|
||||
}
|
||||
}
|
||||
|
||||
return code.Slice(0, headerSize + (int)endAddress);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(ReadOnlySpan<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||
{
|
||||
Operation[] ops = DecodeShader(code, callbacks, flags, out ShaderConfig config, out int size);
|
||||
Operation[] ops = DecodeShader(address, gpuAccessor, flags, out ShaderConfig config, out int size);
|
||||
|
||||
return Translate(ops, config, size);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(ReadOnlySpan<byte> vpACode, ReadOnlySpan<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||
public static ShaderProgram Translate(ulong addressA, ulong addressB, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
||||
{
|
||||
Operation[] vpAOps = DecodeShader(vpACode, callbacks, flags, out _, out _);
|
||||
Operation[] vpBOps = DecodeShader(vpBCode, callbacks, flags, out ShaderConfig config, out int sizeB);
|
||||
Operation[] opsA = DecodeShader(addressA, gpuAccessor, flags, out _, out int sizeA);
|
||||
Operation[] opsB = DecodeShader(addressB, gpuAccessor, flags, out ShaderConfig config, out int sizeB);
|
||||
|
||||
return Translate(Combine(vpAOps, vpBOps), config, sizeB);
|
||||
return Translate(Combine(opsA, opsB), config, sizeB, sizeA);
|
||||
}
|
||||
|
||||
private static ShaderProgram Translate(Operation[] ops, ShaderConfig config, int size)
|
||||
private static ShaderProgram Translate(Operation[] ops, ShaderConfig config, int size, int sizeA = 0)
|
||||
{
|
||||
BasicBlock[] blocks = ControlFlowGraph.MakeCfg(ops);
|
||||
|
||||
|
@ -83,34 +59,34 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
string glslCode = program.Code;
|
||||
|
||||
return new ShaderProgram(spInfo, config.Stage, glslCode, size);
|
||||
return new ShaderProgram(spInfo, config.Stage, glslCode, size, sizeA);
|
||||
}
|
||||
|
||||
private static Operation[] DecodeShader(
|
||||
ReadOnlySpan<byte> code,
|
||||
TranslatorCallbacks callbacks,
|
||||
TranslationFlags flags,
|
||||
out ShaderConfig config,
|
||||
out int size)
|
||||
ulong address,
|
||||
IGpuAccessor gpuAccessor,
|
||||
TranslationFlags flags,
|
||||
out ShaderConfig config,
|
||||
out int size)
|
||||
{
|
||||
Block[] cfg;
|
||||
|
||||
if ((flags & TranslationFlags.Compute) != 0)
|
||||
{
|
||||
config = new ShaderConfig(flags, callbacks);
|
||||
config = new ShaderConfig(gpuAccessor, flags);
|
||||
|
||||
cfg = Decoder.Decode(code, 0);
|
||||
cfg = Decoder.Decode(gpuAccessor, address);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = new ShaderConfig(new ShaderHeader(code), flags, callbacks);
|
||||
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags);
|
||||
|
||||
cfg = Decoder.Decode(code, HeaderSize);
|
||||
cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
|
||||
}
|
||||
|
||||
if (cfg == null)
|
||||
{
|
||||
config.PrintLog("Invalid branch detected, failed to build CFG.");
|
||||
gpuAccessor.Log("Invalid branch detected, failed to build CFG.");
|
||||
|
||||
size = 0;
|
||||
|
||||
|
@ -150,7 +126,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
instName = "???";
|
||||
|
||||
config.PrintLog($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16}).");
|
||||
gpuAccessor.Log($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16}).");
|
||||
}
|
||||
|
||||
string dbgComment = $"0x{op.Address:X6}: 0x{op.RawOpCode:X16} {instName}";
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
public struct TranslatorCallbacks
|
||||
{
|
||||
internal Func<QueryInfoName, int, int> QueryInfo { get; }
|
||||
|
||||
internal Action<string> PrintLog { get; }
|
||||
|
||||
public TranslatorCallbacks(Func<QueryInfoName, int, int> queryInfoCallback, Action<string> printLogCallback)
|
||||
{
|
||||
QueryInfo = queryInfoCallback;
|
||||
PrintLog = printLogCallback;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue