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:
gdkchan 2020-05-05 22:02:28 -03:00 committed by GitHub
parent 7f500e7cae
commit b8eb6abecc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 633 additions and 684 deletions

View file

@ -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 (" +

View file

@ -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);

View 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;
}
}
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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;

View file

@ -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
{

View file

@ -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;
}

View file

@ -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)

View file

@ -1,17 +0,0 @@
namespace Ryujinx.Graphics.Shader
{
public enum QueryInfoName
{
ComputeLocalSizeX,
ComputeLocalSizeY,
ComputeLocalSizeZ,
ComputeLocalMemorySize,
ComputeSharedMemorySize,
IsTextureBuffer,
IsTextureRectangle,
PrimitiveTopology,
StorageBufferOffsetAlignment,
SupportsNonConstantTextureOffset,
TextureFormat
}
}

View file

@ -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;
}

View file

@ -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))
{

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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];

View file

@ -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}";

View file

@ -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;
}
}
}