aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-01-01 12:39:09 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit92703af5558258da078d876b1d46e916b1065978 (patch)
tree6579863103b145b3e7345e42fc03caf870622b43 /Ryujinx.Graphics.Shader
parent40ef18d7599971c7387779d752a73568685d3432 (diff)
Address PR feedback
Diffstat (limited to 'Ryujinx.Graphics.Shader')
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs5
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs26
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs5
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs91
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs2
-rw-r--r--Ryujinx.Graphics.Shader/QueryInfoCallback.cs4
-rw-r--r--Ryujinx.Graphics.Shader/QueryInfoName.cs1
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs49
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs39
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslatorCallbacks.cs17
11 files changed, 124 insertions, 117 deletions
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs
index da557cfa..6bef8e6c 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs
@@ -91,10 +91,5 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return indentation;
}
-
- public string GetTabString()
- {
- return Tab;
- }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
index 866df56d..2145920e 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
@@ -86,6 +86,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
context.Barrier();
}
+ else
+ {
+ context.Config.PrintLog($"Invalid barrier mode: {op.Mode}.");
+ }
}
public static void Ipa(EmitterContext context)
@@ -101,8 +105,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
Operand srcA = Attribute(op.AttributeOffset, iq);
- Operand srcB = GetSrcB(context);
-
Operand res = context.FPSaturate(srcA, op.Saturate);
context.Copy(GetDest(context), res);
@@ -128,7 +130,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (op.Size > IntegerSize.B64)
{
- // TODO: Warning.
+ context.Config.PrintLog($"Invalid LDC size: {op.Size}.");
}
bool isSmallInt = op.Size < IntegerSize.B32;
@@ -156,7 +158,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (isSmallInt)
{
- value = ExtractSmallInt(context, op.Size, wordOffset, value);
+ value = ExtractSmallInt(context, op.Size, bitOffset, value);
}
context.Copy(Register(rd), value);
@@ -261,7 +263,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Not supported or invalid.
+ context.Config.PrintLog($"Invalid reduction type: {type}.");
}
break;
case AtomicOp.BitwiseAnd:
@@ -271,7 +273,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Not supported or invalid.
+ context.Config.PrintLog($"Invalid reduction type: {type}.");
}
break;
case AtomicOp.BitwiseExclusiveOr:
@@ -281,7 +283,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Not supported or invalid.
+ context.Config.PrintLog($"Invalid reduction type: {type}.");
}
break;
case AtomicOp.BitwiseOr:
@@ -291,7 +293,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Not supported or invalid.
+ context.Config.PrintLog($"Invalid reduction type: {type}.");
}
break;
case AtomicOp.Maximum:
@@ -305,7 +307,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Not supported or invalid.
+ context.Config.PrintLog($"Invalid reduction type: {type}.");
}
break;
case AtomicOp.Minimum:
@@ -319,7 +321,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Not supported or invalid.
+ context.Config.PrintLog($"Invalid reduction type: {type}.");
}
break;
}
@@ -333,7 +335,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (op.Size > IntegerSize.B128)
{
- // TODO: Warning.
+ context.Config.PrintLog($"Invalid load size: {op.Size}.");
}
bool isSmallInt = op.Size < IntegerSize.B32;
@@ -419,7 +421,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (op.Size > IntegerSize.B128)
{
- // TODO: Warning.
+ context.Config.PrintLog($"Invalid store size: {op.Size}.");
}
bool isSmallInt = op.Size < IntegerSize.B32;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
index 17e80f4a..ffc4c430 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
@@ -11,8 +11,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
public static void Mov(EmitterContext context)
{
- OpCodeAlu op = (OpCodeAlu)context.CurrOp;
-
context.Copy(GetDest(context), GetSrcB(context));
}
@@ -33,7 +31,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (isCC)
{
- // TODO.
+ // TODO: Support Register to condition code flags copy.
+ context.Config.PrintLog("R2P.CC not implemented.");
}
else
{
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 59096869..7b9794ea 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (type == SamplerType.None)
{
- // TODO: Error, encoding is invalid.
+ context.Config.PrintLog("Invalid image store sampler type.");
return;
}
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // TODO.
+ context.Config.PrintLog("Unsized image store not supported.");
}
Operand[] sources = sourcesList.ToArray();
@@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (type == SamplerType.None)
{
- // TODO: Error, encoding is invalid.
+ context.Config.PrintLog("Invalid texture sampler type.");
return;
}
@@ -210,40 +210,40 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
switch (texsOp.Target)
{
- case Decoders.TextureTarget.Texture1DLodZero:
+ case TextureTarget.Texture1DLodZero:
sourcesList.Add(Ra());
break;
- case Decoders.TextureTarget.Texture2D:
+ case TextureTarget.Texture2D:
sourcesList.Add(Ra());
sourcesList.Add(Rb());
break;
- case Decoders.TextureTarget.Texture2DLodZero:
+ case TextureTarget.Texture2DLodZero:
sourcesList.Add(Ra());
sourcesList.Add(Rb());
sourcesList.Add(ConstF(0));
break;
- case Decoders.TextureTarget.Texture2DLodLevel:
- case Decoders.TextureTarget.Texture2DDepthCompare:
- case Decoders.TextureTarget.Texture3D:
- case Decoders.TextureTarget.TextureCube:
+ case TextureTarget.Texture2DLodLevel:
+ case TextureTarget.Texture2DDepthCompare:
+ case TextureTarget.Texture3D:
+ case TextureTarget.TextureCube:
sourcesList.Add(Ra());
sourcesList.Add(Ra());
sourcesList.Add(Rb());
break;
- case Decoders.TextureTarget.Texture2DLodZeroDepthCompare:
- case Decoders.TextureTarget.Texture3DLodZero:
+ case TextureTarget.Texture2DLodZeroDepthCompare:
+ case TextureTarget.Texture3DLodZero:
sourcesList.Add(Ra());
sourcesList.Add(Ra());
sourcesList.Add(Rb());
sourcesList.Add(ConstF(0));
break;
- case Decoders.TextureTarget.Texture2DLodLevelDepthCompare:
- case Decoders.TextureTarget.TextureCubeLodLevel:
+ case TextureTarget.Texture2DLodLevelDepthCompare:
+ case TextureTarget.TextureCubeLodLevel:
sourcesList.Add(Ra());
sourcesList.Add(Ra());
sourcesList.Add(Rb());
@@ -258,7 +258,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (type == SamplerType.None)
{
- // TODO: Error, encoding is invalid.
+ context.Config.PrintLog("Invalid texel fetch sampler type.");
return;
}
@@ -742,8 +742,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
OpCodeTexture op = (OpCodeTexture)context.CurrOp;
- bool isBindless = (flags & TextureFlags.Bindless) != 0;
- bool intCoords = (flags & TextureFlags.IntCoords) != 0;
+ bool isBindless = (flags & TextureFlags.Bindless) != 0;
if (op.Rd.IsRZ)
{
@@ -920,36 +919,36 @@ namespace Ryujinx.Graphics.Shader.Instructions
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
}
- private static SamplerType ConvertSamplerType(Decoders.TextureTarget type)
+ private static SamplerType ConvertSamplerType(TextureTarget type)
{
switch (type)
{
- case Decoders.TextureTarget.Texture1DLodZero:
+ case TextureTarget.Texture1DLodZero:
return SamplerType.Texture1D;
- case Decoders.TextureTarget.Texture2D:
- case Decoders.TextureTarget.Texture2DLodZero:
- case Decoders.TextureTarget.Texture2DLodLevel:
+ case TextureTarget.Texture2D:
+ case TextureTarget.Texture2DLodZero:
+ case TextureTarget.Texture2DLodLevel:
return SamplerType.Texture2D;
- case Decoders.TextureTarget.Texture2DDepthCompare:
- case Decoders.TextureTarget.Texture2DLodLevelDepthCompare:
- case Decoders.TextureTarget.Texture2DLodZeroDepthCompare:
+ case TextureTarget.Texture2DDepthCompare:
+ case TextureTarget.Texture2DLodLevelDepthCompare:
+ case TextureTarget.Texture2DLodZeroDepthCompare:
return SamplerType.Texture2D | SamplerType.Shadow;
- case Decoders.TextureTarget.Texture2DArray:
- case Decoders.TextureTarget.Texture2DArrayLodZero:
+ case TextureTarget.Texture2DArray:
+ case TextureTarget.Texture2DArrayLodZero:
return SamplerType.Texture2D | SamplerType.Array;
- case Decoders.TextureTarget.Texture2DArrayLodZeroDepthCompare:
+ case TextureTarget.Texture2DArrayLodZeroDepthCompare:
return SamplerType.Texture2D | SamplerType.Array | SamplerType.Shadow;
- case Decoders.TextureTarget.Texture3D:
- case Decoders.TextureTarget.Texture3DLodZero:
+ case TextureTarget.Texture3D:
+ case TextureTarget.Texture3DLodZero:
return SamplerType.Texture3D;
- case Decoders.TextureTarget.TextureCube:
- case Decoders.TextureTarget.TextureCubeLodLevel:
+ case TextureTarget.TextureCube:
+ case TextureTarget.TextureCubeLodLevel:
return SamplerType.TextureCube;
}
@@ -987,22 +986,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
switch (type)
{
- case Decoders.TextureTarget.Texture1DLodZero:
- case Decoders.TextureTarget.Texture2DLodZero:
- case Decoders.TextureTarget.Texture2DLodLevel:
- case Decoders.TextureTarget.Texture2DLodLevelDepthCompare:
- case Decoders.TextureTarget.Texture2DLodZeroDepthCompare:
- case Decoders.TextureTarget.Texture2DArrayLodZero:
- case Decoders.TextureTarget.Texture2DArrayLodZeroDepthCompare:
- case Decoders.TextureTarget.Texture3DLodZero:
- case Decoders.TextureTarget.TextureCubeLodLevel:
+ case TextureTarget.Texture1DLodZero:
+ case TextureTarget.Texture2DLodZero:
+ case TextureTarget.Texture2DLodLevel:
+ case TextureTarget.Texture2DLodLevelDepthCompare:
+ case TextureTarget.Texture2DLodZeroDepthCompare:
+ case TextureTarget.Texture2DArrayLodZero:
+ case TextureTarget.Texture2DArrayLodZeroDepthCompare:
+ case TextureTarget.Texture3DLodZero:
+ case TextureTarget.TextureCubeLodLevel:
return TextureFlags.LodLevel;
- case Decoders.TextureTarget.Texture2D:
- case Decoders.TextureTarget.Texture2DDepthCompare:
- case Decoders.TextureTarget.Texture2DArray:
- case Decoders.TextureTarget.Texture3D:
- case Decoders.TextureTarget.TextureCube:
+ case TextureTarget.Texture2D:
+ case TextureTarget.Texture2DDepthCompare:
+ case TextureTarget.Texture2DArray:
+ case TextureTarget.Texture3D:
+ case TextureTarget.TextureCube:
return TextureFlags.None;
}
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
index 9c4d5f1a..8f81ecb4 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- // Invalid.
+ context.Config.PrintLog($"Invalid vote operation: {op.VoteOp}.");
}
if (!op.Rd.IsRZ)
diff --git a/Ryujinx.Graphics.Shader/QueryInfoCallback.cs b/Ryujinx.Graphics.Shader/QueryInfoCallback.cs
deleted file mode 100644
index 28261a77..00000000
--- a/Ryujinx.Graphics.Shader/QueryInfoCallback.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace Ryujinx.Graphics.Shader
-{
- public delegate int QueryInfoCallback(QueryInfoName info, int index);
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/QueryInfoName.cs b/Ryujinx.Graphics.Shader/QueryInfoName.cs
index 1d87c2c8..c4f2cb6c 100644
--- a/Ryujinx.Graphics.Shader/QueryInfoName.cs
+++ b/Ryujinx.Graphics.Shader/QueryInfoName.cs
@@ -8,7 +8,6 @@ namespace Ryujinx.Graphics.Shader
ComputeSharedMemorySize,
IsTextureBuffer,
IsTextureRectangle,
- MaximumViewportDimensions,
PrimitiveTopology,
StorageBufferOffsetAlignment,
SupportsNonConstantTextureOffset
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index e6334fea..fbe19765 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.Shader.Translation
private ShaderConfig _config;
+ public ShaderConfig Config => _config;
+
private List<Operation> _operations;
private Dictionary<ulong, Operand> _labels;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index d73a268e..8a0f25fe 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -16,30 +16,30 @@ namespace Ryujinx.Graphics.Shader.Translation
public TranslationFlags Flags { get; }
- private QueryInfoCallback _queryInfoCallback;
+ private TranslatorCallbacks _callbacks;
- public ShaderConfig(TranslationFlags flags, QueryInfoCallback queryInfoCallback)
+ public ShaderConfig(TranslationFlags flags, TranslatorCallbacks callbacks)
{
- Stage = ShaderStage.Compute;
- OutputTopology = OutputTopology.PointList;
- MaxOutputVertices = 0;
- OmapTargets = null;
- OmapSampleMask = false;
- OmapDepth = false;
- Flags = flags;
- _queryInfoCallback = queryInfoCallback;
+ Stage = ShaderStage.Compute;
+ OutputTopology = OutputTopology.PointList;
+ MaxOutputVertices = 0;
+ OmapTargets = null;
+ OmapSampleMask = false;
+ OmapDepth = false;
+ Flags = flags;
+ _callbacks = callbacks;
}
- public ShaderConfig(ShaderHeader header, TranslationFlags flags, QueryInfoCallback queryInfoCallback)
+ public ShaderConfig(ShaderHeader header, TranslationFlags flags, TranslatorCallbacks callbacks)
{
- Stage = header.Stage;
- OutputTopology = header.OutputTopology;
- MaxOutputVertices = header.MaxOutputVertexCount;
- OmapTargets = header.OmapTargets;
- OmapSampleMask = header.OmapSampleMask;
- OmapDepth = header.OmapDepth;
- Flags = flags;
- _queryInfoCallback = queryInfoCallback;
+ Stage = header.Stage;
+ OutputTopology = header.OutputTopology;
+ MaxOutputVertices = header.MaxOutputVertexCount;
+ OmapTargets = header.OmapTargets;
+ OmapSampleMask = header.OmapSampleMask;
+ OmapDepth = header.OmapDepth;
+ Flags = flags;
+ _callbacks = callbacks;
}
public int GetDepthRegister()
@@ -68,9 +68,9 @@ namespace Ryujinx.Graphics.Shader.Translation
public int QueryInfo(QueryInfoName info, int index = 0)
{
- if (_queryInfoCallback != null)
+ if (_callbacks.QueryInfo != null)
{
- return _queryInfoCallback(info, index);
+ return _callbacks.QueryInfo(info, index);
}
else
{
@@ -86,8 +86,6 @@ namespace Ryujinx.Graphics.Shader.Translation
return Convert.ToInt32(false);
case QueryInfoName.IsTextureRectangle:
return Convert.ToInt32(false);
- case QueryInfoName.MaximumViewportDimensions:
- return 0x8000;
case QueryInfoName.PrimitiveTopology:
return (int)InputTopology.Points;
case QueryInfoName.StorageBufferOffsetAlignment:
@@ -99,5 +97,10 @@ namespace Ryujinx.Graphics.Shader.Translation
return 0;
}
+
+ public void PrintLog(string message)
+ {
+ _callbacks.PrintLog?.Invoke(message);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index af209edf..bdc6a094 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -40,21 +40,17 @@ namespace Ryujinx.Graphics.Shader.Translation
return code.Slice(0, headerSize + (int)endAddress);
}
- public static ShaderProgram Translate(Span<byte> code, QueryInfoCallback queryInfoCallback, TranslationFlags flags)
+ public static ShaderProgram Translate(Span<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
{
- bool compute = (flags & TranslationFlags.Compute) != 0;
-
- Operation[] ops = DecodeShader(code, queryInfoCallback, flags, out ShaderConfig config, out int size);
+ Operation[] ops = DecodeShader(code, callbacks, flags, out ShaderConfig config, out int size);
return Translate(ops, config, size);
}
- public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, QueryInfoCallback queryInfoCallback, TranslationFlags flags)
+ public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
{
- bool debugMode = (flags & TranslationFlags.DebugMode) != 0;
-
- Operation[] vpAOps = DecodeShader(vpACode, queryInfoCallback, flags, out _, out _);
- Operation[] vpBOps = DecodeShader(vpBCode, queryInfoCallback, flags, out ShaderConfig config, out int sizeB);
+ Operation[] vpAOps = DecodeShader(vpACode, callbacks, flags, out _, out _);
+ Operation[] vpBOps = DecodeShader(vpBCode, callbacks, flags, out ShaderConfig config, out int sizeB);
return Translate(Combine(vpAOps, vpBOps), config, sizeB);
}
@@ -94,34 +90,34 @@ namespace Ryujinx.Graphics.Shader.Translation
}
private static Operation[] DecodeShader(
- Span<byte> code,
- QueryInfoCallback queryInfoCallback,
- TranslationFlags flags,
- out ShaderConfig config,
- out int size)
+ Span<byte> code,
+ TranslatorCallbacks callbacks,
+ TranslationFlags flags,
+ out ShaderConfig config,
+ out int size)
{
Block[] cfg;
if ((flags & TranslationFlags.Compute) != 0)
{
- config = new ShaderConfig(flags, queryInfoCallback);
+ config = new ShaderConfig(flags, callbacks);
cfg = Decoder.Decode(code, 0);
}
else
{
- config = new ShaderConfig(new ShaderHeader(code), flags, queryInfoCallback);
+ config = new ShaderConfig(new ShaderHeader(code), flags, callbacks);
cfg = Decoder.Decode(code, HeaderSize);
}
if (cfg == null)
{
- // TODO: Error.
+ config.PrintLog("Invalid branch detected, failed to build CFG.");
size = 0;
- return new Operation[0];
+ return Array.Empty<Operation>();
}
EmitterContext context = new EmitterContext(config);
@@ -156,6 +152,8 @@ namespace Ryujinx.Graphics.Shader.Translation
else
{
instName = "???";
+
+ config.PrintLog($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16}).");
}
string dbgComment = $"0x{op.Address:X6}: 0x{op.RawOpCode:X16} {instName}";
@@ -210,10 +208,7 @@ namespace Ryujinx.Graphics.Shader.Translation
context.CurrOp = op;
- if (op.Emitter != null)
- {
- op.Emitter(context);
- }
+ op.Emitter?.Invoke(context);
if (predSkipLbl != null)
{
diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorCallbacks.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorCallbacks.cs
new file mode 100644
index 00000000..e0e9852f
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Translation/TranslatorCallbacks.cs
@@ -0,0 +1,17 @@
+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;
+ }
+ }
+}