Split main project into core,graphics and chocolarm4 subproject (#29)
This commit is contained in:
parent
cb665bb715
commit
62b827f474
257 changed files with 415 additions and 285 deletions
468
Ryujinx.Graphics/Gpu/BCn.cs
Normal file
468
Ryujinx.Graphics/Gpu/BCn.cs
Normal file
|
@ -0,0 +1,468 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
static class BCn
|
||||
{
|
||||
public static byte[] DecodeBC1(NsGpuTexture Tex, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8);
|
||||
|
||||
for (int Y = 0; Y < H; Y++)
|
||||
{
|
||||
for (int X = 0; X < W; X++)
|
||||
{
|
||||
int IOffs = Offset + Swizzle.GetSwizzledAddress64(X, Y) * 8;
|
||||
|
||||
byte[] Tile = BCnDecodeTile(Tex.Data, IOffs, true);
|
||||
|
||||
int TOffset = 0;
|
||||
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
|
||||
|
||||
Output[OOffset + 0] = Tile[TOffset + 0];
|
||||
Output[OOffset + 1] = Tile[TOffset + 1];
|
||||
Output[OOffset + 2] = Tile[TOffset + 2];
|
||||
Output[OOffset + 3] = Tile[TOffset + 3];
|
||||
|
||||
TOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC2(NsGpuTexture Tex, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4);
|
||||
|
||||
for (int Y = 0; Y < H; Y++)
|
||||
{
|
||||
for (int X = 0; X < W; X++)
|
||||
{
|
||||
int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16;
|
||||
|
||||
byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false);
|
||||
|
||||
int AlphaLow = Get32(Tex.Data, IOffs + 0);
|
||||
int AlphaHigh = Get32(Tex.Data, IOffs + 4);
|
||||
|
||||
ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32;
|
||||
|
||||
int TOffset = 0;
|
||||
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
ulong Alpha = (AlphaCh >> (TY * 16 + TX * 4)) & 0xf;
|
||||
|
||||
int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
|
||||
|
||||
Output[OOffset + 0] = Tile[TOffset + 0];
|
||||
Output[OOffset + 1] = Tile[TOffset + 1];
|
||||
Output[OOffset + 2] = Tile[TOffset + 2];
|
||||
Output[OOffset + 3] = (byte)(Alpha | (Alpha << 4));
|
||||
|
||||
TOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC3(NsGpuTexture Tex, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4);
|
||||
|
||||
for (int Y = 0; Y < H; Y++)
|
||||
{
|
||||
for (int X = 0; X < W; X++)
|
||||
{
|
||||
int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16;
|
||||
|
||||
byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false);
|
||||
|
||||
byte[] Alpha = new byte[8];
|
||||
|
||||
Alpha[0] = Tex.Data[IOffs + 0];
|
||||
Alpha[1] = Tex.Data[IOffs + 1];
|
||||
|
||||
CalculateBC3Alpha(Alpha);
|
||||
|
||||
int AlphaLow = Get32(Tex.Data, IOffs + 2);
|
||||
int AlphaHigh = Get16(Tex.Data, IOffs + 6);
|
||||
|
||||
ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32;
|
||||
|
||||
int TOffset = 0;
|
||||
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
|
||||
|
||||
byte AlphaPx = Alpha[(AlphaCh >> (TY * 12 + TX * 3)) & 7];
|
||||
|
||||
Output[OOffset + 0] = Tile[TOffset + 0];
|
||||
Output[OOffset + 1] = Tile[TOffset + 1];
|
||||
Output[OOffset + 2] = Tile[TOffset + 2];
|
||||
Output[OOffset + 3] = AlphaPx;
|
||||
|
||||
TOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC4(NsGpuTexture Tex, int Offset)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8);
|
||||
|
||||
for (int Y = 0; Y < H; Y++)
|
||||
{
|
||||
for (int X = 0; X < W; X++)
|
||||
{
|
||||
int IOffs = Swizzle.GetSwizzledAddress64(X, Y) * 8;
|
||||
|
||||
byte[] Red = new byte[8];
|
||||
|
||||
Red[0] = Tex.Data[IOffs + 0];
|
||||
Red[1] = Tex.Data[IOffs + 1];
|
||||
|
||||
CalculateBC3Alpha(Red);
|
||||
|
||||
int RedLow = Get32(Tex.Data, IOffs + 2);
|
||||
int RedHigh = Get16(Tex.Data, IOffs + 6);
|
||||
|
||||
ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32;
|
||||
|
||||
int TOffset = 0;
|
||||
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
|
||||
|
||||
byte RedPx = Red[(RedCh >> (TY * 12 + TX * 3)) & 7];
|
||||
|
||||
Output[OOffset + 0] = RedPx;
|
||||
Output[OOffset + 1] = RedPx;
|
||||
Output[OOffset + 2] = RedPx;
|
||||
Output[OOffset + 3] = 0xff;
|
||||
|
||||
TOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC5(NsGpuTexture Tex, int Offset, bool SNorm)
|
||||
{
|
||||
int W = (Tex.Width + 3) / 4;
|
||||
int H = (Tex.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[W * H * 64];
|
||||
|
||||
SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4);
|
||||
|
||||
for (int Y = 0; Y < H; Y++)
|
||||
{
|
||||
for (int X = 0; X < W; X++)
|
||||
{
|
||||
int IOffs = Swizzle.GetSwizzledAddress128(X, Y) * 16;
|
||||
|
||||
byte[] Red = new byte[8];
|
||||
byte[] Green = new byte[8];
|
||||
|
||||
Red[0] = Tex.Data[IOffs + 0];
|
||||
Red[1] = Tex.Data[IOffs + 1];
|
||||
|
||||
Green[0] = Tex.Data[IOffs + 8];
|
||||
Green[1] = Tex.Data[IOffs + 9];
|
||||
|
||||
if (SNorm)
|
||||
{
|
||||
CalculateBC3AlphaS(Red);
|
||||
CalculateBC3AlphaS(Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateBC3Alpha(Red);
|
||||
CalculateBC3Alpha(Green);
|
||||
}
|
||||
|
||||
int RedLow = Get32(Tex.Data, IOffs + 2);
|
||||
int RedHigh = Get16(Tex.Data, IOffs + 6);
|
||||
|
||||
int GreenLow = Get32(Tex.Data, IOffs + 10);
|
||||
int GreenHigh = Get16(Tex.Data, IOffs + 14);
|
||||
|
||||
ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32;
|
||||
ulong GreenCh = (uint)GreenLow | (ulong)GreenHigh << 32;
|
||||
|
||||
int TOffset = 0;
|
||||
|
||||
if (SNorm)
|
||||
{
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
int Shift = TY * 12 + TX * 3;
|
||||
|
||||
int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
|
||||
|
||||
byte RedPx = Red [(RedCh >> Shift) & 7];
|
||||
byte GreenPx = Green[(GreenCh >> Shift) & 7];
|
||||
|
||||
RedPx += 0x80;
|
||||
GreenPx += 0x80;
|
||||
|
||||
float NX = (RedPx / 255f) * 2 - 1;
|
||||
float NY = (GreenPx / 255f) * 2 - 1;
|
||||
|
||||
float NZ = (float)Math.Sqrt(1 - (NX * NX + NY * NY));
|
||||
|
||||
Output[OOffset + 0] = Clamp((NZ + 1) * 0.5f);
|
||||
Output[OOffset + 1] = Clamp((NY + 1) * 0.5f);
|
||||
Output[OOffset + 2] = Clamp((NX + 1) * 0.5f);
|
||||
Output[OOffset + 3] = 0xff;
|
||||
|
||||
TOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
int Shift = TY * 12 + TX * 3;
|
||||
|
||||
int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
|
||||
|
||||
byte RedPx = Red [(RedCh >> Shift) & 7];
|
||||
byte GreenPx = Green[(GreenCh >> Shift) & 7];
|
||||
|
||||
Output[OOffset + 0] = RedPx;
|
||||
Output[OOffset + 1] = RedPx;
|
||||
Output[OOffset + 2] = RedPx;
|
||||
Output[OOffset + 3] = GreenPx;
|
||||
|
||||
TOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
private static byte Clamp(float Value)
|
||||
{
|
||||
if (Value > 1)
|
||||
{
|
||||
return 0xff;
|
||||
}
|
||||
else if (Value < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (byte)(Value * 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CalculateBC3Alpha(byte[] Alpha)
|
||||
{
|
||||
for (int i = 2; i < 8; i++)
|
||||
{
|
||||
if (Alpha[0] > Alpha[1])
|
||||
{
|
||||
Alpha[i] = (byte)(((8 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7);
|
||||
}
|
||||
else if (i < 6)
|
||||
{
|
||||
Alpha[i] = (byte)(((6 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7);
|
||||
}
|
||||
else if (i == 6)
|
||||
{
|
||||
Alpha[i] = 0;
|
||||
}
|
||||
else /* i == 7 */
|
||||
{
|
||||
Alpha[i] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CalculateBC3AlphaS(byte[] Alpha)
|
||||
{
|
||||
for (int i = 2; i < 8; i++)
|
||||
{
|
||||
if ((sbyte)Alpha[0] > (sbyte)Alpha[1])
|
||||
{
|
||||
Alpha[i] = (byte)(((8 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7);
|
||||
}
|
||||
else if (i < 6)
|
||||
{
|
||||
Alpha[i] = (byte)(((6 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7);
|
||||
}
|
||||
else if (i == 6)
|
||||
{
|
||||
Alpha[i] = 0x80;
|
||||
}
|
||||
else /* i == 7 */
|
||||
{
|
||||
Alpha[i] = 0x7f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] BCnDecodeTile(
|
||||
byte[] Input,
|
||||
int Offset,
|
||||
bool IsBC1)
|
||||
{
|
||||
Color[] CLUT = new Color[4];
|
||||
|
||||
int c0 = Get16(Input, Offset + 0);
|
||||
int c1 = Get16(Input, Offset + 2);
|
||||
|
||||
CLUT[0] = DecodeRGB565(c0);
|
||||
CLUT[1] = DecodeRGB565(c1);
|
||||
CLUT[2] = CalculateCLUT2(CLUT[0], CLUT[1], c0, c1, IsBC1);
|
||||
CLUT[3] = CalculateCLUT3(CLUT[0], CLUT[1], c0, c1, IsBC1);
|
||||
|
||||
int Indices = Get32(Input, Offset + 4);
|
||||
|
||||
int IdxShift = 0;
|
||||
|
||||
byte[] Output = new byte[4 * 4 * 4];
|
||||
|
||||
int OOffset = 0;
|
||||
|
||||
for (int TY = 0; TY < 4; TY++)
|
||||
{
|
||||
for (int TX = 0; TX < 4; TX++)
|
||||
{
|
||||
int Idx = (Indices >> IdxShift) & 3;
|
||||
|
||||
IdxShift += 2;
|
||||
|
||||
Color Pixel = CLUT[Idx];
|
||||
|
||||
Output[OOffset + 0] = Pixel.R;
|
||||
Output[OOffset + 1] = Pixel.G;
|
||||
Output[OOffset + 2] = Pixel.B;
|
||||
Output[OOffset + 3] = Pixel.A;
|
||||
|
||||
OOffset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
private static Color CalculateCLUT2(Color C0, Color C1, int c0, int c1, bool IsBC1)
|
||||
{
|
||||
if (c0 > c1 || !IsBC1)
|
||||
{
|
||||
return Color.FromArgb(
|
||||
(2 * C0.R + C1.R) / 3,
|
||||
(2 * C0.G + C1.G) / 3,
|
||||
(2 * C0.B + C1.B) / 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.FromArgb(
|
||||
(C0.R + C1.R) / 2,
|
||||
(C0.G + C1.G) / 2,
|
||||
(C0.B + C1.B) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static Color CalculateCLUT3(Color C0, Color C1, int c0, int c1, bool IsBC1)
|
||||
{
|
||||
if (c0 > c1 || !IsBC1)
|
||||
{
|
||||
return
|
||||
Color.FromArgb(
|
||||
(2 * C1.R + C0.R) / 3,
|
||||
(2 * C1.G + C0.G) / 3,
|
||||
(2 * C1.B + C0.B) / 3);
|
||||
}
|
||||
|
||||
return Color.Transparent;
|
||||
}
|
||||
|
||||
private static Color DecodeRGB565(int Value)
|
||||
{
|
||||
int B = ((Value >> 0) & 0x1f) << 3;
|
||||
int G = ((Value >> 5) & 0x3f) << 2;
|
||||
int R = ((Value >> 11) & 0x1f) << 3;
|
||||
|
||||
return Color.FromArgb(
|
||||
R | (R >> 5),
|
||||
G | (G >> 6),
|
||||
B | (B >> 5));
|
||||
}
|
||||
|
||||
private static int Get16(byte[] Data, int Address)
|
||||
{
|
||||
return
|
||||
Data[Address + 0] << 0 |
|
||||
Data[Address + 1] << 8;
|
||||
}
|
||||
|
||||
private static int Get32(byte[] Data, int Address)
|
||||
{
|
||||
return
|
||||
Data[Address + 0] << 0 |
|
||||
Data[Address + 1] << 8 |
|
||||
Data[Address + 2] << 16 |
|
||||
Data[Address + 3] << 24;
|
||||
}
|
||||
}
|
||||
}
|
53
Ryujinx.Graphics/Gpu/NsGpu.cs
Normal file
53
Ryujinx.Graphics/Gpu/NsGpu.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
public class NsGpu
|
||||
{
|
||||
public IGalRenderer Renderer { get; private set; }
|
||||
|
||||
internal NsGpuMemoryMgr MemoryMgr { get; private set; }
|
||||
|
||||
internal NsGpuPGraph PGraph { get; private set; }
|
||||
|
||||
public NsGpu(IGalRenderer Renderer)
|
||||
{
|
||||
this.Renderer = Renderer;
|
||||
|
||||
MemoryMgr = new NsGpuMemoryMgr();
|
||||
|
||||
PGraph = new NsGpuPGraph(this);
|
||||
}
|
||||
|
||||
public long GetCpuAddr(long Position)
|
||||
{
|
||||
return MemoryMgr.GetCpuAddr(Position);
|
||||
}
|
||||
|
||||
public long MapMemory(long CpuAddr, long Size)
|
||||
{
|
||||
return MemoryMgr.Map(CpuAddr, Size);
|
||||
}
|
||||
|
||||
public long MapMemory(long CpuAddr, long GpuAddr, long Size)
|
||||
{
|
||||
return MemoryMgr.Map(CpuAddr, GpuAddr, Size);
|
||||
}
|
||||
|
||||
public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory)
|
||||
{
|
||||
PGraph.ProcessPushBuffer(PushBuffer, Memory);
|
||||
}
|
||||
|
||||
public long ReserveMemory(long Size, long Align)
|
||||
{
|
||||
return MemoryMgr.Reserve(Size, Align);
|
||||
}
|
||||
|
||||
public long ReserveMemory(long GpuAddr, long Size, long Align)
|
||||
{
|
||||
return MemoryMgr.Reserve(GpuAddr, Size, Align);
|
||||
}
|
||||
}
|
||||
}
|
13
Ryujinx.Graphics/Gpu/NsGpuEngine.cs
Normal file
13
Ryujinx.Graphics/Gpu/NsGpuEngine.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
enum NsGpuEngine
|
||||
{
|
||||
None = 0,
|
||||
_2d = 0x902d,
|
||||
_3d = 0xb197,
|
||||
Compute = 0xb1c0,
|
||||
Kepler = 0xa140,
|
||||
Dma = 0xb0b5,
|
||||
GpFifo = 0xb06f
|
||||
}
|
||||
}
|
204
Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
Normal file
204
Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
Normal file
|
@ -0,0 +1,204 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
class NsGpuMemoryMgr
|
||||
{
|
||||
private const long AddrSize = 1L << 40;
|
||||
|
||||
private const int PTLvl0Bits = 14;
|
||||
private const int PTLvl1Bits = 14;
|
||||
private const int PTPageBits = 12;
|
||||
|
||||
private const int PTLvl0Size = 1 << PTLvl0Bits;
|
||||
private const int PTLvl1Size = 1 << PTLvl1Bits;
|
||||
private const int PageSize = 1 << PTPageBits;
|
||||
|
||||
private const int PTLvl0Mask = PTLvl0Size - 1;
|
||||
private const int PTLvl1Mask = PTLvl1Size - 1;
|
||||
private const int PageMask = PageSize - 1;
|
||||
|
||||
private const int PTLvl0Bit = PTPageBits + PTLvl0Bits;
|
||||
private const int PTLvl1Bit = PTPageBits;
|
||||
|
||||
private const long PteUnmapped = -1;
|
||||
private const long PteReserved = -2;
|
||||
|
||||
private long[][] PageTable;
|
||||
|
||||
public NsGpuMemoryMgr()
|
||||
{
|
||||
PageTable = new long[PTLvl0Size][];
|
||||
}
|
||||
|
||||
public long Map(long CpuAddr, long GpuAddr, long Size)
|
||||
{
|
||||
CpuAddr &= ~PageMask;
|
||||
GpuAddr &= ~PageMask;
|
||||
|
||||
for (long Offset = 0; Offset < Size; Offset += PageSize)
|
||||
{
|
||||
if (GetPTAddr(GpuAddr + Offset) != PteReserved)
|
||||
{
|
||||
return Map(CpuAddr, Size);
|
||||
}
|
||||
}
|
||||
|
||||
for (long Offset = 0; Offset < Size; Offset += PageSize)
|
||||
{
|
||||
SetPTAddr(GpuAddr + Offset, CpuAddr + Offset);
|
||||
}
|
||||
|
||||
return GpuAddr;
|
||||
}
|
||||
|
||||
public long Map(long CpuAddr, long Size)
|
||||
{
|
||||
CpuAddr &= ~PageMask;
|
||||
|
||||
long Position = GetFreePosition(Size);
|
||||
|
||||
if (Position != -1)
|
||||
{
|
||||
for (long Offset = 0; Offset < Size; Offset += PageSize)
|
||||
{
|
||||
SetPTAddr(Position + Offset, CpuAddr + Offset);
|
||||
}
|
||||
}
|
||||
|
||||
return Position;
|
||||
}
|
||||
|
||||
public long Reserve(long GpuAddr, long Size, long Align)
|
||||
{
|
||||
for (long Offset = 0; Offset < Size; Offset += PageSize)
|
||||
{
|
||||
if (HasPTAddr(GpuAddr + Offset))
|
||||
{
|
||||
return Reserve(Size, Align);
|
||||
}
|
||||
}
|
||||
|
||||
for (long Offset = 0; Offset < Size; Offset += PageSize)
|
||||
{
|
||||
SetPTAddr(GpuAddr + Offset, PteReserved);
|
||||
}
|
||||
|
||||
return GpuAddr;
|
||||
}
|
||||
|
||||
public long Reserve(long Size, long Align)
|
||||
{
|
||||
long Position = GetFreePosition(Size, Align);
|
||||
|
||||
if (Position != -1)
|
||||
{
|
||||
for (long Offset = 0; Offset < Size; Offset += PageSize)
|
||||
{
|
||||
SetPTAddr(Position + Offset, PteReserved);
|
||||
}
|
||||
}
|
||||
|
||||
return Position;
|
||||
}
|
||||
|
||||
private long GetFreePosition(long Size, long Align = 1)
|
||||
{
|
||||
long Position = 0;
|
||||
long FreeSize = 0;
|
||||
|
||||
if (Align < 1)
|
||||
{
|
||||
Align = 1;
|
||||
}
|
||||
|
||||
Align = (Align + PageMask) & ~PageMask;
|
||||
|
||||
while (Position + FreeSize < AddrSize)
|
||||
{
|
||||
if (!HasPTAddr(Position + FreeSize))
|
||||
{
|
||||
FreeSize += PageSize;
|
||||
|
||||
if (FreeSize >= Size)
|
||||
{
|
||||
return Position;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Position += FreeSize + PageSize;
|
||||
FreeSize = 0;
|
||||
|
||||
long Remainder = Position % Align;
|
||||
|
||||
if (Remainder != 0)
|
||||
{
|
||||
Position = (Position - Remainder) + Align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public long GetCpuAddr(long Position)
|
||||
{
|
||||
long BasePos = GetPTAddr(Position);
|
||||
|
||||
if (BasePos < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return BasePos + (Position & PageMask);
|
||||
}
|
||||
|
||||
private bool HasPTAddr(long Position)
|
||||
{
|
||||
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
|
||||
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
|
||||
|
||||
if (PageTable[L0] == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return PageTable[L0][L1] != PteUnmapped;
|
||||
}
|
||||
|
||||
private long GetPTAddr(long Position)
|
||||
{
|
||||
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
|
||||
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
|
||||
|
||||
if (PageTable[L0] == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return PageTable[L0][L1];
|
||||
}
|
||||
|
||||
private void SetPTAddr(long Position, long TgtAddr)
|
||||
{
|
||||
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
|
||||
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
|
||||
|
||||
if (PageTable[L0] == null)
|
||||
{
|
||||
PageTable[L0] = new long[PTLvl1Size];
|
||||
|
||||
for (int Index = 0; Index < PTLvl1Size; Index++)
|
||||
{
|
||||
PageTable[L0][Index] = PteUnmapped;
|
||||
}
|
||||
}
|
||||
|
||||
PageTable[L0][L1] = TgtAddr;
|
||||
}
|
||||
}
|
||||
}
|
79
Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs
Normal file
79
Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
public struct NsGpuPBEntry
|
||||
{
|
||||
public NsGpuRegister Register { get; private set; }
|
||||
|
||||
public int SubChannel { get; private set; }
|
||||
|
||||
private int[] m_Arguments;
|
||||
|
||||
public ReadOnlyCollection<int> Arguments => Array.AsReadOnly(m_Arguments);
|
||||
|
||||
public NsGpuPBEntry(NsGpuRegister Register, int SubChannel, params int[] Arguments)
|
||||
{
|
||||
this.Register = Register;
|
||||
this.SubChannel = SubChannel;
|
||||
this.m_Arguments = Arguments;
|
||||
}
|
||||
|
||||
public static NsGpuPBEntry[] DecodePushBuffer(byte[] Data)
|
||||
{
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
List<NsGpuPBEntry> GpFifos = new List<NsGpuPBEntry>();
|
||||
|
||||
bool CanRead() => MS.Position + 4 <= MS.Length;
|
||||
|
||||
while (CanRead())
|
||||
{
|
||||
int Packed = Reader.ReadInt32();
|
||||
|
||||
int Reg = (Packed << 2) & 0x7ffc;
|
||||
int SubC = (Packed >> 13) & 7;
|
||||
int Args = (Packed >> 16) & 0x1fff;
|
||||
int Mode = (Packed >> 29) & 7;
|
||||
|
||||
if (Mode == 4)
|
||||
{
|
||||
//Inline Mode.
|
||||
GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Args));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Word mode.
|
||||
if (Mode == 1)
|
||||
{
|
||||
//Sequential Mode.
|
||||
for (int Index = 0; Index < Args && CanRead(); Index++, Reg += 4)
|
||||
{
|
||||
GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Reader.ReadInt32()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Non-Sequential Mode.
|
||||
int[] Arguments = new int[Args];
|
||||
|
||||
for (int Index = 0; Index < Args && CanRead(); Index++)
|
||||
{
|
||||
Arguments[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GpFifos.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
276
Ryujinx.Graphics/Gpu/NsGpuPGraph.cs
Normal file
276
Ryujinx.Graphics/Gpu/NsGpuPGraph.cs
Normal file
|
@ -0,0 +1,276 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
class NsGpuPGraph
|
||||
{
|
||||
private NsGpu Gpu;
|
||||
|
||||
private int[] Registers;
|
||||
|
||||
public NsGpuEngine[] SubChannels;
|
||||
|
||||
private Dictionary<long, int> CurrentVertexBuffers;
|
||||
|
||||
public NsGpuPGraph(NsGpu Gpu)
|
||||
{
|
||||
this.Gpu = Gpu;
|
||||
|
||||
Registers = new int[0x1000];
|
||||
|
||||
SubChannels = new NsGpuEngine[8];
|
||||
|
||||
CurrentVertexBuffers = new Dictionary<long, int>();
|
||||
}
|
||||
|
||||
public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory)
|
||||
{
|
||||
bool HasQuery = false;
|
||||
|
||||
foreach (NsGpuPBEntry Entry in PushBuffer)
|
||||
{
|
||||
if (Entry.Arguments.Count == 1)
|
||||
{
|
||||
SetRegister(Entry.Register, Entry.Arguments[0]);
|
||||
}
|
||||
|
||||
switch (Entry.Register)
|
||||
{
|
||||
case NsGpuRegister.BindChannel:
|
||||
if (Entry.Arguments.Count > 0)
|
||||
{
|
||||
SubChannels[Entry.SubChannel] = (NsGpuEngine)Entry.Arguments[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case NsGpuRegister._3dVertexArray0Fetch:
|
||||
SendVertexBuffers(Memory);
|
||||
break;
|
||||
|
||||
case NsGpuRegister._3dCbData0:
|
||||
if (GetRegister(NsGpuRegister._3dCbPos) == 0x20)
|
||||
{
|
||||
SendTexture(Memory);
|
||||
}
|
||||
break;
|
||||
|
||||
case NsGpuRegister._3dQueryAddressHigh:
|
||||
case NsGpuRegister._3dQueryAddressLow:
|
||||
case NsGpuRegister._3dQuerySequence:
|
||||
case NsGpuRegister._3dQueryGet:
|
||||
HasQuery = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasQuery)
|
||||
{
|
||||
long Position =
|
||||
(long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 |
|
||||
(long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0;
|
||||
|
||||
int Seq = GetRegister(NsGpuRegister._3dQuerySequence);
|
||||
int Get = GetRegister(NsGpuRegister._3dQueryGet);
|
||||
|
||||
int Mode = Get & 3;
|
||||
|
||||
if (Mode == 0)
|
||||
{
|
||||
//Write
|
||||
Position = Gpu.MemoryMgr.GetCpuAddr(Position);
|
||||
|
||||
if (Position != -1)
|
||||
{
|
||||
Gpu.Renderer.QueueAction(delegate()
|
||||
{
|
||||
Memory.WriteInt32(Position, Seq);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendVertexBuffers(AMemory Memory)
|
||||
{
|
||||
long Position =
|
||||
(long)GetRegister(NsGpuRegister._3dVertexArray0StartHigh) << 32 |
|
||||
(long)GetRegister(NsGpuRegister._3dVertexArray0StartLow) << 0;
|
||||
|
||||
long Limit =
|
||||
(long)GetRegister(NsGpuRegister._3dVertexArray0LimitHigh) << 32 |
|
||||
(long)GetRegister(NsGpuRegister._3dVertexArray0LimitLow) << 0;
|
||||
|
||||
int VbIndex = CurrentVertexBuffers.Count;
|
||||
|
||||
if (!CurrentVertexBuffers.TryAdd(Position, VbIndex))
|
||||
{
|
||||
VbIndex = CurrentVertexBuffers[Position];
|
||||
}
|
||||
|
||||
if (Limit != 0)
|
||||
{
|
||||
long Size = (Limit - Position) + 1;
|
||||
|
||||
Position = Gpu.MemoryMgr.GetCpuAddr(Position);
|
||||
|
||||
if (Position != -1)
|
||||
{
|
||||
byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, (int)Size);
|
||||
|
||||
int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff;
|
||||
|
||||
List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>();
|
||||
|
||||
for (int Attr = 0; Attr < 16; Attr++)
|
||||
{
|
||||
int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4);
|
||||
|
||||
GalVertexAttrib Attrib = new GalVertexAttrib(Attr,
|
||||
(Packed >> 0) & 0x1f,
|
||||
((Packed >> 6) & 0x1) != 0,
|
||||
(Packed >> 7) & 0x3fff,
|
||||
(GalVertexAttribSize)((Packed >> 21) & 0x3f),
|
||||
(GalVertexAttribType)((Packed >> 27) & 0x7),
|
||||
((Packed >> 31) & 0x1) != 0);
|
||||
|
||||
if (Attrib.Offset < Stride)
|
||||
{
|
||||
Attribs.Add(Attrib);
|
||||
}
|
||||
}
|
||||
|
||||
Gpu.Renderer.QueueAction(delegate()
|
||||
{
|
||||
Gpu.Renderer.SendVertexBuffer(VbIndex, Buffer, Stride, Attribs.ToArray());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendTexture(AMemory Memory)
|
||||
{
|
||||
long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 |
|
||||
(long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0;
|
||||
|
||||
int CbData = GetRegister(NsGpuRegister._3dCbData0);
|
||||
|
||||
int TicIndex = (CbData >> 0) & 0xfffff;
|
||||
int TscIndex = (CbData >> 20) & 0xfff; //I guess?
|
||||
|
||||
TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20);
|
||||
|
||||
if (TicPos != -1)
|
||||
{
|
||||
int Word0 = Memory.ReadInt32(TicPos + 0x0);
|
||||
int Word1 = Memory.ReadInt32(TicPos + 0x4);
|
||||
int Word2 = Memory.ReadInt32(TicPos + 0x8);
|
||||
int Word3 = Memory.ReadInt32(TicPos + 0xc);
|
||||
int Word4 = Memory.ReadInt32(TicPos + 0x10);
|
||||
int Word5 = Memory.ReadInt32(TicPos + 0x14);
|
||||
int Word6 = Memory.ReadInt32(TicPos + 0x18);
|
||||
int Word7 = Memory.ReadInt32(TicPos + 0x1c);
|
||||
|
||||
long TexAddress = Word1;
|
||||
|
||||
TexAddress |= (long)(Word2 & 0xff) << 32;
|
||||
|
||||
TexAddress = Gpu.MemoryMgr.GetCpuAddr(TexAddress);
|
||||
|
||||
if (TexAddress != -1)
|
||||
{
|
||||
NsGpuTextureFormat Format = (NsGpuTextureFormat)(Word0 & 0x7f);
|
||||
|
||||
int Width = (Word4 & 0xffff) + 1;
|
||||
int Height = (Word5 & 0xffff) + 1;
|
||||
|
||||
byte[] Buffer = GetDecodedTexture(Memory, Format, TexAddress, Width, Height);
|
||||
|
||||
if (Buffer != null)
|
||||
{
|
||||
Gpu.Renderer.QueueAction(delegate()
|
||||
{
|
||||
Gpu.Renderer.SendR8G8B8A8Texture(0, Buffer, Width, Height);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GetDecodedTexture(
|
||||
AMemory Memory,
|
||||
NsGpuTextureFormat Format,
|
||||
long Position,
|
||||
int Width,
|
||||
int Height)
|
||||
{
|
||||
byte[] Data = null;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case NsGpuTextureFormat.BC1:
|
||||
{
|
||||
int Size = (Width * Height) >> 1;
|
||||
|
||||
Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
|
||||
|
||||
Data = BCn.DecodeBC1(new NsGpuTexture()
|
||||
{
|
||||
Width = Width,
|
||||
Height = Height,
|
||||
Data = Data
|
||||
}, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NsGpuTextureFormat.BC2:
|
||||
{
|
||||
int Size = Width * Height;
|
||||
|
||||
Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
|
||||
|
||||
Data = BCn.DecodeBC2(new NsGpuTexture()
|
||||
{
|
||||
Width = Width,
|
||||
Height = Height,
|
||||
Data = Data
|
||||
}, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NsGpuTextureFormat.BC3:
|
||||
{
|
||||
int Size = Width * Height;
|
||||
|
||||
Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
|
||||
|
||||
Data = BCn.DecodeBC3(new NsGpuTexture()
|
||||
{
|
||||
Width = Width,
|
||||
Height = Height,
|
||||
Data = Data
|
||||
}, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//default: throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
public int GetRegister(NsGpuRegister Register)
|
||||
{
|
||||
return Registers[((int)Register >> 2) & 0xfff];
|
||||
}
|
||||
|
||||
public void SetRegister(NsGpuRegister Register, int Value)
|
||||
{
|
||||
Registers[((int)Register >> 2) & 0xfff] = Value;
|
||||
}
|
||||
}
|
||||
}
|
93
Ryujinx.Graphics/Gpu/NsGpuRegister.cs
Normal file
93
Ryujinx.Graphics/Gpu/NsGpuRegister.cs
Normal file
|
@ -0,0 +1,93 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
public enum NsGpuRegister
|
||||
{
|
||||
BindChannel = 0,
|
||||
|
||||
_2dClipEnable = 0x0290,
|
||||
_2dOperation = 0x02ac,
|
||||
|
||||
_3dGlobalBase = 0x02c8,
|
||||
_3dRt0AddressHigh = 0x0800,
|
||||
_3dRt0AddressLow = 0x0804,
|
||||
_3dRt0Horiz = 0x0808,
|
||||
_3dRt0Vert = 0x080c,
|
||||
_3dRt0Format = 0x0810,
|
||||
_3dRt0BlockDimensions = 0x0814,
|
||||
_3dRt0ArrayMode = 0x0818,
|
||||
_3dRt0LayerStride = 0x081c,
|
||||
_3dRt0BaseLayer = 0x0820,
|
||||
_3dViewportScaleX = 0x0a00,
|
||||
_3dViewportScaleY = 0x0a04,
|
||||
_3dViewportScaleZ = 0x0a08,
|
||||
_3dViewportTranslateX = 0x0a0c,
|
||||
_3dViewportTranslateY = 0x0a10,
|
||||
_3dViewportTranslateZ = 0x0a14,
|
||||
_3dViewportHoriz = 0x0c00,
|
||||
_3dViewportVert = 0x0c04,
|
||||
_3dDepthRangeNear = 0x0c08,
|
||||
_3dDepthRangeFar = 0x0c0c,
|
||||
_3dClearColorR = 0x0d80,
|
||||
_3dClearColorG = 0x0d84,
|
||||
_3dClearColorB = 0x0d88,
|
||||
_3dClearColorA = 0x0d8c,
|
||||
_3dScreenScissorHoriz = 0x0ff4,
|
||||
_3dScreenScissorVert = 0x0ff8,
|
||||
_3dVertexAttrib0Format = 0x1160,
|
||||
_3dVertexAttrib1Format = 0x1164,
|
||||
_3dVertexAttrib2Format = 0x1168,
|
||||
_3dVertexAttrib3Format = 0x116c,
|
||||
_3dVertexAttrib4Format = 0x1170,
|
||||
_3dVertexAttrib5Format = 0x1174,
|
||||
_3dVertexAttrib6Format = 0x1178,
|
||||
_3dVertexAttrib7Format = 0x117c,
|
||||
_3dVertexAttrib8Format = 0x1180,
|
||||
_3dVertexAttrib9Format = 0x1184,
|
||||
_3dVertexAttrib10Format = 0x1188,
|
||||
_3dVertexAttrib11Format = 0x118c,
|
||||
_3dVertexAttrib12Format = 0x1190,
|
||||
_3dVertexAttrib13Format = 0x1194,
|
||||
_3dVertexAttrib14Format = 0x1198,
|
||||
_3dVertexAttrib15Format = 0x119c,
|
||||
_3dScreenYControl = 0x13ac,
|
||||
_3dTscAddressHigh = 0x155c,
|
||||
_3dTscAddressLow = 0x1560,
|
||||
_3dTscLimit = 0x1564,
|
||||
_3dTicAddressHigh = 0x1574,
|
||||
_3dTicAddressLow = 0x1578,
|
||||
_3dTicLimit = 0x157c,
|
||||
_3dMultiSampleMode = 0x15d0,
|
||||
_3dVertexEndGl = 0x1614,
|
||||
_3dVertexBeginGl = 0x1618,
|
||||
_3dQueryAddressHigh = 0x1b00,
|
||||
_3dQueryAddressLow = 0x1b04,
|
||||
_3dQuerySequence = 0x1b08,
|
||||
_3dQueryGet = 0x1b0c,
|
||||
_3dVertexArray0Fetch = 0x1c00,
|
||||
_3dVertexArray0StartHigh = 0x1c04,
|
||||
_3dVertexArray0StartLow = 0x1c08,
|
||||
_3dVertexArray1Fetch = 0x1c10, //todo: the rest
|
||||
_3dVertexArray0LimitHigh = 0x1f00,
|
||||
_3dVertexArray0LimitLow = 0x1f04,
|
||||
_3dCbSize = 0x2380,
|
||||
_3dCbAddressHigh = 0x2384,
|
||||
_3dCbAddressLow = 0x2388,
|
||||
_3dCbPos = 0x238c,
|
||||
_3dCbData0 = 0x2390,
|
||||
_3dCbData1 = 0x2394,
|
||||
_3dCbData2 = 0x2398,
|
||||
_3dCbData3 = 0x239c,
|
||||
_3dCbData4 = 0x23a0,
|
||||
_3dCbData5 = 0x23a4,
|
||||
_3dCbData6 = 0x23a8,
|
||||
_3dCbData7 = 0x23ac,
|
||||
_3dCbData8 = 0x23b0,
|
||||
_3dCbData9 = 0x23b4,
|
||||
_3dCbData10 = 0x23b8,
|
||||
_3dCbData11 = 0x23bc,
|
||||
_3dCbData12 = 0x23c0,
|
||||
_3dCbData13 = 0x23c4,
|
||||
_3dCbData14 = 0x23c8,
|
||||
_3dCbData15 = 0x23cc,
|
||||
}
|
||||
}
|
10
Ryujinx.Graphics/Gpu/NsGpuTexture.cs
Normal file
10
Ryujinx.Graphics/Gpu/NsGpuTexture.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
struct NsGpuTexture
|
||||
{
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
public byte[] Data;
|
||||
}
|
||||
}
|
9
Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs
Normal file
9
Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
enum NsGpuTextureFormat
|
||||
{
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26
|
||||
}
|
||||
}
|
144
Ryujinx.Graphics/Gpu/SwizzleAddr.cs
Normal file
144
Ryujinx.Graphics/Gpu/SwizzleAddr.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
class SwizzleAddr
|
||||
{
|
||||
private int Width;
|
||||
|
||||
private int XB;
|
||||
private int YB;
|
||||
|
||||
public SwizzleAddr(int Width, int Height, int Pad)
|
||||
{
|
||||
int W = Pow2RoundUp(Width);
|
||||
int H = Pow2RoundUp(Height);
|
||||
|
||||
XB = CountZeros(W);
|
||||
YB = CountZeros(H);
|
||||
|
||||
int HH = H >> 1;
|
||||
|
||||
if (!IsPow2(Height) && Height <= HH + HH / 3 && YB > 3)
|
||||
{
|
||||
YB--;
|
||||
}
|
||||
|
||||
this.Width = RoundSize(Width, Pad);
|
||||
}
|
||||
|
||||
private static int Pow2RoundUp(int Value)
|
||||
{
|
||||
Value--;
|
||||
|
||||
Value |= (Value >> 1);
|
||||
Value |= (Value >> 2);
|
||||
Value |= (Value >> 4);
|
||||
Value |= (Value >> 8);
|
||||
Value |= (Value >> 16);
|
||||
|
||||
return ++Value;
|
||||
}
|
||||
|
||||
private static bool IsPow2(int Value)
|
||||
{
|
||||
return Value != 0 && (Value & (Value - 1)) == 0;
|
||||
}
|
||||
|
||||
private static int CountZeros(int Value)
|
||||
{
|
||||
int Count = 0;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if ((Value & (1 << i)) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Count++;
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
private static int RoundSize(int Size, int Pad)
|
||||
{
|
||||
int Mask = Pad - 1;
|
||||
|
||||
if ((Size & Mask) != 0)
|
||||
{
|
||||
Size &= ~Mask;
|
||||
Size += Pad;
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
public int GetSwizzledAddress8(int X, int Y)
|
||||
{
|
||||
return GetSwizzledAddress(X, Y, 4);
|
||||
}
|
||||
|
||||
public int GetSwizzledAddress16(int X, int Y)
|
||||
{
|
||||
return GetSwizzledAddress(X, Y, 3);
|
||||
}
|
||||
|
||||
public int GetSwizzledAddress32(int X, int Y)
|
||||
{
|
||||
return GetSwizzledAddress(X, Y, 2);
|
||||
}
|
||||
|
||||
public int GetSwizzledAddress64(int X, int Y)
|
||||
{
|
||||
return GetSwizzledAddress(X, Y, 1);
|
||||
}
|
||||
|
||||
public int GetSwizzledAddress128(int X, int Y)
|
||||
{
|
||||
return GetSwizzledAddress(X, Y, 0);
|
||||
}
|
||||
|
||||
private int GetSwizzledAddress(int X, int Y, int XBase)
|
||||
{
|
||||
/*
|
||||
* Examples of patterns:
|
||||
* x x y x y y x y 0 0 0 0 64 x 64 dxt5
|
||||
* x x x x x y y y y x y y x y 0 0 0 0 512 x 512 dxt5
|
||||
* y x x x x x x y y y y x y y x y 0 0 0 0 1024 x 1024 dxt5
|
||||
* y y x x x x x x y y y y x y y x y x 0 0 0 2048 x 2048 dxt1
|
||||
* y y y x x x x x x y y y y x y y x y x x 0 0 1024 x 1024 rgba8888
|
||||
*
|
||||
* Read from right to left, LSB first.
|
||||
*/
|
||||
int XCnt = XBase;
|
||||
int YCnt = 1;
|
||||
int XUsed = 0;
|
||||
int YUsed = 0;
|
||||
int Address = 0;
|
||||
|
||||
while (XUsed < XBase + 2 && XUsed + XCnt < XB)
|
||||
{
|
||||
int XMask = (1 << XCnt) - 1;
|
||||
int YMask = (1 << YCnt) - 1;
|
||||
|
||||
Address |= (X & XMask) << XUsed + YUsed;
|
||||
Address |= (Y & YMask) << XUsed + YUsed + XCnt;
|
||||
|
||||
X >>= XCnt;
|
||||
Y >>= YCnt;
|
||||
|
||||
XUsed += XCnt;
|
||||
YUsed += YCnt;
|
||||
|
||||
XCnt = Math.Min(XB - XUsed, 1);
|
||||
YCnt = Math.Min(YB - YUsed, YCnt << 1);
|
||||
}
|
||||
|
||||
Address |= (X + Y * (Width >> XUsed)) << (XUsed + YUsed);
|
||||
|
||||
return Address;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue