using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.GAL { public unsafe struct PinnedSpan<T> : IDisposable where T : unmanaged { private void* _ptr; private int _size; private Action _disposeAction; /// <summary> /// Creates a new PinnedSpan from an existing ReadOnlySpan. The span *must* be pinned in memory. /// The data must be guaranteed to live until disposeAction is called. /// </summary> /// <param name="span">Existing span</param> /// <param name="disposeAction">Action to call on dispose</param> /// <remarks> /// If a dispose action is not provided, it is safe to assume the resource will be available until the next call. /// </remarks> public static PinnedSpan<T> UnsafeFromSpan(ReadOnlySpan<T> span, Action disposeAction = null) { return new PinnedSpan<T>(Unsafe.AsPointer(ref MemoryMarshal.GetReference(span)), span.Length, disposeAction); } /// <summary> /// Creates a new PinnedSpan from an existing unsafe region. The data must be guaranteed to live until disposeAction is called. /// </summary> /// <param name="ptr">Pointer to the region</param> /// <param name="size">The total items of T the region contains</param> /// <param name="disposeAction">Action to call on dispose</param> /// <remarks> /// If a dispose action is not provided, it is safe to assume the resource will be available until the next call. /// </remarks> public PinnedSpan(void* ptr, int size, Action disposeAction = null) { _ptr = ptr; _size = size; _disposeAction = disposeAction; } public ReadOnlySpan<T> Get() { return new ReadOnlySpan<T>(_ptr, _size * Unsafe.SizeOf<T>()); } public void Dispose() { _disposeAction?.Invoke(); } } }