MethodReport.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu.State;
  4. using System;
  5. using System.Runtime.InteropServices;
  6. namespace Ryujinx.Graphics.Gpu.Engine
  7. {
  8. partial class Methods
  9. {
  10. private const int NsToTicksFractionNumerator = 384;
  11. private const int NsToTicksFractionDenominator = 625;
  12. /// <summary>
  13. /// Writes a GPU counter to guest memory.
  14. /// </summary>
  15. /// <param name="state">Current GPU state</param>
  16. /// <param name="argument">Method call argument</param>
  17. private void Report(GpuState state, int argument)
  18. {
  19. ReportMode mode = (ReportMode)(argument & 3);
  20. ReportCounterType type = (ReportCounterType)((argument >> 23) & 0x1f);
  21. switch (mode)
  22. {
  23. case ReportMode.Release: ReleaseSemaphore(state); break;
  24. case ReportMode.Counter: ReportCounter(state, type); break;
  25. }
  26. }
  27. /// <summary>
  28. /// Writes (or Releases) a GPU semaphore value to guest memory.
  29. /// </summary>
  30. /// <param name="state">Current GPU state</param>
  31. private void ReleaseSemaphore(GpuState state)
  32. {
  33. var rs = state.Get<ReportState>(MethodOffset.ReportState);
  34. _context.MemoryAccessor.Write(rs.Address.Pack(), rs.Payload);
  35. _context.AdvanceSequence();
  36. }
  37. /// <summary>
  38. /// Packed GPU counter data (including GPU timestamp) in memory.
  39. /// </summary>
  40. private struct CounterData
  41. {
  42. public ulong Counter;
  43. public ulong Timestamp;
  44. }
  45. /// <summary>
  46. /// Writes a GPU counter to guest memory.
  47. /// This also writes the current timestamp value.
  48. /// </summary>
  49. /// <param name="state">Current GPU state</param>
  50. /// <param name="type">Counter to be written to memory</param>
  51. private void ReportCounter(GpuState state, ReportCounterType type)
  52. {
  53. CounterData counterData = new CounterData();
  54. ulong counter = 0;
  55. switch (type)
  56. {
  57. case ReportCounterType.Zero:
  58. counter = 0;
  59. break;
  60. case ReportCounterType.SamplesPassed:
  61. counter = _context.Renderer.GetCounter(CounterType.SamplesPassed);
  62. break;
  63. case ReportCounterType.PrimitivesGenerated:
  64. counter = _context.Renderer.GetCounter(CounterType.PrimitivesGenerated);
  65. break;
  66. case ReportCounterType.TransformFeedbackPrimitivesWritten:
  67. counter = _context.Renderer.GetCounter(CounterType.TransformFeedbackPrimitivesWritten);
  68. break;
  69. }
  70. ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
  71. if (GraphicsConfig.FastGpuTime)
  72. {
  73. // Divide by some amount to report time as if operations were performed faster than they really are.
  74. // This can prevent some games from switching to a lower resolution because rendering is too slow.
  75. ticks /= 256;
  76. }
  77. counterData.Counter = counter;
  78. counterData.Timestamp = ticks;
  79. Span<CounterData> counterDataSpan = MemoryMarshal.CreateSpan(ref counterData, 1);
  80. Span<byte> data = MemoryMarshal.Cast<CounterData, byte>(counterDataSpan);
  81. var rs = state.Get<ReportState>(MethodOffset.ReportState);
  82. _context.MemoryAccessor.Write(rs.Address.Pack(), data);
  83. }
  84. /// <summary>
  85. /// Converts a nanoseconds timestamp value to Maxwell time ticks.
  86. /// </summary>
  87. /// <remarks>
  88. /// The frequency is 614400000 Hz.
  89. /// </remarks>
  90. /// <param name="nanoseconds">Timestamp in nanoseconds</param>
  91. /// <returns>Maxwell ticks</returns>
  92. private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
  93. {
  94. // We need to divide first to avoid overflows.
  95. // We fix up the result later by calculating the difference and adding
  96. // that to the result.
  97. ulong divided = nanoseconds / NsToTicksFractionDenominator;
  98. ulong rounded = divided * NsToTicksFractionDenominator;
  99. ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
  100. return divided * NsToTicksFractionNumerator + errorBias;
  101. }
  102. }
  103. }