/ src / Ryujinx.Graphics.Gpu / Engine / Threed / ConditionalRendering.cs
ConditionalRendering.cs
  1  using Ryujinx.Common.Logging;
  2  using Ryujinx.Graphics.GAL;
  3  using Ryujinx.Graphics.Gpu.Engine.Types;
  4  using Ryujinx.Graphics.Gpu.Memory;
  5  
  6  namespace Ryujinx.Graphics.Gpu.Engine.Threed
  7  {
  8      /// <summary>
  9      /// Helper methods used for conditional rendering.
 10      /// </summary>
 11      static class ConditionalRendering
 12      {
 13          /// <summary>
 14          /// Checks if draws and clears should be performed, according
 15          /// to currently set conditional rendering conditions.
 16          /// </summary>
 17          /// <param name="context">GPU context</param>
 18          /// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
 19          /// <param name="address">Conditional rendering buffer address</param>
 20          /// <param name="condition">Conditional rendering condition</param>
 21          /// <returns>True if rendering is enabled, false otherwise</returns>
 22          public static ConditionalRenderEnabled GetRenderEnable(GpuContext context, MemoryManager memoryManager, GpuVa address, Condition condition)
 23          {
 24              switch (condition)
 25              {
 26                  case Condition.Always:
 27                      return ConditionalRenderEnabled.True;
 28                  case Condition.Never:
 29                      return ConditionalRenderEnabled.False;
 30                  case Condition.ResultNonZero:
 31                      return CounterNonZero(context, memoryManager, address.Pack());
 32                  case Condition.Equal:
 33                      return CounterCompare(context, memoryManager, address.Pack(), true);
 34                  case Condition.NotEqual:
 35                      return CounterCompare(context, memoryManager, address.Pack(), false);
 36              }
 37  
 38              Logger.Warning?.Print(LogClass.Gpu, $"Invalid conditional render condition \"{condition}\".");
 39  
 40              return ConditionalRenderEnabled.True;
 41          }
 42  
 43          /// <summary>
 44          /// Checks if the counter value at a given GPU memory address is non-zero.
 45          /// </summary>
 46          /// <param name="context">GPU context</param>
 47          /// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
 48          /// <param name="gpuVa">GPU virtual address of the counter value</param>
 49          /// <returns>True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering</returns>
 50          private static ConditionalRenderEnabled CounterNonZero(GpuContext context, MemoryManager memoryManager, ulong gpuVa)
 51          {
 52              ICounterEvent evt = memoryManager.CounterCache.FindEvent(gpuVa);
 53  
 54              if (evt == null)
 55              {
 56                  return ConditionalRenderEnabled.False;
 57              }
 58  
 59              if (context.Renderer.Pipeline.TryHostConditionalRendering(evt, 0L, false))
 60              {
 61                  return ConditionalRenderEnabled.Host;
 62              }
 63              else
 64              {
 65                  evt.Flush();
 66                  return (memoryManager.Read<ulong>(gpuVa, true) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
 67              }
 68          }
 69  
 70          /// <summary>
 71          /// Checks if the counter at a given GPU memory address passes a specified equality comparison.
 72          /// </summary>
 73          /// <param name="context">GPU context</param>
 74          /// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
 75          /// <param name="gpuVa">GPU virtual address</param>
 76          /// <param name="isEqual">True to check if the values are equal, false to check if they are not equal</param>
 77          /// <returns>True if the condition is met, false otherwise. Returns host if handling with host conditional rendering</returns>
 78          private static ConditionalRenderEnabled CounterCompare(GpuContext context, MemoryManager memoryManager, ulong gpuVa, bool isEqual)
 79          {
 80              ICounterEvent evt = FindEvent(memoryManager.CounterCache, gpuVa);
 81              ICounterEvent evt2 = FindEvent(memoryManager.CounterCache, gpuVa + 16);
 82  
 83              bool useHost;
 84  
 85              if (evt != null && evt2 == null)
 86              {
 87                  useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, memoryManager.Read<ulong>(gpuVa + 16), isEqual);
 88              }
 89              else if (evt == null && evt2 != null)
 90              {
 91                  useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt2, memoryManager.Read<ulong>(gpuVa), isEqual);
 92              }
 93              else if (evt != null && evt2 != null)
 94              {
 95                  useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, evt2, isEqual);
 96              }
 97              else
 98              {
 99                  useHost = false;
100              }
101  
102              if (useHost)
103              {
104                  return ConditionalRenderEnabled.Host;
105              }
106              else
107              {
108                  evt?.Flush();
109                  evt2?.Flush();
110  
111                  ulong x = memoryManager.Read<ulong>(gpuVa, true);
112                  ulong y = memoryManager.Read<ulong>(gpuVa + 16, true);
113  
114                  return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
115              }
116          }
117  
118          /// <summary>
119          /// Tries to find a counter that is supposed to be written at the specified address,
120          /// returning the related event.
121          /// </summary>
122          /// <param name="counterCache">GPU counter cache to search on</param>
123          /// <param name="gpuVa">GPU virtual address where the counter is supposed to be written</param>
124          /// <returns>The counter event, or null if not present</returns>
125          private static ICounterEvent FindEvent(CounterCache counterCache, ulong gpuVa)
126          {
127              return counterCache.FindEvent(gpuVa);
128          }
129      }
130  }