aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Memory
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/Memory')
-rw-r--r--Ryujinx.Graphics/Memory/NvGpuPBEntry.cs23
-rw-r--r--Ryujinx.Graphics/Memory/NvGpuPushBuffer.cs101
-rw-r--r--Ryujinx.Graphics/Memory/NvGpuVmmCache.cs80
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