From 640ea94cd80220fbaaa2af70692f59e6d1b4b4e5 Mon Sep 17 00:00:00 2001 From: gdk Date: Mon, 19 Dec 2022 12:25:44 -0300 Subject: [PATCH] Allow resources to be backed by different PhysicalMemory (still unused) --- .../Engine/Compute/ComputeClass.cs | 10 +- .../Engine/Dma/DmaClass.cs | 8 +- .../InlineToMemory/InlineToMemoryClass.cs | 2 +- .../Engine/MME/MacroHLE.cs | 13 ++- .../Threed/ComputeDraw/VtgAsComputeState.cs | 4 +- .../Engine/Threed/ConstantBufferUpdater.cs | 8 +- .../Engine/Threed/DrawManager.cs | 12 +- .../Engine/Threed/StateUpdater.cs | 18 ++- .../Engine/Threed/ThreedClass.cs | 19 ++- .../Engine/Twod/TwodClass.cs | 9 +- src/Ryujinx.Graphics.Gpu/GpuChannel.cs | 17 +-- src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs | 9 +- .../Image/SamplerPoolCache.cs | 12 +- .../Image/TextureBindingsManager.cs | 27 +++-- .../Image/TextureManager.cs | 3 +- src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 18 ++- .../Image/TexturePoolCache.cs | 12 +- .../Memory/BufferBounds.cs | 14 ++- .../Memory/BufferCache.cs | 20 ++-- .../Memory/BufferManager.cs | 108 ++++++++++-------- .../Memory/BufferTextureBinding.cs | 8 ++ .../Memory/IndexBuffer.cs | 1 + .../Memory/MemoryManager.cs | 38 +++++- .../Memory/VertexBuffer.cs | 1 + .../Shader/GpuAccessor.cs | 4 +- .../Shader/ShaderCache.cs | 10 +- .../Shader/ShaderSpecializationState.cs | 4 +- 27 files changed, 276 insertions(+), 133 deletions(-) diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs index 67743de37..4c88986b5 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs @@ -106,6 +106,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute shaderGpuVa += (uint)qmd.ProgramOffset; + var shaderCache = memoryManager.GetBackingMemory(shaderGpuVa).ShaderCache; + int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize; int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize); @@ -139,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute sharedMemorySize, _channel.BufferManager.HasUnalignedStorageBuffers); - CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); + CachedShaderProgram cs = shaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); _context.Renderer.Pipeline.SetProgram(cs.HostProgram); @@ -153,10 +155,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute { BufferDescriptor sb = info.SBuffers[index]; - ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(sb.SbCbSlot); + (var physical, ulong sbDescAddress) = _channel.BufferManager.GetComputeUniformBufferAddress(sb.SbCbSlot); sbDescAddress += (ulong)sb.SbCbOffset * 4; - SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read(sbDescAddress); + SbDescriptor sbDescriptor = physical.Read(sbDescAddress); uint size; if (sb.SbCbSlot == Constants.DriverReservedUniformBuffer) @@ -184,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute sharedMemorySize, _channel.BufferManager.HasUnalignedStorageBuffers); - cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); + cs = shaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); _context.Renderer.Pipeline.SetProgram(cs.HostProgram); } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs index e6557780b..b302b443e 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs @@ -281,7 +281,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma if (completeSource && completeDest) { - var target = memoryManager.Physical.TextureCache.FindTexture( + var target = memoryManager.GetBackingMemory(dstGpuVa).TextureCache.FindTexture( memoryManager, dstGpuVa, dstBpp, @@ -412,6 +412,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma } else { + var bufferCache = memoryManager.GetBackingMemory(dstGpuVa).BufferCache; + if (remap && _state.State.SetRemapComponentsDstX == SetRemapComponentsDst.ConstA && _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.ConstA && @@ -422,7 +424,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma _state.State.SetRemapComponentsComponentSize == SetRemapComponentsComponentSize.Four) { // Fast path for clears when remap is enabled. - memoryManager.Physical.BufferCache.ClearBuffer(memoryManager, dstGpuVa, size * 4, _state.State.SetRemapConstA); + bufferCache.ClearBuffer(memoryManager, dstGpuVa, size * 4, _state.State.SetRemapConstA); } else { @@ -442,7 +444,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma } else { - memoryManager.Physical.BufferCache.CopyBuffer(memoryManager, srcGpuVa, dstGpuVa, size); + BufferCache.CopyBuffer(_context, memoryManager, srcGpuVa, dstGpuVa, size); } } } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs index e417b9a0a..1c189e149 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs @@ -183,7 +183,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory // Right now the copy code at the bottom assumes that it is used on both which might be incorrect. if (!_isLinear) { - var target = memoryManager.Physical.TextureCache.FindTexture( + var target = memoryManager.GetBackingMemory(_dstGpuVa).TextureCache.FindTexture( memoryManager, _dstGpuVa, 1, diff --git a/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs b/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs index 7d9e1ec02..24548abd1 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs @@ -382,7 +382,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME ulong indirectBufferGpuVa = count.GpuVa; - var bufferCache = _processor.MemoryManager.Physical.BufferCache; + var bufferCache = _processor.MemoryManager.GetBackingMemory(indirectBufferGpuVa).BufferCache; bool useBuffer = bufferCache.CheckModified(_processor.MemoryManager, indirectBufferGpuVa, IndirectIndexedDataEntrySize, out ulong indirectBufferAddress); @@ -392,6 +392,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME _processor.ThreedClass.DrawIndirect( topology, + bufferCache, + null, indirectBufferAddress, 0, 1, @@ -490,15 +492,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME } } - var bufferCache = _processor.MemoryManager.Physical.BufferCache; + var indirectBufferCache = _processor.MemoryManager.GetBackingMemory(indirectBufferGpuVa).BufferCache; + var parameterBufferCache = _processor.MemoryManager.GetBackingMemory(parameterBufferGpuVa).BufferCache; ulong indirectBufferSize = (ulong)maxDrawCount * (ulong)stride; - ulong indirectBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize); - ulong parameterBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, parameterBufferGpuVa, 4); + ulong indirectBufferAddress = indirectBufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize); + ulong parameterBufferAddress = parameterBufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, parameterBufferGpuVa, 4); _processor.ThreedClass.DrawIndirect( topology, + indirectBufferCache, + parameterBufferCache, indirectBufferAddress, parameterBufferAddress, maxDrawCount, diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs index d1a333a71..13c8b5605 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs @@ -371,7 +371,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw var memoryManager = _channel.MemoryManager; address = memoryManager.Translate(address); - BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(address, size); + BufferRange range = memoryManager.GetBackingMemory(address).BufferCache.GetBufferRange(address, size); ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format); bufferTexture.SetStorage(range); @@ -414,7 +414,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw address = memoryManager.Translate(address + indexOffset); ulong misalign = address & ((ulong)_context.Capabilities.TextureBufferOffsetAlignment - 1); - BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(address - misalign, size + misalign); + BufferRange range = memoryManager.GetBackingMemory(address).BufferCache.GetBufferRange(address - misalign, size + misalign); misalignedOffset = (int)misalign >> shift; SetIndexBufferTexture(reservations, range, format); diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs index e30092cee..ff83881fc 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs @@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed // State associated with direct uniform buffer updates. // This state is used to attempt to batch together consecutive updates. + private ulong _ubBeginGpuAddress = 0; private ulong _ubBeginCpuAddress = 0; private ulong _ubFollowUpAddress = 0; private ulong _ubByteCount = 0; @@ -112,12 +113,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed if (_ubFollowUpAddress != 0) { var memoryManager = _channel.MemoryManager; + var physicalMemory = memoryManager.GetBackingMemory(_ubBeginGpuAddress); Span data = MemoryMarshal.Cast(_ubData.AsSpan(0, (int)(_ubByteCount / 4))); - if (memoryManager.Physical.WriteWithRedundancyCheck(_ubBeginCpuAddress, data)) + if (physicalMemory.WriteWithRedundancyCheck(_ubBeginCpuAddress, data)) { - memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount); + physicalMemory.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount); } _ubFollowUpAddress = 0; @@ -140,6 +142,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed FlushUboDirty(); _ubByteCount = 0; + _ubBeginGpuAddress = address; _ubBeginCpuAddress = _channel.MemoryManager.Translate(address); } @@ -168,6 +171,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed FlushUboDirty(); _ubByteCount = 0; + _ubBeginGpuAddress = address; _ubBeginCpuAddress = _channel.MemoryManager.Translate(address); } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index 1c31312ce..ba4dfb7d4 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -630,6 +630,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// /// 3D engine where this method is being called /// Primitive topology + /// Buffer cache owning the buffer with the draw parameters + /// Buffer cache owning the buffer with the draw count /// Address of the buffer with the draw parameters, such as count, first index, etc /// Address of the buffer with the draw count /// Maximum number of draws that can be made @@ -639,6 +641,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed public void DrawIndirect( ThreedClass engine, PrimitiveTopology topology, + BufferCache indirectBufferCache, + BufferCache parameterBufferCache, ulong indirectBufferAddress, ulong parameterBufferAddress, int maxDrawCount, @@ -660,8 +664,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed return; } - PhysicalMemory memory = _channel.MemoryManager.Physical; - bool hasCount = (drawType & IndirectDrawType.Count) != 0; bool indexed = (drawType & IndirectDrawType.Indexed) != 0; @@ -681,8 +683,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed if (hasCount) { - var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride); - var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferAddress, 4); + var indirectBuffer = indirectBufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride); + var parameterBuffer = parameterBufferCache.GetBufferRange(parameterBufferAddress, 4); if (indexed) { @@ -695,7 +697,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } else { - var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride); + var indirectBuffer = indirectBufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride); if (indexed) { diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 1ff821569..cbb183a9c 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -361,10 +361,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed { BufferDescriptor sb = info.SBuffers[index]; - ulong sbDescAddress = _channel.BufferManager.GetGraphicsUniformBufferAddress(stage, sb.SbCbSlot); + (var physical, ulong sbDescAddress) = _channel.BufferManager.GetGraphicsUniformBufferAddress(stage, sb.SbCbSlot); sbDescAddress += (ulong)sb.SbCbOffset * 4; - SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read(sbDescAddress); + SbDescriptor sbDescriptor = physical.Read(sbDescAddress); uint size; if (sb.SbCbSlot == Constants.DriverReservedUniformBuffer) @@ -485,7 +485,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed rtNoAlphaMask |= 1u << index; } - Image.Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture( + var colorTextureCache = memoryManager.GetBackingMemory(colorState.Address.Pack()).TextureCache; + + Image.Texture color = colorTextureCache.FindOrCreateTexture( memoryManager, colorState, _vtgWritesRtLayer || layered, @@ -524,7 +526,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed var dsState = _state.State.RtDepthStencilState; var dsSize = _state.State.RtDepthStencilSize; - depthStencil = memoryManager.Physical.TextureCache.FindOrCreateTexture( + var dsTextureCache = memoryManager.GetBackingMemory(dsState.Address.Pack()).TextureCache; + + depthStencil = dsTextureCache.FindOrCreateTexture( memoryManager, dsState, dsSize, @@ -1381,8 +1385,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// private void UpdateShaderState() { - var shaderCache = _channel.MemoryManager.Physical.ShaderCache; - _vtgWritesRtLayer = false; ShaderAddresses addresses = new(); @@ -1401,6 +1403,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed addressesSpan[index] = baseAddress + shader.Offset; } + // Shader stages on different address spaces are not supported right now, + // but it should never happen in practice anyway. + var shaderCache = _channel.MemoryManager.GetBackingMemory(addresses.VertexB).ShaderCache; + CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses); // Consume the modified flag for spec state so that it isn't checked again. diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs index df9d1f5c9..8857a8bc6 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs @@ -6,6 +6,7 @@ using Ryujinx.Graphics.Gpu.Engine.InlineToMemory; using Ryujinx.Graphics.Gpu.Engine.Threed.Blender; using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Synchronization; +using Ryujinx.Graphics.Gpu.Memory; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -234,7 +235,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } /// - /// Test if two 32 byte structs are equal. + /// Test if two 32 byte structs are equal. /// /// Type of the 32-byte struct /// First struct @@ -803,6 +804,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Performs a indirect draw, with parameters from a GPU buffer. /// /// Primitive topology + /// Buffer cache owning the buffer with the draw parameters + /// Buffer cache owning the buffer with the draw count /// Address of the buffer with the draw parameters, such as count, first index, etc /// Address of the buffer with the draw count /// Maximum number of draws that can be made @@ -811,6 +814,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count public void DrawIndirect( PrimitiveTopology topology, + BufferCache indirectBufferCache, + BufferCache parameterBufferCache, ulong indirectBufferAddress, ulong parameterBufferAddress, int maxDrawCount, @@ -818,7 +823,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed int indexCount, IndirectDrawType drawType) { - _drawManager.DrawIndirect(this, topology, indirectBufferAddress, parameterBufferAddress, maxDrawCount, stride, indexCount, drawType); + _drawManager.DrawIndirect( + this, + topology, + indirectBufferCache, + parameterBufferCache, + indirectBufferAddress, + parameterBufferAddress, + maxDrawCount, + stride, + indexCount, + drawType); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs index b33fb7f73..3835e2b6e 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs @@ -233,6 +233,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod var dstCopyTexture = Unsafe.As(ref _state.State.SetDstFormat); var srcCopyTexture = Unsafe.As(ref _state.State.SetSrcFormat); + var srcTextureCache = memoryManager.GetBackingMemory(srcCopyTexture.Address.Pack()).TextureCache; + var dstTextureCache = memoryManager.GetBackingMemory(dstCopyTexture.Address.Pack()).TextureCache; + long srcX = ((long)_state.State.SetPixelsFromMemorySrcX0Int << 32) | (long)(ulong)_state.State.SetPixelsFromMemorySrcX0Frac; long srcY = ((long)_state.State.PixelsFromMemorySrcY0Int << 32) | (long)(ulong)_state.State.SetPixelsFromMemorySrcY0Frac; @@ -304,7 +307,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod // are the same, as we can't blit between different depth formats. bool srcDepthAlias = srcCopyTexture.Format == dstCopyTexture.Format; - var srcTexture = memoryManager.Physical.TextureCache.FindOrCreateTexture( + var srcTexture = srcTextureCache.FindOrCreateTexture( memoryManager, srcCopyTexture, offset, @@ -325,7 +328,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod return; } - memoryManager.Physical.TextureCache.Lift(srcTexture); + srcTextureCache.Lift(srcTexture); // When the source texture that was found has a depth format, // we must enforce the target texture also has a depth format, @@ -341,7 +344,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod dstCopyTextureFormat = dstCopyTexture.Format.Convert(); } - var dstTexture = memoryManager.Physical.TextureCache.FindOrCreateTexture( + var dstTexture = dstTextureCache.FindOrCreateTexture( memoryManager, dstCopyTexture, 0, diff --git a/src/Ryujinx.Graphics.Gpu/GpuChannel.cs b/src/Ryujinx.Graphics.Gpu/GpuChannel.cs index d70c9645e..063a32913 100644 --- a/src/Ryujinx.Graphics.Gpu/GpuChannel.cs +++ b/src/Ryujinx.Graphics.Gpu/GpuChannel.cs @@ -58,22 +58,24 @@ namespace Ryujinx.Graphics.Gpu public void BindMemory(MemoryManager memoryManager) { var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, memoryManager ?? throw new ArgumentNullException(nameof(memoryManager))); + if (oldMemoryManager == memoryManager) + { + return; + } - memoryManager.Physical.IncrementReferenceCount(); + memoryManager.AttachToChannel(BufferManager.Rebind); if (oldMemoryManager != null) { - oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind; - oldMemoryManager.Physical.DecrementReferenceCount(); + oldMemoryManager.DetachFromChannel(BufferManager.Rebind); oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler; } - memoryManager.Physical.BufferCache.NotifyBuffersModified += BufferManager.Rebind; memoryManager.MemoryUnmapped += MemoryUnmappedHandler; // Since the memory manager changed, make sure we will get pools from addresses of the new memory manager. TextureManager.ReloadPools(); - memoryManager.Physical.BufferCache.QueuePrune(); + memoryManager.QueuePrune(); } /// @@ -86,7 +88,7 @@ namespace Ryujinx.Graphics.Gpu TextureManager.ReloadPools(); var memoryManager = Volatile.Read(ref _memoryManager); - memoryManager?.Physical.BufferCache.QueuePrune(); + memoryManager?.QueuePrune(); } /// @@ -141,8 +143,7 @@ namespace Ryujinx.Graphics.Gpu var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, null); if (oldMemoryManager != null) { - oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind; - oldMemoryManager.Physical.DecrementReferenceCount(); + oldMemoryManager.DetachFromChannel(BufferManager.Rebind); oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler; } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs b/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs index d9881f897..836ae1b2e 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs @@ -1,3 +1,4 @@ +using Ryujinx.Graphics.Gpu.Memory; using System; using System.Collections.Generic; @@ -60,10 +61,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// Finds a cache texture pool, or creates a new one if not found. /// /// GPU channel that the texture pool cache belongs to + /// Backing memory of the pool /// Start address of the texture pool /// Maximum ID of the texture pool /// The found or newly created texture pool - public T FindOrCreate(GpuChannel channel, ulong address, int maximumId) + public T FindOrCreate(GpuChannel channel, PhysicalMemory physicalMemory, ulong address, int maximumId) { // Remove old entries from the cache, if possible. while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval) @@ -98,7 +100,7 @@ namespace Ryujinx.Graphics.Gpu.Image } // If not found, create a new one. - pool = CreatePool(_context, channel, address, maximumId); + pool = CreatePool(_context, channel, physicalMemory, address, maximumId); pool.CacheNode = _pools.AddLast(pool); pool.CacheTimestamp = _currentTimestamp; @@ -111,9 +113,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// GPU context that the pool belongs to /// GPU channel that the pool belongs to + /// Backing memory of the pool /// Address of the pool in guest memory /// Maximum ID of the pool (equal to maximum minus one) - protected abstract T CreatePool(GpuContext context, GpuChannel channel, ulong address, int maximumId); + protected abstract T CreatePool(GpuContext context, GpuChannel channel, PhysicalMemory physicalMemory, ulong address, int maximumId); public void Dispose() { diff --git a/src/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs b/src/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs index 881c37af4..41c54ac3a 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs @@ -1,3 +1,5 @@ +using Ryujinx.Graphics.Gpu.Memory; + namespace Ryujinx.Graphics.Gpu.Image { /// @@ -20,11 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// GPU context that the sampler pool belongs to /// GPU channel that the texture pool belongs to + /// Backing memory of the pool /// Address of the sampler pool in guest memory /// Maximum sampler ID of the sampler pool (equal to maximum samplers minus one) - protected override SamplerPool CreatePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) + protected override SamplerPool CreatePool( + GpuContext context, + GpuChannel channel, + PhysicalMemory physicalMemory, + ulong address, + int maximumId) { - return new SamplerPool(context, channel.MemoryManager.Physical, address, maximumId); + return new SamplerPool(context, physicalMemory, address, maximumId); } } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 8eca18b48..eab971fbc 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -382,7 +382,7 @@ namespace Ryujinx.Graphics.Gpu.Image { ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex); - cachedTextureBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); + cachedTextureBuffer = MemoryMarshal.Cast(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedTextureBufferIndex = textureBufferIndex; if (samplerBufferIndex == textureBufferIndex) @@ -396,7 +396,7 @@ namespace Ryujinx.Graphics.Gpu.Image { ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex); - cachedSamplerBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); + cachedSamplerBuffer = MemoryMarshal.Cast(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedSamplerBufferIndex = samplerBufferIndex; } } @@ -524,7 +524,8 @@ namespace Ryujinx.Graphics.Gpu.Image // Ensure that the buffer texture is using the correct buffer as storage. // Buffers are frequently re-created to accommodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. - _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false); + var bufferCache = _channel.MemoryManager.GetBackingMemory(descriptor.UnpackAddress()).BufferCache; + _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, bufferCache, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false); // Cache is not used for buffer texture, it must always rebind. state.CachedTexture = null; @@ -661,7 +662,8 @@ namespace Ryujinx.Graphics.Gpu.Image format = texture.Format; } - _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true); + var bufferCache = _channel.MemoryManager.GetBackingMemory(descriptor.UnpackAddress()).BufferCache; + _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, bufferCache, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true); // Cache is not used for buffer texture, it must always rebind. state.CachedTexture = null; @@ -726,9 +728,10 @@ namespace Ryujinx.Graphics.Gpu.Image int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, samplerBufferIndex); int textureId = TextureHandle.UnpackTextureId(packedId); + var physical = _channel.MemoryManager.GetBackingMemory(poolGpuVa); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); - TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); + TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, physical, poolAddress, maximumId); TextureDescriptor descriptor; @@ -762,12 +765,12 @@ namespace Ryujinx.Graphics.Gpu.Image { (int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = TextureHandle.UnpackOffsets(wordOffset); - ulong textureBufferAddress = _isCompute + (var texturePhysicalMemory, ulong textureBufferAddress) = _isCompute ? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex) : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex); int handle = textureBufferAddress != 0 - ? _channel.MemoryManager.Physical.Read(textureBufferAddress + (uint)textureWordOffset * 4) + ? texturePhysicalMemory.Read(textureBufferAddress + (uint)textureWordOffset * 4) : 0; // The "wordOffset" (which is really the immediate value used on texture instructions on the shader) @@ -782,12 +785,12 @@ namespace Ryujinx.Graphics.Gpu.Image if (handleType != TextureHandleType.SeparateConstantSamplerHandle) { - ulong samplerBufferAddress = _isCompute + (var samplerPhysicalMemory, ulong samplerBufferAddress) = _isCompute ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex) : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex); samplerHandle = samplerBufferAddress != 0 - ? _channel.MemoryManager.Physical.Read(samplerBufferAddress + (uint)samplerWordOffset * 4) + ? samplerPhysicalMemory.Read(samplerBufferAddress + (uint)samplerWordOffset * 4) : 0; } else @@ -824,7 +827,8 @@ namespace Ryujinx.Graphics.Gpu.Image if (poolAddress != MemoryManager.PteUnmapped) { - texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId); + var physical = _channel.MemoryManager.GetBackingMemory(_texturePoolGpuVa); + texturePool = _texturePoolCache.FindOrCreate(_channel, physical, poolAddress, _texturePoolMaximumId); _texturePool = texturePool; } } @@ -835,7 +839,8 @@ namespace Ryujinx.Graphics.Gpu.Image if (poolAddress != MemoryManager.PteUnmapped) { - samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId); + var physical = _channel.MemoryManager.GetBackingMemory(_samplerPoolGpuVa); + samplerPool = _samplerPoolCache.FindOrCreate(_channel, physical, poolAddress, _samplerPoolMaximumId); _samplerPool = samplerPool; } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index ed181640a..5aa22c86c 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -364,9 +364,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// The texture pool public TexturePool GetTexturePool(ulong poolGpuVa, int maximumId) { + var physical = _channel.MemoryManager.GetBackingMemory(poolGpuVa); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); - TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); + TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, physical, poolAddress, maximumId); return texturePool; } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index 0fdb6cd64..99e2ebb7c 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -89,9 +89,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// GPU context that the texture pool belongs to /// GPU channel that the texture pool belongs to + /// Backing memory of the pool /// Address of the texture pool in guest memory /// Maximum texture ID of the texture pool (equal to maximum textures minus one) - public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId) + public TexturePool(GpuContext context, GpuChannel channel, PhysicalMemory physicalMemory, ulong address, int maximumId) : base(context, physicalMemory, address, maximumId) { _channel = channel; } @@ -122,7 +123,9 @@ namespace Ryujinx.Graphics.Gpu.Image return ref descriptor; } - texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize); + MemoryManager memoryManager = _channel.MemoryManager; + TextureCache textureCache = memoryManager.GetBackingMemory(descriptor.UnpackAddress()).TextureCache; + texture = textureCache.FindOrCreateTexture(memoryManager, TextureSearchFlags.ForSampler, info, layerSize); // If this happens, then the texture address is invalid, we can't add it to the cache. if (texture == null) @@ -280,7 +283,9 @@ namespace Ryujinx.Graphics.Gpu.Image continue; } - MultiRange range = _channel.MemoryManager.Physical.TextureCache.UpdatePartiallyMapped(_channel.MemoryManager, address, texture); + TextureCache textureCache = _channel.MemoryManager.GetBackingMemory(address).TextureCache; + + MultiRange range = textureCache.UpdatePartiallyMapped(_channel.MemoryManager, address, texture); // If the texture is not mapped at all, delete its reference. @@ -305,7 +310,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (!range.Equals(texture.Range)) { // Part of the texture was mapped or unmapped. Replace the range and regenerate tracking handles. - if (!_channel.MemoryManager.Physical.TextureCache.UpdateMapping(texture, range)) + if (!textureCache.UpdateMapping(texture, range)) { // Texture could not be remapped due to a collision, just delete it. if (Interlocked.Exchange(ref Items[request.ID], null) != null) @@ -338,6 +343,8 @@ namespace Ryujinx.Graphics.Gpu.Image /// Size of the range being invalidated protected override void InvalidateRangeImpl(ulong address, ulong size) { + MemoryManager memoryManager = _channel.MemoryManager; + ProcessDereferenceQueue(); ulong endAddress = address + size; @@ -362,7 +369,8 @@ namespace Ryujinx.Graphics.Gpu.Image if (texture.HasOneReference()) { - _channel.MemoryManager.Physical.TextureCache.AddShortCache(texture, ref cachedDescriptor); + TextureCache textureCache = memoryManager.GetBackingMemory(descriptor.UnpackAddress()).TextureCache; + textureCache.AddShortCache(texture, ref cachedDescriptor); } if (Interlocked.Exchange(ref Items[id], null) != null) diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs index 5da2c439c..e1a9c64d8 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs @@ -1,3 +1,5 @@ +using Ryujinx.Graphics.Gpu.Memory; + namespace Ryujinx.Graphics.Gpu.Image { /// @@ -20,11 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// GPU context that the texture pool belongs to /// GPU channel that the texture pool belongs to + /// Backing memory of the pool /// Address of the texture pool in guest memory /// Maximum texture ID of the texture pool (equal to maximum textures minus one) - protected override TexturePool CreatePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) + protected override TexturePool CreatePool( + GpuContext context, + GpuChannel channel, + PhysicalMemory physicalMemory, + ulong address, + int maximumId) { - return new TexturePool(context, channel, address, maximumId); + return new TexturePool(context, channel, physicalMemory, address, maximumId); } } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs index a9ea04cef..cc4cfaf3c 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs @@ -7,6 +7,16 @@ namespace Ryujinx.Graphics.Gpu.Memory /// readonly struct BufferBounds { + /// + /// Physical memory backing the buffer. + /// + public PhysicalMemory Physical { get; } + + /// + /// Buffer cache that owns the buffer. + /// + public BufferCache BufferCache => Physical.BufferCache; + /// /// Region virtual address. /// @@ -25,11 +35,13 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Creates a new buffer region. /// + /// Physical memory backing the buffer /// Region address /// Region size /// Buffer usage flags - public BufferBounds(ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None) + public BufferBounds(PhysicalMemory physical, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None) { + Physical = physical; Address = address; Size = size; Flags = flags; diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs index 05cc312c7..1ac4e2d39 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs @@ -313,22 +313,26 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// This does a GPU side copy. /// + /// GPU context /// GPU memory manager where the buffer is mapped /// GPU virtual address of the copy source /// GPU virtual address of the copy destination /// Size in bytes of the copy - public void CopyBuffer(MemoryManager memoryManager, ulong srcVa, ulong dstVa, ulong size) + public static void CopyBuffer(GpuContext context, MemoryManager memoryManager, ulong srcVa, ulong dstVa, ulong size) { - ulong srcAddress = TranslateAndCreateBuffer(memoryManager, srcVa, size); - ulong dstAddress = TranslateAndCreateBuffer(memoryManager, dstVa, size); + PhysicalMemory srcPhysical = memoryManager.GetBackingMemory(srcVa); + PhysicalMemory dstPhysical = memoryManager.GetBackingMemory(dstVa); - Buffer srcBuffer = GetBuffer(srcAddress, size); - Buffer dstBuffer = GetBuffer(dstAddress, size); + ulong srcAddress = srcPhysical.BufferCache.TranslateAndCreateBuffer(memoryManager, srcVa, size); + ulong dstAddress = dstPhysical.BufferCache.TranslateAndCreateBuffer(memoryManager, dstVa, size); + + Buffer srcBuffer = srcPhysical.BufferCache.GetBuffer(srcAddress, size); + Buffer dstBuffer = dstPhysical.BufferCache.GetBuffer(dstAddress, size); int srcOffset = (int)(srcAddress - srcBuffer.Address); int dstOffset = (int)(dstAddress - dstBuffer.Address); - _context.Renderer.Pipeline.CopyBuffer( + context.Renderer.Pipeline.CopyBuffer( srcBuffer.Handle, dstBuffer.Handle, srcOffset, @@ -344,7 +348,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); - memoryManager.Physical.WriteTrackedResource(dstAddress, memoryManager.Physical.GetSpan(srcAddress, (int)size), ResourceKind.Buffer); + dstPhysical.WriteTrackedResource(dstAddress, srcPhysical.GetSpan(srcAddress, (int)size), ResourceKind.Buffer); } } @@ -368,7 +372,7 @@ namespace Ryujinx.Graphics.Gpu.Memory _context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)size, value); - memoryManager.Physical.FillTrackedResource(address, size, value, ResourceKind.Buffer); + memoryManager.GetBackingMemory(gpuVa).FillTrackedResource(address, size, value, ResourceKind.Buffer); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index 8e9b4b858..307b814dc 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -68,12 +68,13 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Sets the region of a buffer at a given slot. /// /// Buffer slot + /// Physical memory backing the buffer /// Region virtual address /// Region size in bytes /// Buffer usage flags - public void SetBounds(int index, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None) + public void SetBounds(int index, PhysicalMemory physical, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None) { - Buffers[index] = new BufferBounds(address, size, flags); + Buffers[index] = new BufferBounds(physical, address, size, flags); } /// @@ -150,8 +151,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Type of each index buffer element public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type) { - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var bufferCache = _channel.MemoryManager.GetBackingMemory(gpuVa).BufferCache; + ulong address = bufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + _indexBuffer.BufferCache = bufferCache; _indexBuffer.Address = address; _indexBuffer.Size = size; _indexBuffer.Type = type; @@ -181,12 +184,16 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Vertex divisor of the buffer, for instanced draws public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor) { - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var bufferCache = _channel.MemoryManager.GetBackingMemory(gpuVa).BufferCache; + ulong address = bufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); - _vertexBuffers[index].Address = address; - _vertexBuffers[index].Size = size; - _vertexBuffers[index].Stride = stride; - _vertexBuffers[index].Divisor = divisor; + ref VertexBuffer vb = ref _vertexBuffers[index]; + + vb.BufferCache = bufferCache; + vb.Address = address; + vb.Size = size; + vb.Stride = stride; + vb.Divisor = divisor; _vertexBuffersDirty = true; @@ -209,9 +216,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the transform feedback buffer public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size) { - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var physical = _channel.MemoryManager.GetBackingMemory(gpuVa); + ulong address = physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); - _transformFeedbackBuffers[index] = new BufferBounds(address, size); + _transformFeedbackBuffers[index] = new BufferBounds(physical, address, size); _transformFeedbackBuffersDirty = true; } @@ -256,9 +264,10 @@ namespace Ryujinx.Graphics.Gpu.Memory gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment); - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var physical = _channel.MemoryManager.GetBackingMemory(gpuVa); + ulong address = physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); - _cpStorageBuffers.SetBounds(index, address, size, flags); + _cpStorageBuffers.SetBounds(index, physical, address, size, flags); } /// @@ -280,7 +289,8 @@ namespace Ryujinx.Graphics.Gpu.Memory gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment); - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var physical = _channel.MemoryManager.GetBackingMemory(gpuVa); + ulong address = physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); if (buffers.Buffers[index].Address != address || buffers.Buffers[index].Size != size) @@ -288,7 +298,7 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpStorageBuffersDirty = true; } - buffers.SetBounds(index, address, size, flags); + buffers.SetBounds(index, physical, address, size, flags); } /// @@ -300,9 +310,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the storage buffer public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size) { - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var physical = _channel.MemoryManager.GetBackingMemory(gpuVa); + ulong address = physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); - _cpUniformBuffers.SetBounds(index, address, size); + _cpUniformBuffers.SetBounds(index, physical, address, size); } /// @@ -315,9 +326,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Size in bytes of the storage buffer public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size) { - ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); + var physical = _channel.MemoryManager.GetBackingMemory(gpuVa); + ulong address = physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size); - _gpUniformBuffers[stage].SetBounds(index, address, size); + _gpUniformBuffers[stage].SetBounds(index, physical, address, size); _gpUniformBuffersDirty = true; } @@ -413,9 +425,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Index of the uniform buffer binding /// The uniform buffer address, or an undefined value if the buffer is not currently bound - public ulong GetComputeUniformBufferAddress(int index) + public (PhysicalMemory, ulong) GetComputeUniformBufferAddress(int index) { - return _cpUniformBuffers.Buffers[index].Address; + var buffer = _cpUniformBuffers.Buffers[index]; + return (buffer.Physical, buffer.Address); } /// @@ -424,9 +437,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Index of the shader stage /// Index of the uniform buffer binding /// The uniform buffer address, or an undefined value if the buffer is not currently bound - public ulong GetGraphicsUniformBufferAddress(int stage, int index) + public (PhysicalMemory, ulong) GetGraphicsUniformBufferAddress(int stage, int index) { - return _gpUniformBuffers[stage].Buffers[index].Address; + var buffer = _gpUniformBuffers[stage].Buffers[index]; + return (buffer.Physical, buffer.Address); } /// @@ -454,10 +468,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public void CommitComputeBindings() { - var bufferCache = _channel.MemoryManager.Physical.BufferCache; - - BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true); - BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false); + BindBuffers(_cpStorageBuffers, isStorage: true); + BindBuffers(_cpUniformBuffers, isStorage: false); CommitBufferTextureBindings(); @@ -477,7 +489,7 @@ namespace Ryujinx.Graphics.Gpu.Memory foreach (var binding in _bufferTextures) { var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); - var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore); + var range = binding.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. @@ -503,8 +515,6 @@ namespace Ryujinx.Graphics.Gpu.Memory /// True if the index buffer is in use public void CommitGraphicsBindings(bool indexed) { - var bufferCache = _channel.MemoryManager.Physical.BufferCache; - if (indexed) { if (_indexBufferDirty || _rebind) @@ -513,14 +523,14 @@ namespace Ryujinx.Graphics.Gpu.Memory if (_indexBuffer.Address != 0) { - BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size); + BufferRange buffer = _indexBuffer.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size); _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type); } } else if (_indexBuffer.Address != 0) { - bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size); + _indexBuffer.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size); } } else if (_rebind) @@ -545,7 +555,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size); + BufferRange buffer = vb.BufferCache.GetBufferRange(vb.Address, vb.Size); vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor); } @@ -563,7 +573,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - bufferCache.SynchronizeBufferRange(vb.Address, vb.Size); + vb.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size); } } @@ -585,7 +595,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true); + tfbs[index] = tfb.BufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true); } _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs); @@ -614,7 +624,7 @@ namespace Ryujinx.Graphics.Gpu.Memory _context.SupportBufferUpdater.SetTfeOffset(index, tfeOffset); - buffers[index] = new BufferAssignment(index, bufferCache.GetBufferRange(address, size, write: true)); + buffers[index] = new BufferAssignment(index, tfb.BufferCache.GetBufferRange(address, size, write: true)); } } @@ -632,7 +642,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size); + tfb.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size); } } @@ -640,7 +650,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { _gpStorageBuffersDirty = false; - BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true); + BindBuffers(_gpStorageBuffers, isStorage: true); } else { @@ -651,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { _gpUniformBuffersDirty = false; - BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false); + BindBuffers(_gpUniformBuffers, isStorage: false); } else { @@ -668,11 +678,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Bind respective buffer bindings on the host API. /// - /// Buffer cache holding the buffers for the specified ranges /// Buffer memory ranges to bind /// True to bind as storage buffer, false to bind as uniform buffer [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage) + private void BindBuffers(BuffersPerStage[] bindings, bool isStorage) { int rangesCount = 0; @@ -692,8 +701,8 @@ namespace Ryujinx.Graphics.Gpu.Memory { var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); var range = isStorage - ? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite) - : bufferCache.GetBufferRange(bounds.Address, bounds.Size); + ? bounds.BufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite) + : bounds.BufferCache.GetBufferRange(bounds.Address, bounds.Size); ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range); } @@ -709,11 +718,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Bind respective buffer bindings on the host API. /// - /// Buffer cache holding the buffers for the specified ranges /// Buffer memory ranges to bind /// True to bind as storage buffer, false to bind as uniform buffer [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage) + private void BindBuffers(BuffersPerStage buffers, bool isStorage) { int rangesCount = 0; @@ -729,8 +737,8 @@ namespace Ryujinx.Graphics.Gpu.Memory { var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); var range = isStorage - ? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite) - : bufferCache.GetBufferRange(bounds.Address, bounds.Size); + ? bounds.BufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite) + : bounds.BufferCache.GetBufferRange(bounds.Address, bounds.Size); ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range); } @@ -783,7 +791,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size); + bounds.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size); } } } @@ -793,6 +801,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Shader stage accessing the texture /// Buffer texture + /// Buffer cache that owns the buffer texture /// Address of the buffer in memory /// Size of the buffer in bytes /// Binding info for the buffer texture @@ -801,15 +810,16 @@ namespace Ryujinx.Graphics.Gpu.Memory public void SetBufferTextureStorage( ShaderStage stage, ITexture texture, + BufferCache bufferCache, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage) { - _channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size); + bufferCache.CreateBuffer(address, size); - _bufferTextures.Add(new BufferTextureBinding(stage, texture, address, size, bindingInfo, format, isImage)); + _bufferTextures.Add(new BufferTextureBinding(stage, texture, bufferCache, address, size, bindingInfo, format, isImage)); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs index b7a0e7264..726693772 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs @@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public ITexture Texture { get; } + /// + /// Buffer cache that owns the buffer. + /// + public BufferCache BufferCache { get; } + /// /// The base address of the buffer binding. /// @@ -49,6 +54,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Shader stage accessing the texture /// Buffer texture + /// Buffer cache that owns the buffer /// Base address /// Size in bytes /// Binding info @@ -57,6 +63,7 @@ namespace Ryujinx.Graphics.Gpu.Memory public BufferTextureBinding( ShaderStage stage, ITexture texture, + BufferCache bufferCache, ulong address, ulong size, TextureBindingInfo bindingInfo, @@ -65,6 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { Stage = stage; Texture = texture; + BufferCache = bufferCache; Address = address; Size = size; BindingInfo = bindingInfo; diff --git a/src/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs b/src/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs index c72fa50e5..d52718747 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs @@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// struct IndexBuffer { + public BufferCache BufferCache; public ulong Address; public ulong Size; diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 6af12de11..3b93fd59a 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Physical memory where the virtual memory is mapped into. /// - internal PhysicalMemory Physical { get; } + private PhysicalMemory Physical { get; } /// /// Cache of GPU counters. @@ -58,6 +58,35 @@ namespace Ryujinx.Graphics.Gpu.Memory MemoryUnmapped += CounterCache.MemoryUnmappedHandler; } + /// + /// Attaches the memory manager to a new GPU channel. + /// + /// Action to be performed when the buffer cache changes + internal void AttachToChannel(Action rebind) + { + Physical.IncrementReferenceCount(); + Physical.BufferCache.NotifyBuffersModified += rebind; + Physical.BufferCache.QueuePrune(); + } + + /// + /// Attaches the memory manager to a new GPU channel. + /// + /// Action that was performed when the buffer cache changed + internal void DetachFromChannel(Action rebind) + { + Physical.BufferCache.NotifyBuffersModified -= rebind; + Physical.DecrementReferenceCount(); + } + + /// + /// Queues a prune of invalid entries on the buffer cache. + /// + internal void QueuePrune() + { + Physical.BufferCache.QueuePrune(); + } + /// /// Reads data from GPU mapped memory. /// @@ -563,6 +592,11 @@ namespace Ryujinx.Graphics.Gpu.Memory return true; } + internal PhysicalMemory GetBackingMemory(ulong va) + { + return Physical; + } + /// /// Validates a GPU virtual address. /// @@ -756,7 +790,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Physical address private static ulong UnpackPaFromPte(ulong pte) { - return pte & 0xffffffffffffffUL; + return pte & 0xffffffffffffUL; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs b/src/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs index ac334881d..397314a7e 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs @@ -5,6 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// struct VertexBuffer { + public BufferCache BufferCache; public ulong Address; public ulong Size; public int Stride; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index 1d84d0e46..18b101aca 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -55,11 +55,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// public uint ConstantBuffer1Read(int offset) { - ulong baseAddress = _compute + (var physical, ulong baseAddress) = _compute ? _channel.BufferManager.GetComputeUniformBufferAddress(1) : _channel.BufferManager.GetGraphicsUniformBufferAddress(_stageIndex, 1); - return _channel.MemoryManager.Physical.Read(baseAddress + (ulong)offset); + return physical.Read(baseAddress + (ulong)offset); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 38be262a7..04482ca64 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -724,14 +724,14 @@ namespace Ryujinx.Graphics.Gpu.Shader byte[] codeB, bool asCompute) { - ulong cb1DataAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(0, 1); + (var physical, ulong cb1DataAddress) = channel.BufferManager.GetGraphicsUniformBufferAddress(0, 1); var memoryManager = channel.MemoryManager; codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray(); codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray(); - byte[] cb1DataA = memoryManager.Physical.GetSpan(cb1DataAddress, vertexA.Cb1DataSize).ToArray(); - byte[] cb1DataB = memoryManager.Physical.GetSpan(cb1DataAddress, currentStage.Cb1DataSize).ToArray(); + byte[] cb1DataA = physical.GetSpan(cb1DataAddress, vertexA.Cb1DataSize).ToArray(); + byte[] cb1DataB = physical.GetSpan(cb1DataAddress, currentStage.Cb1DataSize).ToArray(); ShaderDumpPaths pathsA = default; ShaderDumpPaths pathsB = default; @@ -766,11 +766,11 @@ namespace Ryujinx.Graphics.Gpu.Shader { var memoryManager = channel.MemoryManager; - ulong cb1DataAddress = context.Stage == ShaderStage.Compute + (var physical, ulong cb1DataAddress) = context.Stage == ShaderStage.Compute ? channel.BufferManager.GetComputeUniformBufferAddress(1) : channel.BufferManager.GetGraphicsUniformBufferAddress(StageToStageIndex(context.Stage), 1); - byte[] cb1Data = memoryManager.Physical.GetSpan(cb1DataAddress, context.Cb1DataSize).ToArray(); + byte[] cb1Data = physical.GetSpan(cb1DataAddress, context.Cb1DataSize).ToArray(); code ??= memoryManager.GetSpan(context.Address, context.Size).ToArray(); ShaderDumpPaths paths = dumper?.Dump(code, context.Stage == ShaderStage.Compute) ?? default; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs index a41f761bd..aab380d4a 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs @@ -611,7 +611,7 @@ namespace Ryujinx.Graphics.Gpu.Shader { ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex); - cachedTextureBuffer = MemoryMarshal.Cast(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); + cachedTextureBuffer = MemoryMarshal.Cast(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedTextureBufferIndex = textureBufferIndex; if (samplerBufferIndex == textureBufferIndex) @@ -625,7 +625,7 @@ namespace Ryujinx.Graphics.Gpu.Shader { ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex); - cachedSamplerBuffer = MemoryMarshal.Cast(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); + cachedSamplerBuffer = MemoryMarshal.Cast(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedSamplerBufferIndex = samplerBufferIndex; }