diff options
Diffstat (limited to 'Ryujinx.Graphics/Memory')
-rw-r--r-- | Ryujinx.Graphics/Memory/NvGpuPBEntry.cs | 23 | ||||
-rw-r--r-- | Ryujinx.Graphics/Memory/NvGpuPushBuffer.cs | 101 | ||||
-rw-r--r-- | Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 80 |
3 files changed, 64 insertions, 140 deletions
diff --git a/Ryujinx.Graphics/Memory/NvGpuPBEntry.cs b/Ryujinx.Graphics/Memory/NvGpuPBEntry.cs deleted file mode 100644 index 6b93c169..00000000 --- a/Ryujinx.Graphics/Memory/NvGpuPBEntry.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.ObjectModel; - -namespace Ryujinx.Graphics.Memory -{ - public struct NvGpuPBEntry - { - public int Method { get; private set; } - - public int SubChannel { get; private set; } - - private int[] m_Arguments; - - public ReadOnlyCollection<int> Arguments => Array.AsReadOnly(m_Arguments); - - public NvGpuPBEntry(int Method, int SubChannel, params int[] Arguments) - { - this.Method = Method; - this.SubChannel = SubChannel; - this.m_Arguments = Arguments; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics/Memory/NvGpuPushBuffer.cs b/Ryujinx.Graphics/Memory/NvGpuPushBuffer.cs deleted file mode 100644 index 0902ebfc..00000000 --- a/Ryujinx.Graphics/Memory/NvGpuPushBuffer.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.Graphics.Memory -{ - public static class NvGpuPushBuffer - { - private enum SubmissionMode - { - Incrementing = 1, - NonIncrementing = 3, - Immediate = 4, - IncrementOnce = 5 - } - - public static NvGpuPBEntry[] Decode(byte[] Data) - { - using (MemoryStream MS = new MemoryStream(Data)) - { - BinaryReader Reader = new BinaryReader(MS); - - List<NvGpuPBEntry> PushBuffer = new List<NvGpuPBEntry>(); - - bool CanRead() => MS.Position + 4 <= MS.Length; - - while (CanRead()) - { - int Packed = Reader.ReadInt32(); - - int Meth = (Packed >> 0) & 0x1fff; - int SubC = (Packed >> 13) & 7; - int Args = (Packed >> 16) & 0x1fff; - int Mode = (Packed >> 29) & 7; - - switch ((SubmissionMode)Mode) - { - case SubmissionMode.Incrementing: - { - for (int Index = 0; Index < Args && CanRead(); Index++, Meth++) - { - PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Reader.ReadInt32())); - } - - break; - } - - case SubmissionMode.NonIncrementing: - { - int[] Arguments = new int[Args]; - - for (int Index = 0; Index < Arguments.Length; Index++) - { - if (!CanRead()) - { - break; - } - - Arguments[Index] = Reader.ReadInt32(); - } - - PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Arguments)); - - break; - } - - case SubmissionMode.Immediate: - { - PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Args)); - - break; - } - - case SubmissionMode.IncrementOnce: - { - if (CanRead()) - { - PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Reader.ReadInt32())); - } - - if (CanRead() && Args > 1) - { - int[] Arguments = new int[Args - 1]; - - for (int Index = 0; Index < Arguments.Length && CanRead(); Index++) - { - Arguments[Index] = Reader.ReadInt32(); - } - - PushBuffer.Add(new NvGpuPBEntry(Meth + 1, SubC, Arguments)); - } - - break; - } - } - } - - return PushBuffer.ToArray(); - } - } - } -}
\ No newline at end of file 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 |