aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs')
-rw-r--r--src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs172
1 files changed, 135 insertions, 37 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index ba31c020..d18a9baf 100644
--- a/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -9,8 +9,45 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
static class Decoder
{
- public static DecodedProgram Decode(ShaderConfig config, ulong startAddress)
+ private class Context
{
+ public AttributeUsage AttributeUsage { get; }
+ public FeatureFlags UsedFeatures { get; private set; }
+ public byte ClipDistancesWritten { get; private set; }
+ public int Cb1DataSize { get; private set; }
+
+ private readonly IGpuAccessor _gpuAccessor;
+
+ public Context(IGpuAccessor gpuAccessor)
+ {
+ _gpuAccessor = gpuAccessor;
+ AttributeUsage = new(gpuAccessor);
+ }
+
+ public uint ConstantBuffer1Read(int offset)
+ {
+ if (Cb1DataSize < offset + 4)
+ {
+ Cb1DataSize = offset + 4;
+ }
+
+ return _gpuAccessor.ConstantBuffer1Read(offset);
+ }
+
+ public void SetUsedFeature(FeatureFlags flags)
+ {
+ UsedFeatures |= flags;
+ }
+
+ public void SetClipDistanceWritten(int index)
+ {
+ ClipDistancesWritten |= (byte)(1 << index);
+ }
+ }
+
+ public static DecodedProgram Decode(ShaderDefinitions definitions, IGpuAccessor gpuAccessor, ulong startAddress)
+ {
+ Context context = new(gpuAccessor);
Queue<DecodedFunction> functionsQueue = new();
Dictionary<ulong, DecodedFunction> functionsVisited = new();
@@ -89,7 +126,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
}
}
- FillBlock(config, currBlock, limitAddress, startAddress);
+ FillBlock(definitions, gpuAccessor, context, currBlock, limitAddress, startAddress);
if (currBlock.OpCodes.Count != 0)
{
@@ -148,7 +185,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
}
// Try to find targets for BRX (indirect branch) instructions.
- hasNewTarget = FindBrxTargets(config, blocks, GetBlock);
+ hasNewTarget = FindBrxTargets(context, blocks, GetBlock);
// If we discovered new branch targets from the BRX instruction,
// we need another round of decoding to decode the new blocks.
@@ -160,7 +197,13 @@ namespace Ryujinx.Graphics.Shader.Decoders
currentFunction.SetBlocks(blocks.ToArray());
}
- return new DecodedProgram(mainFunction, functionsVisited);
+ return new DecodedProgram(
+ mainFunction,
+ functionsVisited,
+ context.AttributeUsage,
+ context.UsedFeatures,
+ context.ClipDistancesWritten,
+ context.Cb1DataSize);
}
private static bool BinarySearch(List<Block> blocks, ulong address, out int index)
@@ -198,10 +241,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
return false;
}
- private static void FillBlock(ShaderConfig config, Block block, ulong limitAddress, ulong startAddress)
+ private static void FillBlock(
+ ShaderDefinitions definitions,
+ IGpuAccessor gpuAccessor,
+ Context context,
+ Block block,
+ ulong limitAddress,
+ ulong startAddress)
{
- IGpuAccessor gpuAccessor = config.GpuAccessor;
-
ulong address = block.Address;
int bufferOffset = 0;
ReadOnlySpan<ulong> buffer = ReadOnlySpan<ulong>.Empty;
@@ -235,27 +282,31 @@ namespace Ryujinx.Graphics.Shader.Decoders
if (op.Props.HasFlag(InstProps.TexB))
{
- config.SetUsedFeature(FeatureFlags.Bindless);
+ context.SetUsedFeature(FeatureFlags.Bindless);
}
- if (op.Name == InstName.Ald || op.Name == InstName.Ast || op.Name == InstName.Ipa)
- {
- SetUserAttributeUses(config, op.Name, opCode);
- }
- else if (op.Name == InstName.Pbk || op.Name == InstName.Pcnt || op.Name == InstName.Ssy)
- {
- block.AddPushOp(op);
- }
- else if (op.Name == InstName.Ldl || op.Name == InstName.Stl)
+ switch (op.Name)
{
- config.SetUsedFeature(FeatureFlags.LocalMemory);
- }
- else if (op.Name == InstName.Atoms ||
- op.Name == InstName.AtomsCas ||
- op.Name == InstName.Lds ||
- op.Name == InstName.Sts)
- {
- config.SetUsedFeature(FeatureFlags.SharedMemory);
+ case InstName.Ald:
+ case InstName.Ast:
+ case InstName.Ipa:
+ SetUserAttributeUses(definitions, context, op.Name, opCode);
+ break;
+ case InstName.Pbk:
+ case InstName.Pcnt:
+ case InstName.Ssy:
+ block.AddPushOp(op);
+ break;
+ case InstName.Ldl:
+ case InstName.Stl:
+ context.SetUsedFeature(FeatureFlags.LocalMemory);
+ break;
+ case InstName.Atoms:
+ case InstName.AtomsCas:
+ case InstName.Lds:
+ case InstName.Sts:
+ context.SetUsedFeature(FeatureFlags.SharedMemory);
+ break;
}
block.OpCodes.Add(op);
@@ -267,7 +318,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
block.EndAddress = address;
}
- private static void SetUserAttributeUses(ShaderConfig config, InstName name, ulong opCode)
+ private static void SetUserAttributeUses(ShaderDefinitions definitions, Context context, InstName name, ulong opCode)
{
int offset;
int count = 1;
@@ -304,13 +355,13 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
if (isStore)
{
- config.SetAllOutputUserAttributes();
- config.SetUsedFeature(FeatureFlags.OaIndexing);
+ context.AttributeUsage.SetAllOutputUserAttributes();
+ definitions.EnableOutputIndexing();
}
else
{
- config.SetAllInputUserAttributes();
- config.SetUsedFeature(FeatureFlags.IaIndexing);
+ context.AttributeUsage.SetAllInputUserAttributes();
+ definitions.EnableInputIndexing();
}
}
else
@@ -328,11 +379,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
if (isStore)
{
- config.SetOutputUserAttributePerPatch(index);
+ context.AttributeUsage.SetOutputUserAttributePerPatch(index);
}
else
{
- config.SetInputUserAttributePerPatch(index);
+ context.AttributeUsage.SetInputUserAttributePerPatch(index);
}
}
}
@@ -343,11 +394,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
if (isStore)
{
- config.SetOutputUserAttribute(index);
+ context.AttributeUsage.SetOutputUserAttribute(index);
}
else
{
- config.SetInputUserAttribute(index, (userAttr >> 2) & 3);
+ context.AttributeUsage.SetInputUserAttribute(index, (userAttr >> 2) & 3);
}
}
@@ -356,7 +407,54 @@ namespace Ryujinx.Graphics.Shader.Decoders
(attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0) ||
(attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)))
{
- config.SetUsedFeature(FeatureFlags.FixedFuncAttr);
+ context.SetUsedFeature(FeatureFlags.FixedFuncAttr);
+ }
+ else
+ {
+ if (isStore)
+ {
+ switch (attr)
+ {
+ case AttributeConsts.Layer:
+ if (definitions.Stage != ShaderStage.Compute && definitions.Stage != ShaderStage.Fragment)
+ {
+ context.SetUsedFeature(FeatureFlags.RtLayer);
+ }
+ break;
+ case AttributeConsts.ClipDistance0:
+ case AttributeConsts.ClipDistance1:
+ case AttributeConsts.ClipDistance2:
+ case AttributeConsts.ClipDistance3:
+ case AttributeConsts.ClipDistance4:
+ case AttributeConsts.ClipDistance5:
+ case AttributeConsts.ClipDistance6:
+ case AttributeConsts.ClipDistance7:
+ if (definitions.Stage == ShaderStage.Vertex)
+ {
+ context.SetClipDistanceWritten((attr - AttributeConsts.ClipDistance0) / 4);
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (attr)
+ {
+ case AttributeConsts.PositionX:
+ case AttributeConsts.PositionY:
+ if (definitions.Stage == ShaderStage.Fragment)
+ {
+ context.SetUsedFeature(FeatureFlags.FragCoordXY);
+ }
+ break;
+ case AttributeConsts.InstanceId:
+ if (definitions.Stage == ShaderStage.Vertex)
+ {
+ context.SetUsedFeature(FeatureFlags.InstanceId);
+ }
+ break;
+ }
+ }
}
}
}
@@ -379,7 +477,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
return condOp.Pred == RegisterConsts.PredicateTrueIndex && !condOp.PredInv;
}
- private static bool FindBrxTargets(ShaderConfig config, IEnumerable<Block> blocks, Func<ulong, Block> getBlock)
+ private static bool FindBrxTargets(Context context, IEnumerable<Block> blocks, Func<ulong, Block> getBlock)
{
bool hasNewTarget = false;
@@ -406,7 +504,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
for (int i = 0; i < cbOffsetsCount; i++)
{
- uint targetOffset = config.ConstantBuffer1Read(cbBaseOffset + i * 4);
+ uint targetOffset = context.ConstantBuffer1Read(cbBaseOffset + i * 4);
ulong targetAddress = baseOffset + targetOffset;
if (visited.Add(targetAddress))