From d2bb458b51bbcbc097f8f53ac2a3b8b15a723a45 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 17 Nov 2018 02:01:31 -0200 Subject: Improved GPU command lists decoding (#499) * Better implementation of the DMA pusher, misc fixes * Remove some debug code * Correct RGBX8 format * Add support for linked Texture Sampler Control * Attempt to fix upside down screen issue --- Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 80 +++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 16 deletions(-) (limited to 'Ryujinx.Graphics/Memory/NvGpuVmmCache.cs') 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 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 CachedRanges; public NvGpuVmmCache() { - CachedRanges = new ValueRangeSet(); + CachedRanges = new ValueRangeSet(); } - 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(Position, Position + NvGpuVmm.PageSize)); + CachedRanges.Remove(new ValueRange(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 NewCached = new ValueRange(PA, PA + Size); + CachedResource NewCachedValue = new CachedResource(Start, Mask); - ValueRange[] Ranges = CachedRanges.GetAllIntersections(NewCached); + ValueRange NewCached = new ValueRange(Start, Start + Size); + + ValueRange[] 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 Current = Ranges[Index]; + ValueRange 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(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(RgStart, RgEnd, Cached)); + if (RgStart > LastEnd) { - CachedRanges.Add(new ValueRange(LastEnd, RgStart, Mask)); + CachedRanges.Add(new ValueRange(LastEnd, RgStart, NewCachedValue)); } LastEnd = RgEnd; @@ -73,10 +121,10 @@ namespace Ryujinx.Graphics.Memory if (LastEnd < NewCached.End) { - CachedRanges.Add(new ValueRange(LastEnd, NewCached.End, Mask)); + CachedRanges.Add(new ValueRange(LastEnd, NewCached.End, NewCachedValue)); } - return Coverage != Size; + return !IsKeyCached || Coverage != Size; } } } \ No newline at end of file -- cgit v1.2.3