Fix shaders with mixed PBK and SSY addresses on the stack (#2329)

* Fix shaders with mixed PBK and SSY addresses on the stack

* Address PR feedback and nits
This commit is contained in:
gdkchan 2021-06-02 20:41:53 -03:00 committed by GitHub
parent b84ba43406
commit 3b90adcd1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 29 deletions

View file

@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary> /// <summary>
/// Version of the codegen (to be changed when codegen or guest format change). /// Version of the codegen (to be changed when codegen or guest format change).
/// </summary> /// </summary>
private const ulong ShaderCodeGenVersion = 2317; private const ulong ShaderCodeGenVersion = 2329;
// Progress reporting helpers // Progress reporting helpers
private volatile int _shaderCount; private volatile int _shaderCount;

View file

@ -318,6 +318,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
opCode is OpCodeExit; opCode is OpCodeExit;
} }
private enum MergeType
{
Brk = 0,
Sync = 1
}
private struct PathBlockState private struct PathBlockState
{ {
public Block Block { get; } public Block Block { get; }
@ -332,6 +338,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
private RestoreType _restoreType; private RestoreType _restoreType;
private ulong _restoreValue; private ulong _restoreValue;
private MergeType _restoreMergeType;
public bool ReturningFromVisit => _restoreType != RestoreType.None; public bool ReturningFromVisit => _restoreType != RestoreType.None;
@ -340,6 +347,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Block = block; Block = block;
_restoreType = RestoreType.None; _restoreType = RestoreType.None;
_restoreValue = 0; _restoreValue = 0;
_restoreMergeType = default;
} }
public PathBlockState(int oldStackSize) public PathBlockState(int oldStackSize)
@ -347,20 +355,22 @@ namespace Ryujinx.Graphics.Shader.Decoders
Block = null; Block = null;
_restoreType = RestoreType.PopPushOp; _restoreType = RestoreType.PopPushOp;
_restoreValue = (ulong)oldStackSize; _restoreValue = (ulong)oldStackSize;
_restoreMergeType = default;
} }
public PathBlockState(ulong syncAddress) public PathBlockState(ulong syncAddress, MergeType mergeType)
{ {
Block = null; Block = null;
_restoreType = RestoreType.PushBranchOp; _restoreType = RestoreType.PushBranchOp;
_restoreValue = syncAddress; _restoreValue = syncAddress;
_restoreMergeType = mergeType;
} }
public void RestoreStackState(Stack<ulong> branchStack) public void RestoreStackState(Stack<(ulong, MergeType)> branchStack)
{ {
if (_restoreType == RestoreType.PushBranchOp) if (_restoreType == RestoreType.PushBranchOp)
{ {
branchStack.Push(_restoreValue); branchStack.Push((_restoreValue, _restoreMergeType));
} }
else if (_restoreType == RestoreType.PopPushOp) else if (_restoreType == RestoreType.PopPushOp)
{ {
@ -380,7 +390,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
HashSet<Block> visited = new HashSet<Block>(); HashSet<Block> visited = new HashSet<Block>();
Stack<ulong> branchStack = new Stack<ulong>(); Stack<(ulong, MergeType)> branchStack = new Stack<(ulong, MergeType)>();
void Push(PathBlockState pbs) void Push(PathBlockState pbs)
{ {
@ -426,7 +436,9 @@ namespace Ryujinx.Graphics.Shader.Decoders
for (int index = pushOpIndex; index < pushOpsCount; index++) for (int index = pushOpIndex; index < pushOpsCount; index++)
{ {
branchStack.Push(current.PushOpCodes[index].GetAbsoluteAddress()); OpCodePush currentPushOp = current.PushOpCodes[index];
MergeType pushMergeType = currentPushOp.Emitter == InstEmit.Ssy ? MergeType.Sync : MergeType.Brk;
branchStack.Push((currentPushOp.GetAbsoluteAddress(), pushMergeType));
} }
} }
@ -452,27 +464,51 @@ namespace Ryujinx.Graphics.Shader.Decoders
} }
else if (current.GetLastOp() is OpCodeBranchPop op) else if (current.GetLastOp() is OpCodeBranchPop op)
{ {
ulong targetAddress = branchStack.Pop(); MergeType popMergeType = op.Emitter == InstEmit.Sync ? MergeType.Sync : MergeType.Brk;
bool found = true;
ulong targetAddress = 0UL;
MergeType mergeType;
do
{
if (branchStack.Count == 0) if (branchStack.Count == 0)
{ {
branchStack.Push(targetAddress); found = false;
break;
}
(targetAddress, mergeType) = branchStack.Pop();
// Push the target address (this will be used to push the address
// back into the SSY/PBK stack when we return from that block),
Push(new PathBlockState(targetAddress, mergeType));
}
while (mergeType != popMergeType);
// Make sure we found the correct address,
// the push and pop instruction types must match, so:
// - BRK can only consume addresses pushed by PBK.
// - SYNC can only consume addresses pushed by SSY.
if (found)
{
if (branchStack.Count == 0)
{
// If the entire stack was consumed, then the current pop instruction
// just consumed the address from out push instruction.
op.Targets.Add(pushOp, op.Targets.Count); op.Targets.Add(pushOp, op.Targets.Count);
pushOp.PopOps.TryAdd(op, Local()); pushOp.PopOps.TryAdd(op, Local());
} }
else else
{ {
// First we push the target address (this will be used to push the // Push the block itself into the work "queue" (well, it's a stack)
// address back into the SSY/PBK stack when we return from that block),
// then we push the block itself into the work "queue" (well, it's a stack)
// for processing. // for processing.
Push(new PathBlockState(targetAddress));
Push(new PathBlockState(blocks[targetAddress])); Push(new PathBlockState(blocks[targetAddress]));
} }
} }
} }
} }
} }
}
} }

View file

@ -1,5 +1,4 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;