Allow resources to be backed by different PhysicalMemory (still unused)

This commit is contained in:
gdk 2022-12-19 12:25:44 -03:00 committed by Gabriel A
parent 638be5f296
commit 640ea94cd8
27 changed files with 276 additions and 133 deletions

View file

@ -106,6 +106,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
shaderGpuVa += (uint)qmd.ProgramOffset; shaderGpuVa += (uint)qmd.ProgramOffset;
var shaderCache = memoryManager.GetBackingMemory(shaderGpuVa).ShaderCache;
int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize; int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;
int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize); int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);
@ -139,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
sharedMemorySize, sharedMemorySize,
_channel.BufferManager.HasUnalignedStorageBuffers); _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); _context.Renderer.Pipeline.SetProgram(cs.HostProgram);
@ -153,10 +155,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
{ {
BufferDescriptor sb = info.SBuffers[index]; 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; sbDescAddress += (ulong)sb.SbCbOffset * 4;
SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress); SbDescriptor sbDescriptor = physical.Read<SbDescriptor>(sbDescAddress);
uint size; uint size;
if (sb.SbCbSlot == Constants.DriverReservedUniformBuffer) if (sb.SbCbSlot == Constants.DriverReservedUniformBuffer)
@ -184,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
sharedMemorySize, sharedMemorySize,
_channel.BufferManager.HasUnalignedStorageBuffers); _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); _context.Renderer.Pipeline.SetProgram(cs.HostProgram);
} }

View file

@ -281,7 +281,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (completeSource && completeDest) if (completeSource && completeDest)
{ {
var target = memoryManager.Physical.TextureCache.FindTexture( var target = memoryManager.GetBackingMemory(dstGpuVa).TextureCache.FindTexture(
memoryManager, memoryManager,
dstGpuVa, dstGpuVa,
dstBpp, dstBpp,
@ -412,6 +412,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
} }
else else
{ {
var bufferCache = memoryManager.GetBackingMemory(dstGpuVa).BufferCache;
if (remap && if (remap &&
_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.ConstA && _state.State.SetRemapComponentsDstX == SetRemapComponentsDst.ConstA &&
_state.State.SetRemapComponentsDstY == SetRemapComponentsDst.ConstA && _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.ConstA &&
@ -422,7 +424,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
_state.State.SetRemapComponentsComponentSize == SetRemapComponentsComponentSize.Four) _state.State.SetRemapComponentsComponentSize == SetRemapComponentsComponentSize.Four)
{ {
// Fast path for clears when remap is enabled. // 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 else
{ {
@ -442,7 +444,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
} }
else else
{ {
memoryManager.Physical.BufferCache.CopyBuffer(memoryManager, srcGpuVa, dstGpuVa, size); BufferCache.CopyBuffer(_context, memoryManager, srcGpuVa, dstGpuVa, size);
} }
} }
} }

View file

@ -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. // Right now the copy code at the bottom assumes that it is used on both which might be incorrect.
if (!_isLinear) if (!_isLinear)
{ {
var target = memoryManager.Physical.TextureCache.FindTexture( var target = memoryManager.GetBackingMemory(_dstGpuVa).TextureCache.FindTexture(
memoryManager, memoryManager,
_dstGpuVa, _dstGpuVa,
1, 1,

View file

@ -382,7 +382,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
ulong indirectBufferGpuVa = count.GpuVa; 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); bool useBuffer = bufferCache.CheckModified(_processor.MemoryManager, indirectBufferGpuVa, IndirectIndexedDataEntrySize, out ulong indirectBufferAddress);
@ -392,6 +392,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
_processor.ThreedClass.DrawIndirect( _processor.ThreedClass.DrawIndirect(
topology, topology,
bufferCache,
null,
indirectBufferAddress, indirectBufferAddress,
0, 0,
1, 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 indirectBufferSize = (ulong)maxDrawCount * (ulong)stride;
ulong indirectBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize); ulong indirectBufferAddress = indirectBufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize);
ulong parameterBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, parameterBufferGpuVa, 4); ulong parameterBufferAddress = parameterBufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, parameterBufferGpuVa, 4);
_processor.ThreedClass.DrawIndirect( _processor.ThreedClass.DrawIndirect(
topology, topology,
indirectBufferCache,
parameterBufferCache,
indirectBufferAddress, indirectBufferAddress,
parameterBufferAddress, parameterBufferAddress,
maxDrawCount, maxDrawCount,

View file

@ -371,7 +371,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
var memoryManager = _channel.MemoryManager; var memoryManager = _channel.MemoryManager;
address = memoryManager.Translate(address); 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); ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format);
bufferTexture.SetStorage(range); bufferTexture.SetStorage(range);
@ -414,7 +414,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
address = memoryManager.Translate(address + indexOffset); address = memoryManager.Translate(address + indexOffset);
ulong misalign = address & ((ulong)_context.Capabilities.TextureBufferOffsetAlignment - 1); 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; misalignedOffset = (int)misalign >> shift;
SetIndexBufferTexture(reservations, range, format); SetIndexBufferTexture(reservations, range, format);

View file

@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
// State associated with direct uniform buffer updates. // State associated with direct uniform buffer updates.
// This state is used to attempt to batch together consecutive updates. // This state is used to attempt to batch together consecutive updates.
private ulong _ubBeginGpuAddress = 0;
private ulong _ubBeginCpuAddress = 0; private ulong _ubBeginCpuAddress = 0;
private ulong _ubFollowUpAddress = 0; private ulong _ubFollowUpAddress = 0;
private ulong _ubByteCount = 0; private ulong _ubByteCount = 0;
@ -112,12 +113,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (_ubFollowUpAddress != 0) if (_ubFollowUpAddress != 0)
{ {
var memoryManager = _channel.MemoryManager; var memoryManager = _channel.MemoryManager;
var physicalMemory = memoryManager.GetBackingMemory(_ubBeginGpuAddress);
Span<byte> data = MemoryMarshal.Cast<int, byte>(_ubData.AsSpan(0, (int)(_ubByteCount / 4))); Span<byte> data = MemoryMarshal.Cast<int, byte>(_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; _ubFollowUpAddress = 0;
@ -140,6 +142,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FlushUboDirty(); FlushUboDirty();
_ubByteCount = 0; _ubByteCount = 0;
_ubBeginGpuAddress = address;
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address); _ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
} }
@ -168,6 +171,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FlushUboDirty(); FlushUboDirty();
_ubByteCount = 0; _ubByteCount = 0;
_ubBeginGpuAddress = address;
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address); _ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
} }

View file

@ -630,6 +630,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary> /// </summary>
/// <param name="engine">3D engine where this method is being called</param> /// <param name="engine">3D engine where this method is being called</param>
/// <param name="topology">Primitive topology</param> /// <param name="topology">Primitive topology</param>
/// <param name="indirectBufferCache">Buffer cache owning the buffer with the draw parameters</param>
/// <param name="parameterBufferCache">Buffer cache owning the buffer with the draw count</param>
/// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param> /// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param>
/// <param name="parameterBufferAddress">Address of the buffer with the draw count</param> /// <param name="parameterBufferAddress">Address of the buffer with the draw count</param>
/// <param name="maxDrawCount">Maximum number of draws that can be made</param> /// <param name="maxDrawCount">Maximum number of draws that can be made</param>
@ -639,6 +641,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public void DrawIndirect( public void DrawIndirect(
ThreedClass engine, ThreedClass engine,
PrimitiveTopology topology, PrimitiveTopology topology,
BufferCache indirectBufferCache,
BufferCache parameterBufferCache,
ulong indirectBufferAddress, ulong indirectBufferAddress,
ulong parameterBufferAddress, ulong parameterBufferAddress,
int maxDrawCount, int maxDrawCount,
@ -660,8 +664,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return; return;
} }
PhysicalMemory memory = _channel.MemoryManager.Physical;
bool hasCount = (drawType & IndirectDrawType.Count) != 0; bool hasCount = (drawType & IndirectDrawType.Count) != 0;
bool indexed = (drawType & IndirectDrawType.Indexed) != 0; bool indexed = (drawType & IndirectDrawType.Indexed) != 0;
@ -681,8 +683,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (hasCount) if (hasCount)
{ {
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride); var indirectBuffer = indirectBufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride);
var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferAddress, 4); var parameterBuffer = parameterBufferCache.GetBufferRange(parameterBufferAddress, 4);
if (indexed) if (indexed)
{ {
@ -695,7 +697,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
} }
else else
{ {
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride); var indirectBuffer = indirectBufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride);
if (indexed) if (indexed)
{ {

View file

@ -361,10 +361,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{ {
BufferDescriptor sb = info.SBuffers[index]; 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; sbDescAddress += (ulong)sb.SbCbOffset * 4;
SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress); SbDescriptor sbDescriptor = physical.Read<SbDescriptor>(sbDescAddress);
uint size; uint size;
if (sb.SbCbSlot == Constants.DriverReservedUniformBuffer) if (sb.SbCbSlot == Constants.DriverReservedUniformBuffer)
@ -485,7 +485,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
rtNoAlphaMask |= 1u << index; rtNoAlphaMask |= 1u << index;
} }
Image.Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture( var colorTextureCache = memoryManager.GetBackingMemory(colorState.Address.Pack()).TextureCache;
Image.Texture color = colorTextureCache.FindOrCreateTexture(
memoryManager, memoryManager,
colorState, colorState,
_vtgWritesRtLayer || layered, _vtgWritesRtLayer || layered,
@ -524,7 +526,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
var dsState = _state.State.RtDepthStencilState; var dsState = _state.State.RtDepthStencilState;
var dsSize = _state.State.RtDepthStencilSize; var dsSize = _state.State.RtDepthStencilSize;
depthStencil = memoryManager.Physical.TextureCache.FindOrCreateTexture( var dsTextureCache = memoryManager.GetBackingMemory(dsState.Address.Pack()).TextureCache;
depthStencil = dsTextureCache.FindOrCreateTexture(
memoryManager, memoryManager,
dsState, dsState,
dsSize, dsSize,
@ -1381,8 +1385,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary> /// </summary>
private void UpdateShaderState() private void UpdateShaderState()
{ {
var shaderCache = _channel.MemoryManager.Physical.ShaderCache;
_vtgWritesRtLayer = false; _vtgWritesRtLayer = false;
ShaderAddresses addresses = new(); ShaderAddresses addresses = new();
@ -1401,6 +1403,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
addressesSpan[index] = baseAddress + shader.Offset; 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); 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. // Consume the modified flag for spec state so that it isn't checked again.

View file

@ -6,6 +6,7 @@ using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
using Ryujinx.Graphics.Gpu.Engine.Threed.Blender; using Ryujinx.Graphics.Gpu.Engine.Threed.Blender;
using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Synchronization; using Ryujinx.Graphics.Gpu.Synchronization;
using Ryujinx.Graphics.Gpu.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -803,6 +804,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Performs a indirect draw, with parameters from a GPU buffer. /// Performs a indirect draw, with parameters from a GPU buffer.
/// </summary> /// </summary>
/// <param name="topology">Primitive topology</param> /// <param name="topology">Primitive topology</param>
/// <param name="indirectBufferCache">Buffer cache owning the buffer with the draw parameters</param>
/// <param name="parameterBufferCache">Buffer cache owning the buffer with the draw count</param>
/// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param> /// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param>
/// <param name="parameterBufferAddress">Address of the buffer with the draw count</param> /// <param name="parameterBufferAddress">Address of the buffer with the draw count</param>
/// <param name="maxDrawCount">Maximum number of draws that can be made</param> /// <param name="maxDrawCount">Maximum number of draws that can be made</param>
@ -811,6 +814,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param> /// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param>
public void DrawIndirect( public void DrawIndirect(
PrimitiveTopology topology, PrimitiveTopology topology,
BufferCache indirectBufferCache,
BufferCache parameterBufferCache,
ulong indirectBufferAddress, ulong indirectBufferAddress,
ulong parameterBufferAddress, ulong parameterBufferAddress,
int maxDrawCount, int maxDrawCount,
@ -818,7 +823,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
int indexCount, int indexCount,
IndirectDrawType drawType) IndirectDrawType drawType)
{ {
_drawManager.DrawIndirect(this, topology, indirectBufferAddress, parameterBufferAddress, maxDrawCount, stride, indexCount, drawType); _drawManager.DrawIndirect(
this,
topology,
indirectBufferCache,
parameterBufferCache,
indirectBufferAddress,
parameterBufferAddress,
maxDrawCount,
stride,
indexCount,
drawType);
} }
/// <summary> /// <summary>

View file

@ -233,6 +233,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
var dstCopyTexture = Unsafe.As<uint, TwodTexture>(ref _state.State.SetDstFormat); var dstCopyTexture = Unsafe.As<uint, TwodTexture>(ref _state.State.SetDstFormat);
var srcCopyTexture = Unsafe.As<uint, TwodTexture>(ref _state.State.SetSrcFormat); var srcCopyTexture = Unsafe.As<uint, TwodTexture>(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 srcX = ((long)_state.State.SetPixelsFromMemorySrcX0Int << 32) | (long)(ulong)_state.State.SetPixelsFromMemorySrcX0Frac;
long srcY = ((long)_state.State.PixelsFromMemorySrcY0Int << 32) | (long)(ulong)_state.State.SetPixelsFromMemorySrcY0Frac; 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. // are the same, as we can't blit between different depth formats.
bool srcDepthAlias = srcCopyTexture.Format == dstCopyTexture.Format; bool srcDepthAlias = srcCopyTexture.Format == dstCopyTexture.Format;
var srcTexture = memoryManager.Physical.TextureCache.FindOrCreateTexture( var srcTexture = srcTextureCache.FindOrCreateTexture(
memoryManager, memoryManager,
srcCopyTexture, srcCopyTexture,
offset, offset,
@ -325,7 +328,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
return; return;
} }
memoryManager.Physical.TextureCache.Lift(srcTexture); srcTextureCache.Lift(srcTexture);
// When the source texture that was found has a depth format, // When the source texture that was found has a depth format,
// we must enforce the target texture also 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(); dstCopyTextureFormat = dstCopyTexture.Format.Convert();
} }
var dstTexture = memoryManager.Physical.TextureCache.FindOrCreateTexture( var dstTexture = dstTextureCache.FindOrCreateTexture(
memoryManager, memoryManager,
dstCopyTexture, dstCopyTexture,
0, 0,

View file

@ -58,22 +58,24 @@ namespace Ryujinx.Graphics.Gpu
public void BindMemory(MemoryManager memoryManager) public void BindMemory(MemoryManager memoryManager)
{ {
var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, memoryManager ?? throw new ArgumentNullException(nameof(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) if (oldMemoryManager != null)
{ {
oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind; oldMemoryManager.DetachFromChannel(BufferManager.Rebind);
oldMemoryManager.Physical.DecrementReferenceCount();
oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler; oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler;
} }
memoryManager.Physical.BufferCache.NotifyBuffersModified += BufferManager.Rebind;
memoryManager.MemoryUnmapped += MemoryUnmappedHandler; memoryManager.MemoryUnmapped += MemoryUnmappedHandler;
// Since the memory manager changed, make sure we will get pools from addresses of the new memory manager. // Since the memory manager changed, make sure we will get pools from addresses of the new memory manager.
TextureManager.ReloadPools(); TextureManager.ReloadPools();
memoryManager.Physical.BufferCache.QueuePrune(); memoryManager.QueuePrune();
} }
/// <summary> /// <summary>
@ -86,7 +88,7 @@ namespace Ryujinx.Graphics.Gpu
TextureManager.ReloadPools(); TextureManager.ReloadPools();
var memoryManager = Volatile.Read(ref _memoryManager); var memoryManager = Volatile.Read(ref _memoryManager);
memoryManager?.Physical.BufferCache.QueuePrune(); memoryManager?.QueuePrune();
} }
/// <summary> /// <summary>
@ -141,8 +143,7 @@ namespace Ryujinx.Graphics.Gpu
var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, null); var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, null);
if (oldMemoryManager != null) if (oldMemoryManager != null)
{ {
oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind; oldMemoryManager.DetachFromChannel(BufferManager.Rebind);
oldMemoryManager.Physical.DecrementReferenceCount();
oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler; oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler;
} }
} }

View file

@ -1,3 +1,4 @@
using Ryujinx.Graphics.Gpu.Memory;
using System; using System;
using System.Collections.Generic; 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. /// Finds a cache texture pool, or creates a new one if not found.
/// </summary> /// </summary>
/// <param name="channel">GPU channel that the texture pool cache belongs to</param> /// <param name="channel">GPU channel that the texture pool cache belongs to</param>
/// <param name="physicalMemory">Backing memory of the pool</param>
/// <param name="address">Start address of the texture pool</param> /// <param name="address">Start address of the texture pool</param>
/// <param name="maximumId">Maximum ID of the texture pool</param> /// <param name="maximumId">Maximum ID of the texture pool</param>
/// <returns>The found or newly created texture pool</returns> /// <returns>The found or newly created texture pool</returns>
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. // Remove old entries from the cache, if possible.
while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval) 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. // 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.CacheNode = _pools.AddLast(pool);
pool.CacheTimestamp = _currentTimestamp; pool.CacheTimestamp = _currentTimestamp;
@ -111,9 +113,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="context">GPU context that the pool belongs to</param> /// <param name="context">GPU context that the pool belongs to</param>
/// <param name="channel">GPU channel that the pool belongs to</param> /// <param name="channel">GPU channel that the pool belongs to</param>
/// <param name="physicalMemory">Backing memory of the pool</param>
/// <param name="address">Address of the pool in guest memory</param> /// <param name="address">Address of the pool in guest memory</param>
/// <param name="maximumId">Maximum ID of the pool (equal to maximum minus one)</param> /// <param name="maximumId">Maximum ID of the pool (equal to maximum minus one)</param>
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() public void Dispose()
{ {

View file

@ -1,3 +1,5 @@
using Ryujinx.Graphics.Gpu.Memory;
namespace Ryujinx.Graphics.Gpu.Image namespace Ryujinx.Graphics.Gpu.Image
{ {
/// <summary> /// <summary>
@ -20,11 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="context">GPU context that the sampler pool belongs to</param> /// <param name="context">GPU context that the sampler pool belongs to</param>
/// <param name="channel">GPU channel that the texture pool belongs to</param> /// <param name="channel">GPU channel that the texture pool belongs to</param>
/// <param name="physicalMemory">Backing memory of the pool</param>
/// <param name="address">Address of the sampler pool in guest memory</param> /// <param name="address">Address of the sampler pool in guest memory</param>
/// <param name="maximumId">Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)</param> /// <param name="maximumId">Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)</param>
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);
} }
} }
} }

View file

@ -382,7 +382,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex); ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex);
cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(_channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size));
cachedTextureBufferIndex = textureBufferIndex; cachedTextureBufferIndex = textureBufferIndex;
if (samplerBufferIndex == textureBufferIndex) if (samplerBufferIndex == textureBufferIndex)
@ -396,7 +396,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex); ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex);
cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(_channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size));
cachedSamplerBufferIndex = samplerBufferIndex; cachedSamplerBufferIndex = samplerBufferIndex;
} }
} }
@ -524,7 +524,8 @@ namespace Ryujinx.Graphics.Gpu.Image
// Ensure that the buffer texture is using the correct buffer as storage. // 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 // 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. // 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. // Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null; state.CachedTexture = null;
@ -661,7 +662,8 @@ namespace Ryujinx.Graphics.Gpu.Image
format = texture.Format; 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. // Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null; state.CachedTexture = null;
@ -726,9 +728,10 @@ namespace Ryujinx.Graphics.Gpu.Image
int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, samplerBufferIndex); int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, samplerBufferIndex);
int textureId = TextureHandle.UnpackTextureId(packedId); int textureId = TextureHandle.UnpackTextureId(packedId);
var physical = _channel.MemoryManager.GetBackingMemory(poolGpuVa);
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, physical, poolAddress, maximumId);
TextureDescriptor descriptor; TextureDescriptor descriptor;
@ -762,12 +765,12 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
(int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = TextureHandle.UnpackOffsets(wordOffset); (int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = TextureHandle.UnpackOffsets(wordOffset);
ulong textureBufferAddress = _isCompute (var texturePhysicalMemory, ulong textureBufferAddress) = _isCompute
? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex) ? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex); : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
int handle = textureBufferAddress != 0 int handle = textureBufferAddress != 0
? _channel.MemoryManager.Physical.Read<int>(textureBufferAddress + (uint)textureWordOffset * 4) ? texturePhysicalMemory.Read<int>(textureBufferAddress + (uint)textureWordOffset * 4)
: 0; : 0;
// The "wordOffset" (which is really the immediate value used on texture instructions on the shader) // 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) if (handleType != TextureHandleType.SeparateConstantSamplerHandle)
{ {
ulong samplerBufferAddress = _isCompute (var samplerPhysicalMemory, ulong samplerBufferAddress) = _isCompute
? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex) ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex); : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
samplerHandle = samplerBufferAddress != 0 samplerHandle = samplerBufferAddress != 0
? _channel.MemoryManager.Physical.Read<int>(samplerBufferAddress + (uint)samplerWordOffset * 4) ? samplerPhysicalMemory.Read<int>(samplerBufferAddress + (uint)samplerWordOffset * 4)
: 0; : 0;
} }
else else
@ -824,7 +827,8 @@ namespace Ryujinx.Graphics.Gpu.Image
if (poolAddress != MemoryManager.PteUnmapped) 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; _texturePool = texturePool;
} }
} }
@ -835,7 +839,8 @@ namespace Ryujinx.Graphics.Gpu.Image
if (poolAddress != MemoryManager.PteUnmapped) 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; _samplerPool = samplerPool;
} }
} }

View file

@ -364,9 +364,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The texture pool</returns> /// <returns>The texture pool</returns>
public TexturePool GetTexturePool(ulong poolGpuVa, int maximumId) public TexturePool GetTexturePool(ulong poolGpuVa, int maximumId)
{ {
var physical = _channel.MemoryManager.GetBackingMemory(poolGpuVa);
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, physical, poolAddress, maximumId);
return texturePool; return texturePool;
} }

View file

@ -89,9 +89,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="context">GPU context that the texture pool belongs to</param> /// <param name="context">GPU context that the texture pool belongs to</param>
/// <param name="channel">GPU channel that the texture pool belongs to</param> /// <param name="channel">GPU channel that the texture pool belongs to</param>
/// <param name="physicalMemory">Backing memory of the pool</param>
/// <param name="address">Address of the texture pool in guest memory</param> /// <param name="address">Address of the texture pool in guest memory</param>
/// <param name="maximumId">Maximum texture ID of the texture pool (equal to maximum textures minus one)</param> /// <param name="maximumId">Maximum texture ID of the texture pool (equal to maximum textures minus one)</param>
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; _channel = channel;
} }
@ -122,7 +123,9 @@ namespace Ryujinx.Graphics.Gpu.Image
return ref descriptor; 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 this happens, then the texture address is invalid, we can't add it to the cache.
if (texture == null) if (texture == null)
@ -280,7 +283,9 @@ namespace Ryujinx.Graphics.Gpu.Image
continue; 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. // 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)) if (!range.Equals(texture.Range))
{ {
// Part of the texture was mapped or unmapped. Replace the range and regenerate tracking handles. // 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. // Texture could not be remapped due to a collision, just delete it.
if (Interlocked.Exchange(ref Items[request.ID], null) != null) if (Interlocked.Exchange(ref Items[request.ID], null) != null)
@ -338,6 +343,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="size">Size of the range being invalidated</param> /// <param name="size">Size of the range being invalidated</param>
protected override void InvalidateRangeImpl(ulong address, ulong size) protected override void InvalidateRangeImpl(ulong address, ulong size)
{ {
MemoryManager memoryManager = _channel.MemoryManager;
ProcessDereferenceQueue(); ProcessDereferenceQueue();
ulong endAddress = address + size; ulong endAddress = address + size;
@ -362,7 +369,8 @@ namespace Ryujinx.Graphics.Gpu.Image
if (texture.HasOneReference()) 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) if (Interlocked.Exchange(ref Items[id], null) != null)

View file

@ -1,3 +1,5 @@
using Ryujinx.Graphics.Gpu.Memory;
namespace Ryujinx.Graphics.Gpu.Image namespace Ryujinx.Graphics.Gpu.Image
{ {
/// <summary> /// <summary>
@ -20,11 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="context">GPU context that the texture pool belongs to</param> /// <param name="context">GPU context that the texture pool belongs to</param>
/// <param name="channel">GPU channel that the texture pool belongs to</param> /// <param name="channel">GPU channel that the texture pool belongs to</param>
/// <param name="physicalMemory">Backing memory of the pool</param>
/// <param name="address">Address of the texture pool in guest memory</param> /// <param name="address">Address of the texture pool in guest memory</param>
/// <param name="maximumId">Maximum texture ID of the texture pool (equal to maximum textures minus one)</param> /// <param name="maximumId">Maximum texture ID of the texture pool (equal to maximum textures minus one)</param>
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);
} }
} }
} }

View file

@ -7,6 +7,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
readonly struct BufferBounds readonly struct BufferBounds
{ {
/// <summary>
/// Physical memory backing the buffer.
/// </summary>
public PhysicalMemory Physical { get; }
/// <summary>
/// Buffer cache that owns the buffer.
/// </summary>
public BufferCache BufferCache => Physical.BufferCache;
/// <summary> /// <summary>
/// Region virtual address. /// Region virtual address.
/// </summary> /// </summary>
@ -25,11 +35,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary> /// <summary>
/// Creates a new buffer region. /// Creates a new buffer region.
/// </summary> /// </summary>
/// <param name="physical">Physical memory backing the buffer</param>
/// <param name="address">Region address</param> /// <param name="address">Region address</param>
/// <param name="size">Region size</param> /// <param name="size">Region size</param>
/// <param name="flags">Buffer usage flags</param> /// <param name="flags">Buffer usage flags</param>
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; Address = address;
Size = size; Size = size;
Flags = flags; Flags = flags;

View file

@ -313,22 +313,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <remarks> /// <remarks>
/// This does a GPU side copy. /// This does a GPU side copy.
/// </remarks> /// </remarks>
/// <param name="context">GPU context</param>
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param> /// <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="srcVa">GPU virtual address of the copy source</param>
/// <param name="dstVa">GPU virtual address of the copy destination</param> /// <param name="dstVa">GPU virtual address of the copy destination</param>
/// <param name="size">Size in bytes of the copy</param> /// <param name="size">Size in bytes of the copy</param>
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); PhysicalMemory srcPhysical = memoryManager.GetBackingMemory(srcVa);
ulong dstAddress = TranslateAndCreateBuffer(memoryManager, dstVa, size); PhysicalMemory dstPhysical = memoryManager.GetBackingMemory(dstVa);
Buffer srcBuffer = GetBuffer(srcAddress, size); ulong srcAddress = srcPhysical.BufferCache.TranslateAndCreateBuffer(memoryManager, srcVa, size);
Buffer dstBuffer = GetBuffer(dstAddress, 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 srcOffset = (int)(srcAddress - srcBuffer.Address);
int dstOffset = (int)(dstAddress - dstBuffer.Address); int dstOffset = (int)(dstAddress - dstBuffer.Address);
_context.Renderer.Pipeline.CopyBuffer( context.Renderer.Pipeline.CopyBuffer(
srcBuffer.Handle, srcBuffer.Handle,
dstBuffer.Handle, dstBuffer.Handle,
srcOffset, 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. // Optimization: If the data being copied is already in memory, then copy it directly instead of flushing from GPU.
dstBuffer.ClearModified(dstAddress, size); 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); _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);
} }
/// <summary> /// <summary>

View file

@ -68,12 +68,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Sets the region of a buffer at a given slot. /// Sets the region of a buffer at a given slot.
/// </summary> /// </summary>
/// <param name="index">Buffer slot</param> /// <param name="index">Buffer slot</param>
/// <param name="physical">Physical memory backing the buffer</param>
/// <param name="address">Region virtual address</param> /// <param name="address">Region virtual address</param>
/// <param name="size">Region size in bytes</param> /// <param name="size">Region size in bytes</param>
/// <param name="flags">Buffer usage flags</param> /// <param name="flags">Buffer usage flags</param>
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);
} }
/// <summary> /// <summary>
@ -150,8 +151,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="type">Type of each index buffer element</param> /// <param name="type">Type of each index buffer element</param>
public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type) 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.Address = address;
_indexBuffer.Size = size; _indexBuffer.Size = size;
_indexBuffer.Type = type; _indexBuffer.Type = type;
@ -181,12 +184,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="divisor">Vertex divisor of the buffer, for instanced draws</param> /// <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) 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; ref VertexBuffer vb = ref _vertexBuffers[index];
_vertexBuffers[index].Size = size;
_vertexBuffers[index].Stride = stride; vb.BufferCache = bufferCache;
_vertexBuffers[index].Divisor = divisor; vb.Address = address;
vb.Size = size;
vb.Stride = stride;
vb.Divisor = divisor;
_vertexBuffersDirty = true; _vertexBuffersDirty = true;
@ -209,9 +216,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the transform feedback buffer</param> /// <param name="size">Size in bytes of the transform feedback buffer</param>
public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size) 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; _transformFeedbackBuffersDirty = true;
} }
@ -256,9 +264,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment); gpuVa = BitUtils.AlignDown<ulong>(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);
} }
/// <summary> /// <summary>
@ -280,7 +289,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment); gpuVa = BitUtils.AlignDown<ulong>(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 || if (buffers.Buffers[index].Address != address ||
buffers.Buffers[index].Size != size) buffers.Buffers[index].Size != size)
@ -288,7 +298,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
_gpStorageBuffersDirty = true; _gpStorageBuffersDirty = true;
} }
buffers.SetBounds(index, address, size, flags); buffers.SetBounds(index, physical, address, size, flags);
} }
/// <summary> /// <summary>
@ -300,9 +310,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the storage buffer</param> /// <param name="size">Size in bytes of the storage buffer</param>
public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size) 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);
} }
/// <summary> /// <summary>
@ -315,9 +326,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the storage buffer</param> /// <param name="size">Size in bytes of the storage buffer</param>
public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size) 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; _gpUniformBuffersDirty = true;
} }
@ -413,9 +425,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
/// <param name="index">Index of the uniform buffer binding</param> /// <param name="index">Index of the uniform buffer binding</param>
/// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns> /// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
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);
} }
/// <summary> /// <summary>
@ -424,9 +437,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="stage">Index of the shader stage</param> /// <param name="stage">Index of the shader stage</param>
/// <param name="index">Index of the uniform buffer binding</param> /// <param name="index">Index of the uniform buffer binding</param>
/// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns> /// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
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);
} }
/// <summary> /// <summary>
@ -454,10 +468,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public void CommitComputeBindings() public void CommitComputeBindings()
{ {
var bufferCache = _channel.MemoryManager.Physical.BufferCache; BindBuffers(_cpStorageBuffers, isStorage: true);
BindBuffers(_cpUniformBuffers, isStorage: false);
BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true);
BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false);
CommitBufferTextureBindings(); CommitBufferTextureBindings();
@ -477,7 +489,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
foreach (var binding in _bufferTextures) foreach (var binding in _bufferTextures)
{ {
var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); 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); binding.Texture.SetStorage(range);
// The texture must be rebound to use the new storage if it was updated. // The texture must be rebound to use the new storage if it was updated.
@ -503,8 +515,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="indexed">True if the index buffer is in use</param> /// <param name="indexed">True if the index buffer is in use</param>
public void CommitGraphicsBindings(bool indexed) public void CommitGraphicsBindings(bool indexed)
{ {
var bufferCache = _channel.MemoryManager.Physical.BufferCache;
if (indexed) if (indexed)
{ {
if (_indexBufferDirty || _rebind) if (_indexBufferDirty || _rebind)
@ -513,14 +523,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_indexBuffer.Address != 0) 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); _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
} }
} }
else if (_indexBuffer.Address != 0) else if (_indexBuffer.Address != 0)
{ {
bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size); _indexBuffer.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
} }
} }
else if (_rebind) else if (_rebind)
@ -545,7 +555,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue; 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); vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
} }
@ -563,7 +573,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue; continue;
} }
bufferCache.SynchronizeBufferRange(vb.Address, vb.Size); vb.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
} }
} }
@ -585,7 +595,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue; 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); _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
@ -614,7 +624,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
_context.SupportBufferUpdater.SetTfeOffset(index, tfeOffset); _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; 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; _gpStorageBuffersDirty = false;
BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true); BindBuffers(_gpStorageBuffers, isStorage: true);
} }
else else
{ {
@ -651,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
_gpUniformBuffersDirty = false; _gpUniformBuffersDirty = false;
BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false); BindBuffers(_gpUniformBuffers, isStorage: false);
} }
else else
{ {
@ -668,11 +678,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary> /// <summary>
/// Bind respective buffer bindings on the host API. /// Bind respective buffer bindings on the host API.
/// </summary> /// </summary>
/// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
/// <param name="bindings">Buffer memory ranges to bind</param> /// <param name="bindings">Buffer memory ranges to bind</param>
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param> /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage) private void BindBuffers(BuffersPerStage[] bindings, bool isStorage)
{ {
int rangesCount = 0; int rangesCount = 0;
@ -692,8 +701,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
var range = isStorage var range = isStorage
? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite) ? bounds.BufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite)
: bufferCache.GetBufferRange(bounds.Address, bounds.Size); : bounds.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range); ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
} }
@ -709,11 +718,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary> /// <summary>
/// Bind respective buffer bindings on the host API. /// Bind respective buffer bindings on the host API.
/// </summary> /// </summary>
/// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
/// <param name="buffers">Buffer memory ranges to bind</param> /// <param name="buffers">Buffer memory ranges to bind</param>
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param> /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage) private void BindBuffers(BuffersPerStage buffers, bool isStorage)
{ {
int rangesCount = 0; int rangesCount = 0;
@ -729,8 +737,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
var range = isStorage var range = isStorage
? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite) ? bounds.BufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite)
: bufferCache.GetBufferRange(bounds.Address, bounds.Size); : bounds.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range); ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
} }
@ -783,7 +791,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue; 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
/// </summary> /// </summary>
/// <param name="stage">Shader stage accessing the texture</param> /// <param name="stage">Shader stage accessing the texture</param>
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="bufferCache">Buffer cache that owns the buffer texture</param>
/// <param name="address">Address of the buffer in memory</param> /// <param name="address">Address of the buffer in memory</param>
/// <param name="size">Size of the buffer in bytes</param> /// <param name="size">Size of the buffer in bytes</param>
/// <param name="bindingInfo">Binding info for the buffer texture</param> /// <param name="bindingInfo">Binding info for the buffer texture</param>
@ -801,15 +810,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
public void SetBufferTextureStorage( public void SetBufferTextureStorage(
ShaderStage stage, ShaderStage stage,
ITexture texture, ITexture texture,
BufferCache bufferCache,
ulong address, ulong address,
ulong size, ulong size,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
Format format, Format format,
bool isImage) 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));
} }
/// <summary> /// <summary>

View file

@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public ITexture Texture { get; } public ITexture Texture { get; }
/// <summary>
/// Buffer cache that owns the buffer.
/// </summary>
public BufferCache BufferCache { get; }
/// <summary> /// <summary>
/// The base address of the buffer binding. /// The base address of the buffer binding.
/// </summary> /// </summary>
@ -49,6 +54,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
/// <param name="stage">Shader stage accessing the texture</param> /// <param name="stage">Shader stage accessing the texture</param>
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="bufferCache">Buffer cache that owns the buffer</param>
/// <param name="address">Base address</param> /// <param name="address">Base address</param>
/// <param name="size">Size in bytes</param> /// <param name="size">Size in bytes</param>
/// <param name="bindingInfo">Binding info</param> /// <param name="bindingInfo">Binding info</param>
@ -57,6 +63,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
public BufferTextureBinding( public BufferTextureBinding(
ShaderStage stage, ShaderStage stage,
ITexture texture, ITexture texture,
BufferCache bufferCache,
ulong address, ulong address,
ulong size, ulong size,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
@ -65,6 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
Stage = stage; Stage = stage;
Texture = texture; Texture = texture;
BufferCache = bufferCache;
Address = address; Address = address;
Size = size; Size = size;
BindingInfo = bindingInfo; BindingInfo = bindingInfo;

View file

@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
struct IndexBuffer struct IndexBuffer
{ {
public BufferCache BufferCache;
public ulong Address; public ulong Address;
public ulong Size; public ulong Size;

View file

@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary> /// <summary>
/// Physical memory where the virtual memory is mapped into. /// Physical memory where the virtual memory is mapped into.
/// </summary> /// </summary>
internal PhysicalMemory Physical { get; } private PhysicalMemory Physical { get; }
/// <summary> /// <summary>
/// Cache of GPU counters. /// Cache of GPU counters.
@ -58,6 +58,35 @@ namespace Ryujinx.Graphics.Gpu.Memory
MemoryUnmapped += CounterCache.MemoryUnmappedHandler; MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
} }
/// <summary>
/// Attaches the memory manager to a new GPU channel.
/// </summary>
/// <param name="rebind">Action to be performed when the buffer cache changes</param>
internal void AttachToChannel(Action rebind)
{
Physical.IncrementReferenceCount();
Physical.BufferCache.NotifyBuffersModified += rebind;
Physical.BufferCache.QueuePrune();
}
/// <summary>
/// Attaches the memory manager to a new GPU channel.
/// </summary>
/// <param name="rebind">Action that was performed when the buffer cache changed</param>
internal void DetachFromChannel(Action rebind)
{
Physical.BufferCache.NotifyBuffersModified -= rebind;
Physical.DecrementReferenceCount();
}
/// <summary>
/// Queues a prune of invalid entries on the buffer cache.
/// </summary>
internal void QueuePrune()
{
Physical.BufferCache.QueuePrune();
}
/// <summary> /// <summary>
/// Reads data from GPU mapped memory. /// Reads data from GPU mapped memory.
/// </summary> /// </summary>
@ -563,6 +592,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
return true; return true;
} }
internal PhysicalMemory GetBackingMemory(ulong va)
{
return Physical;
}
/// <summary> /// <summary>
/// Validates a GPU virtual address. /// Validates a GPU virtual address.
/// </summary> /// </summary>
@ -756,7 +790,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <returns>Physical address</returns> /// <returns>Physical address</returns>
private static ulong UnpackPaFromPte(ulong pte) private static ulong UnpackPaFromPte(ulong pte)
{ {
return pte & 0xffffffffffffffUL; return pte & 0xffffffffffffUL;
} }
} }
} }

View file

@ -5,6 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
struct VertexBuffer struct VertexBuffer
{ {
public BufferCache BufferCache;
public ulong Address; public ulong Address;
public ulong Size; public ulong Size;
public int Stride; public int Stride;

View file

@ -55,11 +55,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <inheritdoc/> /// <inheritdoc/>
public uint ConstantBuffer1Read(int offset) public uint ConstantBuffer1Read(int offset)
{ {
ulong baseAddress = _compute (var physical, ulong baseAddress) = _compute
? _channel.BufferManager.GetComputeUniformBufferAddress(1) ? _channel.BufferManager.GetComputeUniformBufferAddress(1)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(_stageIndex, 1); : _channel.BufferManager.GetGraphicsUniformBufferAddress(_stageIndex, 1);
return _channel.MemoryManager.Physical.Read<uint>(baseAddress + (ulong)offset); return physical.Read<uint>(baseAddress + (ulong)offset);
} }
/// <inheritdoc/> /// <inheritdoc/>

View file

@ -724,14 +724,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
byte[] codeB, byte[] codeB,
bool asCompute) bool asCompute)
{ {
ulong cb1DataAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(0, 1); (var physical, ulong cb1DataAddress) = channel.BufferManager.GetGraphicsUniformBufferAddress(0, 1);
var memoryManager = channel.MemoryManager; var memoryManager = channel.MemoryManager;
codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray(); codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray();
codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray(); codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
byte[] cb1DataA = memoryManager.Physical.GetSpan(cb1DataAddress, vertexA.Cb1DataSize).ToArray(); byte[] cb1DataA = physical.GetSpan(cb1DataAddress, vertexA.Cb1DataSize).ToArray();
byte[] cb1DataB = memoryManager.Physical.GetSpan(cb1DataAddress, currentStage.Cb1DataSize).ToArray(); byte[] cb1DataB = physical.GetSpan(cb1DataAddress, currentStage.Cb1DataSize).ToArray();
ShaderDumpPaths pathsA = default; ShaderDumpPaths pathsA = default;
ShaderDumpPaths pathsB = default; ShaderDumpPaths pathsB = default;
@ -766,11 +766,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
{ {
var memoryManager = channel.MemoryManager; var memoryManager = channel.MemoryManager;
ulong cb1DataAddress = context.Stage == ShaderStage.Compute (var physical, ulong cb1DataAddress) = context.Stage == ShaderStage.Compute
? channel.BufferManager.GetComputeUniformBufferAddress(1) ? channel.BufferManager.GetComputeUniformBufferAddress(1)
: channel.BufferManager.GetGraphicsUniformBufferAddress(StageToStageIndex(context.Stage), 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(); code ??= memoryManager.GetSpan(context.Address, context.Size).ToArray();
ShaderDumpPaths paths = dumper?.Dump(code, context.Stage == ShaderStage.Compute) ?? default; ShaderDumpPaths paths = dumper?.Dump(code, context.Stage == ShaderStage.Compute) ?? default;

View file

@ -611,7 +611,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{ {
ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex); ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex);
cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size));
cachedTextureBufferIndex = textureBufferIndex; cachedTextureBufferIndex = textureBufferIndex;
if (samplerBufferIndex == textureBufferIndex) if (samplerBufferIndex == textureBufferIndex)
@ -625,7 +625,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{ {
ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex); ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex);
cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size)); cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(bounds.Physical.GetSpan(bounds.Address, (int)bounds.Size));
cachedSamplerBufferIndex = samplerBufferIndex; cachedSamplerBufferIndex = samplerBufferIndex;
} }