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
This commit is contained in:
parent
b833183ef6
commit
d2bb458b51
25 changed files with 616 additions and 395 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
CachedRanges.Add(new ValueRange<int>(RgStart, RgEnd, Current.Value | Mask));
|
||||
}
|
||||
else
|
||||
if ((Cached.Mask & Mask) != 0)
|
||||
{
|
||||
Coverage += RgEnd - RgStart;
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue