aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/Memory/NvGpuVmmCache.cs')
-rw-r--r--Ryujinx.Graphics/Memory/NvGpuVmmCache.cs80
1 files changed, 64 insertions, 16 deletions
diff --git a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs
index 57e25a2f..dd6d37c9 100644
--- a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs
+++ b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs
@@ -5,27 +5,54 @@ namespace Ryujinx.Graphics.Memory
{
class NvGpuVmmCache
{
- private ValueRangeSet<int> CachedRanges;
+ private struct CachedResource
+ {
+ public long Key;
+ public int Mask;
+
+ public CachedResource(long Key, int Mask)
+ {
+ this.Key = Key;
+ this.Mask = Mask;
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)(Key * 23 + Mask);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is CachedResource Cached && Equals(Cached);
+ }
+
+ public bool Equals(CachedResource other)
+ {
+ return Key == other.Key && Mask == other.Mask;
+ }
+ }
+
+ private ValueRangeSet<CachedResource> CachedRanges;
public NvGpuVmmCache()
{
- CachedRanges = new ValueRangeSet<int>();
+ CachedRanges = new ValueRangeSet<CachedResource>();
}
- public bool IsRegionModified(MemoryManager Memory, NvGpuBufferType BufferType, long PA, long Size)
+ public bool IsRegionModified(MemoryManager Memory, NvGpuBufferType BufferType, long Start, long Size)
{
- (bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size);
+ (bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(Start, Size);
//Remove all modified ranges.
int Index = 0;
- long Position = PA & ~NvGpuVmm.PageMask;
+ long Position = Start & ~NvGpuVmm.PageMask;
while (ModifiedCount > 0)
{
if (Modified[Index++])
{
- CachedRanges.Remove(new ValueRange<int>(Position, Position + NvGpuVmm.PageSize));
+ CachedRanges.Remove(new ValueRange<CachedResource>(Position, Position + NvGpuVmm.PageSize));
ModifiedCount--;
}
@@ -37,11 +64,19 @@ namespace Ryujinx.Graphics.Memory
//If the region is not yet present on the list, then a new ValueRange
//is directly added with the current resource type as the only bit set.
//Otherwise, it just sets the bit for this new resource type on the current mask.
+ //The physical address of the resource is used as key, those keys are used to keep
+ //track of resources that are already on the cache. A resource may be inside another
+ //resource, and in this case we should return true if the "sub-resource" was not
+ //yet cached.
int Mask = 1 << (int)BufferType;
- ValueRange<int> NewCached = new ValueRange<int>(PA, PA + Size);
+ CachedResource NewCachedValue = new CachedResource(Start, Mask);
- ValueRange<int>[] Ranges = CachedRanges.GetAllIntersections(NewCached);
+ ValueRange<CachedResource> NewCached = new ValueRange<CachedResource>(Start, Start + Size);
+
+ ValueRange<CachedResource>[] Ranges = CachedRanges.GetAllIntersections(NewCached);
+
+ bool IsKeyCached = Ranges.Length > 0 && Ranges[0].Value.Key == Start;
long LastEnd = NewCached.Start;
@@ -49,23 +84,36 @@ namespace Ryujinx.Graphics.Memory
for (Index = 0; Index < Ranges.Length; Index++)
{
- ValueRange<int> Current = Ranges[Index];
+ ValueRange<CachedResource> Current = Ranges[Index];
+
+ CachedResource Cached = Current.Value;
long RgStart = Math.Max(Current.Start, NewCached.Start);
long RgEnd = Math.Min(Current.End, NewCached.End);
- if ((Current.Value & Mask) == 0)
+ if ((Cached.Mask & Mask) != 0)
{
- CachedRanges.Add(new ValueRange<int>(RgStart, RgEnd, Current.Value | Mask));
+ Coverage += RgEnd - RgStart;
}
- else
+
+ //Highest key value has priority, this prevents larger resources
+ //for completely invalidating smaller ones on the cache. For example,
+ //consider that a resource in the range [100, 200) was added, and then
+ //another one in the range [50, 200). We prevent the new resource from
+ //completely replacing the old one by spliting it like this:
+ //New resource key is added at [50, 100), old key is still present at [100, 200).
+ if (Cached.Key < Start)
{
- Coverage += RgEnd - RgStart;
+ Cached.Key = Start;
}
+ Cached.Mask |= Mask;
+
+ CachedRanges.Add(new ValueRange<CachedResource>(RgStart, RgEnd, Cached));
+
if (RgStart > LastEnd)
{
- CachedRanges.Add(new ValueRange<int>(LastEnd, RgStart, Mask));
+ CachedRanges.Add(new ValueRange<CachedResource>(LastEnd, RgStart, NewCachedValue));
}
LastEnd = RgEnd;
@@ -73,10 +121,10 @@ namespace Ryujinx.Graphics.Memory
if (LastEnd < NewCached.End)
{
- CachedRanges.Add(new ValueRange<int>(LastEnd, NewCached.End, Mask));
+ CachedRanges.Add(new ValueRange<CachedResource>(LastEnd, NewCached.End, NewCachedValue));
}
- return Coverage != Size;
+ return !IsKeyCached || Coverage != Size;
}
}
} \ No newline at end of file