aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-04-22 03:00:11 -0300
committerGitHub <noreply@github.com>2020-04-22 16:00:11 +1000
commit6bfe4715f05be10c73a788abd8727293a7eca77e (patch)
tree2cb319f53b0c4b846352a9836772c3eff4b1db1d /Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
parentc46edfab858051e4b800b2705df2c019c1d975cd (diff)
Initial conditional rendering support (#1012)
* Initial conditional rendering support * Properly reset state * Support conditional modes and skeleton a counter cache for future host conditional rendering * Address PR feedback
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory/CounterCache.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/CounterCache.cs140
1 files changed, 140 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs b/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
new file mode 100644
index 00000000..3110cdcc
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
@@ -0,0 +1,140 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+ /// <summary>
+ /// Represents the GPU counter cache.
+ /// </summary>
+ class CounterCache
+ {
+ private struct CounterEntry
+ {
+ public ulong Address { get; }
+
+ public CounterEntry(ulong address)
+ {
+ Address = address;
+ }
+ }
+
+ private readonly List<CounterEntry> _items;
+
+ /// <summary>
+ /// Creates a new instance of the GPU counter cache.
+ /// </summary>
+ public CounterCache()
+ {
+ _items = new List<CounterEntry>();
+ }
+
+ /// <summary>
+ /// Adds a new counter to the counter cache, or updates a existing one.
+ /// </summary>
+ /// <param name="gpuVa">GPU virtual address where the counter will be written in memory</param>
+ public void AddOrUpdate(ulong gpuVa)
+ {
+ int index = BinarySearch(gpuVa);
+
+ CounterEntry entry = new CounterEntry(gpuVa);
+
+ if (index < 0)
+ {
+ _items.Insert(~index, entry);
+ }
+ else
+ {
+ _items[index] = entry;
+ }
+ }
+
+ /// <summary>
+ /// Handles removal of counters written to a memory region being unmapped.
+ /// </summary>
+ /// <param name="sender">Sender object</param>
+ /// <param name="e">Event arguments</param>
+ public void MemoryUnmappedHandler(object sender, UnmapEventArgs e) => RemoveRange(e.Address, e.Size);
+
+ private void RemoveRange(ulong gpuVa, ulong size)
+ {
+ int index = BinarySearch(gpuVa + size - 1);
+
+ if (index < 0)
+ {
+ index = ~index;
+ }
+
+ if (index >= _items.Count || !InRange(gpuVa, size, _items[index].Address))
+ {
+ return;
+ }
+
+ int count = 1;
+
+ while (index > 0 && InRange(gpuVa, size, _items[index - 1].Address))
+ {
+ index--;
+ count++;
+ }
+
+ _items.RemoveRange(index, count);
+ }
+
+ /// <summary>
+ /// Checks whenever an address falls inside a given range.
+ /// </summary>
+ /// <param name="startVa">Range start address</param>
+ /// <param name="size">Range size</param>
+ /// <param name="gpuVa">Address being checked</param>
+ /// <returns>True if the address falls inside the range, false otherwise</returns>
+ private static bool InRange(ulong startVa, ulong size, ulong gpuVa)
+ {
+ return gpuVa >= startVa && gpuVa < startVa + size;
+ }
+
+ /// <summary>
+ /// Check if any counter value was written to the specified GPU virtual memory address.
+ /// </summary>
+ /// <param name="gpuVa">GPU virtual address</param>
+ /// <returns>True if any counter value was written on the specified address, false otherwise</returns>
+ public bool Contains(ulong gpuVa)
+ {
+ return BinarySearch(gpuVa) >= 0;
+ }
+
+ /// <summary>
+ /// Performs binary search of an address on the list.
+ /// </summary>
+ /// <param name="address">Address to search</param>
+ /// <returns>Index of the item, or complement of the index of the nearest item with lower value</returns>
+ private int BinarySearch(ulong address)
+ {
+ int left = 0;
+ int right = _items.Count - 1;
+
+ while (left <= right)
+ {
+ int range = right - left;
+
+ int middle = left + (range >> 1);
+
+ CounterEntry item = _items[middle];
+
+ if (item.Address == address)
+ {
+ return middle;
+ }
+
+ if (address < item.Address)
+ {
+ right = middle - 1;
+ }
+ else
+ {
+ left = middle + 1;
+ }
+ }
+
+ return ~left;
+ }
+ }
+}