diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2023-02-16 18:28:49 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-16 18:28:49 -0300 |
| commit | efb135b74c9c0ff1de2dfd7d2a431bd23185ca66 (patch) | |
| tree | 4defd89a4473e8d1149e041e98171d1b92fa18f2 /Ryujinx.Memory/Tracking | |
| parent | a707842e14dde468781270198ae63757ca3c2716 (diff) | |
Clear CPU side data on GPU buffer clears (#4125)
* Clear CPU side data on GPU buffer clears
* Implement tracked fill operation that can signal other resource types except buffer
* Fix tests, add missing XML doc
* PR feedback
Diffstat (limited to 'Ryujinx.Memory/Tracking')
| -rw-r--r-- | Ryujinx.Memory/Tracking/AbstractRegion.cs | 8 | ||||
| -rw-r--r-- | Ryujinx.Memory/Tracking/MemoryTracking.cs | 38 | ||||
| -rw-r--r-- | Ryujinx.Memory/Tracking/MultiRegionHandle.cs | 14 | ||||
| -rw-r--r-- | Ryujinx.Memory/Tracking/RegionHandle.cs | 24 | ||||
| -rw-r--r-- | Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs | 12 | ||||
| -rw-r--r-- | Ryujinx.Memory/Tracking/VirtualRegion.cs | 16 |
6 files changed, 77 insertions, 35 deletions
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 /// <param name="address">Address accessed</param> /// <param name="size">Size of the region affected in bytes</param> /// <param name="write">Whether the region was written to or read</param> - public abstract void Signal(ulong address, ulong size, bool write); + /// <param name="exemptId">Optional ID of the handles that should not be signalled</param> + public abstract void Signal(ulong address, ulong size, bool write, int? exemptId); /// <summary> /// 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 /// <param name="address">Address accessed</param> /// <param name="size">Size of the region affected in bytes</param> /// <param name="write">Whether the region was written to or read</param> - public abstract void SignalPrecise(ulong address, ulong size, bool write); + /// <param name="exemptId">Optional ID of the handles that should not be signalled</param> + public abstract void SignalPrecise(ulong address, ulong size, bool write, int? exemptId); /// <summary> - /// 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. /// </summary> /// <param name="splitAddress">Address to split the region around</param> 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 /// <param name="size">Size of the region</param> /// <param name="handles">Handles to inherit state from or reuse. When none are present, provide null</param> /// <param name="granularity">Desired granularity of write tracking</param> + /// <param name="id">Handle ID</param> /// <returns>The memory tracking handle</returns> - public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable<IRegionHandle> handles, ulong granularity) + public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable<IRegionHandle> handles, ulong granularity, int id) { - return new MultiRegionHandle(this, address, size, handles, granularity); + return new MultiRegionHandle(this, address, size, handles, granularity, id); } /// <summary> @@ -148,12 +149,13 @@ namespace Ryujinx.Memory.Tracking /// <param name="address">CPU virtual address of the region</param> /// <param name="size">Size of the region</param> /// <param name="granularity">Desired granularity of write tracking</param> + /// <param name="id">Handle ID</param> /// <returns>The memory tracking handle</returns> - 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); } /// <summary> @@ -161,14 +163,16 @@ namespace Ryujinx.Memory.Tracking /// </summary> /// <param name="address">CPU virtual address of the region</param> /// <param name="size">Size of the region</param> + /// <param name="id">Handle ID</param> /// <returns>The memory tracking handle</returns> - 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 /// <param name="size">Size of the region</param> /// <param name="bitmap">The bitmap owning the dirty flag for this handle</param> /// <param name="bit">The bit of this handle within the dirty flag</param> + /// <param name="id">Handle ID</param> /// <returns>The memory tracking handle</returns> - 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; } } /// <summary> - /// Signal that a virtual memory event happened at the given location (one byte). + /// Signal that a virtual memory event happened at the given location. /// </summary> /// <param name="address">Virtual address accessed</param> - /// <param name="write">Whether the address was written to or read</param> + /// <param name="size">Size of the region affected in bytes</param> + /// <param name="write">Whether the region was written to or read</param> /// <returns>True if the event triggered any tracking regions, false otherwise</returns> - 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); } /// <summary> @@ -214,8 +221,9 @@ namespace Ryujinx.Memory.Tracking /// <param name="size">Size of the region affected in bytes</param> /// <param name="write">Whether the region was written to or read</param> /// <param name="precise">True if the access is precise, false otherwise</param> + /// <param name="exemptId">Optional ID that of the handles that should not be signalled</param> /// <returns>True if the event triggered any tracking regions, false otherwise</returns> - 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<IRegionHandle> handles, ulong granularity) + internal MultiRegionHandle( + MemoryTracking tracking, + ulong address, + ulong size, + IEnumerable<IRegionHandle> 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. /// </summary> - private static int CheckCountForInfrequent = 3; + private const int CheckCountForInfrequent = 3; /// <summary> /// Number of frequent dirty/consume in a row to make this handle volatile. /// </summary> - 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 /// <param name="realSize">The real, unaligned size of the handle</param> /// <param name="bitmap">The bitmap the dirty flag for this handle is stored in</param> /// <param name="bit">The bit index representing the dirty flag for this handle</param> + /// <param name="id">Handle ID</param> /// <param name="mapped">True if the region handle starts mapped</param> - 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 /// <param name="size">Size of the region to track</param> /// <param name="realAddress">The real, unaligned address of the handle</param> /// <param name="realSize">The real, unaligned size of the handle</param> + /// <param name="id">Handle ID</param> /// <param name="mapped">True if the region handle starts mapped</param> - 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) + /// <inheritdoc/> + public override void Signal(ulong address, ulong size, bool write, int? exemptId) { IList<RegionHandle> 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) + /// <inheritdoc/> + public override void SignalPrecise(ulong address, ulong size, bool write, int? exemptId) { IList<RegionHandle> 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. |
