diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/Buffer.cs | 25 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferCache.cs | 43 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 58 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs | 31 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs | 70 |
5 files changed, 148 insertions, 79 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs index b4854d81..96e10e77 100644 --- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs +++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs @@ -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> diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs index eb2d08ae..b78cbdaa 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs @@ -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); diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index e43cb3b3..eccc2ca3 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -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; - } } } diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 5776836c..b747b558 100644 --- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -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); diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index 6463b932..289e7c1b 100644 --- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -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(); } } }
\ No newline at end of file |
