NvGpuEngineP2mf.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. using Ryujinx.Graphics.Memory;
  2. using Ryujinx.Graphics.Texture;
  3. using System.Collections.Generic;
  4. using Ryujinx.Profiler;
  5. namespace Ryujinx.Graphics.Graphics3d
  6. {
  7. class NvGpuEngineP2mf : INvGpuEngine
  8. {
  9. public int[] Registers { get; private set; }
  10. private NvGpu _gpu;
  11. private Dictionary<int, NvGpuMethod> _methods;
  12. private int _copyStartX;
  13. private int _copyStartY;
  14. private int _copyWidth;
  15. private int _copyHeight;
  16. private int _copyGobBlockHeight;
  17. private long _copyAddress;
  18. private int _copyOffset;
  19. private int _copySize;
  20. private bool _copyLinear;
  21. private byte[] _buffer;
  22. public NvGpuEngineP2mf(NvGpu gpu)
  23. {
  24. _gpu = gpu;
  25. Registers = new int[0x80];
  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(0x6c, 1, 1, Execute);
  36. AddMethod(0x6d, 1, 1, PushData);
  37. }
  38. public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
  39. {
  40. if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
  41. {
  42. ProfileConfig profile = Profiles.GPU.EngineP2mf.PushData;
  43. profile.SessionItem = method.Method.Name;
  44. Profile.Begin(profile);
  45. method(vmm, methCall);
  46. Profile.End(profile);
  47. }
  48. else
  49. {
  50. WriteRegister(methCall);
  51. }
  52. }
  53. private void Execute(NvGpuVmm vmm, GpuMethodCall methCall)
  54. {
  55. Profile.Begin(Profiles.GPU.EngineP2mf.Execute);
  56. // TODO: Some registers and copy modes are still not implemented.
  57. int control = methCall.Argument;
  58. long dstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
  59. int dstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch);
  60. int dstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim);
  61. int dstX = ReadRegister(NvGpuEngineP2mfReg.DstX);
  62. int dstY = ReadRegister(NvGpuEngineP2mfReg.DstY);
  63. int dstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth);
  64. int dstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight);
  65. int lineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
  66. int lineCount = ReadRegister(NvGpuEngineP2mfReg.LineCount);
  67. _copyLinear = (control & 1) != 0;
  68. _copyGobBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
  69. _copyStartX = dstX;
  70. _copyStartY = dstY;
  71. _copyWidth = dstWidth;
  72. _copyHeight = dstHeight;
  73. _copyAddress = dstAddress;
  74. _copyOffset = 0;
  75. _copySize = lineLengthIn * lineCount;
  76. _buffer = new byte[_copySize];
  77. Profile.End(Profiles.GPU.EngineP2mf.Execute);
  78. }
  79. private void PushData(NvGpuVmm vmm, GpuMethodCall methCall)
  80. {
  81. if (_buffer == null)
  82. {
  83. return;
  84. }
  85. Profile.Begin(Profiles.GPU.EngineP2mf.PushData);
  86. for (int shift = 0; shift < 32 && _copyOffset < _copySize; shift += 8, _copyOffset++)
  87. {
  88. _buffer[_copyOffset] = (byte)(methCall.Argument >> shift);
  89. }
  90. if (methCall.IsLastCall)
  91. {
  92. if (_copyLinear)
  93. {
  94. vmm.WriteBytes(_copyAddress, _buffer);
  95. }
  96. else
  97. {
  98. BlockLinearSwizzle swizzle = new BlockLinearSwizzle(
  99. _copyWidth,
  100. _copyHeight, 1,
  101. _copyGobBlockHeight, 1, 1);
  102. int srcOffset = 0;
  103. for (int y = _copyStartY; y < _copyHeight && srcOffset < _copySize; y++)
  104. for (int x = _copyStartX; x < _copyWidth && srcOffset < _copySize; x++)
  105. {
  106. int dstOffset = swizzle.GetSwizzleOffset(x, y, 0);
  107. vmm.WriteByte(_copyAddress + dstOffset, _buffer[srcOffset++]);
  108. }
  109. }
  110. _buffer = null;
  111. }
  112. Profile.End(Profiles.GPU.EngineP2mf.PushData);
  113. }
  114. private long MakeInt64From2xInt32(NvGpuEngineP2mfReg reg)
  115. {
  116. return
  117. (long)Registers[(int)reg + 0] << 32 |
  118. (uint)Registers[(int)reg + 1];
  119. }
  120. private void WriteRegister(GpuMethodCall methCall)
  121. {
  122. Registers[methCall.Method] = methCall.Argument;
  123. }
  124. private int ReadRegister(NvGpuEngineP2mfReg reg)
  125. {
  126. return Registers[(int)reg];
  127. }
  128. private void WriteRegister(NvGpuEngineP2mfReg reg, int value)
  129. {
  130. Registers[(int)reg] = value;
  131. }
  132. }
  133. }