aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/Gpu/NsGpuPGraph.cs')
-rw-r--r--Ryujinx.Graphics/Gpu/NsGpuPGraph.cs276
1 files changed, 276 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs b/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs
new file mode 100644
index 00000000..eb893f74
--- /dev/null
+++ b/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file