NvGpuEngine3d.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. using Ryujinx.Graphics.Gal;
  2. using Ryujinx.HLE.Gpu.Memory;
  3. using Ryujinx.HLE.Gpu.Texture;
  4. using System;
  5. using System.Collections.Generic;
  6. namespace Ryujinx.HLE.Gpu.Engines
  7. {
  8. class NvGpuEngine3d : INvGpuEngine
  9. {
  10. public int[] Registers { get; private set; }
  11. private NvGpu Gpu;
  12. private Dictionary<int, NvGpuMethod> Methods;
  13. private struct ConstBuffer
  14. {
  15. public bool Enabled;
  16. public long Position;
  17. public int Size;
  18. }
  19. private ConstBuffer[][] ConstBuffers;
  20. private HashSet<long> FrameBuffers;
  21. private List<long>[] UploadedKeys;
  22. public NvGpuEngine3d(NvGpu Gpu)
  23. {
  24. this.Gpu = Gpu;
  25. Registers = new int[0xe00];
  26. Methods = new Dictionary<int, NvGpuMethod>();
  27. void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
  28. {
  29. while (Count-- > 0)
  30. {
  31. Methods.Add(Meth, Method);
  32. Meth += Stride;
  33. }
  34. }
  35. AddMethod(0x585, 1, 1, VertexEndGl);
  36. AddMethod(0x674, 1, 1, ClearBuffers);
  37. AddMethod(0x6c3, 1, 1, QueryControl);
  38. AddMethod(0x8e4, 16, 1, CbData);
  39. AddMethod(0x904, 5, 8, CbBind);
  40. ConstBuffers = new ConstBuffer[6][];
  41. for (int Index = 0; Index < ConstBuffers.Length; Index++)
  42. {
  43. ConstBuffers[Index] = new ConstBuffer[18];
  44. }
  45. FrameBuffers = new HashSet<long>();
  46. UploadedKeys = new List<long>[(int)NvGpuBufferType.Count];
  47. for (int i = 0; i < UploadedKeys.Length; i++)
  48. {
  49. UploadedKeys[i] = new List<long>();
  50. }
  51. }
  52. public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
  53. {
  54. if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
  55. {
  56. Method(Vmm, PBEntry);
  57. }
  58. else
  59. {
  60. WriteRegister(PBEntry);
  61. }
  62. }
  63. private void VertexEndGl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
  64. {
  65. LockCaches();
  66. SetFrameBuffer(Vmm, 0);
  67. long[] Keys = UploadShaders(Vmm);
  68. Gpu.Renderer.Shader.BindProgram();
  69. //Note: Uncomment SetFrontFace SetCullFace when flipping issues are solved
  70. //SetFrontFace();
  71. //SetCullFace();
  72. SetDepth();
  73. SetStencil();
  74. SetAlphaBlending();
  75. SetPrimitiveRestart();
  76. UploadTextures(Vmm, Keys);
  77. UploadUniforms(Vmm);
  78. UploadVertexArrays(Vmm);
  79. UnlockCaches();
  80. }
  81. private void LockCaches()
  82. {
  83. Gpu.Renderer.Rasterizer.LockCaches();
  84. Gpu.Renderer.Texture.LockCache();
  85. }
  86. private void UnlockCaches()
  87. {
  88. Gpu.Renderer.Rasterizer.UnlockCaches();
  89. Gpu.Renderer.Texture.UnlockCache();
  90. }
  91. private void ClearBuffers(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
  92. {
  93. int Arg0 = PBEntry.Arguments[0];
  94. int FbIndex = (Arg0 >> 6) & 0xf;
  95. GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f);
  96. SetFrameBuffer(Vmm, FbIndex);
  97. Gpu.Renderer.Rasterizer.ClearBuffers(Flags);
  98. }
  99. private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex)
  100. {
  101. long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
  102. long Key = Vmm.GetPhysicalAddress(VA);
  103. FrameBuffers.Add(Key);
  104. int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
  105. int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
  106. float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 4);
  107. float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 4);
  108. float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 4);
  109. float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 4);
  110. int VpX = (int)MathF.Max(0, TX - MathF.Abs(SX));
  111. int VpY = (int)MathF.Max(0, TY - MathF.Abs(SY));
  112. int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
  113. int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
  114. Gpu.Renderer.FrameBuffer.Create(Key, Width, Height);
  115. Gpu.Renderer.FrameBuffer.Bind(Key);
  116. Gpu.Renderer.FrameBuffer.SetViewport(VpX, VpY, VpW, VpH);
  117. }
  118. private long[] UploadShaders(NvGpuVmm Vmm)
  119. {
  120. long[] Keys = new long[5];
  121. long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
  122. int Index = 1;
  123. int VpAControl = ReadRegister(NvGpuEngine3dReg.ShaderNControl);
  124. bool VpAEnable = (VpAControl & 1) != 0;
  125. if (VpAEnable)
  126. {
  127. //Note: The maxwell supports 2 vertex programs, usually
  128. //only VP B is used, but in some cases VP A is also used.
  129. //In this case, it seems to function as an extra vertex
  130. //shader stage.
  131. //The graphics abstraction layer has a special overload for this
  132. //case, which should merge the two shaders into one vertex shader.
  133. int VpAOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset);
  134. int VpBOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + 0x10);
  135. long VpAPos = BasePosition + (uint)VpAOffset;
  136. long VpBPos = BasePosition + (uint)VpBOffset;
  137. Gpu.Renderer.Shader.Create(Vmm, VpAPos, VpBPos, GalShaderType.Vertex);
  138. Gpu.Renderer.Shader.Bind(VpBPos);
  139. Index = 2;
  140. }
  141. for (; Index < 6; Index++)
  142. {
  143. GalShaderType Type = GetTypeFromProgram(Index);
  144. int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10);
  145. int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10);
  146. //Note: Vertex Program (B) is always enabled.
  147. bool Enable = (Control & 1) != 0 || Index == 1;
  148. if (!Enable)
  149. {
  150. Gpu.Renderer.Shader.Unbind(Type);
  151. continue;
  152. }
  153. long Key = BasePosition + (uint)Offset;
  154. Keys[(int)Type] = Key;
  155. Gpu.Renderer.Shader.Create(Vmm, Key, Type);
  156. Gpu.Renderer.Shader.Bind(Key);
  157. }
  158. float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
  159. float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
  160. Gpu.Renderer.Shader.SetFlip(SignX, SignY);
  161. return Keys;
  162. }
  163. private static GalShaderType GetTypeFromProgram(int Program)
  164. {
  165. switch (Program)
  166. {
  167. case 0:
  168. case 1: return GalShaderType.Vertex;
  169. case 2: return GalShaderType.TessControl;
  170. case 3: return GalShaderType.TessEvaluation;
  171. case 4: return GalShaderType.Geometry;
  172. case 5: return GalShaderType.Fragment;
  173. }
  174. throw new ArgumentOutOfRangeException(nameof(Program));
  175. }
  176. private void SetFrontFace()
  177. {
  178. float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
  179. float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
  180. GalFrontFace FrontFace = (GalFrontFace)ReadRegister(NvGpuEngine3dReg.FrontFace);
  181. //Flipping breaks facing. Flipping front facing too fixes it
  182. if (SignX != SignY)
  183. {
  184. switch (FrontFace)
  185. {
  186. case GalFrontFace.CW:
  187. FrontFace = GalFrontFace.CCW;
  188. break;
  189. case GalFrontFace.CCW:
  190. FrontFace = GalFrontFace.CW;
  191. break;
  192. }
  193. }
  194. Gpu.Renderer.Rasterizer.SetFrontFace(FrontFace);
  195. }
  196. private void SetCullFace()
  197. {
  198. bool Enable = (ReadRegister(NvGpuEngine3dReg.CullFaceEnable) & 1) != 0;
  199. if (Enable)
  200. {
  201. Gpu.Renderer.Rasterizer.EnableCullFace();
  202. }
  203. else
  204. {
  205. Gpu.Renderer.Rasterizer.DisableCullFace();
  206. }
  207. if (!Enable)
  208. {
  209. return;
  210. }
  211. GalCullFace CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace);
  212. Gpu.Renderer.Rasterizer.SetCullFace(CullFace);
  213. }
  214. private void SetDepth()
  215. {
  216. float ClearDepth = ReadRegisterFloat(NvGpuEngine3dReg.ClearDepth);
  217. Gpu.Renderer.Rasterizer.SetClearDepth(ClearDepth);
  218. bool Enable = (ReadRegister(NvGpuEngine3dReg.DepthTestEnable) & 1) != 0;
  219. if (Enable)
  220. {
  221. Gpu.Renderer.Rasterizer.EnableDepthTest();
  222. }
  223. else
  224. {
  225. Gpu.Renderer.Rasterizer.DisableDepthTest();
  226. }
  227. if (!Enable)
  228. {
  229. return;
  230. }
  231. GalComparisonOp Func = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction);
  232. Gpu.Renderer.Rasterizer.SetDepthFunction(Func);
  233. }
  234. private void SetStencil()
  235. {
  236. int ClearStencil = ReadRegister(NvGpuEngine3dReg.ClearStencil);
  237. Gpu.Renderer.Rasterizer.SetClearStencil(ClearStencil);
  238. bool Enable = (ReadRegister(NvGpuEngine3dReg.StencilEnable) & 1) != 0;
  239. if (Enable)
  240. {
  241. Gpu.Renderer.Rasterizer.EnableStencilTest();
  242. }
  243. else
  244. {
  245. Gpu.Renderer.Rasterizer.DisableStencilTest();
  246. }
  247. if (!Enable)
  248. {
  249. return;
  250. }
  251. void SetFaceStencil(
  252. bool IsFrontFace,
  253. NvGpuEngine3dReg Func,
  254. NvGpuEngine3dReg FuncRef,
  255. NvGpuEngine3dReg FuncMask,
  256. NvGpuEngine3dReg OpFail,
  257. NvGpuEngine3dReg OpZFail,
  258. NvGpuEngine3dReg OpZPass,
  259. NvGpuEngine3dReg Mask)
  260. {
  261. Gpu.Renderer.Rasterizer.SetStencilFunction(
  262. IsFrontFace,
  263. (GalComparisonOp)ReadRegister(Func),
  264. ReadRegister(FuncRef),
  265. ReadRegister(FuncMask));
  266. Gpu.Renderer.Rasterizer.SetStencilOp(
  267. IsFrontFace,
  268. (GalStencilOp)ReadRegister(OpFail),
  269. (GalStencilOp)ReadRegister(OpZFail),
  270. (GalStencilOp)ReadRegister(OpZPass));
  271. Gpu.Renderer.Rasterizer.SetStencilMask(IsFrontFace, ReadRegister(Mask));
  272. }
  273. SetFaceStencil(false,
  274. NvGpuEngine3dReg.StencilBackFuncFunc,
  275. NvGpuEngine3dReg.StencilBackFuncRef,
  276. NvGpuEngine3dReg.StencilBackFuncMask,
  277. NvGpuEngine3dReg.StencilBackOpFail,
  278. NvGpuEngine3dReg.StencilBackOpZFail,
  279. NvGpuEngine3dReg.StencilBackOpZPass,
  280. NvGpuEngine3dReg.StencilBackMask);
  281. SetFaceStencil(true,
  282. NvGpuEngine3dReg.StencilFrontFuncFunc,
  283. NvGpuEngine3dReg.StencilFrontFuncRef,
  284. NvGpuEngine3dReg.StencilFrontFuncMask,
  285. NvGpuEngine3dReg.StencilFrontOpFail,
  286. NvGpuEngine3dReg.StencilFrontOpZFail,
  287. NvGpuEngine3dReg.StencilFrontOpZPass,
  288. NvGpuEngine3dReg.StencilFrontMask);
  289. }
  290. private void SetAlphaBlending()
  291. {
  292. //TODO: Support independent blend properly.
  293. bool Enable = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0;
  294. if (Enable)
  295. {
  296. Gpu.Renderer.Blend.Enable();
  297. }
  298. else
  299. {
  300. Gpu.Renderer.Blend.Disable();
  301. }
  302. if (!Enable)
  303. {
  304. //If blend is not enabled, then the other values have no effect.
  305. //Note that if it is disabled, the register may contain invalid values.
  306. return;
  307. }
  308. bool BlendSeparateAlpha = (ReadRegister(NvGpuEngine3dReg.IBlendNSeparateAlpha) & 1) != 0;
  309. GalBlendEquation EquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationRgb);
  310. GalBlendFactor FuncSrcRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb);
  311. GalBlendFactor FuncDstRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstRgb);
  312. if (BlendSeparateAlpha)
  313. {
  314. GalBlendEquation EquationAlpha = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationAlpha);
  315. GalBlendFactor FuncSrcAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha);
  316. GalBlendFactor FuncDstAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha);
  317. Gpu.Renderer.Blend.SetSeparate(
  318. EquationRgb,
  319. EquationAlpha,
  320. FuncSrcRgb,
  321. FuncDstRgb,
  322. FuncSrcAlpha,
  323. FuncDstAlpha);
  324. }
  325. else
  326. {
  327. Gpu.Renderer.Blend.Set(EquationRgb, FuncSrcRgb, FuncDstRgb);
  328. }
  329. }
  330. private void SetPrimitiveRestart()
  331. {
  332. bool Enable = (ReadRegister(NvGpuEngine3dReg.PrimRestartEnable) & 1) != 0;
  333. if (Enable)
  334. {
  335. Gpu.Renderer.Rasterizer.EnablePrimitiveRestart();
  336. }
  337. else
  338. {
  339. Gpu.Renderer.Rasterizer.DisablePrimitiveRestart();
  340. }
  341. if (!Enable)
  342. {
  343. return;
  344. }
  345. uint Index = (uint)ReadRegister(NvGpuEngine3dReg.PrimRestartIndex);
  346. Gpu.Renderer.Rasterizer.SetPrimitiveRestartIndex(Index);
  347. }
  348. private void UploadTextures(NvGpuVmm Vmm, long[] Keys)
  349. {
  350. long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
  351. int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
  352. //Note: On the emulator renderer, Texture Unit 0 is
  353. //reserved for drawing the frame buffer.
  354. int TexIndex = 1;
  355. for (int Index = 0; Index < Keys.Length; Index++)
  356. {
  357. foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetTextureUsage(Keys[Index]))
  358. {
  359. long Position = ConstBuffers[Index][TextureCbIndex].Position;
  360. UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index);
  361. Gpu.Renderer.Shader.EnsureTextureBinding(DeclInfo.Name, TexIndex);
  362. TexIndex++;
  363. }
  364. }
  365. }
  366. private void UploadTexture(NvGpuVmm Vmm, long BasePosition, int TexIndex, int HndIndex)
  367. {
  368. long Position = BasePosition + HndIndex * 4;
  369. int TextureHandle = Vmm.ReadInt32(Position);
  370. if (TextureHandle == 0)
  371. {
  372. //TODO: Is this correct?
  373. //Some games like puyo puyo will have 0 handles.
  374. //It may be just normal behaviour or a bug caused by sync issues.
  375. //The game does initialize the value properly after through.
  376. return;
  377. }
  378. int TicIndex = (TextureHandle >> 0) & 0xfffff;
  379. int TscIndex = (TextureHandle >> 20) & 0xfff;
  380. long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset);
  381. long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset);
  382. TicPosition += TicIndex * 0x20;
  383. TscPosition += TscIndex * 0x20;
  384. GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition);
  385. long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
  386. Key = Vmm.GetPhysicalAddress(Key);
  387. if (IsFrameBufferPosition(Key))
  388. {
  389. //This texture is a frame buffer texture,
  390. //we shouldn't read anything from memory and bind
  391. //the frame buffer texture instead, since we're not
  392. //really writing anything to memory.
  393. Gpu.Renderer.FrameBuffer.BindTexture(Key, TexIndex);
  394. }
  395. else
  396. {
  397. GalTexture NewTexture = TextureFactory.MakeTexture(Vmm, TicPosition);
  398. long Size = (uint)TextureHelper.GetTextureSize(NewTexture);
  399. bool HasCachedTexture = false;
  400. if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalTexture Texture))
  401. {
  402. if (NewTexture.Equals(Texture) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
  403. {
  404. Gpu.Renderer.Texture.Bind(Key, TexIndex);
  405. HasCachedTexture = true;
  406. }
  407. }
  408. if (!HasCachedTexture)
  409. {
  410. byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
  411. Gpu.Renderer.Texture.Create(Key, Data, NewTexture);
  412. }
  413. Gpu.Renderer.Texture.Bind(Key, TexIndex);
  414. }
  415. Gpu.Renderer.Texture.SetSampler(Sampler);
  416. }
  417. private void UploadUniforms(NvGpuVmm Vmm)
  418. {
  419. long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
  420. for (int Index = 0; Index < 5; Index++)
  421. {
  422. int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + (Index + 1) * 0x10);
  423. int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10);
  424. //Note: Vertex Program (B) is always enabled.
  425. bool Enable = (Control & 1) != 0 || Index == 0;
  426. if (!Enable)
  427. {
  428. continue;
  429. }
  430. for (int Cbuf = 0; Cbuf < ConstBuffers[Index].Length; Cbuf++)
  431. {
  432. ConstBuffer Cb = ConstBuffers[Index][Cbuf];
  433. if (Cb.Enabled)
  434. {
  435. IntPtr DataAddress = Vmm.GetHostAddress(Cb.Position, Cb.Size);
  436. Gpu.Renderer.Shader.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Cb.Size, DataAddress);
  437. }
  438. }
  439. }
  440. }
  441. private void UploadVertexArrays(NvGpuVmm Vmm)
  442. {
  443. long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
  444. long IboKey = Vmm.GetPhysicalAddress(IndexPosition);
  445. int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
  446. int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst);
  447. int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
  448. GalIndexFormat IndexFormat = (GalIndexFormat)IndexEntryFmt;
  449. int IndexEntrySize = 1 << IndexEntryFmt;
  450. if (IndexEntrySize > 4)
  451. {
  452. throw new InvalidOperationException();
  453. }
  454. if (IndexCount != 0)
  455. {
  456. int IbSize = IndexCount * IndexEntrySize;
  457. bool IboCached = Gpu.Renderer.Rasterizer.IsIboCached(IboKey, (uint)IbSize);
  458. if (!IboCached || QueryKeyUpload(Vmm, IboKey, (uint)IbSize, NvGpuBufferType.Index))
  459. {
  460. IntPtr DataAddress = Vmm.GetHostAddress(IndexPosition, IbSize);
  461. Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, DataAddress);
  462. }
  463. Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat);
  464. }
  465. List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
  466. for (int Attr = 0; Attr < 16; Attr++)
  467. {
  468. int Packed = ReadRegister(NvGpuEngine3dReg.VertexAttribNFormat + Attr);
  469. int ArrayIndex = Packed & 0x1f;
  470. if (Attribs[ArrayIndex] == null)
  471. {
  472. Attribs[ArrayIndex] = new List<GalVertexAttrib>();
  473. }
  474. Attribs[ArrayIndex].Add(new GalVertexAttrib(
  475. Attr,
  476. ((Packed >> 6) & 0x1) != 0,
  477. (Packed >> 7) & 0x3fff,
  478. (GalVertexAttribSize)((Packed >> 21) & 0x3f),
  479. (GalVertexAttribType)((Packed >> 27) & 0x7),
  480. ((Packed >> 31) & 0x1) != 0));
  481. }
  482. int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst);
  483. int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount);
  484. int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
  485. for (int Index = 0; Index < 32; Index++)
  486. {
  487. if (Attribs[Index] == null)
  488. {
  489. continue;
  490. }
  491. int Control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + Index * 4);
  492. bool Enable = (Control & 0x1000) != 0;
  493. long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
  494. long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2);
  495. if (!Enable)
  496. {
  497. continue;
  498. }
  499. long VboKey = Vmm.GetPhysicalAddress(VertexPosition);
  500. int Stride = Control & 0xfff;
  501. long VbSize = (VertexEndPos - VertexPosition) + 1;
  502. bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, VbSize);
  503. if (!VboCached || QueryKeyUpload(Vmm, VboKey, VbSize, NvGpuBufferType.Vertex))
  504. {
  505. IntPtr DataAddress = Vmm.GetHostAddress(VertexPosition, VbSize);
  506. Gpu.Renderer.Rasterizer.CreateVbo(VboKey, (int)VbSize, DataAddress);
  507. }
  508. Gpu.Renderer.Rasterizer.SetVertexArray(Stride, VboKey, Attribs[Index].ToArray());
  509. }
  510. GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
  511. if (IndexCount != 0)
  512. {
  513. int VertexBase = ReadRegister(NvGpuEngine3dReg.VertexArrayElemBase);
  514. Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType);
  515. }
  516. else
  517. {
  518. Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType);
  519. }
  520. }
  521. private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
  522. {
  523. long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress);
  524. int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
  525. int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
  526. int Mode = Ctrl & 3;
  527. if (Mode == 0)
  528. {
  529. foreach (List<long> Uploaded in UploadedKeys)
  530. {
  531. Uploaded.Clear();
  532. }
  533. //Write mode.
  534. Vmm.WriteInt32(Position, Seq);
  535. }
  536. WriteRegister(PBEntry);
  537. }
  538. private void CbData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
  539. {
  540. long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress);
  541. int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset);
  542. foreach (int Arg in PBEntry.Arguments)
  543. {
  544. Vmm.WriteInt32(Position + Offset, Arg);
  545. Offset += 4;
  546. }
  547. WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, Offset);
  548. }
  549. private void CbBind(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
  550. {
  551. int Stage = (PBEntry.Method - 0x904) >> 3;
  552. int Index = PBEntry.Arguments[0];
  553. bool Enabled = (Index & 1) != 0;
  554. Index = (Index >> 4) & 0x1f;
  555. long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress);
  556. ConstBuffers[Stage][Index].Position = Position;
  557. ConstBuffers[Stage][Index].Enabled = Enabled;
  558. ConstBuffers[Stage][Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize);
  559. }
  560. private float GetFlipSign(NvGpuEngine3dReg Reg)
  561. {
  562. return MathF.Sign(ReadRegisterFloat(Reg));
  563. }
  564. private long MakeInt64From2xInt32(NvGpuEngine3dReg Reg)
  565. {
  566. return
  567. (long)Registers[(int)Reg + 0] << 32 |
  568. (uint)Registers[(int)Reg + 1];
  569. }
  570. private void WriteRegister(NvGpuPBEntry PBEntry)
  571. {
  572. int ArgsCount = PBEntry.Arguments.Count;
  573. if (ArgsCount > 0)
  574. {
  575. Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
  576. }
  577. }
  578. private int ReadRegister(NvGpuEngine3dReg Reg)
  579. {
  580. return Registers[(int)Reg];
  581. }
  582. private float ReadRegisterFloat(NvGpuEngine3dReg Reg)
  583. {
  584. return BitConverter.Int32BitsToSingle(ReadRegister(Reg));
  585. }
  586. private void WriteRegister(NvGpuEngine3dReg Reg, int Value)
  587. {
  588. Registers[(int)Reg] = Value;
  589. }
  590. public bool IsFrameBufferPosition(long Position)
  591. {
  592. return FrameBuffers.Contains(Position);
  593. }
  594. private bool QueryKeyUpload(NvGpuVmm Vmm, long Key, long Size, NvGpuBufferType Type)
  595. {
  596. List<long> Uploaded = UploadedKeys[(int)Type];
  597. if (Uploaded.Contains(Key))
  598. {
  599. return false;
  600. }
  601. Uploaded.Add(Key);
  602. return Vmm.IsRegionModified(Key, Size, Type);
  603. }
  604. }
  605. }