153 lines
4.2 KiB
C#
153 lines
4.2 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using RefreshCS;
|
|
|
|
namespace MoonWorks.Graphics
|
|
{
|
|
public unsafe class TransferBuffer : RefreshResource
|
|
{
|
|
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTransferBuffer;
|
|
|
|
/// <summary>
|
|
/// Size in bytes.
|
|
/// </summary>
|
|
public uint Size { get; }
|
|
|
|
/// <summary>
|
|
/// Creates a buffer of requested size given a type and element count.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
|
/// <param name="device">The GraphicsDevice.</param>
|
|
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
|
/// <returns></returns>
|
|
public unsafe static TransferBuffer Create<T>(
|
|
GraphicsDevice device,
|
|
uint elementCount
|
|
) where T : unmanaged
|
|
{
|
|
return new TransferBuffer(
|
|
device,
|
|
(uint) Marshal.SizeOf<T>() * elementCount
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a TransferBuffer.
|
|
/// </summary>
|
|
/// <param name="device">An initialized GraphicsDevice.</param>
|
|
/// <param name="sizeInBytes">The length of the buffer. Cannot be resized.</param>
|
|
public TransferBuffer(
|
|
GraphicsDevice device,
|
|
uint sizeInBytes
|
|
) : base(device)
|
|
{
|
|
Handle = Refresh.Refresh_CreateTransferBuffer(
|
|
device.Handle,
|
|
sizeInBytes
|
|
);
|
|
Size = sizeInBytes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Immediately copies data from a Span to the TransferBuffer.
|
|
/// Returns the length of the copy in bytes.
|
|
///
|
|
/// If setDataOption is DISCARD and this TransferBuffer was used in an Upload command,
|
|
/// that command will still use the correct data at the cost of increased memory usage.
|
|
///
|
|
/// If setDataOption is OVERWRITE and this TransferBuffer was used in an Upload command,
|
|
/// the data will be overwritten immediately, which could cause a data race.
|
|
/// </summary>
|
|
public unsafe uint SetData<T>(
|
|
Span<T> data,
|
|
uint bufferOffsetInBytes,
|
|
SetDataOptions setDataOption
|
|
) where T : unmanaged
|
|
{
|
|
var elementSize = Marshal.SizeOf<T>();
|
|
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
|
|
|
#if DEBUG
|
|
AssertBufferBoundsCheck(Size, bufferOffsetInBytes, dataLengthInBytes);
|
|
#endif
|
|
|
|
fixed (T* dataPtr = data)
|
|
{
|
|
Refresh.Refresh_SetData(
|
|
Device.Handle,
|
|
(nint) dataPtr,
|
|
Handle,
|
|
new Refresh.BufferCopy
|
|
{
|
|
srcOffset = 0,
|
|
dstOffset = bufferOffsetInBytes,
|
|
size = dataLengthInBytes
|
|
},
|
|
(Refresh.SetDataOptions) setDataOption
|
|
);
|
|
}
|
|
|
|
return dataLengthInBytes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Immediately copies data from a Span to the TransferBuffer.
|
|
/// Returns the length of the copy in bytes.
|
|
///
|
|
/// If setDataOption is DISCARD and this TransferBuffer was used in an Upload command,
|
|
/// that command will still use the correct data at the cost of increased memory usage.
|
|
///
|
|
/// If setDataOption is OVERWRITE and this TransferBuffer was used in an Upload command,
|
|
/// the data will be overwritten immediately, which could cause a data race.
|
|
/// </summary>
|
|
public unsafe uint SetData<T>(
|
|
Span<T> data,
|
|
SetDataOptions setDataOption
|
|
) where T : unmanaged
|
|
{
|
|
return SetData(data, 0, setDataOption);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Immediately copies data from the TransferBuffer into a Span.
|
|
/// </summary>
|
|
public unsafe void GetData<T>(
|
|
Span<T> data,
|
|
uint bufferOffsetInBytes = 0
|
|
) where T : unmanaged
|
|
{
|
|
var elementSize = Marshal.SizeOf<T>();
|
|
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
|
|
|
#if DEBUG
|
|
AssertBufferBoundsCheck(Size, bufferOffsetInBytes, dataLengthInBytes);
|
|
#endif
|
|
|
|
fixed (T* dataPtr = data)
|
|
{
|
|
Refresh.Refresh_GetData(
|
|
Device.Handle,
|
|
Handle,
|
|
(nint) dataPtr,
|
|
new Refresh.BufferCopy
|
|
{
|
|
srcOffset = bufferOffsetInBytes,
|
|
dstOffset = 0,
|
|
size = dataLengthInBytes
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
private void AssertBufferBoundsCheck(uint bufferLengthInBytes, uint offsetInBytes, uint copyLengthInBytes)
|
|
{
|
|
if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
|
|
{
|
|
throw new InvalidOperationException($"SetData overflow! Transfer buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|