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:
gdkchan 2018-11-17 02:01:31 -02:00 committed by Ac_K
parent b833183ef6
commit d2bb458b51
25 changed files with 616 additions and 395 deletions

View file

@ -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;
}
}
}