Inline2Memory.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.Gpu.State;
  3. using Ryujinx.Graphics.Texture;
  4. using System;
  5. using System.Runtime.InteropServices;
  6. namespace Ryujinx.Graphics.Gpu.Engine
  7. {
  8. partial class Methods
  9. {
  10. private Inline2MemoryParams _params;
  11. private bool _isLinear;
  12. private int _offset;
  13. private int _size;
  14. private bool _finished;
  15. private int[] _buffer;
  16. public void LaunchDma(GpuState state, int argument)
  17. {
  18. _params = state.Get<Inline2MemoryParams>(MethodOffset.I2mParams);
  19. _isLinear = (argument & 1) != 0;
  20. _offset = 0;
  21. _size = _params.LineLengthIn * _params.LineCount;
  22. int count = BitUtils.DivRoundUp(_size, 4);
  23. if (_buffer == null || _buffer.Length < count)
  24. {
  25. _buffer = new int[count];
  26. }
  27. ulong dstBaseAddress = _context.MemoryManager.Translate(_params.DstAddress.Pack());
  28. _context.Methods.TextureManager.Flush(dstBaseAddress, (ulong)_size);
  29. _finished = false;
  30. }
  31. public void LoadInlineData(GpuState state, int argument)
  32. {
  33. if (!_finished)
  34. {
  35. _buffer[_offset++] = argument;
  36. if (_offset * 4 >= _size)
  37. {
  38. FinishTransfer();
  39. }
  40. }
  41. }
  42. private void FinishTransfer()
  43. {
  44. Span<byte> data = MemoryMarshal.Cast<int, byte>(_buffer).Slice(0, _size);
  45. if (_isLinear && _params.LineCount == 1)
  46. {
  47. ulong address = _context.MemoryManager.Translate( _params.DstAddress.Pack());
  48. _context.PhysicalMemory.Write(address, data);
  49. }
  50. else
  51. {
  52. var dstCalculator = new OffsetCalculator(
  53. _params.DstWidth,
  54. _params.DstHeight,
  55. _params.DstStride,
  56. _isLinear,
  57. _params.DstMemoryLayout.UnpackGobBlocksInY(),
  58. 1);
  59. int srcOffset = 0;
  60. ulong dstBaseAddress = _context.MemoryManager.Translate(_params.DstAddress.Pack());
  61. for (int y = _params.DstY; y < _params.DstY + _params.LineCount; y++)
  62. {
  63. int x1 = _params.DstX;
  64. int x2 = _params.DstX + _params.LineLengthIn;
  65. int x2Trunc = _params.DstX + BitUtils.AlignDown(_params.LineLengthIn, 16);
  66. int x;
  67. for (x = x1; x < x2Trunc; x += 16, srcOffset += 16)
  68. {
  69. int dstOffset = dstCalculator.GetOffset(x, y);
  70. ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
  71. Span<byte> pixel = data.Slice(srcOffset, 16);
  72. _context.PhysicalMemory.Write(dstAddress, pixel);
  73. }
  74. for (; x < x2; x++, srcOffset++)
  75. {
  76. int dstOffset = dstCalculator.GetOffset(x, y);
  77. ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
  78. Span<byte> pixel = data.Slice(srcOffset, 1);
  79. _context.PhysicalMemory.Write(dstAddress, pixel);
  80. }
  81. }
  82. }
  83. _finished = true;
  84. }
  85. }
  86. }