diff options
Diffstat (limited to 'Ryujinx.Graphics/Memory')
| -rw-r--r-- | Ryujinx.Graphics/Memory/NvGpuVmm.cs | 4 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 135 |
2 files changed, 46 insertions, 93 deletions
diff --git a/Ryujinx.Graphics/Memory/NvGpuVmm.cs b/Ryujinx.Graphics/Memory/NvGpuVmm.cs index cfd1aaeb..7fdef473 100644 --- a/Ryujinx.Graphics/Memory/NvGpuVmm.cs +++ b/Ryujinx.Graphics/Memory/NvGpuVmm.cs @@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Memory { this.Memory = Memory; - Cache = new NvGpuVmmCache(); + Cache = new NvGpuVmmCache(Memory); PageTable = new long[PTLvl0Size][]; } @@ -262,7 +262,7 @@ namespace Ryujinx.Graphics.Memory public bool IsRegionModified(long PA, long Size, NvGpuBufferType BufferType) { - return Cache.IsRegionModified(Memory, BufferType, PA, Size); + return Cache.IsRegionModified(PA, Size, BufferType); } public bool TryGetHostAddress(long Position, long Size, out IntPtr Ptr) diff --git a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs index dd6d37c9..2f50463d 100644 --- a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs +++ b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs @@ -1,130 +1,83 @@ +using ChocolArm64.Events; using ChocolArm64.Memory; -using System; +using System.Collections.Concurrent; namespace Ryujinx.Graphics.Memory { class NvGpuVmmCache { - private struct CachedResource - { - public long Key; - public int Mask; + private const int PageBits = MemoryManager.PageBits; - public CachedResource(long Key, int Mask) - { - this.Key = Key; - this.Mask = Mask; - } + private const long PageSize = MemoryManager.PageSize; + private const long PageMask = MemoryManager.PageMask; - public override int GetHashCode() - { - return (int)(Key * 23 + Mask); - } + private ConcurrentDictionary<long, int>[] CachedPages; - public override bool Equals(object obj) - { - return obj is CachedResource Cached && Equals(Cached); - } + private MemoryManager _memory; - public bool Equals(CachedResource other) - { - return Key == other.Key && Mask == other.Mask; - } - } + public NvGpuVmmCache(MemoryManager memory) + { + _memory = memory; - private ValueRangeSet<CachedResource> CachedRanges; + _memory.ObservedAccess += MemoryAccessHandler; - public NvGpuVmmCache() - { - CachedRanges = new ValueRangeSet<CachedResource>(); + CachedPages = new ConcurrentDictionary<long, int>[1 << 20]; } - public bool IsRegionModified(MemoryManager Memory, NvGpuBufferType BufferType, long Start, long Size) + private void MemoryAccessHandler(object sender, MemoryAccessEventArgs e) { - (bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(Start, Size); + long pa = _memory.GetPhysicalAddress(e.Position); - //Remove all modified ranges. - int Index = 0; - - long Position = Start & ~NvGpuVmm.PageMask; - - while (ModifiedCount > 0) - { - if (Modified[Index++]) - { - CachedRanges.Remove(new ValueRange<CachedResource>(Position, Position + NvGpuVmm.PageSize)); - - ModifiedCount--; - } - - Position += NvGpuVmm.PageSize; - } - - //Mask has the bit set for the current resource type. - //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; + CachedPages[pa >> PageBits]?.Clear(); + } - CachedResource NewCachedValue = new CachedResource(Start, Mask); + public bool IsRegionModified(long position, long size, NvGpuBufferType bufferType) + { + long pa = _memory.GetPhysicalAddress(position); - ValueRange<CachedResource> NewCached = new ValueRange<CachedResource>(Start, Start + Size); + long addr = pa; - ValueRange<CachedResource>[] Ranges = CachedRanges.GetAllIntersections(NewCached); + long endAddr = (addr + size + PageMask) & ~PageMask; - bool IsKeyCached = Ranges.Length > 0 && Ranges[0].Value.Key == Start; + int newBuffMask = 1 << (int)bufferType; - long LastEnd = NewCached.Start; + _memory.StartObservingRegion(position, size); - long Coverage = 0; + long cachedPagesCount = 0; - for (Index = 0; Index < Ranges.Length; Index++) + while (addr < endAddr) { - ValueRange<CachedResource> Current = Ranges[Index]; - - CachedResource Cached = Current.Value; + long page = addr >> PageBits; - long RgStart = Math.Max(Current.Start, NewCached.Start); - long RgEnd = Math.Min(Current.End, NewCached.End); + ConcurrentDictionary<long, int> dictionary = CachedPages[page]; - if ((Cached.Mask & Mask) != 0) + if (dictionary == null) { - Coverage += RgEnd - RgStart; + dictionary = new ConcurrentDictionary<long, int>(); + + CachedPages[page] = dictionary; } - //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) + if (dictionary.TryGetValue(pa, out int currBuffMask)) { - Cached.Key = Start; + if ((currBuffMask & newBuffMask) != 0) + { + cachedPagesCount++; + } + else + { + dictionary[pa] |= newBuffMask; + } } - - Cached.Mask |= Mask; - - CachedRanges.Add(new ValueRange<CachedResource>(RgStart, RgEnd, Cached)); - - if (RgStart > LastEnd) + else { - CachedRanges.Add(new ValueRange<CachedResource>(LastEnd, RgStart, NewCachedValue)); + dictionary[pa] = newBuffMask; } - LastEnd = RgEnd; - } - - if (LastEnd < NewCached.End) - { - CachedRanges.Add(new ValueRange<CachedResource>(LastEnd, NewCached.End, NewCachedValue)); + addr += PageSize; } - return !IsKeyCached || Coverage != Size; + return cachedPagesCount != (endAddr - pa + PageMask) >> PageBits; } } }
\ No newline at end of file |
