aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory')
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/Buffer.cs37
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs34
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs10
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs33
4 files changed, 92 insertions, 22 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
index af69e693..76125e31 100644
--- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common.Logging;
using Ryujinx.Cpu.Tracking;
using Ryujinx.Graphics.GAL;
using Ryujinx.Memory.Range;
@@ -104,6 +105,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_useGranular)
{
_memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, baseHandles);
+
+ _memoryTrackingGranular.RegisterPreciseAction(address, size, PreciseAction);
}
else
{
@@ -123,6 +126,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
handle.Dispose();
}
}
+
+ _memoryTracking.RegisterPreciseAction(PreciseAction);
}
_externalFlushDelegate = new RegionSignal(ExternalFlush);
@@ -453,6 +458,38 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
+ /// An action to be performed when a precise memory access occurs to this resource.
+ /// For buffers, this skips flush-on-write by punching holes directly into the modified range list.
+ /// </summary>
+ /// <param name="address">Address of the memory action</param>
+ /// <param name="size">Size in bytes</param>
+ /// <param name="write">True if the access was a write, false otherwise</param>
+ private bool PreciseAction(ulong address, ulong size, bool write)
+ {
+ if (!write)
+ {
+ // We only want to skip flush-on-write.
+ return false;
+ }
+
+ if (address < Address)
+ {
+ address = Address;
+ }
+
+ ulong maxSize = Address + Size - address;
+
+ if (size > maxSize)
+ {
+ size = maxSize;
+ }
+
+ ForceDirty(address, size);
+
+ return true;
+ }
+
+ /// <summary>
/// Called when part of the memory for this buffer has been unmapped.
/// Calls are from non-GPU threads.
/// </summary>
diff --git a/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs b/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs
index 8a9c6767..bc07bfad 100644
--- a/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs
@@ -4,6 +4,9 @@ using System;
namespace Ryujinx.Graphics.Gpu.Memory
{
+ /// <summary>
+ /// A tracking handle for a region of GPU VA, represented by one or more tracking handles in CPU VA.
+ /// </summary>
class GpuRegionHandle : IRegionHandle
{
private readonly CpuRegionHandle[] _cpuRegionHandles;
@@ -28,11 +31,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
public ulong Size => throw new NotSupportedException();
public ulong EndAddress => throw new NotSupportedException();
+ /// <summary>
+ /// Create a new GpuRegionHandle, made up of mulitple CpuRegionHandles.
+ /// </summary>
+ /// <param name="cpuRegionHandles">The CpuRegionHandles that make up this handle</param>
public GpuRegionHandle(CpuRegionHandle[] cpuRegionHandles)
{
_cpuRegionHandles = cpuRegionHandles;
}
+ /// <summary>
+ /// Dispose the child handles.
+ /// </summary>
public void Dispose()
{
foreach (var regionHandle in _cpuRegionHandles)
@@ -41,6 +51,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
}
+ /// <summary>
+ /// Register an action to perform when the tracked region is read or written.
+ /// The action is automatically removed after it runs.
+ /// </summary>
+ /// <param name="action">Action to call on read or write</param>
public void RegisterAction(RegionSignal action)
{
foreach (var regionHandle in _cpuRegionHandles)
@@ -49,6 +64,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
}
+ /// <summary>
+ /// Register an action to perform when a precise access occurs (one with exact address and size).
+ /// If the action returns true, read/write tracking are skipped.
+ /// </summary>
+ /// <param name="action">Action to call on read or write</param>
+ public void RegisterPreciseAction(PreciseRegionSignal action)
+ {
+ foreach (var regionHandle in _cpuRegionHandles)
+ {
+ regionHandle.RegisterPreciseAction(action);
+ }
+ }
+
+ /// <summary>
+ /// Consume the dirty flag for the handles, and reprotect so it can be set on the next write.
+ /// </summary>
public void Reprotect(bool asDirty = false)
{
foreach (var regionHandle in _cpuRegionHandles)
@@ -57,6 +88,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
}
+ /// <summary>
+ /// Force the handles to be dirty, without reprotecting.
+ /// </summary>
public void ForceDirty()
{
foreach (var regionHandle in _cpuRegionHandles)
diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 2dc1edd2..3968cb96 100644
--- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
@@ -195,6 +195,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
+ /// Writes data to GPU mapped memory, destined for a tracked resource.
+ /// </summary>
+ /// <param name="va">GPU virtual address to write the data into</param>
+ /// <param name="data">The data to be written</param>
+ public void WriteTrackedResource(ulong va, ReadOnlySpan<byte> data)
+ {
+ WriteImpl(va, data, Physical.WriteTrackedResource);
+ }
+
+ /// <summary>
/// Writes data to GPU mapped memory without write tracking.
/// </summary>
/// <param name="va">GPU virtual address to write the data into</param>
diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
index 0ec41a8f..d292fab0 100644
--- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
@@ -81,28 +81,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Write data to memory that is destined for a resource in a cache.
- /// This avoids triggering write tracking when possible, which can avoid flushes and incrementing sequence number.
- /// </summary>
- /// <param name="memoryManager">The GPU memory manager</param>
- /// <param name="gpuVa">GPU virtual address to write the data into</param>
- /// <param name="data">The data to be written</param>
- public void CacheResourceWrite(MemoryManager memoryManager, ulong gpuVa, ReadOnlySpan<byte> data)
- {
- if (TextureCache.IsTextureInRange(memoryManager, gpuVa, (ulong)data.Length))
- {
- // No fast path yet - copy the data back and trigger write tracking.
- memoryManager.Write(gpuVa, data);
- _context.AdvanceSequence();
- }
- else
- {
- BufferCache.ForceDirty(memoryManager, gpuVa, (ulong)data.Length);
- memoryManager.WriteUntracked(gpuVa, data);
- }
- }
-
- /// <summary>
/// Gets a span of data from the application process.
/// </summary>
/// <param name="address">Start address of the range</param>
@@ -180,6 +158,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
+ /// Writes data to the application process, triggering a precise memory tracking event.
+ /// </summary>
+ /// <param name="address">Address to write into</param>
+ /// <param name="data">Data to be written</param>
+ public void WriteTrackedResource(ulong address, ReadOnlySpan<byte> data)
+ {
+ _cpuMemory.SignalMemoryTracking(address, (ulong)data.Length, true, precise: true);
+ _cpuMemory.WriteUntracked(address, data);
+ }
+
+ /// <summary>
/// Writes data to the application process.
/// </summary>
/// <param name="address">Address to write into</param>