From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001 From: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:22:00 +0200 Subject: Move solution and projects to src --- .../Multithreading/BufferMap.cs | 194 +++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/BufferMap.cs (limited to 'src/Ryujinx.Graphics.GAL/Multithreading/BufferMap.cs') diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/BufferMap.cs b/src/Ryujinx.Graphics.GAL/Multithreading/BufferMap.cs new file mode 100644 index 00000000..24b0af2d --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/BufferMap.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Ryujinx.Graphics.GAL.Multithreading +{ + /// + /// Buffer handles given to the client are not the same as those provided by the backend, + /// as their handle is created at a later point on the queue. + /// The handle returned is a unique identifier that will map to the real buffer when it is available. + /// Note that any uses within the queue should be safe, but outside you must use MapBufferBlocking. + /// + class BufferMap + { + private ulong _bufferHandle = 0; + + private Dictionary _bufferMap = new Dictionary(); + private HashSet _inFlight = new HashSet(); + private AutoResetEvent _inFlightChanged = new AutoResetEvent(false); + + internal BufferHandle CreateBufferHandle() + { + ulong handle64 = Interlocked.Increment(ref _bufferHandle); + + BufferHandle threadedHandle = Unsafe.As(ref handle64); + + lock (_inFlight) + { + _inFlight.Add(threadedHandle); + } + + return threadedHandle; + } + + internal void AssignBuffer(BufferHandle threadedHandle, BufferHandle realHandle) + { + lock (_bufferMap) + { + _bufferMap[threadedHandle] = realHandle; + } + + lock (_inFlight) + { + _inFlight.Remove(threadedHandle); + } + + _inFlightChanged.Set(); + } + + internal void UnassignBuffer(BufferHandle threadedHandle) + { + lock (_bufferMap) + { + _bufferMap.Remove(threadedHandle); + } + } + + internal BufferHandle MapBuffer(BufferHandle handle) + { + // Maps a threaded buffer to a backend one. + // Threaded buffers are returned on creation as the buffer + // isn't actually created until the queue runs the command. + + BufferHandle result; + + lock (_bufferMap) + { + if (!_bufferMap.TryGetValue(handle, out result)) + { + result = BufferHandle.Null; + } + + return result; + } + } + + internal BufferHandle MapBufferBlocking(BufferHandle handle) + { + // Blocks until the handle is available. + + BufferHandle result; + + lock (_bufferMap) + { + if (_bufferMap.TryGetValue(handle, out result)) + { + return result; + } + } + + bool signal = false; + + while (true) + { + lock (_inFlight) + { + if (!_inFlight.Contains(handle)) + { + break; + } + } + + _inFlightChanged.WaitOne(); + signal = true; + } + + if (signal) + { + // Signal other threads which might still be waiting. + _inFlightChanged.Set(); + } + + return MapBuffer(handle); + } + + internal BufferRange MapBufferRange(BufferRange range) + { + return new BufferRange(MapBuffer(range.Handle), range.Offset, range.Size); + } + + internal Span MapBufferRanges(Span ranges) + { + // Rewrite the buffer ranges to point to the mapped handles. + + lock (_bufferMap) + { + for (int i = 0; i < ranges.Length; i++) + { + ref BufferRange range = ref ranges[i]; + BufferHandle result; + + if (!_bufferMap.TryGetValue(range.Handle, out result)) + { + result = BufferHandle.Null; + } + + range = new BufferRange(result, range.Offset, range.Size); + } + } + + return ranges; + } + + internal Span MapBufferRanges(Span ranges) + { + // Rewrite the buffer ranges to point to the mapped handles. + + lock (_bufferMap) + { + for (int i = 0; i < ranges.Length; i++) + { + ref BufferAssignment assignment = ref ranges[i]; + BufferRange range = assignment.Range; + BufferHandle result; + + if (!_bufferMap.TryGetValue(range.Handle, out result)) + { + result = BufferHandle.Null; + } + + assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size)); + } + } + + return ranges; + } + + internal Span MapBufferRanges(Span ranges) + { + // Rewrite the buffer ranges to point to the mapped handles. + + lock (_bufferMap) + { + for (int i = 0; i < ranges.Length; i++) + { + BufferRange range = ranges[i].Buffer; + BufferHandle result; + + if (!_bufferMap.TryGetValue(range.Handle, out result)) + { + result = BufferHandle.Null; + } + + range = new BufferRange(result, range.Offset, range.Size); + + ranges[i] = new VertexBufferDescriptor(range, ranges[i].Stride, ranges[i].Divisor); + } + } + + return ranges; + } + } +} -- cgit v1.2.3