Make the shader translator more error resilient

This commit is contained in:
gdk 2019-11-15 00:01:54 -03:00 committed by Thog
parent eea73bc421
commit 04102e5c9d
3 changed files with 49 additions and 19 deletions

View file

@ -29,6 +29,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>(); Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
ulong maxAddress = (ulong)code.Length - headerSize;
Block GetBlock(ulong blkAddress) Block GetBlock(ulong blkAddress)
{ {
if (!visited.TryGetValue(blkAddress, out Block block)) if (!visited.TryGetValue(blkAddress, out Block block))
@ -45,8 +47,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
GetBlock(0); GetBlock(0);
ulong maxAddress = (ulong)code.Length - headerSize;
while (workQueue.TryDequeue(out Block currBlock)) while (workQueue.TryDequeue(out Block currBlock))
{ {
// Check if the current block is inside another block. // Check if the current block is inside another block.
@ -93,6 +93,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
// including those from SSY/PBK instructions. // including those from SSY/PBK instructions.
foreach (OpCodePush pushOp in currBlock.PushOpCodes) foreach (OpCodePush pushOp in currBlock.PushOpCodes)
{ {
if (pushOp.GetAbsoluteAddress() >= maxAddress)
{
return null;
}
GetBlock(pushOp.GetAbsoluteAddress()); GetBlock(pushOp.GetAbsoluteAddress());
} }
@ -104,6 +109,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
if (lastOp is OpCodeBranch opBr) if (lastOp is OpCodeBranch opBr)
{ {
if (opBr.GetAbsoluteAddress() >= maxAddress)
{
return null;
}
currBlock.Branch = GetBlock(opBr.GetAbsoluteAddress()); currBlock.Branch = GetBlock(opBr.GetAbsoluteAddress());
} }
else if (lastOp is OpCodeBranchIndir opBrIndir) else if (lastOp is OpCodeBranchIndir opBrIndir)
@ -431,11 +441,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
} }
else if (current.GetLastOp() is OpCodeBranchPop op) else if (current.GetLastOp() is OpCodeBranchPop op)
{ {
ulong syncAddress = branchStack.Pop(); ulong targetAddress = branchStack.Pop();
if (branchStack.Count == 0) if (branchStack.Count == 0)
{ {
branchStack.Push(syncAddress); branchStack.Push(targetAddress);
op.Targets.Add(pushOp, op.Targets.Count); op.Targets.Add(pushOp, op.Targets.Count);
@ -443,8 +453,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
} }
else else
{ {
Push(new PathBlockState(syncAddress)); Push(new PathBlockState(targetAddress));
Push(new PathBlockState(blocks[syncAddress])); Push(new PathBlockState(blocks[targetAddress]));
} }
} }
} }

View file

@ -170,7 +170,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (op is OpCodeTexs texsOp) if (op is OpCodeTexs texsOp)
{ {
type = GetSamplerType (texsOp.Target); type = GetSamplerType (texsOp.Target);
flags = GetSamplerFlags(texsOp.Target); flags = GetTextureFlags(texsOp.Target);
if ((type & SamplerType.Array) != 0) if ((type & SamplerType.Array) != 0)
{ {
@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
else if (op is OpCodeTlds tldsOp) else if (op is OpCodeTlds tldsOp)
{ {
type = GetSamplerType (tldsOp.Target); type = GetSamplerType (tldsOp.Target);
flags = GetSamplerFlags(tldsOp.Target) | TextureFlags.IntCoords; flags = GetTextureFlags(tldsOp.Target) | TextureFlags.IntCoords;
switch (tldsOp.Target) switch (tldsOp.Target)
{ {
@ -874,7 +874,9 @@ namespace Ryujinx.Graphics.Shader.Instructions
return SamplerType.Texture3D; return SamplerType.Texture3D;
} }
throw new ArgumentException($"Invalid image target \"{target}\"."); // TODO: Error.
return SamplerType.Texture2D;
} }
private static SamplerType GetSamplerType(TextureDimensions dimensions) private static SamplerType GetSamplerType(TextureDimensions dimensions)
@ -923,7 +925,9 @@ namespace Ryujinx.Graphics.Shader.Instructions
return SamplerType.TextureCube; return SamplerType.TextureCube;
} }
throw new ArgumentException($"Invalid texture type \"{type}\"."); // TODO: Error.
return SamplerType.Texture2D;
} }
private static SamplerType GetSamplerType(TexelLoadTarget type) private static SamplerType GetSamplerType(TexelLoadTarget type)
@ -950,10 +954,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
return SamplerType.Texture2D | SamplerType.Array; return SamplerType.Texture2D | SamplerType.Array;
} }
throw new ArgumentException($"Invalid texture type \"{type}\"."); // TODO: Error.
return SamplerType.Texture2D;
} }
private static TextureFlags GetSamplerFlags(Decoders.TextureTarget type) private static TextureFlags GetTextureFlags(Decoders.TextureTarget type)
{ {
switch (type) switch (type)
{ {
@ -976,10 +982,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
return TextureFlags.None; return TextureFlags.None;
} }
throw new ArgumentException($"Invalid texture type \"{type}\"."); // TODO: Error.
return TextureFlags.None;
} }
private static TextureFlags GetSamplerFlags(TexelLoadTarget type) private static TextureFlags GetTextureFlags(TexelLoadTarget type)
{ {
switch (type) switch (type)
{ {
@ -997,7 +1005,9 @@ namespace Ryujinx.Graphics.Shader.Instructions
return TextureFlags.LodLevel | TextureFlags.Offset; return TextureFlags.LodLevel | TextureFlags.Offset;
} }
throw new ArgumentException($"Invalid texture type \"{type}\"."); // TODO: Error.
return TextureFlags.None;
} }
} }
} }

View file

@ -105,6 +105,8 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(ops); BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(ops);
if (irBlocks.Length > 0)
{
Dominance.FindDominators(irBlocks[0], irBlocks.Length); Dominance.FindDominators(irBlocks[0], irBlocks.Length);
Dominance.FindDominanceFrontiers(irBlocks); Dominance.FindDominanceFrontiers(irBlocks);
@ -112,6 +114,7 @@ namespace Ryujinx.Graphics.Shader.Translation
Ssa.Rename(irBlocks); Ssa.Rename(irBlocks);
Optimizer.Optimize(irBlocks, config.Stage); Optimizer.Optimize(irBlocks, config.Stage);
}
StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(irBlocks, config); StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(irBlocks, config);
@ -158,6 +161,13 @@ namespace Ryujinx.Graphics.Shader.Translation
context = new EmitterContext(header.Stage, header); context = new EmitterContext(header.Stage, header);
} }
if (cfg == null)
{
size = 0;
return new Operation[0];
}
ulong maxEndAddress = 0; ulong maxEndAddress = 0;
for (int blkIndex = 0; blkIndex < cfg.Length; blkIndex++) for (int blkIndex = 0; blkIndex < cfg.Length; blkIndex++)