2018-12-12 01:48:54 +00:00
|
|
|
using ChocolArm64.Events;
|
2018-06-09 01:15:56 +01:00
|
|
|
using ChocolArm64.Memory;
|
2018-12-12 01:48:54 +00:00
|
|
|
using System.Collections.Concurrent;
|
2018-06-09 01:15:56 +01:00
|
|
|
|
2018-09-08 18:51:50 +01:00
|
|
|
namespace Ryujinx.Graphics.Memory
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
|
|
|
class NvGpuVmmCache
|
|
|
|
{
|
2018-12-12 01:48:54 +00:00
|
|
|
private const int PageBits = MemoryManager.PageBits;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
private const long PageSize = MemoryManager.PageSize;
|
|
|
|
private const long PageMask = MemoryManager.PageMask;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
private ConcurrentDictionary<long, int>[] CachedPages;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
private MemoryManager _memory;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
public NvGpuVmmCache(MemoryManager memory)
|
|
|
|
{
|
|
|
|
_memory = memory;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
_memory.ObservedAccess += MemoryAccessHandler;
|
2018-06-09 01:15:56 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
CachedPages = new ConcurrentDictionary<long, int>[1 << 20];
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
private void MemoryAccessHandler(object sender, MemoryAccessEventArgs e)
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
2018-12-12 01:48:54 +00:00
|
|
|
long pa = _memory.GetPhysicalAddress(e.Position);
|
2018-07-08 20:55:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
CachedPages[pa >> PageBits]?.Clear();
|
|
|
|
}
|
2018-06-09 01:15:56 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
public bool IsRegionModified(long position, long size, NvGpuBufferType bufferType)
|
|
|
|
{
|
|
|
|
long pa = _memory.GetPhysicalAddress(position);
|
2018-07-29 05:39:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
long addr = pa;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
long endAddr = (addr + size + PageMask) & ~PageMask;
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
int newBuffMask = 1 << (int)bufferType;
|
2018-07-29 05:39:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
_memory.StartObservingRegion(position, size);
|
2018-07-29 05:39:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
long cachedPagesCount = 0;
|
2018-07-29 05:39:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
while (addr < endAddr)
|
2018-07-29 05:39:15 +01:00
|
|
|
{
|
2018-12-12 01:48:54 +00:00
|
|
|
long page = addr >> PageBits;
|
2018-07-29 05:39:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
ConcurrentDictionary<long, int> dictionary = CachedPages[page];
|
2018-07-29 05:39:15 +01:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
if (dictionary == null)
|
2018-07-29 05:39:15 +01:00
|
|
|
{
|
2018-12-12 01:48:54 +00:00
|
|
|
dictionary = new ConcurrentDictionary<long, int>();
|
|
|
|
|
|
|
|
CachedPages[page] = dictionary;
|
2018-07-29 05:39:15 +01:00
|
|
|
}
|
2018-11-17 04:01:31 +00:00
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
if (dictionary.TryGetValue(pa, out int currBuffMask))
|
2018-07-29 05:39:15 +01:00
|
|
|
{
|
2018-12-12 01:48:54 +00:00
|
|
|
if ((currBuffMask & newBuffMask) != 0)
|
|
|
|
{
|
|
|
|
cachedPagesCount++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dictionary[pa] |= newBuffMask;
|
|
|
|
}
|
2018-07-29 05:39:15 +01:00
|
|
|
}
|
2018-12-12 01:48:54 +00:00
|
|
|
else
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
2018-12-12 01:48:54 +00:00
|
|
|
dictionary[pa] = newBuffMask;
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
addr += PageSize;
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-12-12 01:48:54 +00:00
|
|
|
return cachedPagesCount != (endAddr - pa + PageMask) >> PageBits;
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|