refactor CopyPass

sdl2_gpu
cosmonaut 2024-06-04 19:35:17 -07:00
parent 97dee2a170
commit 3cfb43438c
13 changed files with 381 additions and 344 deletions

View File

@ -48,12 +48,13 @@ namespace MoonWorks
/// </summary>
/// <param name="windowCreateInfo">The parameters that will be used to create the MainWindow.</param>
/// <param name="frameLimiterSettings">The frame limiter settings.</param>
/// <param name="preferredBackends">Bitflags of which GPU backends to attempt to initialize.</param>
/// <param name="targetTimestep">How often Game.Update will run in terms of ticks per second.</param>
/// <param name="debugMode">If true, enables extra debug checks. Should be turned off for release builds.</param>
public Game(
WindowCreateInfo windowCreateInfo,
FrameLimiterSettings frameLimiterSettings,
Span<Backend> preferredBackends,
BackendFlags preferredBackends,
int targetTimestep = 60,
bool debugMode = false
) {
@ -75,8 +76,6 @@ namespace MoonWorks
return;
}
Logger.Initialize();
Logger.LogInfo("Initializing input...");
Inputs = new Inputs();
@ -89,7 +88,7 @@ namespace MoonWorks
Logger.LogInfo("Initializing main window...");
MainWindow = new Window(windowCreateInfo, GraphicsDevice.WindowFlags | SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN);
if (!GraphicsDevice.ClaimWindow(MainWindow, windowCreateInfo.PresentMode))
if (!GraphicsDevice.ClaimWindow(MainWindow, windowCreateInfo.SwapchainComposition, windowCreateInfo.PresentMode))
{
throw new System.SystemException("Could not claim window!");
}

View File

@ -617,6 +617,7 @@ public class CommandBuffer
renderPass.Handle
);
renderPass.SetHandle(nint.Zero);
Device.RenderPassPool.Return(renderPass);
}
@ -730,6 +731,45 @@ public class CommandBuffer
return computePass;
}
public unsafe ComputePass BeginComputePass(
Span<StorageTextureReadWriteBinding> readWriteTextureBindings,
Span<StorageBufferReadWriteBinding> readWriteBufferBindings
) {
#if DEBUG
AssertNotSubmitted();
AssertNotInPass("Cannot begin compute pass while in another pass!");
computePassActive = true;
#endif
var sdlTextureBindings = NativeMemory.Alloc(
(nuint) (readWriteTextureBindings.Length * Marshal.SizeOf<StorageTextureReadWriteBinding>())
);
var sdlBufferBindings = NativeMemory.Alloc(
(nuint) (readWriteBufferBindings.Length * Marshal.SizeOf<StorageBufferReadWriteBinding>())
);
var computePassHandle = SDL_Gpu.SDL_GpuBeginComputePass(
Handle,
(SDL_Gpu.StorageTextureReadWriteBinding*) sdlTextureBindings,
(uint) readWriteTextureBindings.Length,
(SDL_Gpu.StorageBufferReadWriteBinding*) sdlBufferBindings,
(uint) readWriteBufferBindings.Length
);
var computePass = Device.ComputePassPool.Obtain();
computePass.SetHandle(computePassHandle);
#if DEBUG
computePass.active = true;
#endif
NativeMemory.Free(sdlTextureBindings);
NativeMemory.Free(sdlBufferBindings);
return computePass;
}
public void EndComputePass(ComputePass computePass)
{
#if DEBUG
@ -742,6 +782,9 @@ public class CommandBuffer
SDL_Gpu.SDL_GpuEndComputePass(
computePass.Handle
);
computePass.SetHandle(nint.Zero);
Device.ComputePassPool.Return(computePass);
}
// Copy Pass
@ -751,7 +794,7 @@ public class CommandBuffer
/// All copy commands must be made within a copy pass.
/// It is an error to call this during any kind of pass.
/// </summary>
public void BeginCopyPass()
public CopyPass BeginCopyPass()
{
#if DEBUG
AssertNotSubmitted();
@ -759,228 +802,15 @@ public class CommandBuffer
copyPassActive = true;
#endif
Refresh.Refresh_BeginCopyPass(
Device.Handle,
Handle
);
var copyPassHandle = SDL_Gpu.SDL_GpuBeginCopyPass(Handle);
var copyPass = Device.CopyPassPool.Obtain();
copyPass.SetHandle(copyPassHandle);
return copyPass;
}
/// <summary>
/// Uploads data from a TransferBuffer to a TextureSlice.
/// This copy occurs on the GPU timeline.
///
/// Overwriting the contents of the TransferBuffer before the command buffer
/// has finished execution will cause undefined behavior.
///
/// You MAY assume that the copy has finished for subsequent commands.
/// </summary>
/// <param name="writeOption">Specifies data dependency behavior.</param>
public void UploadToTexture(
TransferBuffer transferBuffer,
in TextureRegion textureRegion,
in BufferImageCopy copyParams,
WriteOptions writeOption
)
{
#if DEBUG
AssertNotSubmitted();
AssertInCopyPass("Cannot upload to texture outside of copy pass!");
AssertBufferBoundsCheck(transferBuffer.Size, copyParams.BufferOffset, textureRegion.Size);
#endif
Refresh.Refresh_UploadToTexture(
Device.Handle,
Handle,
transferBuffer.Handle,
textureRegion.ToRefreshTextureRegion(),
copyParams.ToRefresh(),
(Refresh.WriteOptions) writeOption
);
}
/// <summary>
/// Uploads the contents of an entire buffer to a texture with no mips.
/// </summary>
public void UploadToTexture(
TransferBuffer transferBuffer,
Texture texture,
WriteOptions writeOption
) {
UploadToTexture(
transferBuffer,
new TextureRegion(texture),
new BufferImageCopy(0, 0, 0),
writeOption
);
}
/// <summary>
/// Uploads data from a TransferBuffer to a GpuBuffer.
/// This copy occurs on the GPU timeline.
///
/// Overwriting the contents of the TransferBuffer before the command buffer
/// has finished execution will cause undefined behavior.
///
/// You MAY assume that the copy has finished for subsequent commands.
/// </summary>
public void UploadToBuffer(
TransferBuffer transferBuffer,
GpuBuffer gpuBuffer,
in BufferCopy copyParams,
WriteOptions option
) {
#if DEBUG
AssertNotSubmitted();
AssertInCopyPass("Cannot upload to texture outside of copy pass!");
AssertBufferBoundsCheck(transferBuffer.Size, copyParams.SrcOffset, copyParams.Size);
AssertBufferBoundsCheck(gpuBuffer.Size, copyParams.DstOffset, copyParams.Size);
#endif
Refresh.Refresh_UploadToBuffer(
Device.Handle,
Handle,
transferBuffer.Handle,
gpuBuffer.Handle,
copyParams.ToRefresh(),
(Refresh.WriteOptions) option
);
}
/// <summary>
/// Copies the entire contents of a TransferBuffer to a GpuBuffer.
/// </summary>
public void UploadToBuffer(
TransferBuffer transferBuffer,
GpuBuffer gpuBuffer,
WriteOptions option
) {
UploadToBuffer(
transferBuffer,
gpuBuffer,
new BufferCopy(0, 0, transferBuffer.Size),
option
);
}
/// <summary>
/// Copies data element-wise into from a TransferBuffer to a GpuBuffer.
/// </summary>
public void UploadToBuffer<T>(
TransferBuffer transferBuffer,
GpuBuffer gpuBuffer,
uint sourceStartElement,
uint destinationStartElement,
uint numElements,
WriteOptions option
) where T : unmanaged
{
var elementSize = Marshal.SizeOf<T>();
var dataLengthInBytes = (uint) (elementSize * numElements);
var srcOffsetInBytes = (uint) (elementSize * sourceStartElement);
var dstOffsetInBytes = (uint) (elementSize * destinationStartElement);
UploadToBuffer(
transferBuffer,
gpuBuffer,
new BufferCopy(
srcOffsetInBytes,
dstOffsetInBytes,
dataLengthInBytes
),
option
);
}
/// <summary>
/// Copies the contents of a TextureSlice to another TextureSlice.
/// The slices must have the same dimensions.
/// This copy occurs on the GPU timeline.
///
/// You MAY assume that the copy has finished in subsequent commands.
/// </summary>
public void CopyTextureToTexture(
in TextureRegion source,
in TextureRegion destination,
WriteOptions option
) {
#if DEBUG
AssertNotSubmitted();
AssertInCopyPass("Cannot download from texture outside of copy pass!");
AssertTextureBoundsCheck(destination.Size, source.Size);
#endif
Refresh.Refresh_CopyTextureToTexture(
Device.Handle,
Handle,
source.ToRefreshTextureRegion(),
destination.ToRefreshTextureRegion(),
(Refresh.WriteOptions) option
);
}
/// <summary>
/// Copies the contents of an entire Texture with no mips to another Texture with no mips.
/// The textures must have the same dimensions.
/// </summary>
public void CopyTextureToTexture(
Texture source,
Texture destination,
WriteOptions option
) {
CopyTextureToTexture(
new TextureRegion(source),
new TextureRegion(destination),
option
);
}
/// <summary>
/// Copies data from a GpuBuffer to another GpuBuffer.
/// This copy occurs on the GPU timeline.
///
/// You MAY assume that the copy has finished in subsequent commands.
/// </summary>
public void CopyBufferToBuffer(
GpuBuffer source,
GpuBuffer destination,
in BufferCopy copyParams,
WriteOptions option
) {
#if DEBUG
AssertNotSubmitted();
AssertInCopyPass("Cannot download from texture outside of copy pass!");
AssertBufferBoundsCheck(source.Size, copyParams.SrcOffset, copyParams.Size);
AssertBufferBoundsCheck(destination.Size, copyParams.DstOffset, copyParams.Size);
#endif
Refresh.Refresh_CopyBufferToBuffer(
Device.Handle,
Handle,
source.Handle,
destination.Handle,
copyParams.ToRefresh(),
(Refresh.WriteOptions) option
);
}
/// <summary>
/// Copies the entire contents of a GpuBuffer to another GpuBuffer.
/// </summary>
public void CopyBufferToBuffer(
GpuBuffer source,
GpuBuffer destination,
WriteOptions option
) {
CopyBufferToBuffer(
source,
destination,
new BufferCopy(0, 0, source.Size),
option
);
}
public void EndCopyPass()
public void EndCopyPass(CopyPass copyPass)
{
#if DEBUG
AssertNotSubmitted();
@ -988,10 +818,12 @@ public class CommandBuffer
copyPassActive = false;
#endif
Refresh.Refresh_EndCopyPass(
Device.Handle,
Handle
SDL_Gpu.SDL_GpuEndCopyPass(
copyPass.Handle
);
copyPass.SetHandle(nint.Zero);
Device.CopyPassPool.Return(copyPass);
}
#if DEBUG
@ -1011,22 +843,6 @@ public class CommandBuffer
}
}
private void AssertComputeBufferCount(int count)
{
if (currentComputePipeline.ComputeShaderInfo.BufferBindingCount != count)
{
throw new System.InvalidOperationException($"Compute pipeline expects {currentComputePipeline.ComputeShaderInfo.BufferBindingCount} buffers, but received {count}");
}
}
private void AssertComputeTextureCount(int count)
{
if (currentComputePipeline.ComputeShaderInfo.ImageBindingCount != count)
{
throw new System.InvalidOperationException($"Compute pipeline expects {currentComputePipeline.ComputeShaderInfo.ImageBindingCount} textures, but received {count}");
}
}
private void AssertTextureNotNull(ColorAttachmentInfo colorAttachmentInfo)
{
if (colorAttachmentInfo.TextureSlice.Texture == null || colorAttachmentInfo.TextureSlice.Texture.Handle == IntPtr.Zero)
@ -1059,7 +875,7 @@ public class CommandBuffer
throw new System.ArgumentException("Render pass depth stencil attachment Texture cannot be null!");
}
if ((depthStencilAttachmentInfo.TextureSlice.Texture.UsageFlags & TextureUsageFlags.DepthStencilTarget) == 0)
if ((depthStencilAttachmentInfo.TextureSlice.Texture.UsageFlags & TextureUsageFlags.DepthStencil) == 0)
{
throw new System.ArgumentException("Render pass depth stencil attachment UsageFlags must include TextureUsageFlags.DepthStencilTarget!");
}

203
src/Graphics/CopyPass.cs Normal file
View File

@ -0,0 +1,203 @@
using System.Runtime.InteropServices;
using SDL2_gpuCS;
namespace MoonWorks.Graphics;
public class CopyPass
{
public nint Handle { get; private set; }
internal void SetHandle(nint handle)
{
Handle = handle;
}
/// <summary>
/// Uploads data from a TransferBuffer to a TextureSlice.
/// This copy occurs on the GPU timeline.
///
/// Overwriting the contents of the TransferBuffer before the command buffer
/// has finished execution will cause undefined behavior.
///
/// You MAY assume that the copy has finished for subsequent commands.
/// </summary>
/// <param name="cycle">If true, cycles the texture if the given slice is bound.</param>
public void UploadToTexture(
TransferBuffer transferBuffer,
in TextureRegion textureRegion,
in BufferImageCopy copyParams,
bool cycle
) {
#if DEBUG
AssertBufferBoundsCheck(transferBuffer.Size, copyParams.BufferOffset, textureRegion.Size);
#endif
SDL_Gpu.SDL_GpuUploadToTexture(
Handle,
transferBuffer.Handle,
textureRegion.ToSDL(),
copyParams.ToSDL(),
Conversions.BoolToInt(cycle)
);
}
/// <summary>
/// Uploads the contents of an entire buffer to a 2D texture with no mips.
/// </summary>
public void UploadToTexture(
TransferBuffer transferBuffer,
Texture texture,
bool cycle
) {
UploadToTexture(
transferBuffer,
new TextureRegion(texture),
new BufferImageCopy(0, 0, 0),
cycle
);
}
/// <summary>
/// Uploads data from a TransferBuffer to a GpuBuffer.
/// This copy occurs on the GPU timeline.
///
/// Overwriting the contents of the TransferBuffer before the command buffer
/// has finished execution will cause undefined behavior.
///
/// You MAY assume that the copy has finished for subsequent commands.
/// </summary>
/// <param name="cycle">If true, cycles the buffer if it is bound.</param>
public void UploadToBuffer(
TransferBuffer transferBuffer,
GpuBuffer buffer,
in BufferCopy copyParams,
bool cycle
) {
#if DEBUG
AssertBufferBoundsCheck(transferBuffer.Size, copyParams.SrcOffset, copyParams.Size);
AssertBufferBoundsCheck(buffer.Size, copyParams.DstOffset, copyParams.Size);
#endif
SDL_Gpu.SDL_GpuUploadToBuffer(
Handle,
transferBuffer.Handle,
buffer.Handle,
copyParams.ToSDL(),
Conversions.BoolToInt(cycle)
);
}
/// <summary>
/// Copies the entire contents of a TransferBuffer to a GpuBuffer.
/// </summary>
public void UploadToBuffer(
TransferBuffer transferBuffer,
GpuBuffer buffer,
bool cycle
) {
UploadToBuffer(
transferBuffer,
buffer,
new BufferCopy(0, 0, transferBuffer.Size),
cycle
);
}
/// <summary>
/// Copies data element-wise into from a TransferBuffer to a GpuBuffer.
/// </summary>
public void UploadToBuffer<T>(
TransferBuffer transferBuffer,
GpuBuffer buffer,
uint sourceStartElement,
uint destinationStartElement,
uint numElements,
bool cycle
) where T : unmanaged
{
var elementSize = Marshal.SizeOf<T>();
var dataLengthInBytes = (uint) (elementSize * numElements);
var srcOffsetInBytes = (uint) (elementSize * sourceStartElement);
var dstOffsetInBytes = (uint) (elementSize * destinationStartElement);
UploadToBuffer(
transferBuffer,
buffer,
new BufferCopy(srcOffsetInBytes, dstOffsetInBytes, dataLengthInBytes),
cycle
);
}
/// <summary>
/// Copies the contents of a TextureRegion to another TextureRegion.
/// The regions must have the same dimensions.
/// This copy occurs on the GPU timeline.
///
/// You MAY assume that the copy has finished in subsequent commands.
/// </summary>
public void CopyTextureToTexture(
in TextureRegion source,
in TextureRegion destination,
bool cycle
) {
#if DEBUG
AssertTextureBoundsCheck(destination.Size, source.Size);
if (source.Width != destination.Width || source.Height != destination.Height || source.Depth != destination.Depth)
{
throw new System.InvalidOperationException("Texture copy must have the same dimensions!");
}
#endif
SDL_Gpu.SDL_GpuCopyTextureToTexture(
Handle,
source.ToSDL(),
destination.ToSDL(),
Conversions.BoolToInt(cycle)
);
}
/// <summary>
/// Copies data from a GpuBuffer to another GpuBuffer.
/// This copy occurs on the GPU timeline.
///
/// You MAY assume that the copy has finished in subsequent commands.
/// </summary>
public void CopyBufferToBuffer(
GpuBuffer source,
GpuBuffer destination,
in BufferCopy copyParams,
bool cycle
) {
#if DEBUG
AssertBufferBoundsCheck(source.Size, copyParams.SrcOffset, copyParams.Size);
AssertBufferBoundsCheck(destination.Size, copyParams.DstOffset, copyParams.Size);
#endif
SDL_Gpu.SDL_GpuCopyBufferToBuffer(
Handle,
source.Handle,
destination.Handle,
copyParams.ToSDL(),
Conversions.BoolToInt(cycle)
);
}
#if DEBUG
private void AssertBufferBoundsCheck(uint bufferLengthInBytes, uint offsetInBytes, uint copyLengthInBytes)
{
if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
{
throw new System.InvalidOperationException($"SetBufferData overflow! buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
}
}
private void AssertTextureBoundsCheck(uint textureSizeInBytes, uint dataLengthInBytes)
{
if (dataLengthInBytes > textureSizeInBytes)
{
throw new System.InvalidOperationException($"SetTextureData overflow! texture size {textureSizeInBytes}, data size {dataLengthInBytes}");
}
}
#endif
}

View File

@ -0,0 +1,25 @@
using System.Collections.Concurrent;
namespace MoonWorks.Graphics;
internal class CopyPassPool
{
private ConcurrentQueue<CopyPass> CopyPasses = new ConcurrentQueue<CopyPass>();
public CopyPass Obtain()
{
if (CopyPasses.TryDequeue(out var copyPass))
{
return copyPass;
}
else
{
return new CopyPass();
}
}
public void Return(CopyPass copyPass)
{
CopyPasses.Enqueue(copyPass);
}
}

View File

@ -41,6 +41,7 @@ namespace MoonWorks.Graphics
private FencePool FencePool;
internal RenderPassPool RenderPassPool;
internal ComputePassPool ComputePassPool;
internal CopyPassPool CopyPassPool;
internal unsafe GraphicsDevice(
BackendFlags preferredBackends,

View File

@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Runtime.InteropServices;
using RefreshCS;
using SDL2;
namespace MoonWorks.Graphics
{

View File

@ -26,8 +26,8 @@ namespace MoonWorks.Graphics
uint textureDataOffset = 0;
uint textureDataSize = 1024;
List<(GpuBuffer, BufferCopy, WriteOptions)> BufferUploads = new List<(GpuBuffer, BufferCopy, WriteOptions)>();
List<(TextureRegion, uint, WriteOptions)> TextureUploads = new List<(TextureRegion, uint, WriteOptions)>();
List<(GpuBuffer, BufferCopy, bool)> BufferUploads = new List<(GpuBuffer, BufferCopy, bool)>();
List<(TextureRegion, uint, bool)> TextureUploads = new List<(TextureRegion, uint, bool)>();
public ResourceUploader(GraphicsDevice device) : base(device)
{
@ -45,7 +45,7 @@ namespace MoonWorks.Graphics
var lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length);
var gpuBuffer = new GpuBuffer(Device, usageFlags, lengthInBytes);
SetBufferData(gpuBuffer, 0, data, WriteOptions.Unsafe);
SetBufferData(gpuBuffer, 0, data, false);
return gpuBuffer;
}
@ -53,7 +53,7 @@ namespace MoonWorks.Graphics
/// <summary>
/// Prepares upload of data into a GpuBuffer.
/// </summary>
public void SetBufferData<T>(GpuBuffer buffer, uint bufferOffsetInElements, Span<T> data, WriteOptions option) where T : unmanaged
public void SetBufferData<T>(GpuBuffer buffer, uint bufferOffsetInElements, Span<T> data, bool cycle) where T : unmanaged
{
uint elementSize = (uint) Marshal.SizeOf<T>();
uint offsetInBytes = elementSize * bufferOffsetInElements;
@ -66,7 +66,7 @@ namespace MoonWorks.Graphics
}
var bufferCopyParams = new BufferCopy(resourceOffset, offsetInBytes, lengthInBytes);
BufferUploads.Add((buffer, bufferCopyParams, option));
BufferUploads.Add((buffer, bufferCopyParams, cycle));
}
// Textures
@ -74,7 +74,7 @@ namespace MoonWorks.Graphics
public Texture CreateTexture2D<T>(Span<T> pixelData, uint width, uint height) where T : unmanaged
{
var texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
SetTextureData(texture, pixelData, WriteOptions.Unsafe);
SetTextureData(texture, pixelData, false);
return texture;
}
@ -164,7 +164,7 @@ namespace MoonWorks.Graphics
Depth = 1
};
SetTextureData(textureRegion, byteSpan, WriteOptions.Unsafe);
SetTextureData(textureRegion, byteSpan, false);
NativeMemory.Free(byteBuffer);
}
@ -187,7 +187,7 @@ namespace MoonWorks.Graphics
var pixelData = ImageUtils.GetPixelDataFromBytes(compressedImageData, out var _, out var _, out var sizeInBytes);
var pixelSpan = new Span<byte>((void*) pixelData, (int) sizeInBytes);
SetTextureData(textureRegion, pixelSpan, WriteOptions.Unsafe);
SetTextureData(textureRegion, pixelSpan, false);
ImageUtils.FreePixelData(pixelData);
}
@ -211,7 +211,7 @@ namespace MoonWorks.Graphics
/// <summary>
/// Prepares upload of pixel data into a TextureSlice.
/// </summary>
public void SetTextureData<T>(TextureRegion textureRegion, Span<T> data, WriteOptions option) where T : unmanaged
public void SetTextureData<T>(TextureRegion textureRegion, Span<T> data, bool cycle) where T : unmanaged
{
var elementSize = Marshal.SizeOf<T>();
var dataLengthInBytes = (uint) (elementSize * data.Length);
@ -222,7 +222,7 @@ namespace MoonWorks.Graphics
resourceOffset = CopyTextureData(dataPtr, dataLengthInBytes, Texture.BytesPerPixel(textureRegion.TextureSlice.Texture.Format));
}
TextureUploads.Add((textureRegion, resourceOffset, option));
TextureUploads.Add((textureRegion, resourceOffset, cycle));
}
// Upload
@ -263,11 +263,11 @@ namespace MoonWorks.Graphics
if (BufferTransferBuffer == null || BufferTransferBuffer.Size < bufferDataSize)
{
BufferTransferBuffer?.Dispose();
BufferTransferBuffer = new TransferBuffer(Device, TransferUsage.Buffer, bufferDataSize);
BufferTransferBuffer = new TransferBuffer(Device, TransferUsage.Buffer, TransferBufferMapFlags.Write, bufferDataSize);
}
var dataSpan = new Span<byte>(bufferData, (int) bufferDataSize);
BufferTransferBuffer.SetData(dataSpan, TransferOptions.Cycle);
BufferTransferBuffer.SetData(dataSpan, true);
}
@ -276,21 +276,21 @@ namespace MoonWorks.Graphics
if (TextureTransferBuffer == null || TextureTransferBuffer.Size < textureDataSize)
{
TextureTransferBuffer?.Dispose();
TextureTransferBuffer = new TransferBuffer(Device, TransferUsage.Texture, textureDataSize);
TextureTransferBuffer = new TransferBuffer(Device, TransferUsage.Texture, TransferBufferMapFlags.Write, textureDataSize);
}
var dataSpan = new Span<byte>(textureData, (int) textureDataSize);
TextureTransferBuffer.SetData(dataSpan, TransferOptions.Cycle);
TextureTransferBuffer.SetData(dataSpan, true);
}
}
private void RecordUploadCommands(CommandBuffer commandBuffer)
{
commandBuffer.BeginCopyPass();
var copyPass = commandBuffer.BeginCopyPass();
foreach (var (gpuBuffer, bufferCopyParams, option) in BufferUploads)
{
commandBuffer.UploadToBuffer(
copyPass.UploadToBuffer(
BufferTransferBuffer,
gpuBuffer,
bufferCopyParams,
@ -300,7 +300,7 @@ namespace MoonWorks.Graphics
foreach (var (textureRegion, offset, option) in TextureUploads)
{
commandBuffer.UploadToTexture(
copyPass.UploadToTexture(
TextureTransferBuffer,
textureRegion,
new BufferImageCopy(
@ -312,7 +312,7 @@ namespace MoonWorks.Graphics
);
}
commandBuffer.EndCopyPass();
commandBuffer.EndCopyPass(copyPass);
BufferUploads.Clear();
TextureUploads.Clear();

View File

@ -1,26 +1,25 @@
using System;
using RefreshCS;
using SDL2_gpuCS;
namespace MoonWorks.Graphics
namespace MoonWorks.Graphics;
/// <summary>
/// Fences allow you to track the status of a submitted command buffer. <br/>
/// You should only acquire a Fence if you will need to track the command buffer. <br/>
/// You should make sure to call GraphicsDevice.ReleaseFence when done with a Fence to avoid memory growth. <br/>
/// The Fence object itself is basically just a wrapper for the Refresh_Fence. <br/>
/// The internal handle is replaced so that we can pool Fence objects to manage garbage.
/// </summary>
public class Fence : SDL_GpuResource
{
/// <summary>
/// Fences allow you to track the status of a submitted command buffer. <br/>
/// You should only acquire a Fence if you will need to track the command buffer. <br/>
/// You should make sure to call GraphicsDevice.ReleaseFence when done with a Fence to avoid memory growth. <br/>
/// The Fence object itself is basically just a wrapper for the Refresh_Fence. <br/>
/// The internal handle is replaced so that we can pool Fence objects to manage garbage.
/// </summary>
public class Fence : SDL_GpuResource
protected override Action<nint, nint> ReleaseFunction => SDL_Gpu.SDL_GpuReleaseFence;
internal Fence(GraphicsDevice device) : base(device)
{
protected override Action<nint, nint> ReleaseFunction => Refresh.Refresh_ReleaseFence;
}
internal Fence(GraphicsDevice device) : base(device)
{
}
internal void SetHandle(nint handle)
{
Handle = handle;
}
internal void SetHandle(nint handle)
{
Handle = handle;
}
}

View File

@ -1,24 +1,23 @@
using System;
using RefreshCS;
using SDL2_gpuCS;
namespace MoonWorks.Graphics
namespace MoonWorks.Graphics;
/// <summary>
/// A sampler specifies how a texture will be sampled in a shader.
/// </summary>
public class Sampler : SDL_GpuResource
{
/// <summary>
/// A sampler specifies how a texture will be sampled in a shader.
/// </summary>
public class Sampler : SDL_GpuResource
{
protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_QueueDestroySampler;
protected override Action<IntPtr, IntPtr> ReleaseFunction => SDL_Gpu.SDL_GpuReleaseSampler;
public Sampler(
GraphicsDevice device,
in SamplerCreateInfo samplerCreateInfo
) : base(device)
{
Handle = Refresh.Refresh_CreateSampler(
device.Handle,
samplerCreateInfo.ToRefreshSamplerStateCreateInfo()
);
}
public Sampler(
GraphicsDevice device,
in SamplerCreateInfo samplerCreateInfo
) : base(device)
{
Handle = SDL_Gpu.SDL_GpuCreateSampler(
device.Handle,
samplerCreateInfo.ToSDL()
);
}
}

View File

@ -1,12 +1,12 @@
using System;
using System.Runtime.InteropServices;
using RefreshCS;
using SDL2_gpuCS;
namespace MoonWorks.Graphics
{
public unsafe class TransferBuffer : SDL_GpuResource
{
protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_QueueDestroyTransferBuffer;
protected override Action<IntPtr, IntPtr> ReleaseFunction => SDL_Gpu.SDL_GpuReleaseTransferBuffer;
/// <summary>
/// Size in bytes.
@ -23,12 +23,14 @@ namespace MoonWorks.Graphics
public unsafe static TransferBuffer Create<T>(
GraphicsDevice device,
TransferUsage usage,
TransferBufferMapFlags mapFlags,
uint elementCount
) where T : unmanaged
{
return new TransferBuffer(
device,
usage,
mapFlags,
(uint) Marshal.SizeOf<T>() * elementCount
);
}
@ -42,12 +44,14 @@ namespace MoonWorks.Graphics
public TransferBuffer(
GraphicsDevice device,
TransferUsage usage,
TransferBufferMapFlags mapFlags,
uint sizeInBytes
) : base(device)
{
Handle = Refresh.Refresh_CreateTransferBuffer(
Handle = SDL_Gpu.SDL_GpuCreateTransferBuffer(
device.Handle,
(Refresh.TransferUsage) usage,
(SDL_Gpu.TransferUsage) usage,
(SDL_Gpu.TransferBufferMapFlags) mapFlags,
sizeInBytes
);
Size = sizeInBytes;
@ -57,16 +61,16 @@ namespace MoonWorks.Graphics
/// 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 cycle is set to true and this TransferBuffer was used in an Upload command,
/// that command will still use the corret 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.
/// If cycle is set to false, the data will be overwritten immediately,
/// which could cause a data race.
/// </summary>
public unsafe uint SetData<T>(
Span<T> data,
uint bufferOffsetInBytes,
TransferOptions setDataOption
bool cycle
) where T : unmanaged
{
var elementSize = Marshal.SizeOf<T>();
@ -78,17 +82,17 @@ namespace MoonWorks.Graphics
fixed (T* dataPtr = data)
{
Refresh.Refresh_SetTransferData(
SDL_Gpu.SDL_GpuSetTransferData(
Device.Handle,
(nint) dataPtr,
Handle,
new Refresh.BufferCopy
new SDL_Gpu.BufferCopy
{
srcOffset = 0,
dstOffset = bufferOffsetInBytes,
size = dataLengthInBytes
SourceOffset = 0,
DestinationOffset = bufferOffsetInBytes,
Size = dataLengthInBytes
},
(Refresh.TransferOptions) setDataOption
Conversions.BoolToInt(cycle)
);
}
@ -99,18 +103,18 @@ namespace MoonWorks.Graphics
/// 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 cycle is set to true and this TransferBuffer was used in an Upload command,
/// that command will still use the corret 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.
/// If cycle is set to false, the data will be overwritten immediately,
/// which could cause a data race.
/// </summary>
public unsafe uint SetData<T>(
Span<T> data,
TransferOptions setDataOption
bool cycle
) where T : unmanaged
{
return SetData(data, 0, setDataOption);
return SetData(data, 0, cycle);
}
/// <summary>
@ -130,15 +134,15 @@ namespace MoonWorks.Graphics
fixed (T* dataPtr = data)
{
Refresh.Refresh_GetTransferData(
SDL_Gpu.SDL_GpuGetTransferData(
Device.Handle,
Handle,
(nint) dataPtr,
new Refresh.BufferCopy
new SDL_Gpu.BufferCopy
{
srcOffset = bufferOffsetInBytes,
dstOffset = 0,
size = dataLengthInBytes
SourceOffset = bufferOffsetInBytes,
DestinationOffset = 0,
Size = dataLengthInBytes
}
);
}

View File

@ -788,7 +788,7 @@ public struct BufferCopy
Size = size;
}
public SDL_Gpu.BufferCopy ToRefresh()
public SDL_Gpu.BufferCopy ToSDL()
{
return new SDL_Gpu.BufferCopy
{
@ -811,7 +811,7 @@ public readonly record struct BufferImageCopy(
uint BufferStride,
uint BufferImageHeight
) {
public SDL_Gpu.BufferImageCopy ToRefresh()
public SDL_Gpu.BufferImageCopy ToSDL()
{
return new SDL_Gpu.BufferImageCopy
{

View File

@ -1,5 +1,4 @@
using System;
using RefreshCS;
namespace MoonWorks
{
@ -9,19 +8,6 @@ namespace MoonWorks
public static Action<string> LogWarn = LogWarnDefault;
public static Action<string> LogError = LogErrorDefault;
private static RefreshCS.Refresh.Refresh_LogFunc LogInfoFunc = RefreshLogInfo;
private static RefreshCS.Refresh.Refresh_LogFunc LogWarnFunc = RefreshLogWarn;
private static RefreshCS.Refresh.Refresh_LogFunc LogErrorFunc = RefreshLogError;
internal static void Initialize()
{
Refresh.Refresh_HookLogFunctions(
LogInfoFunc,
LogWarnFunc,
LogErrorFunc
);
}
private static void LogInfoDefault(string str)
{
Console.ForegroundColor = ConsoleColor.Green;

View File

@ -22,9 +22,13 @@
/// </summary>
public ScreenMode ScreenMode;
/// <summary>
/// Specifies the swapchain composition. Use SDR unless you know what you're doing.
/// </summary>
public Graphics.SwapchainComposition SwapchainComposition;
/// <summary>
/// Specifies the presentation mode for the window. Roughly equivalent to V-Sync.
/// </summary>
public PresentMode PresentMode;
public Graphics.PresentMode PresentMode;
/// <summary>
/// Whether the window can be resized using the operating system's window dragging feature.
/// </summary>
@ -39,7 +43,7 @@
uint windowWidth,
uint windowHeight,
ScreenMode screenMode,
PresentMode presentMode,
Graphics.PresentMode presentMode,
bool systemResizable = false,
bool startMaximized = false
) {