| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- using System;
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
- using System.Threading;
- namespace Ryujinx.Graphics.GAL.Multithreading
- {
- /// <summary>
- /// 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.
- /// </summary>
- class BufferMap
- {
- private ulong _bufferHandle = 0;
- private Dictionary<BufferHandle, BufferHandle> _bufferMap = new Dictionary<BufferHandle, BufferHandle>();
- private HashSet<BufferHandle> _inFlight = new HashSet<BufferHandle>();
- private AutoResetEvent _inFlightChanged = new AutoResetEvent(false);
- internal BufferHandle CreateBufferHandle()
- {
- ulong handle64 = Interlocked.Increment(ref _bufferHandle);
- BufferHandle threadedHandle = Unsafe.As<ulong, BufferHandle>(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<BufferRange> MapBufferRanges(Span<BufferRange> 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<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> 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;
- }
- }
- }
|