NvGpuEngine2d.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. using Ryujinx.Graphics.Gal;
  2. using Ryujinx.Graphics.Memory;
  3. using Ryujinx.Graphics.Texture;
  4. using Ryujinx.Profiler;
  5. namespace Ryujinx.Graphics.Graphics3d
  6. {
  7. class NvGpuEngine2d : INvGpuEngine
  8. {
  9. private enum CopyOperation
  10. {
  11. SrcCopyAnd,
  12. RopAnd,
  13. Blend,
  14. SrcCopy,
  15. Rop,
  16. SrcCopyPremult,
  17. BlendPremult
  18. }
  19. public int[] Registers { get; private set; }
  20. private NvGpu _gpu;
  21. public NvGpuEngine2d(NvGpu gpu)
  22. {
  23. _gpu = gpu;
  24. Registers = new int[0x238];
  25. }
  26. public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
  27. {
  28. WriteRegister(methCall);
  29. if ((NvGpuEngine2dReg)methCall.Method == NvGpuEngine2dReg.BlitSrcYInt)
  30. {
  31. TextureCopy(vmm);
  32. }
  33. }
  34. private void TextureCopy(NvGpuVmm vmm)
  35. {
  36. Profile.Begin(Profiles.GPU.Engine2d.TextureCopy);
  37. CopyOperation operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
  38. int dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
  39. bool dstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
  40. int dstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
  41. int dstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
  42. int dstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
  43. int dstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
  44. int dstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
  45. int dstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
  46. int srcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
  47. bool srcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
  48. int srcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
  49. int srcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
  50. int srcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
  51. int srcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
  52. int srcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
  53. int srcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
  54. int dstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX);
  55. int dstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY);
  56. int dstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW);
  57. int dstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH);
  58. long blitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract);
  59. long blitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract);
  60. long srcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract);
  61. long srcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract);
  62. GalImageFormat srcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)srcFormat);
  63. GalImageFormat dstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)dstFormat);
  64. GalMemoryLayout srcLayout = GetLayout(srcLinear);
  65. GalMemoryLayout dstLayout = GetLayout(dstLinear);
  66. int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf);
  67. int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
  68. long srcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
  69. long dstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
  70. long srcKey = vmm.GetPhysicalAddress(srcAddress);
  71. long dstKey = vmm.GetPhysicalAddress(dstAddress);
  72. bool isSrcLayered = false;
  73. bool isDstLayered = false;
  74. GalTextureTarget srcTarget = GalTextureTarget.TwoD;
  75. if (srcDepth != 0)
  76. {
  77. srcTarget = GalTextureTarget.TwoDArray;
  78. srcDepth++;
  79. isSrcLayered = true;
  80. }
  81. else
  82. {
  83. srcDepth = 1;
  84. }
  85. GalTextureTarget dstTarget = GalTextureTarget.TwoD;
  86. if (dstDepth != 0)
  87. {
  88. dstTarget = GalTextureTarget.TwoDArray;
  89. dstDepth++;
  90. isDstLayered = true;
  91. }
  92. else
  93. {
  94. dstDepth = 1;
  95. }
  96. GalImage srcTexture = new GalImage(
  97. srcWidth,
  98. srcHeight,
  99. 1, srcDepth, 1,
  100. srcBlockHeight, 1,
  101. srcLayout,
  102. srcImgFormat,
  103. srcTarget);
  104. GalImage dstTexture = new GalImage(
  105. dstWidth,
  106. dstHeight,
  107. 1, dstDepth, 1,
  108. dstBlockHeight, 1,
  109. dstLayout,
  110. dstImgFormat,
  111. dstTarget);
  112. srcTexture.Pitch = srcPitch;
  113. dstTexture.Pitch = dstPitch;
  114. long GetLayerOffset(GalImage image, int layer)
  115. {
  116. int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
  117. return ImageUtils.GetLayerOffset(image, targetMipLevel) * layer;
  118. }
  119. int srcLayerIndex = -1;
  120. if (isSrcLayered && _gpu.ResourceManager.TryGetTextureLayer(srcKey, out srcLayerIndex) && srcLayerIndex != 0)
  121. {
  122. srcKey = srcKey - GetLayerOffset(srcTexture, srcLayerIndex);
  123. }
  124. int dstLayerIndex = -1;
  125. if (isDstLayered && _gpu.ResourceManager.TryGetTextureLayer(dstKey, out dstLayerIndex) && dstLayerIndex != 0)
  126. {
  127. dstKey = dstKey - GetLayerOffset(dstTexture, dstLayerIndex);
  128. }
  129. _gpu.ResourceManager.SendTexture(vmm, srcKey, srcTexture);
  130. _gpu.ResourceManager.SendTexture(vmm, dstKey, dstTexture);
  131. if (isSrcLayered && srcLayerIndex == -1)
  132. {
  133. for (int layer = 0; layer < srcTexture.LayerCount; layer++)
  134. {
  135. _gpu.ResourceManager.SetTextureArrayLayer(srcKey + GetLayerOffset(srcTexture, layer), layer);
  136. }
  137. srcLayerIndex = 0;
  138. }
  139. if (isDstLayered && dstLayerIndex == -1)
  140. {
  141. for (int layer = 0; layer < dstTexture.LayerCount; layer++)
  142. {
  143. _gpu.ResourceManager.SetTextureArrayLayer(dstKey + GetLayerOffset(dstTexture, layer), layer);
  144. }
  145. dstLayerIndex = 0;
  146. }
  147. int srcBlitX1 = (int)(srcBlitX >> 32);
  148. int srcBlitY1 = (int)(srcBlitY >> 32);
  149. int srcBlitX2 = (int)(srcBlitX + dstBlitW * blitDuDx >> 32);
  150. int srcBlitY2 = (int)(srcBlitY + dstBlitH * blitDvDy >> 32);
  151. _gpu.Renderer.RenderTarget.Copy(
  152. srcTexture,
  153. dstTexture,
  154. srcKey,
  155. dstKey,
  156. srcLayerIndex,
  157. dstLayerIndex,
  158. srcBlitX1,
  159. srcBlitY1,
  160. srcBlitX2,
  161. srcBlitY2,
  162. dstBlitX,
  163. dstBlitY,
  164. dstBlitX + dstBlitW,
  165. dstBlitY + dstBlitH);
  166. // Do a guest side copy as well. This is necessary when
  167. // the texture is modified by the guest, however it doesn't
  168. // work when resources that the gpu can write to are copied,
  169. // like framebuffers.
  170. // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer)
  171. ImageUtils.CopyTexture(
  172. vmm,
  173. srcTexture,
  174. dstTexture,
  175. srcAddress,
  176. dstAddress,
  177. srcBlitX1,
  178. srcBlitY1,
  179. dstBlitX,
  180. dstBlitY,
  181. dstBlitW,
  182. dstBlitH);
  183. vmm.IsRegionModified(dstKey, ImageUtils.GetSize(dstTexture), NvGpuBufferType.Texture);
  184. Profile.End(Profiles.GPU.Engine2d.TextureCopy);
  185. }
  186. private static GalMemoryLayout GetLayout(bool linear)
  187. {
  188. return linear
  189. ? GalMemoryLayout.Pitch
  190. : GalMemoryLayout.BlockLinear;
  191. }
  192. private long MakeInt64From2xInt32(NvGpuEngine2dReg reg)
  193. {
  194. return
  195. (long)Registers[(int)reg + 0] << 32 |
  196. (uint)Registers[(int)reg + 1];
  197. }
  198. private void WriteRegister(GpuMethodCall methCall)
  199. {
  200. Registers[methCall.Method] = methCall.Argument;
  201. }
  202. private long ReadRegisterFixed1_31_32(NvGpuEngine2dReg reg)
  203. {
  204. long low = (uint)ReadRegister(reg + 0);
  205. long high = (uint)ReadRegister(reg + 1);
  206. return low | (high << 32);
  207. }
  208. private int ReadRegister(NvGpuEngine2dReg reg)
  209. {
  210. return Registers[(int)reg];
  211. }
  212. }
  213. }