Host1xDevice.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.Device;
  4. using Ryujinx.Graphics.Gpu.Synchronization;
  5. using System;
  6. using System.Numerics;
  7. namespace Ryujinx.Graphics.Host1x
  8. {
  9. public sealed class Host1xDevice : IDisposable
  10. {
  11. private readonly SyncptIncrManager _syncptIncrMgr;
  12. private readonly AsyncWorkQueue<int[]> _commandQueue;
  13. private readonly Devices _devices = new Devices();
  14. public Host1xClass Class { get; }
  15. private IDeviceState _device;
  16. private int _count;
  17. private int _offset;
  18. private int _mask;
  19. private bool _incrementing;
  20. public Host1xDevice(SynchronizationManager syncMgr)
  21. {
  22. _syncptIncrMgr = new SyncptIncrManager(syncMgr);
  23. _commandQueue = new AsyncWorkQueue<int[]>(Process, "Ryujinx.Host1xProcessor");
  24. Class = new Host1xClass(syncMgr);
  25. _devices.RegisterDevice(ClassId.Host1x, Class);
  26. }
  27. public void RegisterDevice(ClassId classId, IDeviceState device)
  28. {
  29. var thi = new ThiDevice(classId, device ?? throw new ArgumentNullException(nameof(device)), _syncptIncrMgr);
  30. _devices.RegisterDevice(classId, thi);
  31. }
  32. public void Submit(ReadOnlySpan<int> commandBuffer)
  33. {
  34. _commandQueue.Add(commandBuffer.ToArray());
  35. }
  36. private void Process(int[] commandBuffer)
  37. {
  38. for (int index = 0; index < commandBuffer.Length; index++)
  39. {
  40. Step(commandBuffer[index]);
  41. }
  42. }
  43. private void Step(int value)
  44. {
  45. if (_mask != 0)
  46. {
  47. int lbs = BitOperations.TrailingZeroCount(_mask);
  48. _mask &= ~(1 << lbs);
  49. DeviceWrite(_offset + lbs, value);
  50. return;
  51. }
  52. else if (_count != 0)
  53. {
  54. _count--;
  55. DeviceWrite(_offset, value);
  56. if (_incrementing)
  57. {
  58. _offset++;
  59. }
  60. return;
  61. }
  62. OpCode opCode = (OpCode)((value >> 28) & 0xf);
  63. switch (opCode)
  64. {
  65. case OpCode.SetClass:
  66. _mask = value & 0x3f;
  67. ClassId classId = (ClassId)((value >> 6) & 0x3ff);
  68. _offset = (value >> 16) & 0xfff;
  69. _device = _devices.GetDevice(classId);
  70. break;
  71. case OpCode.Incr:
  72. case OpCode.NonIncr:
  73. _count = value & 0xffff;
  74. _offset = (value >> 16) & 0xfff;
  75. _incrementing = opCode == OpCode.Incr;
  76. break;
  77. case OpCode.Mask:
  78. _mask = value & 0xffff;
  79. _offset = (value >> 16) & 0xfff;
  80. break;
  81. case OpCode.Imm:
  82. int data = value & 0xfff;
  83. _offset = (value >> 16) & 0xfff;
  84. DeviceWrite(_offset, data);
  85. break;
  86. default:
  87. Logger.Error?.Print(LogClass.Host1x, $"Unsupported opcode \"{opCode}\".");
  88. break;
  89. }
  90. }
  91. private void DeviceWrite(int offset, int data)
  92. {
  93. _device?.Write(offset * 4, data);
  94. }
  95. public void Dispose()
  96. {
  97. _commandQueue.Dispose();
  98. _devices.Dispose();
  99. }
  100. }
  101. }