diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
index a7f6ec06..26041ecc 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
@@ -16,11 +16,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// Method call argument
public void Dispatch(GpuState state, int argument)
{
- FlushUboDirty();
+ var memoryManager = state.Channel.MemoryManager;
+
+ FlushUboDirty(memoryManager);
uint qmdAddress = (uint)state.Get(MethodOffset.DispatchParamsAddress);
- var qmd = _context.MemoryManager.Read((ulong)qmdAddress << 8);
+ var qmd = state.Channel.MemoryManager.Read((ulong)qmdAddress << 8);
GpuVa shaderBaseAddress = state.Get(MethodOffset.ShaderBaseAddress);
@@ -43,7 +45,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
state.Channel.BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
}
- ShaderBundle cs = ShaderCache.GetComputeShader(
+ ShaderBundle cs = memoryManager.Physical.ShaderCache.GetComputeShader(
state,
shaderGpuVa,
qmd.CtaThreadDimension0,
@@ -82,7 +84,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
cbDescAddress += (ulong)cbDescOffset;
- SbDescriptor cbDescriptor = _context.PhysicalMemory.Read(cbDescAddress);
+ SbDescriptor cbDescriptor = state.Channel.MemoryManager.Physical.Read(cbDescAddress);
state.Channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
}
@@ -97,7 +99,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
sbDescAddress += (ulong)sbDescOffset;
- SbDescriptor sbDescriptor = _context.PhysicalMemory.Read(sbDescAddress);
+ SbDescriptor sbDescriptor = state.Channel.MemoryManager.Physical.Read(sbDescAddress);
state.Channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
index 84d35350..75b19c37 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
@@ -79,13 +79,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
// TODO: Acquire operations (Wait), interrupts for invalid combinations.
if (operation == SemaphoredOperation.Release)
{
- _context.MemoryManager.Write(address, value);
+ _parent.MemoryManager.Write(address, value);
}
else if (operation == SemaphoredOperation.Reduction)
{
bool signed = _state.State.SemaphoredFormat == SemaphoredFormat.Signed;
- int mem = _context.MemoryManager.Read(address);
+ int mem = _parent.MemoryManager.Read(address);
switch (_state.State.SemaphoredReduction)
{
@@ -115,7 +115,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
break;
}
- _context.MemoryManager.Write(address, value);
+ _parent.MemoryManager.Write(address, value);
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoDevice.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoDevice.cs
index 0e284ac5..ada3bc4b 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoDevice.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoDevice.cs
@@ -1,4 +1,5 @@
-using System;
+using Ryujinx.Graphics.Gpu.Memory;
+using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -53,11 +54,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
///
/// Fetch the command buffer.
///
- public void Fetch(GpuContext context)
+ public void Fetch(MemoryManager memoryManager)
{
if (Words == null)
{
- Words = MemoryMarshal.Cast(context.MemoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, true)).ToArray();
+ Words = MemoryMarshal.Cast(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, true)).ToArray();
}
}
}
@@ -155,7 +156,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
if (beforeBarrier && commandBuffer.Type == CommandBufferType.Prefetch)
{
- commandBuffer.Fetch(_context);
+ commandBuffer.Fetch(processor.MemoryManager);
}
if (commandBuffer.Type == CommandBufferType.NoPrefetch)
@@ -182,13 +183,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
public void DispatchCalls()
{
// Use this opportunity to also dispose any pending channels that were closed.
- _context.DisposePendingChannels();
+ _context.RunDeferredActions();
// Process command buffers.
while (_ibEnable && !_interrupt && _commandBufferQueue.TryDequeue(out CommandBuffer entry))
{
_currentCommandBuffer = entry;
- _currentCommandBuffer.Fetch(_context);
+ _currentCommandBuffer.Fetch(entry.Processor.MemoryManager);
// If we are changing the current channel,
// we need to force all the host state to be updated.
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
index dc8a1c75..c683d179 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
@@ -1,4 +1,5 @@
-using Ryujinx.Graphics.Gpu.State;
+using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Gpu.State;
using System;
using System.Runtime.CompilerServices;
@@ -13,6 +14,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
private const int MacroIndexMask = MacrosCount - 1;
private readonly GpuContext _context;
+ private readonly GpuChannel _channel;
+
+ public MemoryManager MemoryManager => _channel.MemoryManager;
///
/// Internal GPFIFO state.
@@ -39,6 +43,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
public GPFifoProcessor(GpuContext context, GpuChannel channel)
{
_context = context;
+ _channel = channel;
_fifoClass = new GPFifoClass(context, this);
_subChannels = new GpuState[8];
diff --git a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
index a31ec72a..3d23b785 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
@@ -40,10 +40,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
_buffer = new int[count];
}
- ulong dstBaseAddress = _context.MemoryManager.Translate(_params.DstAddress.Pack());
+ ulong dstBaseAddress = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
// Trigger read tracking, to flush any managed resources in the destination region.
- _context.PhysicalMemory.GetSpan(dstBaseAddress, _size, true);
+ state.Channel.MemoryManager.Physical.GetSpan(dstBaseAddress, _size, true);
_finished = false;
}
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (_offset * 4 >= _size)
{
- FinishTransfer();
+ FinishTransfer(state);
}
}
}
@@ -69,15 +69,16 @@ namespace Ryujinx.Graphics.Gpu.Engine
///
/// Performs actual copy of the inline data after the transfer is finished.
///
- private void FinishTransfer()
+ /// Current GPU state
+ private void FinishTransfer(GpuState state)
{
Span data = MemoryMarshal.Cast(_buffer).Slice(0, _size);
if (_isLinear && _params.LineCount == 1)
{
- ulong address = _context.MemoryManager.Translate(_params.DstAddress.Pack());
+ ulong address = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
- _context.PhysicalMemory.Write(address, data);
+ state.Channel.MemoryManager.Physical.Write(address, data);
}
else
{
@@ -91,7 +92,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
int srcOffset = 0;
- ulong dstBaseAddress = _context.MemoryManager.Translate(_params.DstAddress.Pack());
+ ulong dstBaseAddress = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
for (int y = _params.DstY; y < _params.DstY + _params.LineCount; y++)
{
@@ -109,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
Span pixel = data.Slice(srcOffset, 16);
- _context.PhysicalMemory.Write(dstAddress, pixel);
+ state.Channel.MemoryManager.Physical.Write(dstAddress, pixel);
}
for (; x < x2; x++, srcOffset++)
@@ -120,7 +121,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
Span pixel = data.Slice(srcOffset, 1);
- _context.PhysicalMemory.Write(dstAddress, pixel);
+ state.Channel.MemoryManager.Physical.Write(dstAddress, pixel);
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs b/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs
index 0d7c272c..039ed78e 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs
@@ -1,5 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.State;
namespace Ryujinx.Graphics.Gpu.Engine
@@ -23,11 +24,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
case Condition.Never:
return ConditionalRenderEnabled.False;
case Condition.ResultNonZero:
- return CounterNonZero(condState.Address.Pack());
+ return CounterNonZero(state, condState.Address.Pack());
case Condition.Equal:
- return CounterCompare(condState.Address.Pack(), true);
+ return CounterCompare(state, condState.Address.Pack(), true);
case Condition.NotEqual:
- return CounterCompare(condState.Address.Pack(), false);
+ return CounterCompare(state, condState.Address.Pack(), false);
}
Logger.Warning?.Print(LogClass.Gpu, $"Invalid conditional render condition \"{condState.Condition}\".");
@@ -38,11 +39,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
///
/// Checks if the counter value at a given GPU memory address is non-zero.
///
+ /// GPU state
/// GPU virtual address of the counter value
/// True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering
- private ConditionalRenderEnabled CounterNonZero(ulong gpuVa)
+ private ConditionalRenderEnabled CounterNonZero(GpuState state, ulong gpuVa)
{
- ICounterEvent evt = _counterCache.FindEvent(gpuVa);
+ ICounterEvent evt = state.Channel.MemoryManager.CounterCache.FindEvent(gpuVa);
if (evt == null)
{
@@ -56,30 +58,31 @@ namespace Ryujinx.Graphics.Gpu.Engine
else
{
evt.Flush();
- return (_context.MemoryManager.Read(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
+ return (state.Channel.MemoryManager.Read(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
}
}
///
/// Checks if the counter at a given GPU memory address passes a specified equality comparison.
///
+ /// GPU state
/// GPU virtual address
/// True to check if the values are equal, false to check if they are not equal
/// True if the condition is met, false otherwise. Returns host if handling with host conditional rendering
- private ConditionalRenderEnabled CounterCompare(ulong gpuVa, bool isEqual)
+ private ConditionalRenderEnabled CounterCompare(GpuState state, ulong gpuVa, bool isEqual)
{
- ICounterEvent evt = FindEvent(gpuVa);
- ICounterEvent evt2 = FindEvent(gpuVa + 16);
+ ICounterEvent evt = FindEvent(state.Channel.MemoryManager.CounterCache, gpuVa);
+ ICounterEvent evt2 = FindEvent(state.Channel.MemoryManager.CounterCache, gpuVa + 16);
bool useHost;
if (evt != null && evt2 == null)
{
- useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt, _context.MemoryManager.Read(gpuVa + 16), isEqual);
+ useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt, state.Channel.MemoryManager.Read(gpuVa + 16), isEqual);
}
else if (evt == null && evt2 != null)
{
- useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt2, _context.MemoryManager.Read(gpuVa), isEqual);
+ useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt2, state.Channel.MemoryManager.Read(gpuVa), isEqual);
}
else if (evt != null && evt2 != null)
{
@@ -99,8 +102,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
evt?.Flush();
evt2?.Flush();
- ulong x = _context.MemoryManager.Read(gpuVa);
- ulong y = _context.MemoryManager.Read(gpuVa + 16);
+ ulong x = state.Channel.MemoryManager.Read(gpuVa);
+ ulong y = state.Channel.MemoryManager.Read(gpuVa + 16);
return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
}
@@ -110,11 +113,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// Tries to find a counter that is supposed to be written at the specified address,
/// returning the related event.
///
+ /// GPU counter cache to search on
/// GPU virtual address where the counter is supposed to be written
/// The counter event, or null if not present
- private ICounterEvent FindEvent(ulong gpuVa)
+ private static ICounterEvent FindEvent(CounterCache counterCache, ulong gpuVa)
{
- return _counterCache.FindEvent(gpuVa);
+ return counterCache.FindEvent(gpuVa);
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
index c4d8a83d..9064051a 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
@@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
return;
}
- FlushUboDirty();
+ FlushUboDirty(state.Channel.MemoryManager);
if (copy2D)
{
@@ -98,21 +98,27 @@ namespace Ryujinx.Graphics.Gpu.Engine
dst.MemoryLayout.UnpackGobBlocksInZ(),
dstBpp);
- ulong srcBaseAddress = _context.MemoryManager.Translate(cbp.SrcAddress.Pack());
- ulong dstBaseAddress = _context.MemoryManager.Translate(cbp.DstAddress.Pack());
+ ulong srcBaseAddress = state.Channel.MemoryManager.Translate(cbp.SrcAddress.Pack());
+ ulong dstBaseAddress = state.Channel.MemoryManager.Translate(cbp.DstAddress.Pack());
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, cbp.XCount, cbp.YCount);
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, cbp.XCount, cbp.YCount);
- ReadOnlySpan srcSpan = _context.PhysicalMemory.GetSpan(srcBaseAddress + (ulong)srcBaseOffset, srcSize, true);
- Span dstSpan = _context.PhysicalMemory.GetSpan(dstBaseAddress + (ulong)dstBaseOffset, dstSize).ToArray();
+ ReadOnlySpan srcSpan = state.Channel.MemoryManager.Physical.GetSpan(srcBaseAddress + (ulong)srcBaseOffset, srcSize, true);
+ Span dstSpan = state.Channel.MemoryManager.Physical.GetSpan(dstBaseAddress + (ulong)dstBaseOffset, dstSize).ToArray();
bool completeSource = IsTextureCopyComplete(cbp, src, srcLinear, srcBpp, cbp.SrcStride);
bool completeDest = IsTextureCopyComplete(cbp, dst, dstLinear, dstBpp, cbp.DstStride);
if (completeSource && completeDest)
{
- Image.Texture target = TextureCache.FindTexture(dst, cbp, swizzle, dstLinear);
+ Image.Texture target = state.Channel.MemoryManager.Physical.TextureCache.FindTexture(
+ state.Channel.MemoryManager,
+ dst,
+ cbp,
+ swizzle,
+ dstLinear);
+
if (target != null)
{
ReadOnlySpan data;
@@ -154,7 +160,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely.
- _context.PhysicalMemory.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
+ state.Channel.MemoryManager.Physical.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
return;
}
@@ -195,7 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
_ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.")
};
- _context.PhysicalMemory.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
+ state.Channel.MemoryManager.Physical.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
}
else
{
@@ -209,13 +215,21 @@ namespace Ryujinx.Graphics.Gpu.Engine
swizzle.UnpackComponentSize() == 4)
{
// Fast path for clears when remap is enabled.
- BufferCache.ClearBuffer(cbp.DstAddress, (uint)size * 4, state.Get(MethodOffset.CopyBufferConstA));
+ state.Channel.MemoryManager.Physical.BufferCache.ClearBuffer(
+ state.Channel.MemoryManager,
+ cbp.DstAddress,
+ (uint)size * 4,
+ state.Get(MethodOffset.CopyBufferConstA));
}
else
{
// TODO: Implement remap functionality.
// Buffer to buffer copy.
- BufferCache.CopyBuffer(cbp.SrcAddress, cbp.DstAddress, (uint)size);
+ state.Channel.MemoryManager.Physical.BufferCache.CopyBuffer(
+ state.Channel.MemoryManager,
+ cbp.SrcAddress,
+ cbp.DstAddress,
+ (uint)size);
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs
index d0570262..946d0dd5 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs
@@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// Method call argument
private void CopyTexture(GpuState state, int argument)
{
+ var memoryManager = state.Channel.MemoryManager;
+
var dstCopyTexture = state.Get(MethodOffset.CopyDstTexture);
var srcCopyTexture = state.Get(MethodOffset.CopySrcTexture);
@@ -80,7 +82,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
srcX1 = 0;
}
- Texture srcTexture = TextureCache.FindOrCreateTexture(srcCopyTexture, offset, srcCopyTextureFormat, true, srcHint);
+ Texture srcTexture = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ srcCopyTexture,
+ offset,
+ srcCopyTextureFormat,
+ true,
+ srcHint);
if (srcTexture == null)
{
@@ -101,7 +109,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
dstCopyTextureFormat = dstCopyTexture.Format.Convert();
}
- Texture dstTexture = TextureCache.FindOrCreateTexture(dstCopyTexture, 0, dstCopyTextureFormat, srcTexture.ScaleMode == TextureScaleMode.Scaled, dstHint);
+ Texture dstTexture = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ dstCopyTexture,
+ 0,
+ dstCopyTextureFormat,
+ srcTexture.ScaleMode == TextureScaleMode.Scaled,
+ dstHint);
if (dstTexture == null)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs b/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs
index 8320ba65..2dd0bbfa 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs
@@ -12,8 +12,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
private const int NsToTicksFractionNumerator = 384;
private const int NsToTicksFractionDenominator = 625;
- private readonly CounterCache _counterCache = new CounterCache();
-
///
/// Writes a GPU counter to guest memory.
///
@@ -39,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
var rs = state.Get(MethodOffset.ReportState);
- _context.MemoryManager.Write(rs.Address.Pack(), rs.Payload);
+ state.Channel.MemoryManager.Write(rs.Address.Pack(), rs.Payload);
_context.AdvanceSequence();
}
@@ -85,7 +83,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (counter?.Invalid != true)
{
- _context.MemoryManager.Write(gpuVa, counterData);
+ state.Channel.MemoryManager.Write(gpuVa, counterData);
}
};
@@ -105,7 +103,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
break;
}
- _counterCache.AddOrUpdate(gpuVa, counter);
+ state.Channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs
index 33533e8b..0746efa5 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs
@@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
int index = (argument >> 4) & 0x1f;
- FlushUboDirty();
+ FlushUboDirty(state.Channel.MemoryManager);
if (enable)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
index 981d2e94..1343dbe7 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
@@ -16,11 +16,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
///
/// Flushes any queued ubo updates.
///
- private void FlushUboDirty()
+ /// GPU memory manager where the uniform buffer is mapped
+ private void FlushUboDirty(MemoryManager memoryManager)
{
if (_ubFollowUpAddress != 0)
{
- BufferCache.ForceDirty(_ubFollowUpAddress - _ubByteCount, _ubByteCount);
+ memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
_ubFollowUpAddress = 0;
}
@@ -39,13 +40,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (_ubFollowUpAddress != address)
{
- FlushUboDirty();
+ FlushUboDirty(state.Channel.MemoryManager);
_ubByteCount = 0;
- _ubBeginCpuAddress = _context.MemoryManager.Translate(address);
+ _ubBeginCpuAddress = state.Channel.MemoryManager.Translate(address);
}
- _context.PhysicalMemory.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref argument, 1)));
+ var byteData = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref argument, 1));
+ state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
_ubFollowUpAddress = address + 4;
_ubByteCount += 4;
@@ -68,13 +70,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (_ubFollowUpAddress != address)
{
- FlushUboDirty();
+ FlushUboDirty(state.Channel.MemoryManager);
_ubByteCount = 0;
- _ubBeginCpuAddress = _context.MemoryManager.Translate(address);
+ _ubBeginCpuAddress = state.Channel.MemoryManager.Translate(address);
}
- _context.PhysicalMemory.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, MemoryMarshal.Cast(data));
+ var byteData = MemoryMarshal.Cast(data);
+ state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
_ubFollowUpAddress = address + size;
_ubByteCount += size;
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index 96741cd6..aaac9441 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -22,21 +22,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
private readonly GpuContext _context;
private readonly ShaderProgramInfo[] _currentProgramInfo;
- ///
- /// In-memory shader cache.
- ///
- public ShaderCache ShaderCache { get; }
-
- ///
- /// GPU buffer manager.
- ///
- public BufferCache BufferCache { get; }
-
- ///
- /// GPU texture manager.
- ///
- public TextureCache TextureCache { get; }
-
private bool _isAnyVbInstanced;
private bool _vsUsesInstanceId;
private byte _vsClipDistancesWritten;
@@ -53,16 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
_context = context;
- ShaderCache = new ShaderCache(_context);
-
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
-
- BufferCache = new BufferCache(context);
- TextureCache = new TextureCache(context);
-
- context.MemoryManager.MemoryUnmapped += _counterCache.MemoryUnmappedHandler;
- context.MemoryManager.MemoryUnmapped += TextureCache.MemoryUnmappedHandler;
- context.MemoryManager.MemoryUnmapped += BufferCache.MemoryUnmappedHandler;
}
///
@@ -130,7 +106,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
_prevTfEnable = false;
}
- FlushUboDirty();
+ FlushUboDirty(state.Channel.MemoryManager);
// Shaders must be the first one to be updated if modified, because
// some of the other state depends on information from the currently
@@ -342,7 +318,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
sbDescAddress += (ulong)sbDescOffset;
- SbDescriptor sbDescriptor = _context.PhysicalMemory.Read(sbDescAddress);
+ SbDescriptor sbDescriptor = state.Channel.MemoryManager.Physical.Read(sbDescAddress);
state.Channel.BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
}
@@ -357,6 +333,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// If this is not -1, it indicates that only the given indexed target will be used.
private void UpdateRenderTargetState(GpuState state, bool useControl, int singleUse = -1)
{
+ var memoryManager = state.Channel.MemoryManager;
var rtControl = state.Get(MethodOffset.RtControl);
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
@@ -384,7 +361,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
continue;
}
- Texture color = TextureCache.FindOrCreateTexture(colorState, samplesInX, samplesInY, sizeHint);
+ Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ colorState,
+ samplesInX,
+ samplesInY,
+ sizeHint);
changedScale |= state.Channel.TextureManager.SetRenderTargetColor(index, color);
}
@@ -398,7 +380,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
var dsState = state.Get(MethodOffset.RtDepthStencilState);
var dsSize = state.Get(MethodOffset.RtDepthStencilSize);
- depthStencil = TextureCache.FindOrCreateTexture(dsState, dsSize, samplesInX, samplesInY, sizeHint);
+ depthStencil = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ dsState,
+ dsSize,
+ samplesInX,
+ samplesInY,
+ sizeHint);
}
changedScale |= state.Channel.TextureManager.SetRenderTargetDepthStencil(depthStencil);
@@ -1012,7 +1000,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
addressesArray[index] = baseAddress + shader.Offset;
}
- ShaderBundle gs = ShaderCache.GetGraphicsShader(state, addresses);
+ ShaderBundle gs = state.Channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(state, addresses);
byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
diff --git a/Ryujinx.Graphics.Gpu/GpuChannel.cs b/Ryujinx.Graphics.Gpu/GpuChannel.cs
index 79143449..e9f08eb8 100644
--- a/Ryujinx.Graphics.Gpu/GpuChannel.cs
+++ b/Ryujinx.Graphics.Gpu/GpuChannel.cs
@@ -2,6 +2,7 @@
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory;
using System;
+using System.Threading;
namespace Ryujinx.Graphics.Gpu
{
@@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Gpu
private readonly GpuContext _context;
private readonly GPFifoDevice _device;
private readonly GPFifoProcessor _processor;
+ private MemoryManager _memoryManager;
///
/// Channel buffer bindings manager.
@@ -24,6 +26,11 @@ namespace Ryujinx.Graphics.Gpu
///
internal TextureManager TextureManager { get; }
+ ///
+ /// Current channel memory manager.
+ ///
+ internal MemoryManager MemoryManager => _memoryManager;
+
///
/// Creates a new instance of a GPU channel.
///
@@ -33,10 +40,30 @@ namespace Ryujinx.Graphics.Gpu
_context = context;
_device = context.GPFifo;
_processor = new GPFifoProcessor(context, this);
- BufferManager = new BufferManager(context);
+ BufferManager = new BufferManager(context, this);
TextureManager = new TextureManager(context, this);
}
+ ///
+ /// Binds a memory manager to the channel.
+ /// All submitted and in-flight commands will use the specified memory manager for any memory operations.
+ ///
+ /// The new memory manager to be bound
+ public void BindMemory(MemoryManager memoryManager)
+ {
+ var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, memoryManager ?? throw new ArgumentNullException(nameof(memoryManager)));
+
+ memoryManager.Physical.IncrementReferenceCount();
+
+ if (oldMemoryManager != null)
+ {
+ oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind;
+ oldMemoryManager.Physical.DecrementReferenceCount();
+ }
+
+ memoryManager.Physical.BufferCache.NotifyBuffersModified += BufferManager.Rebind;
+ }
+
///
/// Push a GPFIFO entry in the form of a prefetched command buffer.
/// It is intended to be used by nvservices to handle special cases.
@@ -62,17 +89,23 @@ namespace Ryujinx.Graphics.Gpu
///
public void Dispose()
{
- _context.DisposedChannels.Enqueue(this);
+ _context.DeferredActions.Enqueue(Destroy);
}
///
/// Performs disposal of the host GPU resources used by this channel, that are not shared.
/// This must only be called from the render thread.
///
- internal void Destroy()
+ private void Destroy()
{
- BufferManager.Dispose();
TextureManager.Dispose();
+
+ var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, null);
+ if (oldMemoryManager != null)
+ {
+ oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind;
+ oldMemoryManager.Physical.DecrementReferenceCount();
+ }
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/GpuContext.cs b/Ryujinx.Graphics.Gpu/GpuContext.cs
index 2ba832bb..7fae249e 100644
--- a/Ryujinx.Graphics.Gpu/GpuContext.cs
+++ b/Ryujinx.Graphics.Gpu/GpuContext.cs
@@ -2,8 +2,10 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Gpu.Synchronization;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
@@ -24,16 +26,6 @@ namespace Ryujinx.Graphics.Gpu
///
public IRenderer Renderer { get; }
- ///
- /// Physical memory access (it actually accesses the process memory, not actual physical memory).
- ///
- internal PhysicalMemory PhysicalMemory { get; private set; }
-
- ///
- /// GPU memory manager.
- ///
- public MemoryManager MemoryManager { get; }
-
///
/// GPU engine methods processing.
///
@@ -73,11 +65,14 @@ namespace Ryujinx.Graphics.Gpu
internal List SyncActions { get; }
///
- /// Queue with closed channels for deferred disposal from the render thread.
+ /// Queue with deferred actions that must run on the render thread.
///
- internal Queue DisposedChannels { get; }
+ internal Queue DeferredActions { get; }
- private readonly Lazy _caps;
+ ///
+ /// Registry with physical memories that can be used with this GPU context, keyed by owner process ID.
+ ///
+ internal ConcurrentDictionary PhysicalMemoryRegistry { get; }
///
/// Host hardware capabilities.
@@ -87,11 +82,9 @@ namespace Ryujinx.Graphics.Gpu
///
/// Event for signalling shader cache loading progress.
///
- public event Action ShaderCacheStateChanged
- {
- add => Methods.ShaderCache.ShaderCacheStateChanged += value;
- remove => Methods.ShaderCache.ShaderCacheStateChanged -= value;
- }
+ public event Action ShaderCacheStateChanged;
+
+ private readonly Lazy _caps;
///
/// Creates a new instance of the GPU emulation context.
@@ -101,8 +94,6 @@ namespace Ryujinx.Graphics.Gpu
{
Renderer = renderer;
- MemoryManager = new MemoryManager(this);
-
Methods = new Methods(this);
GPFifo = new GPFifoDevice(this);
@@ -111,20 +102,83 @@ namespace Ryujinx.Graphics.Gpu
Window = new Window(this);
- _caps = new Lazy(Renderer.GetCapabilities);
-
HostInitalized = new ManualResetEvent(false);
SyncActions = new List();
- DisposedChannels = new Queue();
+ DeferredActions = new Queue();
+
+ PhysicalMemoryRegistry = new ConcurrentDictionary();
+
+ _caps = new Lazy(Renderer.GetCapabilities);
}
+ ///
+ /// Creates a new GPU channel.
+ ///
+ /// The GPU channel
public GpuChannel CreateChannel()
{
return new GpuChannel(this);
}
+ ///
+ /// Creates a new GPU memory manager.
+ ///
+ /// ID of the process that owns the memory manager
+ /// The memory manager
+ /// Thrown when is invalid
+ public MemoryManager CreateMemoryManager(long pid)
+ {
+ if (!PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
+ {
+ throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
+ }
+
+ return new MemoryManager(physicalMemory);
+ }
+
+ ///
+ /// Registers virtual memory used by a process for GPU memory access, caching and read/write tracking.
+ ///
+ /// ID of the process that owns
+ /// Virtual memory owned by the process
+ /// Thrown if was already registered
+ public void RegisterProcess(long pid, Cpu.IVirtualMemoryManagerTracked cpuMemory)
+ {
+ var physicalMemory = new PhysicalMemory(this, cpuMemory);
+ if (!PhysicalMemoryRegistry.TryAdd(pid, physicalMemory))
+ {
+ throw new ArgumentException("The PID was already registered", nameof(pid));
+ }
+
+ physicalMemory.ShaderCache.ShaderCacheStateChanged += ShaderCacheStateUpdate;
+ }
+
+ ///
+ /// Unregisters a process, indicating that its memory will no longer be used, and that caches can be freed.
+ ///
+ /// ID of the process
+ public void UnregisterProcess(long pid)
+ {
+ if (PhysicalMemoryRegistry.TryRemove(pid, out var physicalMemory))
+ {
+ physicalMemory.ShaderCache.ShaderCacheStateChanged -= ShaderCacheStateUpdate;
+ physicalMemory.Dispose();
+ }
+ }
+
+ ///
+ /// Shader cache state update handler.
+ ///
+ /// Current state of the shader cache load process
+ /// Number of the current shader being processed
+ /// Total number of shaders to process
+ private void ShaderCacheStateUpdate(ShaderCacheState state, int current, int total)
+ {
+ ShaderCacheStateChanged?.Invoke(state, current, total);
+ }
+
///
/// Initialize the GPU shader cache.
///
@@ -132,7 +186,10 @@ namespace Ryujinx.Graphics.Gpu
{
HostInitalized.WaitOne();
- Methods.ShaderCache.Initialize();
+ foreach (var physicalMemory in PhysicalMemoryRegistry.Values)
+ {
+ physicalMemory.ShaderCache.Initialize();
+ }
}
///
@@ -144,16 +201,6 @@ namespace Ryujinx.Graphics.Gpu
SequenceNumber++;
}
- ///
- /// Sets the process memory manager, after the application process is initialized.
- /// This is required for any GPU memory access.
- ///
- /// CPU memory manager
- public void SetVmm(Cpu.IVirtualMemoryManagerTracked cpuMemory)
- {
- PhysicalMemory = new PhysicalMemory(cpuMemory);
- }
-
///
/// Registers an action to be performed the next time a syncpoint is incremented.
/// This will also ensure a host sync object is created, and is incremented.
@@ -186,14 +233,14 @@ namespace Ryujinx.Graphics.Gpu
}
///
- /// Performs deferred disposal of closed channels.
- /// This must only be called from the render thread.
+ /// Performs deferred actions.
+ /// This is useful for actions that must run on the render thread, such as resource disposal.
///
- internal void DisposePendingChannels()
+ internal void RunDeferredActions()
{
- while (DisposedChannels.TryDequeue(out GpuChannel channel))
+ while (DeferredActions.TryDequeue(out Action action))
{
- channel.Destroy();
+ action();
}
}
@@ -205,15 +252,19 @@ namespace Ryujinx.Graphics.Gpu
///
public void Dispose()
{
- DisposePendingChannels();
- Methods.ShaderCache.Dispose();
- Methods.BufferCache.Dispose();
- Methods.TextureCache.Dispose();
Renderer.Dispose();
GPFifo.Dispose();
HostInitalized.Dispose();
- PhysicalMemory.Dispose();
+ // Has to be disposed before processing deferred actions, as it will produce some.
+ foreach (var physicalMemory in PhysicalMemoryRegistry.Values)
+ {
+ physicalMemory.Dispose();
+ }
+
+ PhysicalMemoryRegistry.Clear();
+
+ RunDeferredActions();
}
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs
index 0b4c2993..a06a7ccf 100644
--- a/Ryujinx.Graphics.Gpu/Image/Pool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs
@@ -1,4 +1,5 @@
using Ryujinx.Cpu.Tracking;
+using Ryujinx.Graphics.Gpu.Memory;
using System;
namespace Ryujinx.Graphics.Gpu.Image
@@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image
protected const int DescriptorSize = 0x20;
protected GpuContext Context;
+ protected PhysicalMemory PhysicalMemory;
protected T1[] Items;
protected T2[] DescriptorCache;
@@ -38,9 +40,17 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly CpuMultiRegionHandle _memoryTracking;
private readonly Action _modifiedDelegate;
- public Pool(GpuContext context, ulong address, int maximumId)
+ ///
+ /// Creates a new instance of the GPU resource pool.
+ ///
+ /// GPU context that the pool belongs to
+ /// Physical memory where the resource descriptors are mapped
+ /// Address of the pool in physical memory
+ /// Maximum index of an item on the pool (inclusive)
+ public Pool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId)
{
- Context = context;
+ Context = context;
+ PhysicalMemory = physicalMemory;
MaximumId = maximumId;
int count = maximumId + 1;
@@ -53,11 +63,10 @@ namespace Ryujinx.Graphics.Gpu.Image
Address = address;
Size = size;
- _memoryTracking = context.PhysicalMemory.BeginGranularTracking(address, size);
+ _memoryTracking = physicalMemory.BeginGranularTracking(address, size);
_modifiedDelegate = RegionModified;
}
-
///
/// Gets the descriptor for a given ID.
///
@@ -65,7 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// The descriptor
public T2 GetDescriptor(int id)
{
- return Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize);
+ return PhysicalMemory.Read(Address + (ulong)id * DescriptorSize);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
index 1395aea2..aed6cb9c 100644
--- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
@@ -1,3 +1,5 @@
+using Ryujinx.Graphics.Gpu.Memory;
+
namespace Ryujinx.Graphics.Gpu.Image
{
///
@@ -11,9 +13,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the sampler pool.
///
/// GPU context that the sampler pool belongs to
+ /// Physical memory where the sampler descriptors are mapped
/// Address of the sampler pool in guest memory
/// Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)
- public SamplerPool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { }
+ public SamplerPool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId) : base(context, physicalMemory, address, maximumId) { }
///
/// Gets the sampler with the given ID.
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 0948c494..6ca15ea1 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -28,6 +28,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
private GpuContext _context;
+ private PhysicalMemory _physicalMemory;
private SizeInfo _sizeInfo;
@@ -139,6 +140,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the cached GPU texture.
///
/// GPU context that the texture belongs to
+ /// Physical memory where the texture is mapped
/// Texture information
/// Size information of the texture
/// Physical memory ranges where the texture data is located
@@ -147,16 +149,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// The floating point scale factor to initialize with
/// The scale mode to initialize with
private Texture(
- GpuContext context,
- TextureInfo info,
- SizeInfo sizeInfo,
- MultiRange range,
- int firstLayer,
- int firstLevel,
- float scaleFactor,
+ GpuContext context,
+ PhysicalMemory physicalMemory,
+ TextureInfo info,
+ SizeInfo sizeInfo,
+ MultiRange range,
+ int firstLayer,
+ int firstLevel,
+ float scaleFactor,
TextureScaleMode scaleMode)
{
- InitializeTexture(context, info, sizeInfo, range);
+ InitializeTexture(context, physicalMemory, info, sizeInfo, range);
FirstLayer = firstLayer;
FirstLevel = firstLevel;
@@ -171,16 +174,23 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the cached GPU texture.
///
/// GPU context that the texture belongs to
+ /// Physical memory where the texture is mapped
/// Texture information
/// Size information of the texture
/// Physical memory ranges where the texture data is located
/// The scale mode to initialize with. If scaled, the texture's data is loaded immediately and scaled up
- public Texture(GpuContext context, TextureInfo info, SizeInfo sizeInfo, MultiRange range, TextureScaleMode scaleMode)
+ public Texture(
+ GpuContext context,
+ PhysicalMemory physicalMemory,
+ TextureInfo info,
+ SizeInfo sizeInfo,
+ MultiRange range,
+ TextureScaleMode scaleMode)
{
ScaleFactor = 1f; // Texture is first loaded at scale 1x.
ScaleMode = scaleMode;
- InitializeTexture(context, info, sizeInfo, range);
+ InitializeTexture(context, physicalMemory, info, sizeInfo, range);
}
///
@@ -189,14 +199,21 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Other fields are initialized with their default values.
///
/// GPU context that the texture belongs to
+ /// Physical memory where the texture is mapped
/// Texture information
/// Size information of the texture
/// Physical memory ranges where the texture data is located
- private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo, MultiRange range)
+ private void InitializeTexture(
+ GpuContext context,
+ PhysicalMemory physicalMemory,
+ TextureInfo info,
+ SizeInfo sizeInfo,
+ MultiRange range)
{
- _context = context;
+ _context = context;
+ _physicalMemory = physicalMemory;
_sizeInfo = sizeInfo;
- Range = range;
+ Range = range;
SetInfo(info);
@@ -255,7 +272,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// True if the texture will have mip views
public void InitializeGroup(bool hasLayerViews, bool hasMipViews)
{
- Group = new TextureGroup(_context, this);
+ Group = new TextureGroup(_context, _physicalMemory, this);
Group.Initialize(ref _sizeInfo, hasLayerViews, hasMipViews);
}
@@ -276,6 +293,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
Texture texture = new Texture(
_context,
+ _physicalMemory,
info,
sizeInfo,
range,
@@ -638,7 +656,7 @@ namespace Ryujinx.Graphics.Gpu.Image
BlacklistScale();
}
- ReadOnlySpan data = _context.PhysicalMemory.GetSpan(Range);
+ ReadOnlySpan data = _physicalMemory.GetSpan(Range);
IsModified = false;
@@ -805,11 +823,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (tracked)
{
- _context.PhysicalMemory.Write(Range, GetTextureDataFromGpu(tracked));
+ _physicalMemory.Write(Range, GetTextureDataFromGpu(tracked));
}
else
{
- _context.PhysicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(tracked));
+ _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(tracked));
}
}
@@ -846,7 +864,7 @@ namespace Ryujinx.Graphics.Gpu.Image
texture = _flushHostTexture = GetScaledHostTexture(1f, _flushHostTexture);
}
- _context.PhysicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(false, texture));
+ _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(false, texture));
});
}
@@ -1280,7 +1298,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_viewStorage.RemoveView(this);
}
- _context.Methods.TextureCache.RemoveTextureFromCache(this);
+ _physicalMemory.TextureCache.RemoveTextureFromCache(this);
}
Debug.Assert(newRefCount >= 0);
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index 3689975d..14bc27a9 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Type of the sampler pool indexing used for bound samplers
public void SetSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
{
- ulong address = _context.MemoryManager.Translate(gpuVa);
+ ulong address = _channel.MemoryManager.Translate(gpuVa);
if (_samplerPool != null)
{
@@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_samplerPool.Dispose();
}
- _samplerPool = new SamplerPool(_context, address, maximumId);
+ _samplerPool = new SamplerPool(_context, _channel.MemoryManager.Physical, address, maximumId);
_samplerIndex = samplerIndex;
}
@@ -142,7 +142,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Maximum ID of the pool (total count minus one)
public void SetTexturePool(ulong gpuVa, int maximumId)
{
- ulong address = _context.MemoryManager.Translate(gpuVa);
+ ulong address = _channel.MemoryManager.Translate(gpuVa);
_texturePoolAddress = address;
_texturePoolMaximumId = maximumId;
@@ -228,6 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public void CommitBindings()
{
TexturePool texturePool = _texturePoolCache.FindOrCreate(
+ _channel,
_texturePoolAddress,
_texturePoolMaximumId);
@@ -437,9 +438,9 @@ namespace Ryujinx.Graphics.Gpu.Image
var poolState = state.Get(MethodOffset.TexturePoolState);
- ulong poolAddress = _context.MemoryManager.Translate(poolState.Address.Pack());
+ ulong poolAddress = _channel.MemoryManager.Translate(poolState.Address.Pack());
- TexturePool texturePool = _texturePoolCache.FindOrCreate(poolAddress, poolState.MaximumId);
+ TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, poolState.MaximumId);
return texturePool.GetDescriptor(textureId);
}
@@ -455,12 +456,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// The packed texture and sampler ID (the real texture handle)
private int ReadPackedId(int stageIndex, int wordOffset, int textureBufferIndex, int samplerBufferIndex)
{
- var bufferManager = _context.Methods.BufferCache;
ulong textureBufferAddress = _isCompute
? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
- int handle = _context.PhysicalMemory.Read(textureBufferAddress + (ulong)(wordOffset & HandleMask) * 4);
+ int handle = _channel.MemoryManager.Physical.Read(textureBufferAddress + (ulong)(wordOffset & HandleMask) * 4);
// The "wordOffset" (which is really the immediate value used on texture instructions on the shader)
// is a 13-bit value. However, in order to also support separate samplers and textures (which uses
@@ -474,7 +474,7 @@ namespace Ryujinx.Graphics.Gpu.Image
? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
- handle |= _context.PhysicalMemory.Read(samplerBufferAddress + (ulong)((wordOffset >> HandleHigh) - 1) * 4);
+ handle |= _channel.MemoryManager.Physical.Read(samplerBufferAddress + (ulong)((wordOffset >> HandleHigh) - 1) * 4);
}
return handle;
@@ -514,7 +514,6 @@ namespace Ryujinx.Graphics.Gpu.Image
public void Dispose()
{
_samplerPool?.Dispose();
- _texturePoolCache.Dispose();
}
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 24fa723a..37a2219f 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private const int OverlapsBufferMaxCapacity = 10000;
private readonly GpuContext _context;
+ private readonly PhysicalMemory _physicalMemory;
private readonly MultiRangeList _textures;
@@ -44,9 +45,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the texture manager.
///
/// The GPU context that the texture manager belongs to
- public TextureCache(GpuContext context)
+ /// Physical memory where the textures managed by this cache are mapped
+ public TextureCache(GpuContext context, PhysicalMemory physicalMemory)
{
_context = context;
+ _physicalMemory = physicalMemory;
_textures = new MultiRangeList();
@@ -68,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Image
lock (_textures)
{
- overlapCount = _textures.FindOverlaps(_context.MemoryManager.Translate(e.Address), e.Size, ref overlaps);
+ overlapCount = _textures.FindOverlaps(((MemoryManager)sender).Translate(e.Address), e.Size, ref overlaps);
}
for (int i = 0; i < overlapCount; i++)
@@ -139,13 +142,20 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Tries to find an existing texture, or create a new one if not found.
///
+ /// GPU memory manager where the texture is mapped
/// Copy texture to find or create
/// Offset to be added to the physical texture address
/// Format information of the copy texture
/// Indicates if the texture should be scaled from the start
/// A hint indicating the minimum used size for the texture
/// The texture
- public Texture FindOrCreateTexture(CopyTexture copyTexture, ulong offset, FormatInfo formatInfo, bool preferScaling = true, Size? sizeHint = null)
+ public Texture FindOrCreateTexture(
+ MemoryManager memoryManager,
+ CopyTexture copyTexture,
+ ulong offset,
+ FormatInfo formatInfo,
+ bool preferScaling = true,
+ Size? sizeHint = null)
{
int gobBlocksInY = copyTexture.MemoryLayout.UnpackGobBlocksInY();
int gobBlocksInZ = copyTexture.MemoryLayout.UnpackGobBlocksInZ();
@@ -184,7 +194,7 @@ namespace Ryujinx.Graphics.Gpu.Image
flags |= TextureSearchFlags.WithUpscale;
}
- Texture texture = FindOrCreateTexture(flags, info, 0, sizeHint);
+ Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0, sizeHint);
texture?.SynchronizeMemory();
@@ -194,12 +204,13 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Tries to find an existing texture, or create a new one if not found.
///
+ /// GPU memory manager where the texture is mapped
/// Color buffer texture to find or create
/// Number of samples in the X direction, for MSAA
/// Number of samples in the Y direction, for MSAA
/// A hint indicating the minimum used size for the texture
/// The texture
- public Texture FindOrCreateTexture(RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint)
+ public Texture FindOrCreateTexture(MemoryManager memoryManager, RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint)
{
bool isLinear = colorState.MemoryLayout.UnpackIsLinear();
@@ -263,7 +274,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int layerSize = !isLinear ? colorState.LayerSize * 4 : 0;
- Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
+ Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
texture?.SynchronizeMemory();
@@ -273,13 +284,20 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Tries to find an existing texture, or create a new one if not found.
///
+ /// GPU memory manager where the texture is mapped
/// Depth-stencil buffer texture to find or create
/// Size of the depth-stencil texture
/// Number of samples in the X direction, for MSAA
/// Number of samples in the Y direction, for MSAA
/// A hint indicating the minimum used size for the texture
/// The texture
- public Texture FindOrCreateTexture(RtDepthStencilState dsState, Size3D size, int samplesInX, int samplesInY, Size sizeHint)
+ public Texture FindOrCreateTexture(
+ MemoryManager memoryManager,
+ RtDepthStencilState dsState,
+ Size3D size,
+ int samplesInX,
+ int samplesInY,
+ Size sizeHint)
{
int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY();
int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ();
@@ -306,7 +324,7 @@ namespace Ryujinx.Graphics.Gpu.Image
target,
formatInfo);
- Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
+ Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
texture?.SynchronizeMemory();
@@ -316,13 +334,20 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Tries to find an existing texture, or create a new one if not found.
///
+ /// GPU memory manager where the texture is mapped
/// The texture search flags, defines texture comparison rules
/// Texture information of the texture to be found or created
/// Size in bytes of a single texture layer
/// A hint indicating the minimum used size for the texture
/// Optional ranges of physical memory where the texture data is located
/// The texture
- public Texture FindOrCreateTexture(TextureSearchFlags flags, TextureInfo info, int layerSize = 0, Size? sizeHint = null, MultiRange? range = null)
+ public Texture FindOrCreateTexture(
+ MemoryManager memoryManager,
+ TextureSearchFlags flags,
+ TextureInfo info,
+ int layerSize = 0,
+ Size? sizeHint = null,
+ MultiRange? range = null)
{
bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0;
@@ -342,7 +367,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
else
{
- address = _context.MemoryManager.Translate(info.GpuAddress);
+ address = memoryManager.Translate(info.GpuAddress);
if (address == MemoryManager.PteUnmapped)
{
@@ -371,22 +396,26 @@ namespace Ryujinx.Graphics.Gpu.Image
if (matchQuality != TextureMatchQuality.NoMatch)
{
// If the parameters match, we need to make sure the texture is mapped to the same memory regions.
-
- // If a range of memory was supplied, just check if the ranges match.
- if (range != null && !overlap.Range.Equals(range.Value))
+ if (range != null)
{
- continue;
+ // If a range of memory was supplied, just check if the ranges match.
+ if (!overlap.Range.Equals(range.Value))
+ {
+ continue;
+ }
}
-
- // If no range was supplied, we can check if the GPU virtual address match. If they do,
- // we know the textures are located at the same memory region.
- // If they don't, it may still be mapped to the same physical region, so we
- // do a more expensive check to tell if they are mapped into the same physical regions.
- // If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
- if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
- !_context.MemoryManager.CompareRange(overlap.Range, info.GpuAddress))
+ else
{
- continue;
+ // If no range was supplied, we can check if the GPU virtual address match. If they do,
+ // we know the textures are located at the same memory region.
+ // If they don't, it may still be mapped to the same physical region, so we
+ // do a more expensive check to tell if they are mapped into the same physical regions.
+ // If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
+ if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
+ !memoryManager.CompareRange(overlap.Range, info.GpuAddress))
+ {
+ continue;
+ }
}
}
@@ -426,7 +455,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (range == null)
{
- range = _context.MemoryManager.GetPhysicalRegions(info.GpuAddress, size);
+ range = memoryManager.GetPhysicalRegions(info.GpuAddress, size);
}
// Find view compatible matches.
@@ -495,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
// Only copy compatible. If there's another choice for a FULLY compatible texture, choose that instead.
- texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode);
+ texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
texture.InitializeGroup(true, true);
texture.InitializeData(false, false);
@@ -531,7 +560,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// No match, create a new texture.
if (texture == null)
{
- texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode);
+ texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
// Step 1: Find textures that are view compatible with the new texture.
// Any textures that are incompatible will contain garbage data, so they should be removed where possible.
@@ -722,14 +751,15 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Tries to find an existing texture matching the given buffer copy destination. If none is found, returns null.
///
+ /// GPU memory manager where the texture is mapped
/// The texture information
/// The copy buffer parameters
/// The copy buffer swizzle
/// True if the texture has a linear layout, false otherwise
/// A matching texture, or null if there is no match
- public Texture FindTexture(CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
+ public Texture FindTexture(MemoryManager memoryManager, CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
{
- ulong address = _context.MemoryManager.Translate(cbp.DstAddress.Pack());
+ ulong address = memoryManager.Translate(cbp.DstAddress.Pack());
if (address == MemoryManager.PteUnmapped)
{
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index 30ca59d4..a43eccd6 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -1,5 +1,6 @@
using Ryujinx.Cpu.Tracking;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
using Ryujinx.Memory.Range;
using System;
@@ -28,7 +29,8 @@ namespace Ryujinx.Graphics.Gpu.Image
///
public bool HasCopyDependencies { get; set; }
- private GpuContext _context;
+ private readonly GpuContext _context;
+ private readonly PhysicalMemory _physicalMemory;
private int[] _allOffsets;
private int[] _sliceSizes;
@@ -51,11 +53,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Create a new texture group.
///
/// GPU context that the texture group belongs to
+ /// Physical memory where the texture is mapped
/// The storage texture for this group
- public TextureGroup(GpuContext context, Texture storage)
+ public TextureGroup(GpuContext context, PhysicalMemory physicalMemory, Texture storage)
{
Storage = storage;
_context = context;
+ _physicalMemory = physicalMemory;
_is3D = storage.Info.Target == Target.Texture3D;
_layers = storage.Info.GetSlices();
@@ -211,7 +215,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int endOffset = (offsetIndex + 1 == _allOffsets.Length) ? (int)Storage.Size : _allOffsets[offsetIndex + 1];
int size = endOffset - offset;
- ReadOnlySpan data = _context.PhysicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
+ ReadOnlySpan data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
data = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
@@ -561,7 +565,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// A CpuRegionHandle covering the given range
private CpuRegionHandle GenerateHandle(ulong address, ulong size)
{
- return _context.PhysicalMemory.BeginTracking(address, size);
+ return _physicalMemory.BeginTracking(address, size);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index 128dd89e..bcce443c 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Image
class TexturePool : Pool
{
private int _sequenceNumber;
+ private readonly GpuChannel _channel;
private readonly ConcurrentQueue _dereferenceQueue = new ConcurrentQueue();
///
@@ -24,9 +25,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the texture pool.
///
/// GPU context that the texture pool belongs to
+ /// GPU channel that the texture pool belongs to
/// 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, ulong address, int maximumId) : base(context, address, maximumId) { }
+ public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
+ {
+ _channel = channel;
+ }
///
/// Gets the texture with the given ID.
@@ -57,7 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ProcessDereferenceQueue();
- texture = Context.Methods.TextureCache.FindOrCreateTexture(TextureSearchFlags.ForSampler, info, layerSize);
+ texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.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)
@@ -148,7 +153,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (texture != null)
{
- TextureDescriptor descriptor = Context.PhysicalMemory.Read(address);
+ TextureDescriptor descriptor = PhysicalMemory.Read(address);
// If the descriptors are the same, the texture is the same,
// we don't need to remove as it was not modified. Just continue.
@@ -214,7 +219,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
{
- if (Context.MemoryManager.IsMapped(gpuVa) && (int)format > 0)
+ if (gpuVa != 0 && (int)format > 0)
{
Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
}
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs b/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs
index c9eebf8b..99c5a88b 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs
@@ -8,13 +8,12 @@ namespace Ryujinx.Graphics.Gpu.Image
/// This can keep multiple texture pools, and return the current one as needed.
/// It is useful for applications that uses multiple texture pools.
///
- class TexturePoolCache : IDisposable
+ class TexturePoolCache
{
private const int MaxCapacity = 4;
- private GpuContext _context;
-
- private LinkedList _pools;
+ private readonly GpuContext _context;
+ private readonly LinkedList _pools;
///
/// Constructs a new instance of the texture pool.
@@ -23,17 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image
public TexturePoolCache(GpuContext context)
{
_context = context;
-
_pools = new LinkedList();
}
///
/// Finds a cache texture pool, or creates a new one if not found.
///
+ /// GPU channel that the texture pool cache belongs to
/// Start address of the texture pool
/// Maximum ID of the texture pool
/// The found or newly created texture pool
- public TexturePool FindOrCreate(ulong address, int maximumId)
+ public TexturePool FindOrCreate(GpuChannel channel, ulong address, int maximumId)
{
TexturePool pool;
@@ -56,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
// If not found, create a new one.
- pool = new TexturePool(_context, address, maximumId);
+ pool = new TexturePool(_context, channel, address, maximumId);
pool.CacheNode = _pools.AddLast(pool);
@@ -73,19 +72,5 @@ namespace Ryujinx.Graphics.Gpu.Image
return pool;
}
-
- ///
- /// Disposes the texture pool cache.
- /// It's an error to use the texture pool cache after disposal.
- ///
- public void Dispose()
- {
- foreach (TexturePool pool in _pools)
- {
- pool.Dispose();
- }
-
- _pools.Clear();
- }
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
index b4854d81..96e10e77 100644
--- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
@@ -13,9 +13,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
class Buffer : IRange, IDisposable
{
- private static ulong GranularBufferThreshold = 4096;
+ private const ulong GranularBufferThreshold = 4096;
private readonly GpuContext _context;
+ private readonly PhysicalMemory _physicalMemory;
///
/// Host buffer handle.
@@ -68,14 +69,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Creates a new instance of the buffer.
///
/// GPU context that the buffer belongs to
+ /// Physical memory where the buffer is mapped
/// Start address of the buffer
/// Size of the buffer in bytes
/// Buffers which this buffer contains, and will inherit tracking handles from
- public Buffer(GpuContext context, ulong address, ulong size, IEnumerable baseBuffers = null)
+ public Buffer(GpuContext context, PhysicalMemory physicalMemory, ulong address, ulong size, IEnumerable baseBuffers = null)
{
- _context = context;
- Address = address;
- Size = size;
+ _context = context;
+ _physicalMemory = physicalMemory;
+ Address = address;
+ Size = size;
Handle = context.Renderer.CreateBuffer((int)size);
@@ -100,11 +103,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_useGranular)
{
- _memoryTrackingGranular = context.PhysicalMemory.BeginGranularTracking(address, size, baseHandles);
+ _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, baseHandles);
}
else
{
- _memoryTracking = context.PhysicalMemory.BeginTracking(address, size);
+ _memoryTracking = physicalMemory.BeginTracking(address, size);
if (baseHandles != null)
{
@@ -207,9 +210,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else
{
- _context.Renderer.SetBufferData(Handle, 0, _context.PhysicalMemory.GetSpan(Address, (int)Size));
+ _context.Renderer.SetBufferData(Handle, 0, _physicalMemory.GetSpan(Address, (int)Size));
}
-
+
_sequenceNumber = _context.SequenceNumber;
}
}
@@ -363,7 +366,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
int offset = (int)(mAddress - Address);
- _context.Renderer.SetBufferData(Handle, offset, _context.PhysicalMemory.GetSpan(mAddress, (int)mSize));
+ _context.Renderer.SetBufferData(Handle, offset, _physicalMemory.GetSpan(mAddress, (int)mSize));
}
///
@@ -412,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
byte[] data = _context.Renderer.GetBufferData(Handle, offset, (int)size);
// TODO: When write tracking shaders, they will need to be aware of changes in overlapping buffers.
- _context.PhysicalMemory.WriteUntracked(address, data);
+ _physicalMemory.WriteUntracked(address, data);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
index eb2d08ae..b78cbdaa 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
@@ -18,7 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
private const ulong BufferAlignmentSize = 0x1000;
private const ulong BufferAlignmentMask = BufferAlignmentSize - 1;
- private GpuContext _context;
+ private readonly GpuContext _context;
+ private readonly PhysicalMemory _physicalMemory;
private readonly RangeList _buffers;
@@ -32,9 +33,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Creates a new instance of the buffer manager.
///
/// The GPU context that the buffer manager belongs to
- public BufferCache(GpuContext context)
+ /// Physical memory where the cached buffers are mapped
+ public BufferCache(GpuContext context, PhysicalMemory physicalMemory)
{
_context = context;
+ _physicalMemory = physicalMemory;
_buffers = new RangeList();
@@ -53,7 +56,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
Buffer[] overlaps = new Buffer[10];
int overlapCount;
- ulong address = _context.MemoryManager.Translate(e.Address);
+ ulong address = ((MemoryManager)sender).Translate(e.Address);
ulong size = e.Size;
lock (_buffers)
@@ -71,17 +74,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Performs address translation of the GPU virtual address, and creates a
/// new buffer, if needed, for the specified range.
///
+ /// GPU memory manager where the buffer is mapped
/// Start GPU virtual address of the buffer
/// Size in bytes of the buffer
/// CPU virtual address of the buffer, after address translation
- public ulong TranslateAndCreateBuffer(ulong gpuVa, ulong size)
+ public ulong TranslateAndCreateBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size)
{
if (gpuVa == 0)
{
return 0;
}
- ulong address = _context.MemoryManager.Translate(gpuVa);
+ ulong address = memoryManager.Translate(gpuVa);
if (address == MemoryManager.PteUnmapped)
{
@@ -122,15 +126,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// The buffer lookup for this function is cached in a dictionary for quick access, which
/// accelerates common UBO updates.
///
+ /// GPU memory manager where the buffer is mapped
/// Start GPU virtual address of the buffer
/// Size in bytes of the buffer
- public void ForceDirty(ulong gpuVa, ulong size)
+ public void ForceDirty(MemoryManager memoryManager, ulong gpuVa, ulong size)
{
- BufferCacheEntry result;
-
- if (!_dirtyCache.TryGetValue(gpuVa, out result) || result.EndGpuAddress < gpuVa + size || result.UnmappedSequence != result.Buffer.UnmappedSequence)
+ if (!_dirtyCache.TryGetValue(gpuVa, out BufferCacheEntry result) ||
+ result.EndGpuAddress < gpuVa + size ||
+ result.UnmappedSequence != result.Buffer.UnmappedSequence)
{
- ulong address = TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa, size);
result = new BufferCacheEntry(address, gpuVa, GetBuffer(address, size));
_dirtyCache[gpuVa] = result;
@@ -179,7 +184,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
}
- Buffer newBuffer = new Buffer(_context, address, endAddress - address, _bufferOverlaps.Take(overlapsCount));
+ Buffer newBuffer = new Buffer(_context, _physicalMemory, address, endAddress - address, _bufferOverlaps.Take(overlapsCount));
lock (_buffers)
{
@@ -207,7 +212,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
else
{
// No overlap, just create a new buffer.
- Buffer buffer = new Buffer(_context, address, size);
+ Buffer buffer = new Buffer(_context, _physicalMemory, address, size);
lock (_buffers)
{
@@ -235,13 +240,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// This does a GPU side copy.
///
+ /// 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(GpuVa srcVa, GpuVa dstVa, ulong size)
+ public void CopyBuffer(MemoryManager memoryManager, GpuVa srcVa, GpuVa dstVa, ulong size)
{
- ulong srcAddress = TranslateAndCreateBuffer(srcVa.Pack(), size);
- ulong dstAddress = TranslateAndCreateBuffer(dstVa.Pack(), size);
+ ulong srcAddress = TranslateAndCreateBuffer(memoryManager, srcVa.Pack(), size);
+ ulong dstAddress = TranslateAndCreateBuffer(memoryManager, dstVa.Pack(), size);
Buffer srcBuffer = GetBuffer(srcAddress, size);
Buffer dstBuffer = GetBuffer(dstAddress, size);
@@ -265,7 +271,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
// Optimization: If the data being copied is already in memory, then copy it directly instead of flushing from GPU.
dstBuffer.ClearModified(dstAddress, size);
- _context.PhysicalMemory.WriteUntracked(dstAddress, _context.PhysicalMemory.GetSpan(srcAddress, (int)size));
+ memoryManager.Physical.WriteUntracked(dstAddress, memoryManager.Physical.GetSpan(srcAddress, (int)size));
}
}
@@ -275,12 +281,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// Both the address and size must be aligned to 4 bytes.
///
+ /// GPU memory manager where the buffer is mapped
/// GPU virtual address of the region to clear
/// Number of bytes to clear
/// Value to be written into the buffer
- public void ClearBuffer(GpuVa gpuVa, ulong size, uint value)
+ public void ClearBuffer(MemoryManager memoryManager, GpuVa gpuVa, ulong size, uint value)
{
- ulong address = TranslateAndCreateBuffer(gpuVa.Pack(), size);
+ ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa.Pack(), size);
Buffer buffer = GetBuffer(address, size);
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index e43cb3b3..eccc2ca3 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -12,11 +12,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// Buffer manager.
///
- class BufferManager : IDisposable
+ class BufferManager
{
private const int StackToHeapThreshold = 16;
private readonly GpuContext _context;
+ private readonly GpuChannel _channel;
private IndexBuffer _indexBuffer;
private readonly VertexBuffer[] _vertexBuffers;
@@ -106,9 +107,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Creates a new instance of the buffer manager.
///
/// GPU context that the buffer manager belongs to
- public BufferManager(GpuContext context)
+ /// GPU channel that the buffer manager belongs to
+ public BufferManager(GpuContext context, GpuChannel channel)
{
_context = context;
+ _channel = channel;
_vertexBuffers = new VertexBuffer[Constants.TotalVertexBuffers];
@@ -127,8 +130,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
_bufferTextures = new List();
-
- context.Methods.BufferCache.NotifyBuffersModified += Rebind;
}
@@ -140,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Type of each index buffer element
public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type)
{
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
_indexBuffer.Address = address;
_indexBuffer.Size = size;
@@ -171,7 +172,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Vertex divisor of the buffer, for instanced draws
public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor)
{
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
_vertexBuffers[index].Address = address;
_vertexBuffers[index].Size = size;
@@ -199,7 +200,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Size in bytes of the transform feedback buffer
public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
{
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
_transformFeedbackBuffers[index] = new BufferBounds(address, size);
_transformFeedbackBuffersDirty = true;
@@ -219,7 +220,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
_cpStorageBuffers.SetBounds(index, address, size, flags);
}
@@ -239,7 +240,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
_gpStorageBuffers[stage].Buffers[index].Size != size)
@@ -259,7 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Size in bytes of the storage buffer
public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)
{
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
_cpUniformBuffers.SetBounds(index, address, size);
}
@@ -274,7 +275,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Size in bytes of the storage buffer
public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size)
{
- ulong address = _context.Methods.BufferCache.TranslateAndCreateBuffer(gpuVa, size);
+ ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
_gpUniformBuffers[stage].SetBounds(index, address, size);
_gpUniformBuffersDirty = true;
@@ -422,7 +423,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
// The storage buffer size is not reliable (it might be lower than the actual size),
// so we bind the entire buffer to allow otherwise out of range accesses to work.
- sRanges[bindingInfo.Binding] = _context.Methods.BufferCache.GetBufferRangeTillEnd(
+ sRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(
bounds.Address,
bounds.Size,
bounds.Flags.HasFlag(BufferUsageFlags.Write));
@@ -443,7 +444,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (bounds.Address != 0)
{
- uRanges[bindingInfo.Binding] = _context.Methods.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
+ uRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
}
}
@@ -465,7 +466,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
foreach (var binding in _bufferTextures)
{
var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
- var range = _context.Methods.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
+ var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
binding.Texture.SetStorage(range);
// The texture must be rebound to use the new storage if it was updated.
@@ -496,14 +497,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_indexBuffer.Address != 0)
{
- BufferRange buffer = _context.Methods.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
+ BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
_context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
}
}
else if (_indexBuffer.Address != 0)
{
- _context.Methods.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
+ _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
}
uint vbEnableMask = _vertexBuffersEnableMask;
@@ -523,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- BufferRange buffer = _context.Methods.BufferCache.GetBufferRange(vb.Address, vb.Size);
+ BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(vb.Address, vb.Size);
vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
}
@@ -541,7 +542,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- _context.Methods.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
+ _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
}
}
@@ -561,7 +562,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- tfbs[index] = _context.Methods.BufferCache.GetBufferRange(tfb.Address, tfb.Size);
+ tfbs[index] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(tfb.Address, tfb.Size);
}
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
@@ -577,7 +578,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- _context.Methods.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
+ _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
}
}
@@ -633,8 +634,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
ranges[bindingInfo.Binding] = isStorage
- ? _context.Methods.BufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
- : _context.Methods.BufferCache.GetBufferRange(bounds.Address, bounds.Size, isWrite);
+ ? _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
+ : _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size, isWrite);
}
}
}
@@ -670,7 +671,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- _context.Methods.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
+ _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
}
}
}
@@ -686,7 +687,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Whether the binding is for an image or a sampler
public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
{
- _context.Methods.BufferCache.CreateBuffer(address, size);
+ _channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
_bufferTextures.Add(new BufferTextureBinding(texture, address, size, bindingInfo, format, isImage));
}
@@ -698,14 +699,5 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
_rebind = true;
}
-
- ///
- /// Disposes the buffer manager.
- /// It is an error to use the buffer manager after disposal.
- ///
- public void Dispose()
- {
- _context.Methods.BufferCache.NotifyBuffersModified -= Rebind;
- }
}
}
diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 5776836c..b747b558 100644
--- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
@@ -34,15 +34,28 @@ namespace Ryujinx.Graphics.Gpu.Memory
public event EventHandler MemoryUnmapped;
- private GpuContext _context;
+ ///
+ /// Physical memory where the virtual memory is mapped into.
+ ///
+ internal PhysicalMemory Physical { get; }
+
+ ///
+ /// Cache of GPU counters.
+ ///
+ internal CounterCache CounterCache { get; }
///
/// Creates a new instance of the GPU memory manager.
///
- public MemoryManager(GpuContext context)
+ /// Physical memory that this memory manager will map into
+ internal MemoryManager(PhysicalMemory physicalMemory)
{
- _context = context;
+ Physical = physicalMemory;
+ CounterCache = new CounterCache();
_pageTable = new ulong[PtLvl0Size][];
+ MemoryUnmapped += Physical.TextureCache.MemoryUnmappedHandler;
+ MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
+ MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
}
///
@@ -67,7 +80,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
if (IsContiguous(va, size))
{
- return _context.PhysicalMemory.GetSpan(Translate(va), size, tracked);
+ return Physical.GetSpan(Translate(va), size, tracked);
}
else
{
@@ -100,7 +113,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
- _context.PhysicalMemory.GetSpan(pa, size, tracked).CopyTo(data.Slice(0, size));
+ Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(0, size));
offset += size;
}
@@ -111,7 +124,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
size = Math.Min(data.Length - offset, (int)PageSize);
- _context.PhysicalMemory.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
+ Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
}
}
@@ -125,7 +138,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
if (IsContiguous(va, size))
{
- return _context.PhysicalMemory.GetWritableRegion(Translate(va), size);
+ return Physical.GetWritableRegion(Translate(va), size);
}
else
{
@@ -155,7 +168,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// The data to be written
public void Write(ulong va, ReadOnlySpan data)
{
- WriteImpl(va, data, _context.PhysicalMemory.Write);
+ WriteImpl(va, data, Physical.Write);
}
///
@@ -165,7 +178,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// The data to be written
public void WriteUntracked(ulong va, ReadOnlySpan data)
{
- WriteImpl(va, data, _context.PhysicalMemory.WriteUntracked);
+ WriteImpl(va, data, Physical.WriteUntracked);
}
private delegate void WriteCallback(ulong address, ReadOnlySpan data);
diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
index 6463b932..289e7c1b 100644
--- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
@@ -1,5 +1,7 @@
using Ryujinx.Cpu;
using Ryujinx.Cpu.Tracking;
+using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking;
@@ -7,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Threading;
namespace Ryujinx.Graphics.Gpu.Memory
{
@@ -18,20 +21,63 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
public const int PageSize = 0x1000;
+ private readonly GpuContext _context;
private IVirtualMemoryManagerTracked _cpuMemory;
+ private int _referenceCount;
+
+ ///
+ /// In-memory shader cache.
+ ///
+ public ShaderCache ShaderCache { get; }
+
+ ///
+ /// GPU buffer manager.
+ ///
+ public BufferCache BufferCache { get; }
+
+ ///
+ /// GPU texture manager.
+ ///
+ public TextureCache TextureCache { get; }
///
/// Creates a new instance of the physical memory.
///
+ /// GPU context that the physical memory belongs to
/// CPU memory manager of the application process
- public PhysicalMemory(IVirtualMemoryManagerTracked cpuMemory)
+ public PhysicalMemory(GpuContext context, IVirtualMemoryManagerTracked cpuMemory)
{
+ _context = context;
_cpuMemory = cpuMemory;
+ ShaderCache = new ShaderCache(context);
+ BufferCache = new BufferCache(context, this);
+ TextureCache = new TextureCache(context, this);
- if (_cpuMemory is IRefCounted rc)
+ if (cpuMemory is IRefCounted rc)
{
rc.IncrementReferenceCount();
}
+
+ _referenceCount = 1;
+ }
+
+ ///
+ /// Increments the memory reference count.
+ ///
+ public void IncrementReferenceCount()
+ {
+ Interlocked.Increment(ref _referenceCount);
+ }
+
+ ///
+ /// Decrements the memory reference count.
+ ///
+ public void DecrementReferenceCount()
+ {
+ if (Interlocked.Decrement(ref _referenceCount) == 0 && _cpuMemory is IRefCounted rc)
+ {
+ rc.DecrementReferenceCount();
+ }
}
///
@@ -147,7 +193,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Ranges of physical memory where the data is located
/// Data to be written
/// Callback method that will perform the write
- private void WriteImpl(MultiRange range, ReadOnlySpan data, WriteCallback writeCallback)
+ private static void WriteImpl(MultiRange range, ReadOnlySpan data, WriteCallback writeCallback)
{
if (range.Count == 1)
{
@@ -227,12 +273,20 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
public void Dispose()
{
- if (_cpuMemory is IRefCounted rc)
- {
- rc.DecrementReferenceCount();
+ _context.DeferredActions.Enqueue(Destroy);
+ }
- _cpuMemory = null;
- }
+ ///
+ /// Performs disposal of the host GPU caches with resources mapped on this physical memory.
+ /// This must only be called from the render thread.
+ ///
+ private void Destroy()
+ {
+ ShaderCache.Dispose();
+ BufferCache.Dispose();
+ TextureCache.Dispose();
+
+ DecrementReferenceCount();
}
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
index 4381301b..62368c1c 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
@@ -79,7 +79,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Data at the memory location
public override T MemoryRead(ulong address)
{
- return _context.MemoryManager.Read(address);
+ return _state.Channel.MemoryManager.Read(address);
}
///
@@ -89,7 +89,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// True if the address is mapped, false otherwise
public bool MemoryMapped(ulong address)
{
- return _context.MemoryManager.IsMapped(address);
+ return _state.Channel.MemoryManager.IsMapped(address);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 72ae0b10..efb0503c 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.Shader.Cache;
using Ryujinx.Graphics.Gpu.Shader.Cache.Definition;
using Ryujinx.Graphics.Gpu.State;
@@ -492,7 +493,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
foreach (ShaderBundle cachedCpShader in list)
{
- if (IsShaderEqual(cachedCpShader, gpuVa))
+ if (IsShaderEqual(state.Channel.MemoryManager, cachedCpShader, gpuVa))
{
return cachedCpShader;
}
@@ -527,7 +528,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
// Compute hash and prepare data for shader disk cache comparison.
- shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts);
+ shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(state.Channel.MemoryManager, shaderContexts);
programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries);
}
@@ -542,7 +543,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
// The shader isn't currently cached, translate it and compile it.
- ShaderCodeHolder shader = TranslateShader(shaderContexts[0]);
+ ShaderCodeHolder shader = TranslateShader(state.Channel.MemoryManager, shaderContexts[0]);
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
@@ -595,7 +596,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
foreach (ShaderBundle cachedGpShaders in list)
{
- if (IsShaderEqual(cachedGpShaders, addresses))
+ if (IsShaderEqual(state.Channel.MemoryManager, cachedGpShaders, addresses))
{
return cachedGpShaders;
}
@@ -647,7 +648,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
// Compute hash and prepare data for shader disk cache comparison.
- shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts);
+ shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(state.Channel.MemoryManager, shaderContexts);
programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd);
}
@@ -664,11 +665,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
// The shader isn't currently cached, translate it and compile it.
ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages];
- shaders[0] = TranslateShader(shaderContexts[1], shaderContexts[0]);
- shaders[1] = TranslateShader(shaderContexts[2]);
- shaders[2] = TranslateShader(shaderContexts[3]);
- shaders[3] = TranslateShader(shaderContexts[4]);
- shaders[4] = TranslateShader(shaderContexts[5]);
+ shaders[0] = TranslateShader(state.Channel.MemoryManager, shaderContexts[1], shaderContexts[0]);
+ shaders[1] = TranslateShader(state.Channel.MemoryManager, shaderContexts[2]);
+ shaders[2] = TranslateShader(state.Channel.MemoryManager, shaderContexts[3]);
+ shaders[3] = TranslateShader(state.Channel.MemoryManager, shaderContexts[4]);
+ shaders[4] = TranslateShader(state.Channel.MemoryManager, shaderContexts[5]);
List hostShaders = new List();
@@ -724,7 +725,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Current GPU state
/// Four transform feedback descriptors for the enabled TFBs, or null if TFB is disabled
- private TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(GpuState state)
+ private static TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(GpuState state)
{
bool tfEnable = state.Get(MethodOffset.TfEnable);
@@ -752,21 +753,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Checks if compute shader code in memory is equal to the cached shader.
///
+ /// Memory manager used to access the GPU memory where the shader is located
/// Cached compute shader
/// GPU virtual address of the shader code in memory
/// True if the code is different, false otherwise
- private bool IsShaderEqual(ShaderBundle cpShader, ulong gpuVa)
+ private static bool IsShaderEqual(MemoryManager memoryManager, ShaderBundle cpShader, ulong gpuVa)
{
- return IsShaderEqual(cpShader.Shaders[0], gpuVa);
+ return IsShaderEqual(memoryManager, cpShader.Shaders[0], gpuVa);
}
///
/// Checks if graphics shader code from all stages in memory are equal to the cached shaders.
///
+ /// Memory manager used to access the GPU memory where the shader is located
/// Cached graphics shaders
/// GPU virtual addresses of all enabled shader stages
/// True if the code is different, false otherwise
- private bool IsShaderEqual(ShaderBundle gpShaders, ShaderAddresses addresses)
+ private static bool IsShaderEqual(MemoryManager memoryManager, ShaderBundle gpShaders, ShaderAddresses addresses)
{
for (int stage = 0; stage < gpShaders.Shaders.Length; stage++)
{
@@ -783,7 +786,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
case 4: gpuVa = addresses.Fragment; break;
}
- if (!IsShaderEqual(shader, gpuVa, addresses.VertexA))
+ if (!IsShaderEqual(memoryManager, shader, gpuVa, addresses.VertexA))
{
return false;
}
@@ -795,24 +798,25 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Checks if the code of the specified cached shader is different from the code in memory.
///
+ /// Memory manager used to access the GPU memory where the shader is located
/// Cached shader to compare with
/// GPU virtual address of the binary shader code
/// Optional GPU virtual address of the "Vertex A" binary shader code
/// True if the code is different, false otherwise
- private bool IsShaderEqual(ShaderCodeHolder shader, ulong gpuVa, ulong gpuVaA = 0)
+ private static bool IsShaderEqual(MemoryManager memoryManager, ShaderCodeHolder shader, ulong gpuVa, ulong gpuVaA = 0)
{
if (shader == null)
{
return true;
}
- ReadOnlySpan memoryCode = _context.MemoryManager.GetSpan(gpuVa, shader.Code.Length);
+ ReadOnlySpan memoryCode = memoryManager.GetSpan(gpuVa, shader.Code.Length);
bool equals = memoryCode.SequenceEqual(shader.Code);
if (equals && shader.Code2 != null)
{
- memoryCode = _context.MemoryManager.GetSpan(gpuVaA, shader.Code2.Length);
+ memoryCode = memoryManager.GetSpan(gpuVaA, shader.Code2.Length);
equals = memoryCode.SequenceEqual(shader.Code2);
}
@@ -882,10 +886,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Translates a previously generated translator context to something that the host API accepts.
///
+ /// Memory manager used to access the GPU memory where the shader is located
/// Current translator context to translate
/// Optional translator context of the shader that should be combined
/// Compiled graphics shader code
- private ShaderCodeHolder TranslateShader(TranslatorContext translatorContext, TranslatorContext translatorContext2 = null)
+ private ShaderCodeHolder TranslateShader(
+ MemoryManager memoryManager,
+ TranslatorContext translatorContext,
+ TranslatorContext translatorContext2 = null)
{
if (translatorContext == null)
{
@@ -894,8 +902,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
if (translatorContext2 != null)
{
- byte[] codeA = _context.MemoryManager.GetSpan(translatorContext2.Address, translatorContext2.Size).ToArray();
- byte[] codeB = _context.MemoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray();
+ byte[] codeA = memoryManager.GetSpan(translatorContext2.Address, translatorContext2.Size).ToArray();
+ byte[] codeB = memoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray();
_dumper.Dump(codeA, compute: false, out string fullPathA, out string codePathA);
_dumper.Dump(codeB, compute: false, out string fullPathB, out string codePathB);
@@ -914,7 +922,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
else
{
- byte[] code = _context.MemoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray();
+ byte[] code = memoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray();
_dumper.Dump(code, translatorContext.Stage == ShaderStage.Compute, out string fullPath, out string codePath);
diff --git a/Ryujinx.Graphics.Gpu/Window.cs b/Ryujinx.Graphics.Gpu/Window.cs
index 28cc17ed..541a80cc 100644
--- a/Ryujinx.Graphics.Gpu/Window.cs
+++ b/Ryujinx.Graphics.Gpu/Window.cs
@@ -22,6 +22,11 @@ namespace Ryujinx.Graphics.Gpu
///
private struct PresentationTexture
{
+ ///
+ /// Texture cache where the texture might be located.
+ ///
+ public TextureCache Cache { get; }
+
///
/// Texture information.
///
@@ -55,6 +60,7 @@ namespace Ryujinx.Graphics.Gpu
///
/// Creates a new instance of the presentation texture.
///
+ /// Texture cache used to look for the texture to be presented
/// Information of the texture to be presented
/// Physical memory locations where the texture data is located
/// Texture crop region
@@ -62,6 +68,7 @@ namespace Ryujinx.Graphics.Gpu
/// Texture release callback
/// User defined object passed to the release callback, can be used to identify the texture
public PresentationTexture(
+ TextureCache cache,
TextureInfo info,
MultiRange range,
ImageCrop crop,
@@ -69,6 +76,7 @@ namespace Ryujinx.Graphics.Gpu
Action
+ /// Process ID of the process that owns the texture pointed to by
/// CPU virtual address of the texture data
/// Texture width
/// Texture height
@@ -111,7 +120,9 @@ namespace Ryujinx.Graphics.Gpu
/// Texture acquire callback
/// Texture release callback
/// User defined object passed to the release callback
+ /// Thrown when is invalid
public void EnqueueFrameThreadSafe(
+ long pid,
ulong address,
int width,
int height,
@@ -125,6 +136,11 @@ namespace Ryujinx.Graphics.Gpu
Action