diff --git a/ARMeilleure/Memory/IMemoryManager.cs b/ARMeilleure/Memory/IMemoryManager.cs
index c4ea70d1..5eb1fadd 100644
--- a/ARMeilleure/Memory/IMemoryManager.cs
+++ b/ARMeilleure/Memory/IMemoryManager.cs
@@ -71,6 +71,7 @@ namespace ARMeilleure.Memory
/// Size of the region
/// True if the region was written, false if read
/// True if the access is precise, false otherwise
- void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false);
+ /// Optional ID of the handles that should not be signalled
+ void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null);
}
}
\ No newline at end of file
diff --git a/ARMeilleure/Signal/NativeSignalHandler.cs b/ARMeilleure/Signal/NativeSignalHandler.cs
index 77eabe26..cddeb817 100644
--- a/ARMeilleure/Signal/NativeSignalHandler.cs
+++ b/ARMeilleure/Signal/NativeSignalHandler.cs
@@ -222,7 +222,7 @@ namespace ARMeilleure.Signal
// Tracking action should be non-null to call it, otherwise assume false return.
context.BranchIfFalse(skipActionLabel, trackingActionPtr);
- Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite, Const(0));
+ Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite);
context.Copy(inRegionLocal, result);
context.MarkLabel(skipActionLabel);
diff --git a/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs
index 222dcae1..437e02ae 100644
--- a/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs
+++ b/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs
@@ -634,13 +634,13 @@ namespace Ryujinx.Cpu.AppleHv
///
/// This function also validates that the given range is both valid and mapped, and will throw if it is not.
///
- public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false)
+ public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
AssertValidAddressAndSize(va, size);
if (precise)
{
- Tracking.VirtualMemoryEvent(va, size, write, precise: true);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: true, exemptId);
return;
}
@@ -663,7 +663,7 @@ namespace Ryujinx.Cpu.AppleHv
if (state >= tag)
{
- Tracking.VirtualMemoryEvent(va, size, write);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId);
return;
}
else if (state == 0)
@@ -706,7 +706,7 @@ namespace Ryujinx.Cpu.AppleHv
// Only trigger tracking from reads if both bits are set on any page.
if (write || (pte & (pte >> 1) & BlockMappedMask) != 0)
{
- Tracking.VirtualMemoryEvent(va, size, write);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId);
break;
}
}
@@ -822,21 +822,21 @@ namespace Ryujinx.Cpu.AppleHv
}
///
- public CpuRegionHandle BeginTracking(ulong address, ulong size)
+ public CpuRegionHandle BeginTracking(ulong address, ulong size, int id)
{
- return new CpuRegionHandle(Tracking.BeginTracking(address, size));
+ return new CpuRegionHandle(Tracking.BeginTracking(address, size, id));
}
///
- public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity)
+ public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id)
{
- return new CpuMultiRegionHandle(Tracking.BeginGranularTracking(address, size, handles, granularity));
+ return new CpuMultiRegionHandle(Tracking.BeginGranularTracking(address, size, handles, granularity, id));
}
///
- public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity)
+ public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
{
- return new CpuSmartMultiRegionHandle(Tracking.BeginSmartGranularTracking(address, size, granularity));
+ return new CpuSmartMultiRegionHandle(Tracking.BeginSmartGranularTracking(address, size, granularity, id));
}
///
diff --git a/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs b/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs
index 8004d39b..92d3c76c 100644
--- a/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs
+++ b/Ryujinx.Cpu/IVirtualMemoryManagerTracked.cs
@@ -28,8 +28,9 @@ namespace Ryujinx.Cpu
///
/// CPU virtual address of the region
/// Size of the region
+ /// Handle ID
/// The memory tracking handle
- CpuRegionHandle BeginTracking(ulong address, ulong size);
+ CpuRegionHandle BeginTracking(ulong address, ulong size, int id);
///
/// Obtains a memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with.
@@ -38,8 +39,9 @@ namespace Ryujinx.Cpu
/// Size of the region
/// Handles to inherit state from or reuse. When none are present, provide null
/// Desired granularity of write tracking
+ /// Handle ID
/// The memory tracking handle
- CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity);
+ CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id);
///
/// Obtains a smart memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with.
@@ -47,7 +49,8 @@ namespace Ryujinx.Cpu
/// CPU virtual address of the region
/// Size of the region
/// Desired granularity of write tracking
+ /// Handle ID
/// The memory tracking handle
- CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity);
+ CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id);
}
}
diff --git a/Ryujinx.Cpu/Jit/MemoryManager.cs b/Ryujinx.Cpu/Jit/MemoryManager.cs
index 014d843b..8542d53e 100644
--- a/Ryujinx.Cpu/Jit/MemoryManager.cs
+++ b/Ryujinx.Cpu/Jit/MemoryManager.cs
@@ -629,31 +629,31 @@ namespace Ryujinx.Cpu.Jit
}
///
- public CpuRegionHandle BeginTracking(ulong address, ulong size)
+ public CpuRegionHandle BeginTracking(ulong address, ulong size, int id)
{
- return new CpuRegionHandle(Tracking.BeginTracking(address, size));
+ return new CpuRegionHandle(Tracking.BeginTracking(address, size, id));
}
///
- public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity)
+ public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id)
{
- return new CpuMultiRegionHandle(Tracking.BeginGranularTracking(address, size, handles, granularity));
+ return new CpuMultiRegionHandle(Tracking.BeginGranularTracking(address, size, handles, granularity, id));
}
///
- public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity)
+ public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
{
- return new CpuSmartMultiRegionHandle(Tracking.BeginSmartGranularTracking(address, size, granularity));
+ return new CpuSmartMultiRegionHandle(Tracking.BeginSmartGranularTracking(address, size, granularity, id));
}
///
- public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false)
+ public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
AssertValidAddressAndSize(va, size);
if (precise)
{
- Tracking.VirtualMemoryEvent(va, size, write, precise: true);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: true, exemptId);
return;
}
@@ -676,7 +676,7 @@ namespace Ryujinx.Cpu.Jit
if ((pte & tag) != 0)
{
- Tracking.VirtualMemoryEvent(va, size, write);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId);
break;
}
diff --git a/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs
index 856b6b9b..090740ab 100644
--- a/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs
+++ b/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs
@@ -518,13 +518,13 @@ namespace Ryujinx.Cpu.Jit
///
/// This function also validates that the given range is both valid and mapped, and will throw if it is not.
///
- public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false)
+ public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
AssertValidAddressAndSize(va, size);
if (precise)
{
- Tracking.VirtualMemoryEvent(va, size, write, precise: true);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: true, exemptId);
return;
}
@@ -547,7 +547,7 @@ namespace Ryujinx.Cpu.Jit
if (state >= tag)
{
- Tracking.VirtualMemoryEvent(va, size, write);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId);
return;
}
else if (state == 0)
@@ -590,7 +590,7 @@ namespace Ryujinx.Cpu.Jit
// Only trigger tracking from reads if both bits are set on any page.
if (write || (pte & (pte >> 1) & BlockMappedMask) != 0)
{
- Tracking.VirtualMemoryEvent(va, size, write);
+ Tracking.VirtualMemoryEvent(va, size, write, precise: false, exemptId);
break;
}
}
@@ -706,21 +706,21 @@ namespace Ryujinx.Cpu.Jit
}
///
- public CpuRegionHandle BeginTracking(ulong address, ulong size)
+ public CpuRegionHandle BeginTracking(ulong address, ulong size, int id)
{
- return new CpuRegionHandle(Tracking.BeginTracking(address, size));
+ return new CpuRegionHandle(Tracking.BeginTracking(address, size, id));
}
///
- public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity)
+ public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id)
{
- return new CpuMultiRegionHandle(Tracking.BeginGranularTracking(address, size, handles, granularity));
+ return new CpuMultiRegionHandle(Tracking.BeginGranularTracking(address, size, handles, granularity, id));
}
///
- public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity)
+ public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
{
- return new CpuSmartMultiRegionHandle(Tracking.BeginSmartGranularTracking(address, size, granularity));
+ return new CpuSmartMultiRegionHandle(Tracking.BeginSmartGranularTracking(address, size, granularity, id));
}
///
diff --git a/Ryujinx.Cpu/MemoryEhMeilleure.cs b/Ryujinx.Cpu/MemoryEhMeilleure.cs
index 806ef811..0b434ea7 100644
--- a/Ryujinx.Cpu/MemoryEhMeilleure.cs
+++ b/Ryujinx.Cpu/MemoryEhMeilleure.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Cpu
{
public class MemoryEhMeilleure : IDisposable
{
- private delegate bool TrackingEventDelegate(ulong address, ulong size, bool write, bool precise = false);
+ private delegate bool TrackingEventDelegate(ulong address, ulong size, bool write);
private readonly MemoryTracking _tracking;
private readonly TrackingEventDelegate _trackingEvent;
diff --git a/Ryujinx.Graphics.Gpu/Image/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs
index ee4c051f..3e557c0b 100644
--- a/Ryujinx.Graphics.Gpu/Image/Pool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs
@@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gpu.Image
Address = address;
Size = size;
- _memoryTracking = physicalMemory.BeginGranularTracking(address, size);
+ _memoryTracking = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Pool);
_memoryTracking.RegisterPreciseAction(address, size, PreciseAction);
_modifiedDelegate = RegionModified;
}
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index 1040b394..12a640e1 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -854,7 +854,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// A CpuRegionHandle covering the given range
private CpuRegionHandle GenerateHandle(ulong address, ulong size)
{
- return _physicalMemory.BeginTracking(address, size);
+ return _physicalMemory.BeginTracking(address, size, ResourceKind.Texture);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
index a624386e..3778cd82 100644
--- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
@@ -105,13 +105,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_useGranular)
{
- _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, baseHandles);
+ _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Buffer, baseHandles);
_memoryTrackingGranular.RegisterPreciseAction(address, size, PreciseAction);
}
else
{
- _memoryTracking = physicalMemory.BeginTracking(address, size);
+ _memoryTracking = physicalMemory.BeginTracking(address, size, ResourceKind.Buffer);
if (baseHandles != null)
{
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
index 00f59083..a5a9b75e 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
@@ -368,7 +368,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
_context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)size, value);
- buffer.SignalModified(address, size);
+ memoryManager.Physical.FillTrackedResource(address, size, value, ResourceKind.Buffer);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
index c1fc0c5c..bd33383e 100644
--- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
@@ -7,6 +7,7 @@ using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking;
using System;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Graphics.Gpu.Memory
@@ -295,23 +296,41 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
}
+ ///
+ /// Fills the specified memory region with a 32-bit integer value.
+ ///
+ /// CPU virtual address of the region
+ /// Size of the region
+ /// Value to fill the region with
+ /// Kind of the resource being filled, which will not be signalled as CPU modified
+ public void FillTrackedResource(ulong address, ulong size, uint value, ResourceKind kind)
+ {
+ _cpuMemory.SignalMemoryTracking(address, size, write: true, precise: true, (int)kind);
+
+ using WritableRegion region = _cpuMemory.GetWritableRegion(address, (int)size);
+
+ MemoryMarshal.Cast(region.Memory.Span).Fill(value);
+ }
+
///
/// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with.
///
/// CPU virtual address of the region
/// Size of the region
+ /// Kind of the resource being tracked
/// The memory tracking handle
- public CpuRegionHandle BeginTracking(ulong address, ulong size)
+ public CpuRegionHandle BeginTracking(ulong address, ulong size, ResourceKind kind)
{
- return _cpuMemory.BeginTracking(address, size);
+ return _cpuMemory.BeginTracking(address, size, (int)kind);
}
///
/// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with.
///
/// Ranges of physical memory where the data is located
+ /// Kind of the resource being tracked
/// The memory tracking handle
- public GpuRegionHandle BeginTracking(MultiRange range)
+ public GpuRegionHandle BeginTracking(MultiRange range, ResourceKind kind)
{
var cpuRegionHandles = new CpuRegionHandle[range.Count];
int count = 0;
@@ -321,7 +340,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
var currentRange = range.GetSubRange(i);
if (currentRange.Address != MemoryManager.PteUnmapped)
{
- cpuRegionHandles[count++] = _cpuMemory.BeginTracking(currentRange.Address, currentRange.Size);
+ cpuRegionHandles[count++] = _cpuMemory.BeginTracking(currentRange.Address, currentRange.Size, (int)kind);
}
}
@@ -338,12 +357,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// CPU virtual address of the region
/// Size of the region
+ /// Kind of the resource being tracked
/// Handles to inherit state from or reuse
/// Desired granularity of write tracking
/// The memory tracking handle
- public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles = null, ulong granularity = 4096)
+ public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, ResourceKind kind, IEnumerable handles = null, ulong granularity = 4096)
{
- return _cpuMemory.BeginGranularTracking(address, size, handles, granularity);
+ return _cpuMemory.BeginGranularTracking(address, size, handles, granularity, (int)kind);
}
///
@@ -351,11 +371,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// CPU virtual address of the region
/// Size of the region
+ /// Kind of the resource being tracked
/// Desired granularity of write tracking
/// The memory tracking handle
- public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity = 4096)
+ public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ResourceKind kind, ulong granularity = 4096)
{
- return _cpuMemory.BeginSmartGranularTracking(address, size, granularity);
+ return _cpuMemory.BeginSmartGranularTracking(address, size, granularity, (int)kind);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs b/Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs
new file mode 100644
index 00000000..55d697b8
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+ ///
+ /// Kind of a GPU resource.
+ ///
+ enum ResourceKind
+ {
+ None,
+ Buffer,
+ Texture,
+ Pool
+ }
+}
diff --git a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
index 06eb4729..6729f4a3 100644
--- a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
+++ b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
@@ -96,7 +96,7 @@ namespace Ryujinx.Memory.Tests
throw new NotImplementedException();
}
- public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false)
+ public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
throw new NotImplementedException();
}
diff --git a/Ryujinx.Memory.Tests/MultiRegionTrackingTests.cs b/Ryujinx.Memory.Tests/MultiRegionTrackingTests.cs
index c607464d..38cb4921 100644
--- a/Ryujinx.Memory.Tests/MultiRegionTrackingTests.cs
+++ b/Ryujinx.Memory.Tests/MultiRegionTrackingTests.cs
@@ -34,8 +34,8 @@ namespace Ryujinx.Memory.Tests
private IMultiRegionHandle GetGranular(bool smart, ulong address, ulong size, ulong granularity)
{
return smart ?
- _tracking.BeginSmartGranularTracking(address, size, granularity) :
- (IMultiRegionHandle)_tracking.BeginGranularTracking(address, size, null, granularity);
+ _tracking.BeginSmartGranularTracking(address, size, granularity, 0) :
+ (IMultiRegionHandle)_tracking.BeginGranularTracking(address, size, null, granularity, 0);
}
private void RandomOrder(Random random, List indices, Action action)
@@ -216,7 +216,7 @@ namespace Ryujinx.Memory.Tests
{
int region = regionSizes[i];
handle.QueryModified(address, (ulong)(PageSize * region), (address, size) => { });
-
+
// There should be a gap between regions,
// So that they don't combine and we can see the full effects.
address += (ulong)(PageSize * (region + 1));
@@ -294,7 +294,7 @@ namespace Ryujinx.Memory.Tests
bool[] actionsTriggered = new bool[3];
- MultiRegionHandle granular = _tracking.BeginGranularTracking(PageSize * 3, PageSize * 3, null, PageSize);
+ MultiRegionHandle granular = _tracking.BeginGranularTracking(PageSize * 3, PageSize * 3, null, PageSize, 0);
PreparePages(granular, 3, PageSize * 3);
// Write to the second handle in the multiregion.
@@ -307,7 +307,7 @@ namespace Ryujinx.Memory.Tests
for (int i = 0; i < 3; i++)
{
- singlePages[i] = _tracking.BeginTracking(PageSize * (8 + (ulong)i), PageSize);
+ singlePages[i] = _tracking.BeginTracking(PageSize * (8 + (ulong)i), PageSize, 0);
singlePages[i].Reprotect();
}
@@ -321,7 +321,7 @@ namespace Ryujinx.Memory.Tests
for (int i = 0; i < 3; i++)
{
- doublePages[i] = _tracking.BeginTracking(PageSize * (11 + (ulong)i * 2), PageSize * 2);
+ doublePages[i] = _tracking.BeginTracking(PageSize * (11 + (ulong)i * 2), PageSize * 2, 0);
doublePages[i].Reprotect();
}
@@ -340,7 +340,7 @@ namespace Ryujinx.Memory.Tests
doublePages
};
- MultiRegionHandle combined = _tracking.BeginGranularTracking(0, PageSize * 18, handleGroups.SelectMany((handles) => handles), PageSize);
+ MultiRegionHandle combined = _tracking.BeginGranularTracking(0, PageSize * 18, handleGroups.SelectMany((handles) => handles), PageSize, 0);
bool[] expectedDirty = new bool[]
{
@@ -405,7 +405,7 @@ namespace Ryujinx.Memory.Tests
{
bool actionTriggered = false;
- MultiRegionHandle granular = _tracking.BeginGranularTracking(PageSize * 3, PageSize * 3, null, PageSize);
+ MultiRegionHandle granular = _tracking.BeginGranularTracking(PageSize * 3, PageSize * 3, null, PageSize, 0);
PreparePages(granular, 3, PageSize * 3);
// Add a precise action to the second and third handle in the multiregion.
diff --git a/Ryujinx.Memory.Tests/TrackingTests.cs b/Ryujinx.Memory.Tests/TrackingTests.cs
index b0c39ab0..eb679804 100644
--- a/Ryujinx.Memory.Tests/TrackingTests.cs
+++ b/Ryujinx.Memory.Tests/TrackingTests.cs
@@ -44,7 +44,7 @@ namespace Ryujinx.Memory.Tests
[Test]
public void SingleRegion()
{
- RegionHandle handle = _tracking.BeginTracking(0, PageSize);
+ RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0);
(ulong address, ulong size)? readTrackingTriggered = null;
handle.RegisterAction((address, size) =>
{
@@ -97,7 +97,7 @@ namespace Ryujinx.Memory.Tests
[Test]
public void OverlappingRegions()
{
- RegionHandle allHandle = _tracking.BeginTracking(0, PageSize * 16);
+ RegionHandle allHandle = _tracking.BeginTracking(0, PageSize * 16, 0);
allHandle.Reprotect();
(ulong address, ulong size)? readTrackingTriggeredAll = null;
@@ -116,7 +116,7 @@ namespace Ryujinx.Memory.Tests
for (int i = 0; i < 16; i++)
{
- containedHandles[i] = _tracking.BeginTracking((ulong)i * PageSize, PageSize);
+ containedHandles[i] = _tracking.BeginTracking((ulong)i * PageSize, PageSize, 0);
containedHandles[i].Reprotect();
}
@@ -163,7 +163,7 @@ namespace Ryujinx.Memory.Tests
ulong alignedEnd = ((address + size + PageSize - 1) / PageSize) * PageSize;
ulong alignedSize = alignedEnd - alignedStart;
- RegionHandle handle = _tracking.BeginTracking(address, size);
+ RegionHandle handle = _tracking.BeginTracking(address, size, 0);
// Anywhere inside the pages the region is contained on should trigger.
@@ -207,7 +207,7 @@ namespace Ryujinx.Memory.Tests
for (int i = 0; i < handles.Length; i++)
{
- handles[i] = _tracking.BeginTracking((ulong)i * PageSize, PageSize);
+ handles[i] = _tracking.BeginTracking((ulong)i * PageSize, PageSize, 0);
handles[i].Reprotect();
}
@@ -263,7 +263,7 @@ namespace Ryujinx.Memory.Tests
Random random = new Random(randSeed + 512);
while (Stopwatch.GetTimestamp() < finishedTime)
{
- RegionHandle handle = _tracking.BeginTracking((ulong)random.Next(maxAddress), (ulong)random.Next(65536));
+ RegionHandle handle = _tracking.BeginTracking((ulong)random.Next(maxAddress), (ulong)random.Next(65536), 0);
handle.Dispose();
@@ -295,7 +295,7 @@ namespace Ryujinx.Memory.Tests
// Read actions should only be triggered once for each registration.
// The implementation should use an interlocked exchange to make sure other threads can't get the action.
- RegionHandle handle = _tracking.BeginTracking(0, PageSize);
+ RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0);
int triggeredCount = 0;
int registeredCount = 0;
@@ -359,7 +359,7 @@ namespace Ryujinx.Memory.Tests
{
// Ensure that disposed handles correctly remove their virtual and physical regions.
- RegionHandle handle = _tracking.BeginTracking(0, PageSize);
+ RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0);
handle.Reprotect();
Assert.AreEqual(1, _tracking.GetRegionCount());
@@ -372,8 +372,8 @@ namespace Ryujinx.Memory.Tests
// We expect there to be three regions after creating both, one for the small region and two covering the big one around it.
// Regions are always split to avoid overlapping, which is why there are three instead of two.
- RegionHandle handleSmall = _tracking.BeginTracking(PageSize, PageSize);
- RegionHandle handleBig = _tracking.BeginTracking(0, PageSize * 4);
+ RegionHandle handleSmall = _tracking.BeginTracking(PageSize, PageSize, 0);
+ RegionHandle handleBig = _tracking.BeginTracking(0, PageSize * 4, 0);
Assert.AreEqual(3, _tracking.GetRegionCount());
@@ -398,7 +398,7 @@ namespace Ryujinx.Memory.Tests
protection = newProtection;
};
- RegionHandle handle = _tracking.BeginTracking(0, PageSize);
+ RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0);
// After creating the handle, there is no protection yet.
Assert.AreEqual(MemoryPermission.ReadAndWrite, protection);
@@ -453,7 +453,7 @@ namespace Ryujinx.Memory.Tests
[Test]
public void PreciseAction()
{
- RegionHandle handle = _tracking.BeginTracking(0, PageSize);
+ RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0);
(ulong address, ulong size, bool write)? preciseTriggered = null;
handle.RegisterPreciseAction((address, size, write) =>
diff --git a/Ryujinx.Memory/AddressSpaceManager.cs b/Ryujinx.Memory/AddressSpaceManager.cs
index b532ce5e..ac89fca6 100644
--- a/Ryujinx.Memory/AddressSpaceManager.cs
+++ b/Ryujinx.Memory/AddressSpaceManager.cs
@@ -462,7 +462,7 @@ namespace Ryujinx.Memory
}
///
- public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false)
+ public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
// Only the ARM Memory Manager has tracking for now.
}
diff --git a/Ryujinx.Memory/IVirtualMemoryManager.cs b/Ryujinx.Memory/IVirtualMemoryManager.cs
index 390371ad..e1851d48 100644
--- a/Ryujinx.Memory/IVirtualMemoryManager.cs
+++ b/Ryujinx.Memory/IVirtualMemoryManager.cs
@@ -175,7 +175,8 @@ namespace Ryujinx.Memory
/// Size of the region
/// True if the region was written, false if read
/// True if the access is precise, false otherwise
- void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false);
+ /// Optional ID of the handles that should not be signalled
+ void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null);
///
/// Reprotect a region of virtual memory for tracking.
diff --git a/Ryujinx.Memory/Tracking/AbstractRegion.cs b/Ryujinx.Memory/Tracking/AbstractRegion.cs
index a3c3990e..bd4c8ab5 100644
--- a/Ryujinx.Memory/Tracking/AbstractRegion.cs
+++ b/Ryujinx.Memory/Tracking/AbstractRegion.cs
@@ -50,7 +50,8 @@ namespace Ryujinx.Memory.Tracking
/// Address accessed
/// Size of the region affected in bytes
/// Whether the region was written to or read
- public abstract void Signal(ulong address, ulong size, bool write);
+ /// Optional ID of the handles that should not be signalled
+ public abstract void Signal(ulong address, ulong size, bool write, int? exemptId);
///
/// Signals to the handles that a precise memory event has occurred. Assumes that the tracking lock has been obtained.
@@ -58,10 +59,11 @@ namespace Ryujinx.Memory.Tracking
/// Address accessed
/// Size of the region affected in bytes
/// Whether the region was written to or read
- public abstract void SignalPrecise(ulong address, ulong size, bool write);
+ /// Optional ID of the handles that should not be signalled
+ public abstract void SignalPrecise(ulong address, ulong size, bool write, int? exemptId);
///
- /// Split this region into two, around the specified address.
+ /// Split this region into two, around the specified address.
/// This region is updated to end at the split address, and a new region is created to represent past that point.
///
/// Address to split the region around
diff --git a/Ryujinx.Memory/Tracking/MemoryTracking.cs b/Ryujinx.Memory/Tracking/MemoryTracking.cs
index 9a35cfb6..bf1e0ad3 100644
--- a/Ryujinx.Memory/Tracking/MemoryTracking.cs
+++ b/Ryujinx.Memory/Tracking/MemoryTracking.cs
@@ -136,10 +136,11 @@ namespace Ryujinx.Memory.Tracking
/// Size of the region
/// Handles to inherit state from or reuse. When none are present, provide null
/// Desired granularity of write tracking
+ /// Handle ID
/// The memory tracking handle
- public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity)
+ public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable handles, ulong granularity, int id)
{
- return new MultiRegionHandle(this, address, size, handles, granularity);
+ return new MultiRegionHandle(this, address, size, handles, granularity, id);
}
///
@@ -148,12 +149,13 @@ namespace Ryujinx.Memory.Tracking
/// CPU virtual address of the region
/// Size of the region
/// Desired granularity of write tracking
+ /// Handle ID
/// The memory tracking handle
- public SmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity)
+ public SmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
{
(address, size) = PageAlign(address, size);
- return new SmartMultiRegionHandle(this, address, size, granularity);
+ return new SmartMultiRegionHandle(this, address, size, granularity, id);
}
///
@@ -161,14 +163,16 @@ namespace Ryujinx.Memory.Tracking
///
/// CPU virtual address of the region
/// Size of the region
+ /// Handle ID
/// The memory tracking handle
- public RegionHandle BeginTracking(ulong address, ulong size)
+ public RegionHandle BeginTracking(ulong address, ulong size, int id)
{
var (paAddress, paSize) = PageAlign(address, size);
lock (TrackingLock)
{
- RegionHandle handle = new RegionHandle(this, paAddress, paSize, address, size, _memoryManager.IsRangeMapped(address, size));
+ bool mapped = _memoryManager.IsRangeMapped(address, size);
+ RegionHandle handle = new RegionHandle(this, paAddress, paSize, address, size, id, mapped);
return handle;
}
@@ -181,28 +185,31 @@ namespace Ryujinx.Memory.Tracking
/// Size of the region
/// The bitmap owning the dirty flag for this handle
/// The bit of this handle within the dirty flag
+ /// Handle ID
/// The memory tracking handle
- internal RegionHandle BeginTrackingBitmap(ulong address, ulong size, ConcurrentBitmap bitmap, int bit)
+ internal RegionHandle BeginTrackingBitmap(ulong address, ulong size, ConcurrentBitmap bitmap, int bit, int id)
{
var (paAddress, paSize) = PageAlign(address, size);
lock (TrackingLock)
{
- RegionHandle handle = new RegionHandle(this, paAddress, paSize, address, size, bitmap, bit, _memoryManager.IsRangeMapped(address, size));
+ bool mapped = _memoryManager.IsRangeMapped(address, size);
+ RegionHandle handle = new RegionHandle(this, paAddress, paSize, address, size, bitmap, bit, id, mapped);
return handle;
}
}
///
- /// Signal that a virtual memory event happened at the given location (one byte).
+ /// Signal that a virtual memory event happened at the given location.
///
/// Virtual address accessed
- /// Whether the address was written to or read
+ /// Size of the region affected in bytes
+ /// Whether the region was written to or read
/// True if the event triggered any tracking regions, false otherwise
- public bool VirtualMemoryEventTracking(ulong address, bool write)
+ public bool VirtualMemoryEvent(ulong address, ulong size, bool write)
{
- return VirtualMemoryEvent(address, 1, write);
+ return VirtualMemoryEvent(address, size, write, precise: false, null);
}
///
@@ -214,8 +221,9 @@ namespace Ryujinx.Memory.Tracking
/// Size of the region affected in bytes
/// Whether the region was written to or read
/// True if the access is precise, false otherwise
+ /// Optional ID that of the handles that should not be signalled
/// True if the event triggered any tracking regions, false otherwise
- public bool VirtualMemoryEvent(ulong address, ulong size, bool write, bool precise = false)
+ public bool VirtualMemoryEvent(ulong address, ulong size, bool write, bool precise, int? exemptId = null)
{
// Look up the virtual region using the region list.
// Signal up the chain to relevant handles.
@@ -250,11 +258,11 @@ namespace Ryujinx.Memory.Tracking
if (precise)
{
- region.SignalPrecise(address, size, write);
+ region.SignalPrecise(address, size, write, exemptId);
}
else
{
- region.Signal(address, size, write);
+ region.Signal(address, size, write, exemptId);
}
}
}
diff --git a/Ryujinx.Memory/Tracking/MultiRegionHandle.cs b/Ryujinx.Memory/Tracking/MultiRegionHandle.cs
index 6ea2b784..68fc5e75 100644
--- a/Ryujinx.Memory/Tracking/MultiRegionHandle.cs
+++ b/Ryujinx.Memory/Tracking/MultiRegionHandle.cs
@@ -30,7 +30,13 @@ namespace Ryujinx.Memory.Tracking
public bool Dirty { get; private set; } = true;
- internal MultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, IEnumerable handles, ulong granularity)
+ internal MultiRegionHandle(
+ MemoryTracking tracking,
+ ulong address,
+ ulong size,
+ IEnumerable handles,
+ ulong granularity,
+ int id)
{
_handles = new RegionHandle[(size + granularity - 1) / granularity];
Granularity = granularity;
@@ -55,7 +61,7 @@ namespace Ryujinx.Memory.Tracking
// Fill any gap left before this handle.
while (i < startIndex)
{
- RegionHandle fillHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i);
+ RegionHandle fillHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id);
fillHandle.Parent = this;
_handles[i++] = fillHandle;
}
@@ -76,7 +82,7 @@ namespace Ryujinx.Memory.Tracking
while (i < endIndex)
{
- RegionHandle splitHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i);
+ RegionHandle splitHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id);
splitHandle.Parent = this;
splitHandle.Reprotect(handle.Dirty);
@@ -99,7 +105,7 @@ namespace Ryujinx.Memory.Tracking
// Fill any remaining space with new handles.
while (i < _handles.Length)
{
- RegionHandle handle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i);
+ RegionHandle handle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id);
handle.Parent = this;
_handles[i++] = handle;
}
diff --git a/Ryujinx.Memory/Tracking/RegionHandle.cs b/Ryujinx.Memory/Tracking/RegionHandle.cs
index 580f94a5..7a59f9f2 100644
--- a/Ryujinx.Memory/Tracking/RegionHandle.cs
+++ b/Ryujinx.Memory/Tracking/RegionHandle.cs
@@ -15,12 +15,12 @@ namespace Ryujinx.Memory.Tracking
/// If more than this number of checks have been performed on a dirty flag since its last reprotect,
/// then it is dirtied infrequently.
///
- private static int CheckCountForInfrequent = 3;
+ private const int CheckCountForInfrequent = 3;
///
/// Number of frequent dirty/consume in a row to make this handle volatile.
///
- private static int VolatileThreshold = 5;
+ private const int VolatileThreshold = 5;
public bool Dirty
{
@@ -35,6 +35,7 @@ namespace Ryujinx.Memory.Tracking
}
internal int SequenceNumber { get; set; }
+ internal int Id { get; }
public bool Unmapped { get; private set; }
@@ -97,14 +98,26 @@ namespace Ryujinx.Memory.Tracking
/// The real, unaligned size of the handle
/// The bitmap the dirty flag for this handle is stored in
/// The bit index representing the dirty flag for this handle
+ /// Handle ID
/// True if the region handle starts mapped
- internal RegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong realAddress, ulong realSize, ConcurrentBitmap bitmap, int bit, bool mapped = true)
+ internal RegionHandle(
+ MemoryTracking tracking,
+ ulong address,
+ ulong size,
+ ulong realAddress,
+ ulong realSize,
+ ConcurrentBitmap bitmap,
+ int bit,
+ int id,
+ bool mapped = true)
{
Bitmap = bitmap;
DirtyBit = bit;
Dirty = mapped;
+ Id = id;
+
Unmapped = !mapped;
Address = address;
Size = size;
@@ -131,11 +144,14 @@ namespace Ryujinx.Memory.Tracking
/// Size of the region to track
/// The real, unaligned address of the handle
/// The real, unaligned size of the handle
+ /// Handle ID
/// True if the region handle starts mapped
- internal RegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong realAddress, ulong realSize, bool mapped = true)
+ internal RegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong realAddress, ulong realSize, int id, bool mapped = true)
{
Bitmap = new ConcurrentBitmap(1, mapped);
+ Id = id;
+
Unmapped = !mapped;
Address = address;
diff --git a/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs b/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs
index 47fe72e5..4acddefa 100644
--- a/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs
+++ b/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs
@@ -18,10 +18,11 @@ namespace Ryujinx.Memory.Tracking
private readonly ulong _granularity;
private readonly ulong _size;
private MemoryTracking _tracking;
+ private readonly int _id;
public bool Dirty { get; private set; } = true;
- internal SmartMultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong granularity)
+ internal SmartMultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong granularity, int id)
{
// For this multi-region handle, the handle list starts empty.
// As regions are queried, they are added to the _handles array at their start index.
@@ -34,6 +35,7 @@ namespace Ryujinx.Memory.Tracking
_address = address;
_size = size;
+ _id = id;
}
public void SignalWrite()
@@ -102,7 +104,7 @@ namespace Ryujinx.Memory.Tracking
RegionSignal signal = handle.PreAction;
handle.Dispose();
- RegionHandle splitLow = _tracking.BeginTracking(address, size);
+ RegionHandle splitLow = _tracking.BeginTracking(address, size, _id);
splitLow.Parent = this;
if (signal != null)
{
@@ -110,7 +112,7 @@ namespace Ryujinx.Memory.Tracking
}
_handles[handleIndex] = splitLow;
- RegionHandle splitHigh = _tracking.BeginTracking(address + size, handle.Size - size);
+ RegionHandle splitHigh = _tracking.BeginTracking(address + size, handle.Size - size, _id);
splitHigh.Parent = this;
if (signal != null)
{
@@ -145,7 +147,7 @@ namespace Ryujinx.Memory.Tracking
if (handle != null)
{
// Fill up to the found handle.
- handle = _tracking.BeginTracking(startAddress, HandlesToBytes(i - startHandle));
+ handle = _tracking.BeginTracking(startAddress, HandlesToBytes(i - startHandle), _id);
handle.Parent = this;
_handles[startHandle] = handle;
return;
@@ -153,7 +155,7 @@ namespace Ryujinx.Memory.Tracking
}
// Can fill the whole range.
- _handles[startHandle] = _tracking.BeginTracking(startAddress, HandlesToBytes(1 + lastHandle - startHandle));
+ _handles[startHandle] = _tracking.BeginTracking(startAddress, HandlesToBytes(1 + lastHandle - startHandle), _id);
_handles[startHandle].Parent = this;
}
diff --git a/Ryujinx.Memory/Tracking/VirtualRegion.cs b/Ryujinx.Memory/Tracking/VirtualRegion.cs
index 57a0344a..9651426b 100644
--- a/Ryujinx.Memory/Tracking/VirtualRegion.cs
+++ b/Ryujinx.Memory/Tracking/VirtualRegion.cs
@@ -19,19 +19,24 @@ namespace Ryujinx.Memory.Tracking
_tracking = tracking;
}
- public override void Signal(ulong address, ulong size, bool write)
+ ///
+ public override void Signal(ulong address, ulong size, bool write, int? exemptId)
{
IList handles = Handles;
for (int i = 0; i < handles.Count; i++)
{
- handles[i].Signal(address, size, write, ref handles);
+ if (exemptId == null || handles[i].Id != exemptId.Value)
+ {
+ handles[i].Signal(address, size, write, ref handles);
+ }
}
UpdateProtection();
}
- public override void SignalPrecise(ulong address, ulong size, bool write)
+ ///
+ public override void SignalPrecise(ulong address, ulong size, bool write, int? exemptId)
{
IList handles = Handles;
@@ -39,7 +44,10 @@ namespace Ryujinx.Memory.Tracking
for (int i = 0; i < handles.Count; i++)
{
- allPrecise &= handles[i].SignalPrecise(address, size, write, ref handles);
+ if (exemptId == null || handles[i].Id != exemptId.Value)
+ {
+ allPrecise &= handles[i].SignalPrecise(address, size, write, ref handles);
+ }
}
// Only update protection if a regular signal handler was called.
diff --git a/Ryujinx.Tests/Memory/MockMemoryManager.cs b/Ryujinx.Tests/Memory/MockMemoryManager.cs
index 3f769263..eeecf419 100644
--- a/Ryujinx.Tests/Memory/MockMemoryManager.cs
+++ b/Ryujinx.Tests/Memory/MockMemoryManager.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Tests.Memory
throw new NotImplementedException();
}
- public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false)
+ public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
throw new NotImplementedException();
}