diff --git a/src/SharpEmu.HLE/GpuMemory/GuestGpuMemory.cs b/src/SharpEmu.HLE/GpuMemory/GuestGpuMemory.cs index a99f4b5..c46e01c 100644 --- a/src/SharpEmu.HLE/GpuMemory/GuestGpuMemory.cs +++ b/src/SharpEmu.HLE/GpuMemory/GuestGpuMemory.cs @@ -30,6 +30,7 @@ public sealed class GuestGpuMemory : IDisposable private readonly PageGuard _pages; private readonly ReaderWriterLockSlim _spansLock = new(); private readonly SpanSet _spans = new(); + private SpanSnapshot _spanSnapshot = SpanSnapshot.Empty; private long _spanVersion; public long SpanVersion => Interlocked.Read(ref _spanVersion); @@ -153,15 +154,7 @@ public sealed class GuestGpuMemory : IDisposable return false; } - _spansLock.EnterReadLock(); - try - { - return _spans.Contains(address, size); - } - finally - { - _spansLock.ExitReadLock(); - } + return Volatile.Read(ref _spanSnapshot).Contains(address, size); } public void ForEachSpan(Action visit) @@ -207,6 +200,7 @@ public sealed class GuestGpuMemory : IDisposable try { _spans.Add(address, size); + Volatile.Write(ref _spanSnapshot, _spans.Snapshot()); Interlocked.Increment(ref _spanVersion); } finally @@ -280,6 +274,7 @@ public sealed class GuestGpuMemory : IDisposable try { _spans.Remove(address, size); + Volatile.Write(ref _spanSnapshot, _spans.Snapshot()); Interlocked.Increment(ref _spanVersion); } finally diff --git a/src/SharpEmu.HLE/GpuMemory/SpanSet.cs b/src/SharpEmu.HLE/GpuMemory/SpanSet.cs index fcf861f..291417f 100644 --- a/src/SharpEmu.HLE/GpuMemory/SpanSet.cs +++ b/src/SharpEmu.HLE/GpuMemory/SpanSet.cs @@ -3,6 +3,22 @@ namespace SharpEmu.HLE.GpuMemory; +public sealed class SpanSnapshot(ulong[] starts, ulong[] ends) +{ + public static readonly SpanSnapshot Empty = new([], []); + + public bool Contains(ulong address, ulong size) + { + var index = Array.BinarySearch(starts, address); + if (index < 0) + { + index = ~index - 1; + } + + return index >= 0 && ends[index] >= address + size; + } +} + public sealed class SpanSet { private readonly SortedList _spans = new(); @@ -79,6 +95,19 @@ public sealed class SpanSet return index > 0 && _spans.GetValueAtIndex(index - 1) > address; } + public SpanSnapshot Snapshot() + { + var starts = new ulong[_spans.Count]; + var ends = new ulong[_spans.Count]; + for (var index = 0; index < starts.Length; index++) + { + starts[index] = _spans.GetKeyAtIndex(index); + ends[index] = _spans.GetValueAtIndex(index); + } + + return new SpanSnapshot(starts, ends); + } + public void ForEach(Action visit) { foreach (var (start, end) in _spans)