ryujinx/Ryujinx.Graphics.Shader/Decoders/Block.cs
gdkchan d9d18439f6
Use a new approach for shader BRX targets (#2532)
* Use a new approach for shader BRX targets

* Make shader cache actually work

* Improve the shader pattern matching a bit

* Extend LDC search to predecessor blocks, catches more cases

* Nit

* Only save the amount of constant buffer data actually used. Avoids crashes on partially mapped buffers

* Ignore Rd on predicate instructions, as they do not have a Rd register (catches more cases)
2021-08-11 20:59:42 +02:00

149 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.Decoders
{
class Block
{
public ulong Address { get; set; }
public ulong EndAddress { get; set; }
private Block _next;
private Block _branch;
public Block Next
{
get
{
return _next;
}
set
{
_next?.Predecessors.Remove(this);
value?.Predecessors.Add(this);
_next = value;
}
}
public Block Branch
{
get
{
return _branch;
}
set
{
_branch?.Predecessors.Remove(this);
value?.Predecessors.Add(this);
_branch = value;
}
}
public HashSet<Block> Predecessors { get; }
public List<OpCode> OpCodes { get; }
public List<OpCodePush> PushOpCodes { get; }
public Block(ulong address)
{
Address = address;
Predecessors = new HashSet<Block>();
OpCodes = new List<OpCode>();
PushOpCodes = new List<OpCodePush>();
}
public void Split(Block rightBlock)
{
int splitIndex = BinarySearch(OpCodes, rightBlock.Address);
if (OpCodes[splitIndex].Address < rightBlock.Address)
{
splitIndex++;
}
int splitCount = OpCodes.Count - splitIndex;
if (splitCount <= 0)
{
throw new ArgumentException("Can't split at right block address.");
}
rightBlock.EndAddress = EndAddress;
rightBlock.Next = Next;
rightBlock.Branch = Branch;
rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
rightBlock.UpdatePushOps();
EndAddress = rightBlock.Address;
Next = rightBlock;
Branch = null;
OpCodes.RemoveRange(splitIndex, splitCount);
UpdatePushOps();
}
private static int BinarySearch(List<OpCode> opCodes, ulong address)
{
int left = 0;
int middle = 0;
int right = opCodes.Count - 1;
while (left <= right)
{
int size = right - left;
middle = left + (size >> 1);
OpCode opCode = opCodes[middle];
if (address == opCode.Address)
{
break;
}
if (address < opCode.Address)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return middle;
}
public OpCode GetLastOp()
{
if (OpCodes.Count != 0)
{
return OpCodes[OpCodes.Count - 1];
}
return null;
}
public void UpdatePushOps()
{
PushOpCodes.Clear();
for (int index = 0; index < OpCodes.Count; index++)
{
if (!(OpCodes[index] is OpCodePush op))
{
continue;
}
PushOpCodes.Add(op);
}
}
}
}