diff options
Diffstat (limited to 'Ryujinx.Graphics/Memory/NvGpuVmmCache.cs')
-rw-r--r-- | Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 80 |
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 |