refactor CopyPass
parent
97dee2a170
commit
3cfb43438c
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -41,6 +41,7 @@ namespace MoonWorks.Graphics
|
|||
private FencePool FencePool;
|
||||
internal RenderPassPool RenderPassPool;
|
||||
internal ComputePassPool ComputePassPool;
|
||||
internal CopyPassPool CopyPassPool;
|
||||
|
||||
internal unsafe GraphicsDevice(
|
||||
BackendFlags preferredBackends,
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using RefreshCS;
|
||||
using SDL2;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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/>
|
||||
|
@ -12,7 +12,7 @@ namespace MoonWorks.Graphics
|
|||
/// </summary>
|
||||
public class Fence : SDL_GpuResource
|
||||
{
|
||||
protected override Action<nint, nint> ReleaseFunction => Refresh.Refresh_ReleaseFence;
|
||||
protected override Action<nint, nint> ReleaseFunction => SDL_Gpu.SDL_GpuReleaseFence;
|
||||
|
||||
internal Fence(GraphicsDevice device) : base(device)
|
||||
{
|
||||
|
@ -23,4 +23,3 @@ namespace MoonWorks.Graphics
|
|||
Handle = handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
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(
|
||||
Handle = SDL_Gpu.SDL_GpuCreateSampler(
|
||||
device.Handle,
|
||||
samplerCreateInfo.ToRefreshSamplerStateCreateInfo()
|
||||
samplerCreateInfo.ToSDL()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
) {
|
||||
|
|
Loading…
Reference in New Issue