NsGpuPGraph.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Graphics.Gal;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.Graphics.Gpu
  5. {
  6. class NsGpuPGraph
  7. {
  8. private NsGpu Gpu;
  9. private int[] Registers;
  10. public NsGpuEngine[] SubChannels;
  11. private Dictionary<long, int> CurrentVertexBuffers;
  12. public NsGpuPGraph(NsGpu Gpu)
  13. {
  14. this.Gpu = Gpu;
  15. Registers = new int[0x1000];
  16. SubChannels = new NsGpuEngine[8];
  17. CurrentVertexBuffers = new Dictionary<long, int>();
  18. }
  19. public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory)
  20. {
  21. bool HasQuery = false;
  22. foreach (NsGpuPBEntry Entry in PushBuffer)
  23. {
  24. if (Entry.Arguments.Count == 1)
  25. {
  26. SetRegister(Entry.Register, Entry.Arguments[0]);
  27. }
  28. switch (Entry.Register)
  29. {
  30. case NsGpuRegister.BindChannel:
  31. if (Entry.Arguments.Count > 0)
  32. {
  33. SubChannels[Entry.SubChannel] = (NsGpuEngine)Entry.Arguments[0];
  34. }
  35. break;
  36. case NsGpuRegister._3dVertexArray0Fetch:
  37. SendVertexBuffers(Memory);
  38. break;
  39. case NsGpuRegister._3dCbData0:
  40. if (GetRegister(NsGpuRegister._3dCbPos) == 0x20)
  41. {
  42. SendTexture(Memory);
  43. }
  44. break;
  45. case NsGpuRegister._3dQueryAddressHigh:
  46. case NsGpuRegister._3dQueryAddressLow:
  47. case NsGpuRegister._3dQuerySequence:
  48. case NsGpuRegister._3dQueryGet:
  49. HasQuery = true;
  50. break;
  51. }
  52. }
  53. if (HasQuery)
  54. {
  55. long Position =
  56. (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 |
  57. (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0;
  58. int Seq = GetRegister(NsGpuRegister._3dQuerySequence);
  59. int Get = GetRegister(NsGpuRegister._3dQueryGet);
  60. int Mode = Get & 3;
  61. if (Mode == 0)
  62. {
  63. //Write
  64. Position = Gpu.MemoryMgr.GetCpuAddr(Position);
  65. if (Position != -1)
  66. {
  67. Gpu.Renderer.QueueAction(delegate()
  68. {
  69. Memory.WriteInt32(Position, Seq);
  70. });
  71. }
  72. }
  73. }
  74. }
  75. private void SendVertexBuffers(AMemory Memory)
  76. {
  77. long Position =
  78. (long)GetRegister(NsGpuRegister._3dVertexArray0StartHigh) << 32 |
  79. (long)GetRegister(NsGpuRegister._3dVertexArray0StartLow) << 0;
  80. long Limit =
  81. (long)GetRegister(NsGpuRegister._3dVertexArray0LimitHigh) << 32 |
  82. (long)GetRegister(NsGpuRegister._3dVertexArray0LimitLow) << 0;
  83. int VbIndex = CurrentVertexBuffers.Count;
  84. if (!CurrentVertexBuffers.TryAdd(Position, VbIndex))
  85. {
  86. VbIndex = CurrentVertexBuffers[Position];
  87. }
  88. if (Limit != 0)
  89. {
  90. long Size = (Limit - Position) + 1;
  91. Position = Gpu.MemoryMgr.GetCpuAddr(Position);
  92. if (Position != -1)
  93. {
  94. byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, (int)Size);
  95. int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff;
  96. List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>();
  97. for (int Attr = 0; Attr < 16; Attr++)
  98. {
  99. int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4);
  100. GalVertexAttrib Attrib = new GalVertexAttrib(Attr,
  101. (Packed >> 0) & 0x1f,
  102. ((Packed >> 6) & 0x1) != 0,
  103. (Packed >> 7) & 0x3fff,
  104. (GalVertexAttribSize)((Packed >> 21) & 0x3f),
  105. (GalVertexAttribType)((Packed >> 27) & 0x7),
  106. ((Packed >> 31) & 0x1) != 0);
  107. if (Attrib.Offset < Stride)
  108. {
  109. Attribs.Add(Attrib);
  110. }
  111. }
  112. Gpu.Renderer.QueueAction(delegate()
  113. {
  114. Gpu.Renderer.SendVertexBuffer(VbIndex, Buffer, Stride, Attribs.ToArray());
  115. });
  116. }
  117. }
  118. }
  119. private void SendTexture(AMemory Memory)
  120. {
  121. long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 |
  122. (long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0;
  123. int CbData = GetRegister(NsGpuRegister._3dCbData0);
  124. int TicIndex = (CbData >> 0) & 0xfffff;
  125. int TscIndex = (CbData >> 20) & 0xfff; //I guess?
  126. TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20);
  127. if (TicPos != -1)
  128. {
  129. int Word0 = Memory.ReadInt32(TicPos + 0x0);
  130. int Word1 = Memory.ReadInt32(TicPos + 0x4);
  131. int Word2 = Memory.ReadInt32(TicPos + 0x8);
  132. int Word3 = Memory.ReadInt32(TicPos + 0xc);
  133. int Word4 = Memory.ReadInt32(TicPos + 0x10);
  134. int Word5 = Memory.ReadInt32(TicPos + 0x14);
  135. int Word6 = Memory.ReadInt32(TicPos + 0x18);
  136. int Word7 = Memory.ReadInt32(TicPos + 0x1c);
  137. long TexAddress = Word1;
  138. TexAddress |= (long)(Word2 & 0xff) << 32;
  139. TexAddress = Gpu.MemoryMgr.GetCpuAddr(TexAddress);
  140. if (TexAddress != -1)
  141. {
  142. NsGpuTextureFormat Format = (NsGpuTextureFormat)(Word0 & 0x7f);
  143. int Width = (Word4 & 0xffff) + 1;
  144. int Height = (Word5 & 0xffff) + 1;
  145. byte[] Buffer = GetDecodedTexture(Memory, Format, TexAddress, Width, Height);
  146. if (Buffer != null)
  147. {
  148. Gpu.Renderer.QueueAction(delegate()
  149. {
  150. Gpu.Renderer.SendR8G8B8A8Texture(0, Buffer, Width, Height);
  151. });
  152. }
  153. }
  154. }
  155. }
  156. private static byte[] GetDecodedTexture(
  157. AMemory Memory,
  158. NsGpuTextureFormat Format,
  159. long Position,
  160. int Width,
  161. int Height)
  162. {
  163. byte[] Data = null;
  164. switch (Format)
  165. {
  166. case NsGpuTextureFormat.BC1:
  167. {
  168. int Size = (Width * Height) >> 1;
  169. Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
  170. Data = BCn.DecodeBC1(new NsGpuTexture()
  171. {
  172. Width = Width,
  173. Height = Height,
  174. Data = Data
  175. }, 0);
  176. break;
  177. }
  178. case NsGpuTextureFormat.BC2:
  179. {
  180. int Size = Width * Height;
  181. Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
  182. Data = BCn.DecodeBC2(new NsGpuTexture()
  183. {
  184. Width = Width,
  185. Height = Height,
  186. Data = Data
  187. }, 0);
  188. break;
  189. }
  190. case NsGpuTextureFormat.BC3:
  191. {
  192. int Size = Width * Height;
  193. Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
  194. Data = BCn.DecodeBC3(new NsGpuTexture()
  195. {
  196. Width = Width,
  197. Height = Height,
  198. Data = Data
  199. }, 0);
  200. break;
  201. }
  202. //default: throw new NotImplementedException(Format.ToString());
  203. }
  204. return Data;
  205. }
  206. public int GetRegister(NsGpuRegister Register)
  207. {
  208. return Registers[((int)Register >> 2) & 0xfff];
  209. }
  210. public void SetRegister(NsGpuRegister Register, int Value)
  211. {
  212. Registers[((int)Register >> 2) & 0xfff] = Value;
  213. }
  214. }
  215. }