1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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;
}
}
}
|