Initial support for separate GPU address spaces (#2394)
* Make GPU memory manager a member of GPU channel * Move physical memory instance to the memory manager, and the caches to the physical memory * PR feedback
This commit is contained in:
parent
8cc872fb60
commit
fbb4019ed5
44 changed files with 780 additions and 481 deletions
|
@ -13,9 +13,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
class Buffer : IRange, IDisposable
|
||||
{
|
||||
private static ulong GranularBufferThreshold = 4096;
|
||||
private const ulong GranularBufferThreshold = 4096;
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private readonly PhysicalMemory _physicalMemory;
|
||||
|
||||
/// <summary>
|
||||
/// Host buffer handle.
|
||||
|
@ -68,14 +69,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// Creates a new instance of the buffer.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the buffer belongs to</param>
|
||||
/// <param name="physicalMemory">Physical memory where the buffer is mapped</param>
|
||||
/// <param name="address">Start address of the buffer</param>
|
||||
/// <param name="size">Size of the buffer in bytes</param>
|
||||
/// <param name="baseBuffers">Buffers which this buffer contains, and will inherit tracking handles from</param>
|
||||
public Buffer(GpuContext context, ulong address, ulong size, IEnumerable<Buffer> baseBuffers = null)
|
||||
public Buffer(GpuContext context, PhysicalMemory physicalMemory, ulong address, ulong size, IEnumerable<Buffer> baseBuffers = null)
|
||||
{
|
||||
_context = context;
|
||||
Address = address;
|
||||
Size = size;
|
||||
_context = context;
|
||||
_physicalMemory = physicalMemory;
|
||||
Address = address;
|
||||
Size = size;
|
||||
|
||||
Handle = context.Renderer.CreateBuffer((int)size);
|
||||
|
||||
|
@ -100,11 +103,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
if (_useGranular)
|
||||
{
|
||||
_memoryTrackingGranular = context.PhysicalMemory.BeginGranularTracking(address, size, baseHandles);
|
||||
_memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, baseHandles);
|
||||
}
|
||||
else
|
||||
{
|
||||
_memoryTracking = context.PhysicalMemory.BeginTracking(address, size);
|
||||
_memoryTracking = physicalMemory.BeginTracking(address, size);
|
||||
|
||||
if (baseHandles != null)
|
||||
{
|
||||
|
@ -207,9 +210,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.SetBufferData(Handle, 0, _context.PhysicalMemory.GetSpan(Address, (int)Size));
|
||||
_context.Renderer.SetBufferData(Handle, 0, _physicalMemory.GetSpan(Address, (int)Size));
|
||||
}
|
||||
|
||||
|
||||
_sequenceNumber = _context.SequenceNumber;
|
||||
}
|
||||
}
|
||||
|
@ -363,7 +366,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
int offset = (int)(mAddress - Address);
|
||||
|
||||
_context.Renderer.SetBufferData(Handle, offset, _context.PhysicalMemory.GetSpan(mAddress, (int)mSize));
|
||||
_context.Renderer.SetBufferData(Handle, offset, _physicalMemory.GetSpan(mAddress, (int)mSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -412,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
byte[] data = _context.Renderer.GetBufferData(Handle, offset, (int)size);
|
||||
|
||||
// TODO: When write tracking shaders, they will need to be aware of changes in overlapping buffers.
|
||||
_context.PhysicalMemory.WriteUntracked(address, data);
|
||||
_physicalMemory.WriteUntracked(address, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -18,7 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
private const ulong BufferAlignmentSize = 0x1000;
|
||||
private const ulong BufferAlignmentMask = BufferAlignmentSize - 1;
|
||||
|
||||
private GpuContext _context;
|
||||
private readonly GpuContext _context;
|
||||
private readonly PhysicalMemory _physicalMemory;
|
||||
|
||||
private readonly RangeList<Buffer> _buffers;
|
||||
|
||||
|
@ -32,9 +33,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// Creates a new instance of the buffer manager.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU context that the buffer manager belongs to</param>
|
||||
public BufferCache(GpuContext context)
|
||||
/// <param name="physicalMemory">Physical memory where the cached buffers are mapped</param>
|
||||
public BufferCache(GpuContext context, PhysicalMemory physicalMemory)
|
||||
{
|
||||
_context = context;
|
||||
_physicalMemory = physicalMemory;
|
||||
|
||||
_buffers = new RangeList<Buffer>();
|
||||
|
||||
|
@ -53,7 +56,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
Buffer[] overlaps = new Buffer[10];
|
||||
int overlapCount;
|
||||
|
||||
ulong address = _context.MemoryManager.Translate(e.Address);
|
||||
ulong address = ((MemoryManager)sender).Translate(e.Address);
|
||||
ulong size = e.Size;
|
||||
|
||||
lock (_buffers)
|
||||
|
@ -71,17 +74,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// Performs address translation of the GPU virtual address, and creates a
|
||||
/// new buffer, if needed, for the specified range.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
/// <returns>CPU virtual address of the buffer, after address translation</returns>
|
||||
public ulong TranslateAndCreateBuffer(ulong gpuVa, ulong size)
|
||||
public ulong TranslateAndCreateBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size)
|
||||
{
|
||||
if (gpuVa == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong address = _context.MemoryManager.Translate(gpuVa);
|
||||
ulong address = memoryManager.Translate(gpuVa);
|
||||
|
||||
if (address == MemoryManager.PteUnmapped)
|
||||
{
|
||||
|
@ -122,15 +126,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// The buffer lookup for this function is cached in a dictionary for quick access, which
|
||||
/// accelerates common UBO updates.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
public void ForceDirty(ulong gpuVa, ulong size)
|
||||
public void ForceDirty(MemoryManager memoryManager, ulong gpuVa, ulong size)
|
||||
{
|
||||
BufferCacheEntry result;
|
||||
|
||||
if (!_dirtyCache.TryGetValue(gpuVa, out result) || result.EndGpuAddress < gpuVa + size || result.UnmappedSequence != result.Buffer.UnmappedSequence)
|
||||
if (!_dirtyCache.TryGetValue(gpuVa, out BufferCacheEntry result) ||
|
||||
result.EndGpuAddress < gpuVa + size ||
|
||||
result.UnmappedSequence != result.Buffer.UnmappedSequence)
|
||||
{
|
||||
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa, size);
|
||||
result = new BufferCacheEntry(address, gpuVa, GetBuffer(address, size));
|
||||
|
||||
_dirtyCache[gpuVa] = result;
|
||||
|
@ -179,7 +184,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
}
|
||||
}
|
||||
|
||||
Buffer newBuffer = new Buffer(_context, address, endAddress - address, _bufferOverlaps.Take(overlapsCount));
|
||||
Buffer newBuffer = new Buffer(_context, _physicalMemory, address, endAddress - address, _bufferOverlaps.Take(overlapsCount));
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
|
@ -207,7 +212,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
else
|
||||
{
|
||||
// No overlap, just create a new buffer.
|
||||
Buffer buffer = new Buffer(_context, address, size);
|
||||
Buffer buffer = new Buffer(_context, _physicalMemory, address, size);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
|
@ -235,13 +240,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <remarks>
|
||||
/// This does a GPU side copy.
|
||||
/// </remarks>
|
||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||
/// <param name="srcVa">GPU virtual address of the copy source</param>
|
||||
/// <param name="dstVa">GPU virtual address of the copy destination</param>
|
||||
/// <param name="size">Size in bytes of the copy</param>
|
||||
public void CopyBuffer(GpuVa srcVa, GpuVa dstVa, ulong size)
|
||||
public void CopyBuffer(MemoryManager memoryManager, GpuVa srcVa, GpuVa dstVa, ulong size)
|
||||
{
|
||||
ulong srcAddress = TranslateAndCreateBuffer(srcVa.Pack(), size);
|
||||
ulong dstAddress = TranslateAndCreateBuffer(dstVa.Pack(), size);
|
||||
ulong srcAddress = TranslateAndCreateBuffer(memoryManager, srcVa.Pack(), size);
|
||||
ulong dstAddress = TranslateAndCreateBuffer(memoryManager, dstVa.Pack(), size);
|
||||
|
||||
Buffer srcBuffer = GetBuffer(srcAddress, size);
|
||||
Buffer dstBuffer = GetBuffer(dstAddress, size);
|
||||
|
@ -265,7 +271,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
// Optimization: If the data being copied is already in memory, then copy it directly instead of flushing from GPU.
|
||||
|
||||
dstBuffer.ClearModified(dstAddress, size);
|
||||
_context.PhysicalMemory.WriteUntracked(dstAddress, _context.PhysicalMemory.GetSpan(srcAddress, (int)size));
|
||||
memoryManager.Physical.WriteUntracked(dstAddress, memoryManager.Physical.GetSpan(srcAddress, (int)size));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,12 +281,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <remarks>
|
||||
/// Both the address and size must be aligned to 4 bytes.
|
||||
/// </remarks>
|
||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||
/// <param name="gpuVa">GPU virtual address of the region to clear</param>
|
||||
/// <param name="size">Number of bytes to clear</param>
|
||||
/// <param name="value">Value to be written into the buffer</param>
|
||||
public void ClearBuffer(GpuVa gpuVa, ulong size, uint value)
|
||||
public void ClearBuffer(MemoryManager memoryManager, GpuVa gpuVa, ulong size, uint value)
|
||||
{
|
||||
ulong address = TranslateAndCreateBuffer(gpuVa.Pack(), size);
|
||||
ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa.Pack(), size);
|
||||
|
||||
Buffer buffer = GetBuffer(address, size);
|
||||
|
||||
|
|
|
@ -12,11 +12,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <summary>
|
||||
/// Buffer manager.
|
||||
/// </summary>
|
||||
class BufferManager : IDisposable
|
||||
class BufferManager
|
||||
{
|
||||
private const int StackToHeapThreshold = 16;
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
|
||||
private IndexBuffer _indexBuffer;
|
||||
private readonly VertexBuffer[] _vertexBuffers;
|
||||
|
@ -106,9 +107,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// Creates a new instance of the buffer manager.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the buffer manager belongs to</param>
|
||||
public BufferManager(GpuContext context)
|
||||
/// <param name="channel">GPU channel that the buffer manager belongs to</param>
|
||||
public BufferManager(GpuContext context, GpuChannel channel)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
|
||||
_vertexBuffers = new VertexBuffer[Constants.TotalVertexBuffers];
|
||||
|
||||
|
@ -127,8 +130,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
}
|
||||
|
||||
_bufferTextures = new List<BufferTextureBinding>();
|
||||
|
||||
context.Methods.BufferCache.NotifyBuffersModified += Rebind;
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="type">Type of each index buffer element</param>
|
||||
public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type)
|
||||
{
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
_indexBuffer.Address = address;
|
||||
_indexBuffer.Size = size;
|
||||
|
@ -171,7 +172,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="divisor">Vertex divisor of the buffer, for instanced draws</param>
|
||||
public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor)
|
||||
{
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
_vertexBuffers[index].Address = address;
|
||||
_vertexBuffers[index].Size = size;
|
||||
|
@ -199,7 +200,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="size">Size in bytes of the transform feedback buffer</param>
|
||||
public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
|
||||
{
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
_transformFeedbackBuffers[index] = new BufferBounds(address, size);
|
||||
_transformFeedbackBuffersDirty = true;
|
||||
|
@ -219,7 +220,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
_cpStorageBuffers.SetBounds(index, address, size, flags);
|
||||
}
|
||||
|
@ -239,7 +240,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
|
||||
_gpStorageBuffers[stage].Buffers[index].Size != size)
|
||||
|
@ -259,7 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="size">Size in bytes of the storage buffer</param>
|
||||
public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)
|
||||
{
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
_cpUniformBuffers.SetBounds(index, address, size);
|
||||
}
|
||||
|
@ -274,7 +275,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="size">Size in bytes of the storage buffer</param>
|
||||
public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size)
|
||||
{
|
||||
ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
_gpUniformBuffers[stage].SetBounds(index, address, size);
|
||||
_gpUniformBuffersDirty = true;
|
||||
|
@ -422,7 +423,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
// The storage buffer size is not reliable (it might be lower than the actual size),
|
||||
// so we bind the entire buffer to allow otherwise out of range accesses to work.
|
||||
sRanges[bindingInfo.Binding] = _context.Methods.BufferCache.GetBufferRangeTillEnd(
|
||||
sRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(
|
||||
bounds.Address,
|
||||
bounds.Size,
|
||||
bounds.Flags.HasFlag(BufferUsageFlags.Write));
|
||||
|
@ -443,7 +444,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
if (bounds.Address != 0)
|
||||
{
|
||||
uRanges[bindingInfo.Binding] = _context.Methods.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
|
||||
uRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,7 +466,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
foreach (var binding in _bufferTextures)
|
||||
{
|
||||
var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
|
||||
var range = _context.Methods.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
|
||||
var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
|
||||
binding.Texture.SetStorage(range);
|
||||
|
||||
// The texture must be rebound to use the new storage if it was updated.
|
||||
|
@ -496,14 +497,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
if (_indexBuffer.Address != 0)
|
||||
{
|
||||
BufferRange buffer = _context.Methods.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
|
||||
_context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
|
||||
}
|
||||
}
|
||||
else if (_indexBuffer.Address != 0)
|
||||
{
|
||||
_context.Methods.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
_channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
}
|
||||
|
||||
uint vbEnableMask = _vertexBuffersEnableMask;
|
||||
|
@ -523,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
continue;
|
||||
}
|
||||
|
||||
BufferRange buffer = _context.Methods.BufferCache.GetBufferRange(vb.Address, vb.Size);
|
||||
BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(vb.Address, vb.Size);
|
||||
|
||||
vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
|
||||
}
|
||||
|
@ -541,7 +542,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
continue;
|
||||
}
|
||||
|
||||
_context.Methods.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
|
||||
_channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,7 +562,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
continue;
|
||||
}
|
||||
|
||||
tfbs[index] = _context.Methods.BufferCache.GetBufferRange(tfb.Address, tfb.Size);
|
||||
tfbs[index] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(tfb.Address, tfb.Size);
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
|
||||
|
@ -577,7 +578,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
continue;
|
||||
}
|
||||
|
||||
_context.Methods.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
|
||||
_channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -633,8 +634,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
|
||||
ranges[bindingInfo.Binding] = isStorage
|
||||
? _context.Methods.BufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
|
||||
: _context.Methods.BufferCache.GetBufferRange(bounds.Address, bounds.Size, isWrite);
|
||||
? _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
|
||||
: _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size, isWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -670,7 +671,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
continue;
|
||||
}
|
||||
|
||||
_context.Methods.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
|
||||
_channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -686,7 +687,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||
public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
|
||||
{
|
||||
_context.Methods.BufferCache.CreateBuffer(address, size);
|
||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
|
||||
|
||||
_bufferTextures.Add(new BufferTextureBinding(texture, address, size, bindingInfo, format, isImage));
|
||||
}
|
||||
|
@ -698,14 +699,5 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
_rebind = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the buffer manager.
|
||||
/// It is an error to use the buffer manager after disposal.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Methods.BufferCache.NotifyBuffersModified -= Rebind;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,15 +34,28 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
public event EventHandler<UnmapEventArgs> MemoryUnmapped;
|
||||
|
||||
private GpuContext _context;
|
||||
/// <summary>
|
||||
/// Physical memory where the virtual memory is mapped into.
|
||||
/// </summary>
|
||||
internal PhysicalMemory Physical { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache of GPU counters.
|
||||
/// </summary>
|
||||
internal CounterCache CounterCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the GPU memory manager.
|
||||
/// </summary>
|
||||
public MemoryManager(GpuContext context)
|
||||
/// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
|
||||
internal MemoryManager(PhysicalMemory physicalMemory)
|
||||
{
|
||||
_context = context;
|
||||
Physical = physicalMemory;
|
||||
CounterCache = new CounterCache();
|
||||
_pageTable = new ulong[PtLvl0Size][];
|
||||
MemoryUnmapped += Physical.TextureCache.MemoryUnmappedHandler;
|
||||
MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
|
||||
MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,7 +80,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
if (IsContiguous(va, size))
|
||||
{
|
||||
return _context.PhysicalMemory.GetSpan(Translate(va), size, tracked);
|
||||
return Physical.GetSpan(Translate(va), size, tracked);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -100,7 +113,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
||||
|
||||
_context.PhysicalMemory.GetSpan(pa, size, tracked).CopyTo(data.Slice(0, size));
|
||||
Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(0, size));
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
@ -111,7 +124,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
size = Math.Min(data.Length - offset, (int)PageSize);
|
||||
|
||||
_context.PhysicalMemory.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
|
||||
Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +138,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
if (IsContiguous(va, size))
|
||||
{
|
||||
return _context.PhysicalMemory.GetWritableRegion(Translate(va), size);
|
||||
return Physical.GetWritableRegion(Translate(va), size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -155,7 +168,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="data">The data to be written</param>
|
||||
public void Write(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
WriteImpl(va, data, _context.PhysicalMemory.Write);
|
||||
WriteImpl(va, data, Physical.Write);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -165,7 +178,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="data">The data to be written</param>
|
||||
public void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
WriteImpl(va, data, _context.PhysicalMemory.WriteUntracked);
|
||||
WriteImpl(va, data, Physical.WriteUntracked);
|
||||
}
|
||||
|
||||
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Tracking;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Memory.Range;
|
||||
using Ryujinx.Memory.Tracking;
|
||||
|
@ -7,6 +9,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
|
@ -18,20 +21,63 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
public const int PageSize = 0x1000;
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private IVirtualMemoryManagerTracked _cpuMemory;
|
||||
private int _referenceCount;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory shader cache.
|
||||
/// </summary>
|
||||
public ShaderCache ShaderCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// GPU buffer manager.
|
||||
/// </summary>
|
||||
public BufferCache BufferCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// GPU texture manager.
|
||||
/// </summary>
|
||||
public TextureCache TextureCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the physical memory.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the physical memory belongs to</param>
|
||||
/// <param name="cpuMemory">CPU memory manager of the application process</param>
|
||||
public PhysicalMemory(IVirtualMemoryManagerTracked cpuMemory)
|
||||
public PhysicalMemory(GpuContext context, IVirtualMemoryManagerTracked cpuMemory)
|
||||
{
|
||||
_context = context;
|
||||
_cpuMemory = cpuMemory;
|
||||
ShaderCache = new ShaderCache(context);
|
||||
BufferCache = new BufferCache(context, this);
|
||||
TextureCache = new TextureCache(context, this);
|
||||
|
||||
if (_cpuMemory is IRefCounted rc)
|
||||
if (cpuMemory is IRefCounted rc)
|
||||
{
|
||||
rc.IncrementReferenceCount();
|
||||
}
|
||||
|
||||
_referenceCount = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the memory reference count.
|
||||
/// </summary>
|
||||
public void IncrementReferenceCount()
|
||||
{
|
||||
Interlocked.Increment(ref _referenceCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrements the memory reference count.
|
||||
/// </summary>
|
||||
public void DecrementReferenceCount()
|
||||
{
|
||||
if (Interlocked.Decrement(ref _referenceCount) == 0 && _cpuMemory is IRefCounted rc)
|
||||
{
|
||||
rc.DecrementReferenceCount();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -147,7 +193,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="range">Ranges of physical memory where the data is located</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <param name="writeCallback">Callback method that will perform the write</param>
|
||||
private void WriteImpl(MultiRange range, ReadOnlySpan<byte> data, WriteCallback writeCallback)
|
||||
private static void WriteImpl(MultiRange range, ReadOnlySpan<byte> data, WriteCallback writeCallback)
|
||||
{
|
||||
if (range.Count == 1)
|
||||
{
|
||||
|
@ -227,12 +273,20 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_cpuMemory is IRefCounted rc)
|
||||
{
|
||||
rc.DecrementReferenceCount();
|
||||
_context.DeferredActions.Enqueue(Destroy);
|
||||
}
|
||||
|
||||
_cpuMemory = null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Performs disposal of the host GPU caches with resources mapped on this physical memory.
|
||||
/// This must only be called from the render thread.
|
||||
/// </summary>
|
||||
private void Destroy()
|
||||
{
|
||||
ShaderCache.Dispose();
|
||||
BufferCache.Dispose();
|
||||
TextureCache.Dispose();
|
||||
|
||||
DecrementReferenceCount();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue