From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001
From: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
Date: Sat, 8 Apr 2023 01:22:00 +0200
Subject: Move solution and projects to src
---
src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs | 191 ++++++++++++++++++++++++
1 file changed, 191 insertions(+)
create mode 100644 src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
(limited to 'src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs')
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs b/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
new file mode 100644
index 00000000..e763a899
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
@@ -0,0 +1,191 @@
+using Ryujinx.Graphics.GAL;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+ ///
+ /// Represents the GPU counter cache.
+ ///
+ class CounterCache
+ {
+ private readonly struct CounterEntry
+ {
+ public ulong Address { get; }
+ public ICounterEvent Event { get; }
+
+ public CounterEntry(ulong address, ICounterEvent evt)
+ {
+ Address = address;
+ Event = evt;
+ }
+ }
+
+ private readonly List _items;
+
+ ///
+ /// Creates a new instance of the GPU counter cache.
+ ///
+ public CounterCache()
+ {
+ _items = new List();
+ }
+
+ ///
+ /// Adds a new counter to the counter cache, or updates a existing one.
+ ///
+ /// GPU virtual address where the counter will be written in memory
+ public void AddOrUpdate(ulong gpuVa, ICounterEvent evt)
+ {
+ int index = BinarySearch(gpuVa);
+
+ CounterEntry entry = new CounterEntry(gpuVa, evt);
+
+ if (index < 0)
+ {
+ _items.Insert(~index, entry);
+ }
+ else
+ {
+ _items[index] = entry;
+ }
+ }
+
+ ///
+ /// Handles removal of counters written to a memory region being unmapped.
+ ///
+ /// Sender object
+ /// Event arguments
+ 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++;
+ }
+
+ // Notify the removed counter events that their result should no longer be written out.
+ for (int i = 0; i < count; i++)
+ {
+ ICounterEvent evt = _items[index + i].Event;
+ if (evt != null)
+ {
+ evt.Invalid = true;
+ }
+ }
+
+ _items.RemoveRange(index, count);
+ }
+
+ ///
+ /// Checks whenever an address falls inside a given range.
+ ///
+ /// Range start address
+ /// Range size
+ /// Address being checked
+ /// True if the address falls inside the range, false otherwise
+ private static bool InRange(ulong startVa, ulong size, ulong gpuVa)
+ {
+ return gpuVa >= startVa && gpuVa < startVa + size;
+ }
+
+ ///
+ /// Check if any counter value was written to the specified GPU virtual memory address.
+ ///
+ /// GPU virtual address
+ /// True if any counter value was written on the specified address, false otherwise
+ public bool Contains(ulong gpuVa)
+ {
+ return BinarySearch(gpuVa) >= 0;
+ }
+
+ ///
+ /// Flush any counter value written to the specified GPU virtual memory address.
+ ///
+ /// GPU virtual address
+ /// True if any counter value was written on the specified address, false otherwise
+ public bool FindAndFlush(ulong gpuVa)
+ {
+ int index = BinarySearch(gpuVa);
+ if (index > 0)
+ {
+ _items[index].Event?.Flush();
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Find any counter event that would write to the specified GPU virtual memory address.
+ ///
+ /// GPU virtual address
+ /// The counter event, or null if not present
+ public ICounterEvent FindEvent(ulong gpuVa)
+ {
+ int index = BinarySearch(gpuVa);
+ if (index > 0)
+ {
+ return _items[index].Event;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Performs binary search of an address on the list.
+ ///
+ /// Address to search
+ /// Index of the item, or complement of the index of the nearest item with lower value
+ 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;
+ }
+ }
+}
--
cgit v1.2.3