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 }