mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-30 12:27:10 +02:00
Rewrite shader decoding stage (#2698)
* Rewrite shader decoding stage * Fix P2R constant buffer encoding * Fix PSET/PSETP * PR feedback * Log unimplemented shader instructions * Implement NOP * Remove using * PR feedback
This commit is contained in:
parent
9ac9489b8a
commit
a1b0fd1ba9
168 changed files with 12022 additions and 6388 deletions
|
@ -129,6 +129,31 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
}
|
||||
}
|
||||
|
||||
// Remove unreachable blocks.
|
||||
bool hasUnreachable;
|
||||
|
||||
do
|
||||
{
|
||||
hasUnreachable = false;
|
||||
|
||||
for (int blkIndex = 1; blkIndex < blocks.Count; blkIndex++)
|
||||
{
|
||||
BasicBlock block = blocks[blkIndex];
|
||||
|
||||
if (block.Predecessors.Count == 0)
|
||||
{
|
||||
block.Next = null;
|
||||
block.Branch = null;
|
||||
blocks.RemoveAt(blkIndex--);
|
||||
hasUnreachable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
block.Index = blkIndex;
|
||||
}
|
||||
}
|
||||
} while (hasUnreachable);
|
||||
|
||||
return new ControlFlowGraph(blocks.ToArray());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
|
@ -9,7 +11,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
class EmitterContext
|
||||
{
|
||||
public Block CurrBlock { get; set; }
|
||||
public OpCode CurrOp { get; set; }
|
||||
public InstOp CurrOp { get; set; }
|
||||
|
||||
public ShaderConfig Config { get; }
|
||||
|
||||
|
@ -30,6 +32,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
_labels = new Dictionary<ulong, Operand>();
|
||||
}
|
||||
|
||||
public T GetOp<T>() where T : unmanaged
|
||||
{
|
||||
Debug.Assert(Unsafe.SizeOf<T>() == sizeof(ulong));
|
||||
ulong op = CurrOp.RawOpCode;
|
||||
return Unsafe.As<ulong, T>(ref op);
|
||||
}
|
||||
|
||||
public Operand Add(Instruction inst, Operand dest = null, params Operand[] sources)
|
||||
{
|
||||
Operation operation = new Operation(inst, dest, sources);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
|
@ -113,11 +114,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
|
||||
{
|
||||
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);
|
||||
ReadOnlySpan<int> header = MemoryMarshal.Cast<ulong, int>(gpuAccessor.GetCode(address, 0x50));
|
||||
|
||||
int commonWord0 = header[0];
|
||||
int commonWord1 = header[1];
|
||||
int commonWord2 = header[2];
|
||||
int commonWord3 = header[3];
|
||||
int commonWord4 = header[4];
|
||||
|
||||
SphType = commonWord0.Extract(0, 5);
|
||||
Version = commonWord0.Extract(5, 5);
|
||||
|
@ -164,9 +167,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
ImapTypes = new ImapPixelType[32];
|
||||
|
||||
for (ulong i = 0; i < 32; i++)
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
byte imap = gpuAccessor.MemoryRead<byte>(address + 0x18 + i);
|
||||
byte imap = (byte)(header[6 + (i >> 2)] >> ((i & 3) * 8));
|
||||
|
||||
ImapTypes[i] = new ImapPixelType(
|
||||
(PixelImap)((imap >> 0) & 3),
|
||||
|
@ -175,8 +178,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
(PixelImap)((imap >> 6) & 3));
|
||||
}
|
||||
|
||||
int type2OmapTarget = gpuAccessor.MemoryRead<int>(address + 0x48);
|
||||
int type2Omap = gpuAccessor.MemoryRead<int>(address + 0x4c);
|
||||
int type2OmapTarget = header[18];
|
||||
int type2Omap = header[19];
|
||||
|
||||
OmapTargets = new OmapTarget[8];
|
||||
|
||||
|
|
|
@ -150,9 +150,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
for (int index = 0; index < block.OpCodes.Count; index++)
|
||||
{
|
||||
if (block.OpCodes[index] is OpCodeTextureBase texture)
|
||||
InstOp op = block.OpCodes[index];
|
||||
|
||||
if (op.Props.HasFlag(InstProps.Tex))
|
||||
{
|
||||
config.TextureHandlesForCache.Add(texture.HandleOffset);
|
||||
int tidB = (int)((op.RawOpCode >> 36) & 0x1fff);
|
||||
config.TextureHandlesForCache.Add(tidB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,15 +244,15 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++)
|
||||
{
|
||||
OpCode op = block.OpCodes[opIndex];
|
||||
InstOp op = block.OpCodes[opIndex];
|
||||
|
||||
if ((context.Config.Options.Flags & TranslationFlags.DebugMode) != 0)
|
||||
if (context.Config.Options.Flags.HasFlag(TranslationFlags.DebugMode))
|
||||
{
|
||||
string instName;
|
||||
|
||||
if (op.Emitter != null)
|
||||
{
|
||||
instName = op.Emitter.Method.Name;
|
||||
instName = op.Name.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -263,31 +266,36 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
context.Add(new CommentNode(dbgComment));
|
||||
}
|
||||
|
||||
if (op.NeverExecute)
|
||||
InstConditional opConditional = new InstConditional(op.RawOpCode);
|
||||
|
||||
bool noPred = op.Props.HasFlag(InstProps.NoPred);
|
||||
if (!noPred && opConditional.Pred == RegisterConsts.PredicateTrueIndex && opConditional.PredInv)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Operand predSkipLbl = null;
|
||||
|
||||
bool skipPredicateCheck = op is OpCodeBranch opBranch && !opBranch.PushTarget;
|
||||
|
||||
if (op is OpCodeBranchPop opBranchPop)
|
||||
if (op.Name == InstName.Sync || op.Name == InstName.Brk)
|
||||
{
|
||||
// If the instruction is a SYNC or BRK instruction with only one
|
||||
// possible target address, then the instruction is basically
|
||||
// just a simple branch, we can generate code similar to branch
|
||||
// instructions, with the condition check on the branch itself.
|
||||
skipPredicateCheck = opBranchPop.Targets.Count < 2;
|
||||
noPred = block.SyncTargets.Count <= 1;
|
||||
}
|
||||
else if (op.Name == InstName.Bra)
|
||||
{
|
||||
noPred = true;
|
||||
}
|
||||
|
||||
if (!(op.Predicate.IsPT || skipPredicateCheck))
|
||||
if (!(opConditional.Pred == RegisterConsts.PredicateTrueIndex || noPred))
|
||||
{
|
||||
Operand label;
|
||||
|
||||
if (opIndex == block.OpCodes.Count - 1 && block.Next != null)
|
||||
if (opIndex == block.OpCodes.Count - 1 && block.HasNext())
|
||||
{
|
||||
label = context.GetLabel(block.Next.Address);
|
||||
label = context.GetLabel(block.Successors[0].Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -296,9 +304,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
predSkipLbl = label;
|
||||
}
|
||||
|
||||
Operand pred = Register(op.Predicate);
|
||||
Operand pred = Register(opConditional.Pred, RegisterType.Predicate);
|
||||
|
||||
if (op.InvertPredicate)
|
||||
if (opConditional.PredInv)
|
||||
{
|
||||
context.BranchIfTrue(label, pred);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue