Compare commits
14 Commits
178a5ea3cf
...
9195e445b2
Author | SHA1 | Date |
---|---|---|
|
9195e445b2 | |
|
f30d8f0197 | |
|
bde31fbe07 | |
|
a762a80c4f | |
|
099c07aa39 | |
|
cba6ca59d3 | |
|
a004488f81 | |
|
33ed8b2364 | |
|
3c832550d0 | |
|
c84752f38c | |
|
019afa91f5 | |
|
00adec189c | |
|
0e723514df | |
|
e0f4c19dc2 |
|
@ -3,7 +3,6 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>11</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2e346d84016fb7b26dbe7c5b6c485109571c30f4
|
||||
Subproject commit 029f19196a94e13b8ed98d10f47a701221951f2f
|
|
@ -53,10 +53,10 @@ namespace MoonWorks
|
|||
public Game(
|
||||
WindowCreateInfo windowCreateInfo,
|
||||
FrameLimiterSettings frameLimiterSettings,
|
||||
Span<Backend> preferredBackends,
|
||||
int targetTimestep = 60,
|
||||
bool debugMode = false
|
||||
)
|
||||
{
|
||||
) {
|
||||
Logger.LogInfo("Initializing frame limiter...");
|
||||
Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / targetTimestep);
|
||||
gameTimer = Stopwatch.StartNew();
|
||||
|
@ -82,7 +82,7 @@ namespace MoonWorks
|
|||
|
||||
Logger.LogInfo("Initializing graphics device...");
|
||||
GraphicsDevice = new GraphicsDevice(
|
||||
Backend.Vulkan,
|
||||
preferredBackends,
|
||||
debugMode
|
||||
);
|
||||
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
namespace MoonWorks.Graphics
|
||||
using RefreshCS;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A buffer-offset pair to be used when binding vertex buffers.
|
||||
/// A buffer-offset pair to be used when binding vertex or index buffers.
|
||||
/// </summary>
|
||||
public struct BufferBinding
|
||||
public readonly record struct BufferBinding(
|
||||
GpuBuffer Buffer,
|
||||
uint Offset
|
||||
) {
|
||||
public Refresh.BufferBinding ToRefresh()
|
||||
{
|
||||
public GpuBuffer Buffer;
|
||||
public ulong Offset;
|
||||
|
||||
public BufferBinding(GpuBuffer buffer, ulong offset)
|
||||
return new Refresh.BufferBinding
|
||||
{
|
||||
Buffer = buffer;
|
||||
Offset = offset;
|
||||
gpuBuffer = Buffer.Handle,
|
||||
offset = Offset
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using RefreshCS;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Binding specification to be used when binding buffers for compute shaders.
|
||||
/// </summary>
|
||||
/// <param name="GpuBuffer">The GpuBuffer to bind.</param>
|
||||
/// <param name="WriteOption">
|
||||
/// Specifies data dependency behavior when this buffer is written to in the shader. <br/>
|
||||
///
|
||||
/// Cycle:
|
||||
/// If this buffer has been used in commands that have not finished,
|
||||
/// the implementation may choose to prevent a dependency on those commands
|
||||
/// at the cost of increased memory usage.
|
||||
/// You may NOT assume that any of the previous data is retained.
|
||||
/// This may prevent stalls when frequently updating a resource. <br />
|
||||
///
|
||||
/// SafeOverwrite:
|
||||
/// Overwrites the data safely using a GPU memory barrier.
|
||||
/// </param>
|
||||
public readonly record struct ComputeBufferBinding(
|
||||
GpuBuffer GpuBuffer,
|
||||
WriteOptions WriteOption
|
||||
) {
|
||||
public Refresh.ComputeBufferBinding ToRefresh()
|
||||
{
|
||||
return new Refresh.ComputeBufferBinding
|
||||
{
|
||||
gpuBuffer = GpuBuffer.Handle,
|
||||
writeOption = (Refresh.WriteOptions) WriteOption
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using RefreshCS;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Binding specification used for binding texture slices for compute shaders.
|
||||
/// </summary>
|
||||
/// <param name="TextureSlice">The TextureSlice to bind.</param>
|
||||
/// <param name="WriteOption">
|
||||
/// Specifies data dependency behavior when this texture is written to in the shader. <br/>
|
||||
///
|
||||
/// Cycle:
|
||||
/// If this buffer has been used in commands that have not finished,
|
||||
/// the implementation may choose to prevent a dependency on those commands
|
||||
/// at the cost of increased memory usage.
|
||||
/// You may NOT assume that any of the previous data is retained.
|
||||
/// This may prevent stalls when frequently updating a resource. <br />
|
||||
///
|
||||
/// SafeOverwrite:
|
||||
/// Overwrites the data safely using a GPU memory barrier.
|
||||
/// </param>
|
||||
public readonly record struct ComputeTextureBinding(
|
||||
TextureSlice TextureSlice,
|
||||
WriteOptions WriteOption
|
||||
) {
|
||||
public Refresh.ComputeTextureBinding ToRefresh()
|
||||
{
|
||||
return new Refresh.ComputeTextureBinding
|
||||
{
|
||||
textureSlice = TextureSlice.ToRefreshTextureSlice(),
|
||||
writeOption = (Refresh.WriteOptions) WriteOption
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A texture-level pair to be used when binding compute textures.
|
||||
/// </summary>
|
||||
public struct TextureLevelBinding
|
||||
{
|
||||
public Texture Texture;
|
||||
public uint MipLevel;
|
||||
|
||||
public TextureLevelBinding(Texture texture, uint mipLevel = 0)
|
||||
{
|
||||
Texture = texture;
|
||||
MipLevel = mipLevel;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,21 @@
|
|||
namespace MoonWorks.Graphics
|
||||
using RefreshCS;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A texture-sampler pair to be used when binding samplers.
|
||||
/// </summary>
|
||||
public struct TextureSamplerBinding
|
||||
public readonly record struct TextureSamplerBinding(
|
||||
Texture Texture,
|
||||
Sampler Sampler
|
||||
) {
|
||||
public Refresh.TextureSamplerBinding ToRefresh()
|
||||
{
|
||||
public Texture Texture;
|
||||
public Sampler Sampler;
|
||||
|
||||
public TextureSamplerBinding(Texture texture, Sampler sampler)
|
||||
return new Refresh.TextureSamplerBinding
|
||||
{
|
||||
Texture = texture;
|
||||
Sampler = sampler;
|
||||
texture = Texture.Handle,
|
||||
sampler = Sampler.Handle
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,24 +49,12 @@ namespace MoonWorks.Graphics.Font
|
|||
|
||||
var imagePath = Path.ChangeExtension(fontPath, ".png");
|
||||
ImageUtils.ImageInfoFromFile(imagePath, out var width, out var height, out var sizeInBytes);
|
||||
var texture = Texture.CreateTexture2D(graphicsDevice, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
|
||||
|
||||
var transferBuffer = new TransferBuffer(graphicsDevice, sizeInBytes);
|
||||
ImageUtils.DecodeIntoTransferBuffer(
|
||||
imagePath,
|
||||
transferBuffer,
|
||||
0,
|
||||
SetDataOptions.Overwrite
|
||||
);
|
||||
var uploader = new ResourceUploader(graphicsDevice);
|
||||
var texture = uploader.CreateTexture2DFromCompressed(imagePath);
|
||||
uploader.Upload();
|
||||
uploader.Dispose();
|
||||
|
||||
commandBuffer.BeginCopyPass();
|
||||
commandBuffer.UploadToTexture(
|
||||
transferBuffer,
|
||||
texture
|
||||
);
|
||||
commandBuffer.EndCopyPass();
|
||||
|
||||
transferBuffer.Dispose();
|
||||
NativeMemory.Free(fontFileByteBuffer);
|
||||
NativeMemory.Free(atlasFileByteBuffer);
|
||||
|
||||
|
|
|
@ -124,11 +124,11 @@ namespace MoonWorks.Graphics.Font
|
|||
|
||||
if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
|
||||
{
|
||||
TransferBuffer.SetData(vertexSpan, SetDataOptions.Discard);
|
||||
TransferBuffer.SetData(indexSpan, (uint) vertexSpan.Length, SetDataOptions.Overwrite);
|
||||
TransferBuffer.SetData(vertexSpan, TransferOptions.Cycle);
|
||||
TransferBuffer.SetData(indexSpan, (uint) vertexSpan.Length, TransferOptions.Overwrite);
|
||||
|
||||
commandBuffer.UploadToBuffer(TransferBuffer, VertexBuffer, new BufferCopy(0, 0, (uint) vertexSpan.Length));
|
||||
commandBuffer.UploadToBuffer(TransferBuffer, IndexBuffer, new BufferCopy((uint) vertexSpan.Length, 0, (uint) indexSpan.Length));
|
||||
commandBuffer.UploadToBuffer(TransferBuffer, VertexBuffer, new BufferCopy(0, 0, (uint) vertexSpan.Length), WriteOptions.Cycle);
|
||||
commandBuffer.UploadToBuffer(TransferBuffer, IndexBuffer, new BufferCopy((uint) vertexSpan.Length, 0, (uint) indexSpan.Length), WriteOptions.Cycle);
|
||||
}
|
||||
|
||||
PrimitiveCount = vertexCount / 2;
|
||||
|
|
|
@ -40,11 +40,17 @@ namespace MoonWorks.Graphics
|
|||
private FencePool FencePool;
|
||||
private CommandBufferPool CommandBufferPool;
|
||||
|
||||
internal GraphicsDevice(
|
||||
Backend preferredBackend,
|
||||
internal unsafe GraphicsDevice(
|
||||
Span<Backend> preferredBackends,
|
||||
bool debugMode
|
||||
) {
|
||||
Backend = (Backend) Refresh.Refresh_SelectBackend((Refresh.Backend) preferredBackend, out windowFlags);
|
||||
var backends = stackalloc Refresh.Backend[preferredBackends.Length];
|
||||
for (var i = 0; i < preferredBackends.Length; i += 1)
|
||||
{
|
||||
backends[i] = (Refresh.Backend) preferredBackends[i];
|
||||
}
|
||||
|
||||
Backend = (Backend) Refresh.Refresh_SelectBackend(backends, (uint) preferredBackends.Length, out windowFlags);
|
||||
|
||||
if (Backend == Backend.Invalid)
|
||||
{
|
||||
|
@ -467,6 +473,118 @@ namespace MoonWorks.Graphics
|
|||
FencePool.Return(fence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ⚠️⚠️⚠️ <br/>
|
||||
/// Downloads data from a Texture to a TransferBuffer.
|
||||
/// This copy occurs immediately on the CPU timeline.<br/>
|
||||
///
|
||||
/// If you modify this texture in a command buffer and then call this function without calling
|
||||
/// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.<br/>
|
||||
///
|
||||
/// This method forces a sync point and is generally a bad thing to do.
|
||||
/// Only use it if you have exhausted all other options.<br/>
|
||||
///
|
||||
/// Remember: friends don't let friends readback.<br/>
|
||||
/// ⚠️⚠️⚠️
|
||||
/// </summary>
|
||||
public void DownloadFromTexture(
|
||||
in TextureRegion textureRegion,
|
||||
TransferBuffer transferBuffer,
|
||||
in BufferImageCopy copyParams,
|
||||
TransferOptions transferOption
|
||||
) {
|
||||
Refresh.Refresh_DownloadFromTexture(
|
||||
Handle,
|
||||
textureRegion.ToRefreshTextureRegion(),
|
||||
transferBuffer.Handle,
|
||||
copyParams.ToRefresh(),
|
||||
(Refresh.TransferOptions) transferOption
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ⚠️⚠️⚠️ <br/>
|
||||
/// Downloads all data from a 2D texture with no mips to a TransferBuffer.
|
||||
/// This copy occurs immediately on the CPU timeline.<br/>
|
||||
///
|
||||
/// If you modify this texture in a command buffer and then call this function without calling
|
||||
/// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.<br/>
|
||||
///
|
||||
/// This method forces a sync point and is generally a bad thing to do.
|
||||
/// Only use it if you have exhausted all other options.<br/>
|
||||
///
|
||||
/// Remember: friends don't let friends readback.<br/>
|
||||
/// ⚠️⚠️⚠️
|
||||
/// </summary>
|
||||
public void DownloadFromTexture(
|
||||
Texture texture,
|
||||
TransferBuffer transferBuffer,
|
||||
TransferOptions transferOption
|
||||
) {
|
||||
DownloadFromTexture(
|
||||
new TextureRegion(texture),
|
||||
transferBuffer,
|
||||
new BufferImageCopy(0, 0, 0),
|
||||
transferOption
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ⚠️⚠️⚠️ <br/>
|
||||
/// Downloads data from a GpuBuffer to a TransferBuffer.
|
||||
/// This copy occurs immediately on the CPU timeline.<br/>
|
||||
///
|
||||
/// If you modify this GpuBuffer in a command buffer and then call this function without calling
|
||||
/// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.<br/>
|
||||
///
|
||||
/// This method forces a sync point and is generally a bad thing to do.
|
||||
/// Only use it if you have exhausted all other options.<br/>
|
||||
///
|
||||
/// Remember: friends don't let friends readback.<br/>
|
||||
/// ⚠️⚠️⚠️
|
||||
/// </summary>
|
||||
public void DownloadFromBuffer(
|
||||
GpuBuffer gpuBuffer,
|
||||
TransferBuffer transferBuffer,
|
||||
in BufferCopy copyParams,
|
||||
TransferOptions transferOption
|
||||
) {
|
||||
Refresh.Refresh_DownloadFromBuffer(
|
||||
Handle,
|
||||
gpuBuffer.Handle,
|
||||
transferBuffer.Handle,
|
||||
copyParams.ToRefresh(),
|
||||
(Refresh.TransferOptions) transferOption
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ⚠️⚠️⚠️ <br/>
|
||||
/// Downloads all data in a GpuBuffer to a TransferBuffer.
|
||||
/// This copy occurs immediately on the CPU timeline.<br/>
|
||||
///
|
||||
/// If you modify this GpuBuffer in a command buffer and then call this function without calling
|
||||
/// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.<br/>
|
||||
///
|
||||
/// This method forces a sync point and is generally a bad thing to do.
|
||||
/// Only use it if you have exhausted all other options.<br/>
|
||||
///
|
||||
/// Remember: friends don't let friends readback.<br/>
|
||||
/// ⚠️⚠️⚠️
|
||||
/// </summary>
|
||||
public void DownloadFromBuffer(
|
||||
GpuBuffer gpuBuffer,
|
||||
TransferBuffer transferBuffer,
|
||||
TransferOptions option
|
||||
) {
|
||||
DownloadFromBuffer(
|
||||
gpuBuffer,
|
||||
transferBuffer,
|
||||
new BufferCopy(0, 0, gpuBuffer.Size),
|
||||
option
|
||||
);
|
||||
}
|
||||
|
||||
private TextureFormat GetSwapchainFormat(Window window)
|
||||
{
|
||||
return (TextureFormat) Refresh.Refresh_GetSwapchainFormat(Handle, window.Handle);
|
||||
|
|
|
@ -145,51 +145,6 @@ namespace MoonWorks.Graphics
|
|||
Refresh.Refresh_Image_Free(pixels);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes image data into a TransferBuffer to prepare for image upload.
|
||||
/// </summary>
|
||||
public static unsafe uint DecodeIntoTransferBuffer(
|
||||
Span<byte> data,
|
||||
TransferBuffer transferBuffer,
|
||||
uint bufferOffsetInBytes,
|
||||
SetDataOptions option
|
||||
) {
|
||||
var pixelData = GetPixelDataFromBytes(data, out var w, out var h, out var sizeInBytes);
|
||||
var length = transferBuffer.SetData(new Span<byte>((void*) pixelData, (int) sizeInBytes), bufferOffsetInBytes, option);
|
||||
FreePixelData(pixelData);
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an image stream into a TransferBuffer to prepare for image upload.
|
||||
/// </summary>
|
||||
public static unsafe uint DecodeIntoTransferBuffer(
|
||||
Stream stream,
|
||||
TransferBuffer transferBuffer,
|
||||
uint bufferOffsetInBytes,
|
||||
SetDataOptions option
|
||||
) {
|
||||
var pixelData = GetPixelDataFromStream(stream, out var w, out var h, out var sizeInBytes);
|
||||
var length = transferBuffer.SetData(new Span<byte>((void*) pixelData, (int) sizeInBytes), bufferOffsetInBytes, option);
|
||||
FreePixelData(pixelData);
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an image file into a TransferBuffer to prepare for image upload.
|
||||
/// </summary>
|
||||
public static unsafe uint DecodeIntoTransferBuffer(
|
||||
string path,
|
||||
TransferBuffer transferBuffer,
|
||||
uint bufferOffsetInBytes,
|
||||
SetDataOptions option
|
||||
) {
|
||||
var pixelData = GetPixelDataFromFile(path, out var w, out var h, out var sizeInBytes);
|
||||
var length = transferBuffer.SetData(new Span<byte>((void*) pixelData, (int) sizeInBytes), bufferOffsetInBytes, option);
|
||||
FreePixelData(pixelData);
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves pixel data contained in a TransferBuffer to a PNG file.
|
||||
/// </summary>
|
||||
|
|
|
@ -297,16 +297,22 @@ namespace MoonWorks.Graphics
|
|||
IntOpaqueWhite
|
||||
}
|
||||
|
||||
public enum SetDataOptions
|
||||
public enum TransferOptions
|
||||
{
|
||||
Discard,
|
||||
Cycle,
|
||||
Overwrite
|
||||
}
|
||||
|
||||
public enum WriteOptions
|
||||
{
|
||||
Cycle,
|
||||
SafeOverwrite
|
||||
}
|
||||
|
||||
public enum Backend
|
||||
{
|
||||
DontCare,
|
||||
Vulkan,
|
||||
D3D11,
|
||||
PS5,
|
||||
Invalid
|
||||
}
|
||||
|
|
|
@ -154,11 +154,7 @@ namespace MoonWorks.Graphics
|
|||
public StencilOp PassOp;
|
||||
public StencilOp DepthFailOp;
|
||||
public CompareOp CompareOp;
|
||||
public uint CompareMask;
|
||||
public uint WriteMask;
|
||||
public uint Reference;
|
||||
|
||||
// FIXME: can we do an explicit cast here?
|
||||
public Refresh.StencilOpState ToRefresh()
|
||||
{
|
||||
return new Refresh.StencilOpState
|
||||
|
@ -166,61 +162,97 @@ namespace MoonWorks.Graphics
|
|||
failOp = (Refresh.StencilOp) FailOp,
|
||||
passOp = (Refresh.StencilOp) PassOp,
|
||||
depthFailOp = (Refresh.StencilOp) DepthFailOp,
|
||||
compareOp = (Refresh.CompareOp) CompareOp,
|
||||
compareMask = CompareMask,
|
||||
writeMask = WriteMask,
|
||||
reference = Reference
|
||||
compareOp = (Refresh.CompareOp) CompareOp
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
/// <summary>
|
||||
/// Determines how a color texture will be read/written in a render pass.
|
||||
/// </summary>
|
||||
public struct ColorAttachmentInfo
|
||||
{
|
||||
public Texture Texture;
|
||||
public uint Depth;
|
||||
public uint Layer;
|
||||
public uint Level;
|
||||
public TextureSlice TextureSlice;
|
||||
|
||||
/// <summary>
|
||||
/// If LoadOp is set to Clear, the texture slice will be cleared to this color.
|
||||
/// </summary>
|
||||
public Color ClearColor;
|
||||
|
||||
/// <summary>
|
||||
/// Determines what is done with the texture slice memory
|
||||
/// at the beginning of the render pass. <br/>
|
||||
///
|
||||
/// Load:
|
||||
/// Loads the data currently in the texture slice. <br/>
|
||||
///
|
||||
/// Clear:
|
||||
/// Clears the texture slice to a single color. <br/>
|
||||
///
|
||||
/// DontCare:
|
||||
/// The driver will do whatever it wants with the texture slice data.
|
||||
/// This is a good option if you know that every single pixel will be written in the render pass.
|
||||
/// </summary>
|
||||
public LoadOp LoadOp;
|
||||
|
||||
/// <summary>
|
||||
/// Determines what is done with the texture slice memory
|
||||
/// at the end of the render pass. <br/>
|
||||
///
|
||||
/// Store:
|
||||
/// Stores the results of the render pass in the texture slice memory. <br/>
|
||||
///
|
||||
/// DontCare:
|
||||
/// The driver will do whatever it wants with the texture slice memory.
|
||||
/// </summary>
|
||||
public StoreOp StoreOp;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies data dependency behavior. This option is ignored if LoadOp is Load. <br/>
|
||||
///
|
||||
/// Cycle:
|
||||
/// If this texture slice has been used in commands that have not completed,
|
||||
/// the implementation may prevent a dependency on those commands
|
||||
/// at the cost of increased memory usage.
|
||||
/// You may NOT assume that any of the previous texture (not slice!) data is retained.
|
||||
/// This may prevent stalls when frequently reusing a texture slice in rendering. <br/>
|
||||
///
|
||||
/// SafeOverwrite:
|
||||
/// Overwrites the data safely using a GPU memory barrier.
|
||||
/// </summary>
|
||||
public WriteOptions WriteOption;
|
||||
|
||||
public ColorAttachmentInfo(
|
||||
Texture texture,
|
||||
TextureSlice textureSlice,
|
||||
WriteOptions writeOption,
|
||||
Color clearColor,
|
||||
StoreOp storeOp = StoreOp.Store
|
||||
) {
|
||||
Texture = texture;
|
||||
Depth = 0;
|
||||
Layer = 0;
|
||||
Level = 0;
|
||||
TextureSlice = textureSlice;
|
||||
ClearColor = clearColor;
|
||||
LoadOp = LoadOp.Clear;
|
||||
StoreOp = storeOp;
|
||||
WriteOption = writeOption;
|
||||
}
|
||||
|
||||
public ColorAttachmentInfo(
|
||||
Texture texture,
|
||||
TextureSlice textureSlice,
|
||||
WriteOptions writeOption,
|
||||
LoadOp loadOp = LoadOp.DontCare,
|
||||
StoreOp storeOp = StoreOp.Store
|
||||
) {
|
||||
Texture = texture;
|
||||
Depth = 0;
|
||||
Layer = 0;
|
||||
Level = 0;
|
||||
TextureSlice = textureSlice;
|
||||
ClearColor = Color.White;
|
||||
LoadOp = loadOp;
|
||||
StoreOp = storeOp;
|
||||
WriteOption = writeOption;
|
||||
}
|
||||
|
||||
public Refresh.ColorAttachmentInfo ToRefresh()
|
||||
{
|
||||
return new Refresh.ColorAttachmentInfo
|
||||
{
|
||||
texture = Texture.Handle,
|
||||
depth = Depth,
|
||||
layer = Layer,
|
||||
level = Level,
|
||||
textureSlice = TextureSlice.ToRefreshTextureSlice(),
|
||||
clearColor = new Refresh.Vec4
|
||||
{
|
||||
x = ClearColor.R / 255f,
|
||||
|
@ -229,92 +261,142 @@ namespace MoonWorks.Graphics
|
|||
w = ClearColor.A / 255f
|
||||
},
|
||||
loadOp = (Refresh.LoadOp) LoadOp,
|
||||
storeOp = (Refresh.StoreOp) StoreOp
|
||||
storeOp = (Refresh.StoreOp) StoreOp,
|
||||
writeOption = (Refresh.WriteOptions) WriteOption
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
/// <summary>
|
||||
/// Determines how a depth/stencil texture will be read/written in a render pass.
|
||||
/// </summary>
|
||||
public struct DepthStencilAttachmentInfo
|
||||
{
|
||||
public Texture Texture;
|
||||
public uint Depth;
|
||||
public uint Layer;
|
||||
public uint Level;
|
||||
public TextureSlice TextureSlice;
|
||||
|
||||
/// <summary>
|
||||
/// If LoadOp is set to Clear, the texture slice depth will be cleared to this depth value. <br/>
|
||||
/// If StencilLoadOp is set to Clear, the texture slice stencil value will be cleared to this stencil value.
|
||||
/// </summary>
|
||||
public DepthStencilValue DepthStencilClearValue;
|
||||
|
||||
/// <summary>
|
||||
/// Determines what is done with the texture slice depth values
|
||||
/// at the beginning of the render pass. <br/>
|
||||
///
|
||||
/// Load:
|
||||
/// Loads the data currently in the texture slice. <br/>
|
||||
///
|
||||
/// Clear:
|
||||
/// Clears the texture slice to a single depth value. <br/>
|
||||
///
|
||||
/// DontCare:
|
||||
/// The driver will do whatever it wants with the texture slice data.
|
||||
/// This is a good option if you know that every single pixel will be written in the render pass.
|
||||
/// </summary>
|
||||
public LoadOp LoadOp;
|
||||
|
||||
/// <summary>
|
||||
/// Determines what is done with the texture slice depth values
|
||||
/// at the end of the render pass. <br/>
|
||||
///
|
||||
/// Store:
|
||||
/// Stores the results of the render pass in the texture slice memory. <br/>
|
||||
///
|
||||
/// DontCare:
|
||||
/// The driver will do whatever it wants with the texture slice memory.
|
||||
/// This is usually a good option for depth textures that don't need to be reused.
|
||||
/// </summary>
|
||||
public StoreOp StoreOp;
|
||||
|
||||
/// <summary>
|
||||
/// Determines what is done with the texture slice stencil values
|
||||
/// at the beginning of the render pass. <br/>
|
||||
///
|
||||
/// Load:
|
||||
/// Loads the data currently in the texture slice. <br/>
|
||||
///
|
||||
/// Clear:
|
||||
/// Clears the texture slice to a single stencil value. <br/>
|
||||
///
|
||||
/// DontCare:
|
||||
/// The driver will do whatever it wants with the texture slice data.
|
||||
/// This is a good option if you know that every single pixel will be written in the render pass.
|
||||
/// </summary>
|
||||
public LoadOp StencilLoadOp;
|
||||
|
||||
/// <summary>
|
||||
/// Determines what is done with the texture slice stencil values
|
||||
/// at the end of the render pass. <br/>
|
||||
///
|
||||
/// Store:
|
||||
/// Stores the results of the render pass in the texture slice memory. <br/>
|
||||
///
|
||||
/// DontCare:
|
||||
/// The driver will do whatever it wants with the texture slice memory.
|
||||
/// This is usually a good option for stencil textures that don't need to be reused.
|
||||
/// </summary>
|
||||
public StoreOp StencilStoreOp;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies data dependency behavior. This option is ignored if LoadOp or StencilLoadOp is Load. <br/>
|
||||
///
|
||||
/// Cycle:
|
||||
/// If this texture slice has been used in commands that have not completed,
|
||||
/// the implementation may prevent a dependency on those commands
|
||||
/// at the cost of increased memory usage.
|
||||
/// You may NOT assume that any of the previous texture (not slice!) data is retained.
|
||||
/// This may prevent stalls when frequently reusing a texture slice in rendering. <br/>
|
||||
///
|
||||
/// SafeOverwrite:
|
||||
/// Overwrites the data safely using a GPU memory barrier.
|
||||
/// </summary>
|
||||
public WriteOptions WriteOption;
|
||||
|
||||
public DepthStencilAttachmentInfo(
|
||||
Texture texture,
|
||||
TextureSlice textureSlice,
|
||||
WriteOptions writeOption,
|
||||
DepthStencilValue clearValue,
|
||||
StoreOp depthStoreOp = StoreOp.Store,
|
||||
StoreOp stencilStoreOp = StoreOp.Store
|
||||
)
|
||||
{
|
||||
Texture = texture;
|
||||
Depth = 0;
|
||||
Layer = 0;
|
||||
Level = 0;
|
||||
StoreOp depthStoreOp = StoreOp.DontCare,
|
||||
StoreOp stencilStoreOp = StoreOp.DontCare
|
||||
){
|
||||
TextureSlice = textureSlice;
|
||||
DepthStencilClearValue = clearValue;
|
||||
LoadOp = LoadOp.Clear;
|
||||
StoreOp = depthStoreOp;
|
||||
StencilLoadOp = LoadOp.Clear;
|
||||
StencilStoreOp = stencilStoreOp;
|
||||
WriteOption = writeOption;
|
||||
}
|
||||
|
||||
public DepthStencilAttachmentInfo(
|
||||
Texture texture,
|
||||
TextureSlice textureSlice,
|
||||
WriteOptions writeOption,
|
||||
LoadOp loadOp = LoadOp.DontCare,
|
||||
StoreOp storeOp = StoreOp.Store,
|
||||
StoreOp storeOp = StoreOp.DontCare,
|
||||
LoadOp stencilLoadOp = LoadOp.DontCare,
|
||||
StoreOp stencilStoreOp = StoreOp.Store
|
||||
StoreOp stencilStoreOp = StoreOp.DontCare
|
||||
) {
|
||||
Texture = texture;
|
||||
Depth = 0;
|
||||
Layer = 0;
|
||||
Level = 0;
|
||||
TextureSlice = textureSlice;
|
||||
DepthStencilClearValue = new DepthStencilValue();
|
||||
LoadOp = loadOp;
|
||||
StoreOp = storeOp;
|
||||
StencilLoadOp = stencilLoadOp;
|
||||
StencilStoreOp = stencilStoreOp;
|
||||
}
|
||||
|
||||
public DepthStencilAttachmentInfo(
|
||||
Texture texture,
|
||||
DepthStencilValue depthStencilValue,
|
||||
LoadOp loadOp,
|
||||
StoreOp storeOp,
|
||||
LoadOp stencilLoadOp,
|
||||
StoreOp stencilStoreOp
|
||||
) {
|
||||
Texture = texture;
|
||||
Depth = 0;
|
||||
Layer = 0;
|
||||
Level = 0;
|
||||
DepthStencilClearValue = depthStencilValue;
|
||||
LoadOp = loadOp;
|
||||
StoreOp = storeOp;
|
||||
StencilLoadOp = stencilLoadOp;
|
||||
StencilStoreOp = stencilStoreOp;
|
||||
WriteOption = writeOption;
|
||||
}
|
||||
|
||||
public Refresh.DepthStencilAttachmentInfo ToRefresh()
|
||||
{
|
||||
return new Refresh.DepthStencilAttachmentInfo
|
||||
{
|
||||
texture = Texture.Handle,
|
||||
depth = Depth,
|
||||
layer = Layer,
|
||||
level = Level,
|
||||
textureSlice = TextureSlice.ToRefreshTextureSlice(),
|
||||
depthStencilClearValue = DepthStencilClearValue.ToRefresh(),
|
||||
loadOp = (Refresh.LoadOp) LoadOp,
|
||||
storeOp = (Refresh.StoreOp) StoreOp,
|
||||
stencilLoadOp = (Refresh.LoadOp) StencilLoadOp,
|
||||
stencilStoreOp = (Refresh.StoreOp) StencilStoreOp
|
||||
stencilStoreOp = (Refresh.StoreOp) StencilStoreOp,
|
||||
writeOption = (Refresh.WriteOptions) WriteOption
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -383,23 +465,18 @@ namespace MoonWorks.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parameters for a copy between buffer and image.
|
||||
/// </summary>
|
||||
/// <param name="BufferOffset">The offset into the buffer.</param>
|
||||
/// <param name="BufferStride">If 0, image data is assumed tightly packed.</param>
|
||||
/// <param name="BufferImageHeight">If 0, image data is assumed tightly packed.</param>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BufferImageCopy
|
||||
{
|
||||
public uint BufferOffset;
|
||||
public uint BufferStride; // if 0, image assumed to be tightly packed
|
||||
public uint BufferImageHeight; // if 0, image assumed to be tightly packed
|
||||
|
||||
public BufferImageCopy(
|
||||
uint bufferOffset,
|
||||
uint bufferStride,
|
||||
uint bufferImageHeight
|
||||
public readonly record struct BufferImageCopy(
|
||||
uint BufferOffset,
|
||||
uint BufferStride,
|
||||
uint BufferImageHeight
|
||||
) {
|
||||
BufferOffset = bufferOffset;
|
||||
BufferStride = bufferStride;
|
||||
BufferImageHeight = bufferImageHeight;
|
||||
}
|
||||
|
||||
public Refresh.BufferImageCopy ToRefresh()
|
||||
{
|
||||
return new Refresh.BufferImageCopy
|
||||
|
|
|
@ -21,8 +21,8 @@ namespace MoonWorks.Graphics
|
|||
uint dataOffset = 0;
|
||||
uint dataSize = 1024;
|
||||
|
||||
List<(GpuBuffer, BufferCopy)> BufferUploads = new List<(GpuBuffer, BufferCopy)>();
|
||||
List<(TextureSlice, uint)> TextureUploads = new List<(TextureSlice, uint)>();
|
||||
List<(GpuBuffer, BufferCopy, WriteOptions)> BufferUploads = new List<(GpuBuffer, BufferCopy, WriteOptions)>();
|
||||
List<(TextureRegion, uint, WriteOptions)> TextureUploads = new List<(TextureRegion, uint, WriteOptions)>();
|
||||
|
||||
public ResourceUploader(GraphicsDevice device) : base(device)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace MoonWorks.Graphics
|
|||
var lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length);
|
||||
var gpuBuffer = new GpuBuffer(Device, usageFlags, lengthInBytes);
|
||||
|
||||
SetBufferData(gpuBuffer, 0, data);
|
||||
SetBufferData(gpuBuffer, 0, data, WriteOptions.SafeOverwrite);
|
||||
|
||||
return gpuBuffer;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace MoonWorks.Graphics
|
|||
/// <summary>
|
||||
/// Prepares upload of data into a GpuBuffer.
|
||||
/// </summary>
|
||||
public void SetBufferData<T>(GpuBuffer buffer, uint bufferOffsetInElements, Span<T> data) where T : unmanaged
|
||||
public void SetBufferData<T>(GpuBuffer buffer, uint bufferOffsetInElements, Span<T> data, WriteOptions option) where T : unmanaged
|
||||
{
|
||||
uint elementSize = (uint) Marshal.SizeOf<T>();
|
||||
uint offsetInBytes = elementSize * bufferOffsetInElements;
|
||||
|
@ -60,15 +60,15 @@ namespace MoonWorks.Graphics
|
|||
}
|
||||
|
||||
var bufferCopyParams = new BufferCopy(resourceOffset, offsetInBytes, lengthInBytes);
|
||||
BufferUploads.Add((buffer, bufferCopyParams));
|
||||
BufferUploads.Add((buffer, bufferCopyParams, option));
|
||||
}
|
||||
|
||||
// Textures
|
||||
|
||||
public Texture CreateTexture2D(Span<byte> pixelData, uint width, uint height)
|
||||
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);
|
||||
SetTextureData(texture, pixelData, WriteOptions.SafeOverwrite);
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
@ -142,12 +142,14 @@ namespace MoonWorks.Graphics
|
|||
var byteSpan = new Span<byte>(byteBuffer, levelSize);
|
||||
stream.ReadExactly(byteSpan);
|
||||
|
||||
var textureSlice = new TextureSlice
|
||||
var textureRegion = new TextureRegion
|
||||
{
|
||||
TextureSlice = new TextureSlice
|
||||
{
|
||||
Texture = texture,
|
||||
MipLevel = (uint) level,
|
||||
BaseLayer = (uint) face,
|
||||
LayerCount = 1,
|
||||
Layer = (uint) face,
|
||||
MipLevel = (uint) level
|
||||
},
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Z = 0,
|
||||
|
@ -156,7 +158,7 @@ namespace MoonWorks.Graphics
|
|||
Depth = 1
|
||||
};
|
||||
|
||||
SetTextureData(textureSlice, byteSpan);
|
||||
SetTextureData(textureRegion, byteSpan, WriteOptions.SafeOverwrite);
|
||||
|
||||
NativeMemory.Free(byteBuffer);
|
||||
}
|
||||
|
@ -174,36 +176,36 @@ namespace MoonWorks.Graphics
|
|||
return CreateTextureFromDDS(stream);
|
||||
}
|
||||
|
||||
public void SetTextureDataFromCompressed(TextureSlice textureSlice, Span<byte> compressedImageData)
|
||||
public void SetTextureDataFromCompressed(TextureRegion textureRegion, Span<byte> compressedImageData)
|
||||
{
|
||||
var pixelData = ImageUtils.GetPixelDataFromBytes(compressedImageData, out var _, out var _, out var sizeInBytes);
|
||||
var pixelSpan = new Span<byte>((void*) pixelData, (int) sizeInBytes);
|
||||
|
||||
SetTextureData(textureSlice, pixelSpan);
|
||||
SetTextureData(textureRegion, pixelSpan, WriteOptions.SafeOverwrite);
|
||||
|
||||
ImageUtils.FreePixelData(pixelData);
|
||||
}
|
||||
|
||||
public void SetTextureDataFromCompressed(TextureSlice textureSlice, Stream compressedImageStream)
|
||||
public void SetTextureDataFromCompressed(TextureRegion textureRegion, Stream compressedImageStream)
|
||||
{
|
||||
var length = compressedImageStream.Length;
|
||||
var buffer = NativeMemory.Alloc((nuint) length);
|
||||
var span = new Span<byte>(buffer, (int) length);
|
||||
compressedImageStream.ReadExactly(span);
|
||||
SetTextureDataFromCompressed(textureSlice, span);
|
||||
SetTextureDataFromCompressed(textureRegion, span);
|
||||
NativeMemory.Free(buffer);
|
||||
}
|
||||
|
||||
public void SetTextureDataFromCompressed(TextureSlice textureSlice, string compressedImageFilePath)
|
||||
public void SetTextureDataFromCompressed(TextureRegion textureRegion, string compressedImageFilePath)
|
||||
{
|
||||
var fileStream = new FileStream(compressedImageFilePath, FileMode.Open, FileAccess.Read);
|
||||
SetTextureDataFromCompressed(textureSlice, fileStream);
|
||||
SetTextureDataFromCompressed(textureRegion, fileStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepares upload of pixel data into a TextureSlice.
|
||||
/// </summary>
|
||||
public void SetTextureData<T>(TextureSlice textureSlice, Span<T> data) where T : unmanaged
|
||||
public void SetTextureData<T>(TextureRegion textureRegion, Span<T> data, WriteOptions option) where T : unmanaged
|
||||
{
|
||||
var elementSize = Marshal.SizeOf<T>();
|
||||
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
||||
|
@ -211,10 +213,10 @@ namespace MoonWorks.Graphics
|
|||
uint resourceOffset;
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
resourceOffset = CopyDataAligned(dataPtr, dataLengthInBytes, Texture.TexelSize(textureSlice.Texture.Format));
|
||||
resourceOffset = CopyDataAligned(dataPtr, dataLengthInBytes, Texture.TexelSize(textureRegion.TextureSlice.Texture.Format));
|
||||
}
|
||||
|
||||
TextureUploads.Add((textureSlice, resourceOffset));
|
||||
TextureUploads.Add((textureRegion, resourceOffset, option));
|
||||
}
|
||||
|
||||
// Upload
|
||||
|
@ -257,32 +259,34 @@ namespace MoonWorks.Graphics
|
|||
}
|
||||
|
||||
var dataSpan = new Span<byte>(data, (int) dataSize);
|
||||
TransferBuffer.SetData(dataSpan, SetDataOptions.Discard);
|
||||
TransferBuffer.SetData(dataSpan, TransferOptions.Cycle);
|
||||
}
|
||||
|
||||
private void RecordUploadCommands(CommandBuffer commandBuffer)
|
||||
{
|
||||
commandBuffer.BeginCopyPass();
|
||||
|
||||
foreach (var (gpuBuffer, bufferCopyParams) in BufferUploads)
|
||||
foreach (var (gpuBuffer, bufferCopyParams, option) in BufferUploads)
|
||||
{
|
||||
commandBuffer.UploadToBuffer(
|
||||
TransferBuffer,
|
||||
gpuBuffer,
|
||||
bufferCopyParams
|
||||
bufferCopyParams,
|
||||
option
|
||||
);
|
||||
}
|
||||
|
||||
foreach (var (textureSlice, offset) in TextureUploads)
|
||||
foreach (var (textureRegion, offset, option) in TextureUploads)
|
||||
{
|
||||
commandBuffer.UploadToTexture(
|
||||
TransferBuffer,
|
||||
textureSlice,
|
||||
textureRegion,
|
||||
new BufferImageCopy(
|
||||
offset,
|
||||
0,
|
||||
0
|
||||
)
|
||||
),
|
||||
option
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,11 @@ namespace MoonWorks.Graphics
|
|||
refreshGraphicsPipelineCreateInfo.blendConstants[2] = blendConstants.B;
|
||||
refreshGraphicsPipelineCreateInfo.blendConstants[3] = blendConstants.A;
|
||||
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilState = depthStencilState.StencilState.ToRefresh();
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.backStencilState = depthStencilState.BackStencilState.ToRefresh();
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.frontStencilState = depthStencilState.FrontStencilState.ToRefresh();
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.compareMask = depthStencilState.CompareMask;
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.writeMask = depthStencilState.WriteMask;
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.reference = depthStencilState.Reference;
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.compareOp = (Refresh.CompareOp) depthStencilState.CompareOp;
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthBoundsTestEnable = Conversions.BoolToByte(depthStencilState.DepthBoundsTestEnable);
|
||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthTestEnable = Conversions.BoolToByte(depthStencilState.DepthTestEnable);
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace MoonWorks.Graphics
|
|||
public uint Depth { get; }
|
||||
public TextureFormat Format { get; internal set; }
|
||||
public bool IsCube { get; }
|
||||
public uint LayerCount { get; }
|
||||
public uint LevelCount { get; }
|
||||
public SampleCount SampleCount { get; }
|
||||
public TextureUsageFlags UsageFlags { get; }
|
||||
|
@ -46,6 +47,7 @@ namespace MoonWorks.Graphics
|
|||
Height = height,
|
||||
Depth = 1,
|
||||
IsCube = false,
|
||||
LayerCount = 1,
|
||||
LevelCount = levelCount,
|
||||
SampleCount = sampleCount,
|
||||
Format = format,
|
||||
|
@ -56,15 +58,43 @@ namespace MoonWorks.Graphics
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a 3D texture.
|
||||
/// Creates a 2D texture array.
|
||||
/// </summary>
|
||||
/// <param name="device">An initialized GraphicsDevice.</param>
|
||||
/// <param name="width">The width of the texture.</param>
|
||||
/// <param name="height">The height of the texture.</param>
|
||||
/// <param name="depth">The depth of the texture.</param>
|
||||
/// <param name="layerCount">The layer count of the texture.</param>
|
||||
/// <param name="format">The format of the texture.</param>
|
||||
/// <param name="usageFlags">Specifies how the texture will be used.</param>
|
||||
/// <param name="levelCount">Specifies the number of mip levels.</param>
|
||||
public static Texture CreateTexture2DArray(
|
||||
GraphicsDevice device,
|
||||
uint width,
|
||||
uint height,
|
||||
uint layerCount,
|
||||
TextureFormat format,
|
||||
TextureUsageFlags usageFlags,
|
||||
uint levelCount = 1
|
||||
) {
|
||||
var textureCreateInfo = new TextureCreateInfo
|
||||
{
|
||||
Width = width,
|
||||
Height = height,
|
||||
Depth = 1,
|
||||
IsCube = false,
|
||||
LayerCount = layerCount,
|
||||
LevelCount = levelCount,
|
||||
Format = format,
|
||||
UsageFlags = usageFlags
|
||||
};
|
||||
|
||||
return new Texture(device, textureCreateInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a 3D texture.
|
||||
/// Note that the width, height and depth all form one slice and cannot be subdivided in a texture slice.
|
||||
/// </summary>
|
||||
public static Texture CreateTexture3D(
|
||||
GraphicsDevice device,
|
||||
uint width,
|
||||
|
@ -80,6 +110,7 @@ namespace MoonWorks.Graphics
|
|||
Height = height,
|
||||
Depth = depth,
|
||||
IsCube = false,
|
||||
LayerCount = 1,
|
||||
LevelCount = levelCount,
|
||||
Format = format,
|
||||
UsageFlags = usageFlags
|
||||
|
@ -109,6 +140,7 @@ namespace MoonWorks.Graphics
|
|||
Height = size,
|
||||
Depth = 1,
|
||||
IsCube = true,
|
||||
LayerCount = 6,
|
||||
LevelCount = levelCount,
|
||||
Format = format,
|
||||
UsageFlags = usageFlags
|
||||
|
@ -137,16 +169,14 @@ namespace MoonWorks.Graphics
|
|||
Height = textureCreateInfo.Height;
|
||||
Depth = textureCreateInfo.Depth;
|
||||
IsCube = textureCreateInfo.IsCube;
|
||||
LayerCount = textureCreateInfo.LayerCount;
|
||||
LevelCount = textureCreateInfo.LevelCount;
|
||||
SampleCount = textureCreateInfo.SampleCount;
|
||||
UsageFlags = textureCreateInfo.UsageFlags;
|
||||
Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
|
||||
}
|
||||
|
||||
public static implicit operator TextureSlice(Texture t) => new TextureSlice(t);
|
||||
|
||||
// Used by AcquireSwapchainTexture.
|
||||
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
||||
// Used by Window. Swapchain texture handles are managed by the driver backend.
|
||||
internal Texture(
|
||||
GraphicsDevice device,
|
||||
TextureFormat format
|
||||
|
@ -270,5 +300,8 @@ namespace MoonWorks.Graphics
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator TextureSlice(Texture t) => new TextureSlice(t);
|
||||
public static implicit operator TextureRegion(Texture t) => new TextureRegion(t);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace MoonWorks.Graphics
|
|||
public unsafe uint SetData<T>(
|
||||
Span<T> data,
|
||||
uint bufferOffsetInBytes,
|
||||
SetDataOptions setDataOption
|
||||
TransferOptions setDataOption
|
||||
) where T : unmanaged
|
||||
{
|
||||
var elementSize = Marshal.SizeOf<T>();
|
||||
|
@ -73,7 +73,7 @@ namespace MoonWorks.Graphics
|
|||
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
Refresh.Refresh_SetData(
|
||||
Refresh.Refresh_SetTransferData(
|
||||
Device.Handle,
|
||||
(nint) dataPtr,
|
||||
Handle,
|
||||
|
@ -83,7 +83,7 @@ namespace MoonWorks.Graphics
|
|||
dstOffset = bufferOffsetInBytes,
|
||||
size = dataLengthInBytes
|
||||
},
|
||||
(Refresh.SetDataOptions) setDataOption
|
||||
(Refresh.TransferOptions) setDataOption
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ namespace MoonWorks.Graphics
|
|||
/// </summary>
|
||||
public unsafe uint SetData<T>(
|
||||
Span<T> data,
|
||||
SetDataOptions setDataOption
|
||||
TransferOptions setDataOption
|
||||
) where T : unmanaged
|
||||
{
|
||||
return SetData(data, 0, setDataOption);
|
||||
|
@ -125,7 +125,7 @@ namespace MoonWorks.Graphics
|
|||
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
Refresh.Refresh_GetData(
|
||||
Refresh.Refresh_GetTransferData(
|
||||
Device.Handle,
|
||||
Handle,
|
||||
(nint) dataPtr,
|
||||
|
@ -144,7 +144,7 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
|
||||
{
|
||||
throw new InvalidOperationException($"SetData overflow! Transfer buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
|
||||
throw new InvalidOperationException($"Data overflow! Transfer buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,9 +11,29 @@
|
|||
public bool DepthTestEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Describes the stencil operation.
|
||||
/// Describes the back-face stencil operation.
|
||||
/// </summary>
|
||||
public StencilOpState StencilState;
|
||||
public StencilOpState BackStencilState;
|
||||
|
||||
/// <summary>
|
||||
/// Describes the front-face stencil operation.
|
||||
/// </summary>
|
||||
public StencilOpState FrontStencilState;
|
||||
|
||||
/// <summary>
|
||||
/// The compare mask for stencil ops.
|
||||
/// </summary>
|
||||
public uint CompareMask;
|
||||
|
||||
/// <summary>
|
||||
/// The write mask for stencil ops.
|
||||
/// </summary>
|
||||
public uint WriteMask;
|
||||
|
||||
/// <summary>
|
||||
/// The stencil reference value.
|
||||
/// </summary>
|
||||
public uint Reference;
|
||||
|
||||
/// <summary>
|
||||
/// The comparison operator used in the depth test.
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MoonWorks.Graphics
|
|||
public uint Height;
|
||||
public uint Depth;
|
||||
public bool IsCube;
|
||||
public uint LayerCount;
|
||||
public uint LevelCount;
|
||||
public SampleCount SampleCount;
|
||||
public TextureFormat Format;
|
||||
|
@ -24,6 +25,7 @@ namespace MoonWorks.Graphics
|
|||
height = Height,
|
||||
depth = Depth,
|
||||
isCube = Conversions.BoolToByte(IsCube),
|
||||
layerCount = LayerCount,
|
||||
levelCount = LevelCount,
|
||||
sampleCount = (Refresh.SampleCount) SampleCount,
|
||||
format = (Refresh.TextureFormat) Format,
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
using RefreshCS;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A texture region specifies a subregion of a texture.
|
||||
/// These are used by copy commands.
|
||||
/// </summary>
|
||||
public struct TextureRegion
|
||||
{
|
||||
public TextureSlice TextureSlice;
|
||||
public uint X;
|
||||
public uint Y;
|
||||
public uint Z;
|
||||
public uint Width;
|
||||
public uint Height;
|
||||
public uint Depth;
|
||||
|
||||
public uint Size => (Width * Height * Depth * Texture.BytesPerPixel(TextureSlice.Texture.Format) / Texture.BlockSizeSquared(TextureSlice.Texture.Format)) >> (int) TextureSlice.MipLevel;
|
||||
|
||||
public TextureRegion(Texture texture)
|
||||
{
|
||||
TextureSlice = new TextureSlice(texture);
|
||||
X = 0;
|
||||
Y = 0;
|
||||
Z = 0;
|
||||
Width = texture.Width;
|
||||
Height = texture.Height;
|
||||
Depth = texture.Depth;
|
||||
}
|
||||
|
||||
public Refresh.TextureRegion ToRefreshTextureRegion()
|
||||
{
|
||||
return new Refresh.TextureRegion
|
||||
{
|
||||
textureSlice = TextureSlice.ToRefreshTextureSlice(),
|
||||
x = X,
|
||||
y = Y,
|
||||
z = Z,
|
||||
w = Width,
|
||||
h = Height,
|
||||
d = Depth
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,55 +3,31 @@
|
|||
namespace MoonWorks.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A texture slice specifies a subregion of a texture.
|
||||
/// Many operations can use texture slices in place of textures for the sake of convenience.
|
||||
/// A texture slice specifies a subresource of a texture.
|
||||
/// </summary>
|
||||
public struct TextureSlice
|
||||
{
|
||||
public Texture Texture;
|
||||
public uint MipLevel;
|
||||
public uint BaseLayer;
|
||||
public uint LayerCount;
|
||||
public uint X;
|
||||
public uint Y;
|
||||
public uint Z;
|
||||
public uint Width;
|
||||
public uint Height;
|
||||
public uint Depth;
|
||||
public uint Layer;
|
||||
|
||||
public uint Size => (Width * Height * Depth * LayerCount * Texture.BytesPerPixel(Texture.Format) / Texture.BlockSizeSquared(Texture.Format)) >> (int) MipLevel;
|
||||
public uint Size => (Texture.Width * Texture.Height * Texture.Depth * Texture.BytesPerPixel(Texture.Format) / Texture.BlockSizeSquared(Texture.Format)) >> (int) MipLevel;
|
||||
|
||||
public TextureSlice(Texture texture)
|
||||
{
|
||||
Texture = texture;
|
||||
MipLevel = 0;
|
||||
BaseLayer = 0;
|
||||
LayerCount = (uint) (texture.IsCube ? 6 : 1);
|
||||
X = 0;
|
||||
Y = 0;
|
||||
Z = 0;
|
||||
Width = texture.Width;
|
||||
Height = texture.Height;
|
||||
Depth = texture.Depth;
|
||||
Layer = 0;
|
||||
}
|
||||
|
||||
public Refresh.TextureSlice ToRefreshTextureSlice()
|
||||
{
|
||||
Refresh.TextureSlice textureSlice = new Refresh.TextureSlice
|
||||
return new Refresh.TextureSlice
|
||||
{
|
||||
texture = Texture.Handle,
|
||||
mipLevel = MipLevel,
|
||||
baseLayer = BaseLayer,
|
||||
layerCount = LayerCount,
|
||||
x = X,
|
||||
y = Y,
|
||||
z = Z,
|
||||
w = Width,
|
||||
h = Height,
|
||||
d = Depth
|
||||
layer = Layer
|
||||
};
|
||||
|
||||
return textureSlice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,9 +243,9 @@ namespace MoonWorks.Video
|
|||
TransferBuffer?.Dispose();
|
||||
TransferBuffer = new TransferBuffer(Device, (uint) (ySpan.Length + uSpan.Length + vSpan.Length));
|
||||
}
|
||||
TransferBuffer.SetData(ySpan, 0, SetDataOptions.Discard);
|
||||
TransferBuffer.SetData(uSpan, (uint) ySpan.Length, SetDataOptions.Overwrite);
|
||||
TransferBuffer.SetData(vSpan, (uint) (ySpan.Length + uSpan.Length), SetDataOptions.Overwrite);
|
||||
TransferBuffer.SetData(ySpan, 0, TransferOptions.Cycle);
|
||||
TransferBuffer.SetData(uSpan, (uint) ySpan.Length, TransferOptions.Overwrite);
|
||||
TransferBuffer.SetData(vSpan, (uint) (ySpan.Length + uSpan.Length), TransferOptions.Overwrite);
|
||||
|
||||
commandBuffer.BeginCopyPass();
|
||||
|
||||
|
@ -257,7 +257,8 @@ namespace MoonWorks.Video
|
|||
BufferOffset = 0,
|
||||
BufferStride = CurrentStream.yStride,
|
||||
BufferImageHeight = yTexture.Height
|
||||
}
|
||||
},
|
||||
WriteOptions.Cycle
|
||||
);
|
||||
|
||||
commandBuffer.UploadToTexture(
|
||||
|
@ -267,7 +268,8 @@ namespace MoonWorks.Video
|
|||
BufferOffset = (uint) ySpan.Length,
|
||||
BufferStride = CurrentStream.uvStride,
|
||||
BufferImageHeight = uTexture.Height
|
||||
}
|
||||
},
|
||||
WriteOptions.Cycle
|
||||
);
|
||||
|
||||
commandBuffer.UploadToTexture(
|
||||
|
@ -278,13 +280,14 @@ namespace MoonWorks.Video
|
|||
BufferOffset = (uint) (ySpan.Length + uSpan.Length),
|
||||
BufferStride = CurrentStream.uvStride,
|
||||
BufferImageHeight = vTexture.Height
|
||||
}
|
||||
},
|
||||
WriteOptions.Cycle
|
||||
);
|
||||
|
||||
commandBuffer.EndCopyPass();
|
||||
|
||||
commandBuffer.BeginRenderPass(
|
||||
new ColorAttachmentInfo(RenderTexture, Color.Black)
|
||||
new ColorAttachmentInfo(RenderTexture, WriteOptions.Cycle, Color.Black)
|
||||
);
|
||||
|
||||
commandBuffer.BindGraphicsPipeline(Device.VideoPipeline);
|
||||
|
|
|
@ -21,6 +21,15 @@ namespace MoonWorks
|
|||
public bool Claimed { get; internal set; }
|
||||
public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; }
|
||||
|
||||
public (int, int) Position
|
||||
{
|
||||
get
|
||||
{
|
||||
SDL.SDL_GetWindowPosition(Handle, out var x, out var y);
|
||||
return (x, y);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsDisposed;
|
||||
|
||||
private static Dictionary<uint, Window> idLookup = new Dictionary<uint, Window>();
|
||||
|
@ -113,6 +122,14 @@ namespace MoonWorks
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the window position.
|
||||
/// </summary>
|
||||
public void SetPosition(int x, int y)
|
||||
{
|
||||
SDL.SDL_SetWindowPosition(Handle, x, y);
|
||||
}
|
||||
|
||||
internal static Window Lookup(uint windowID)
|
||||
{
|
||||
return idLookup.ContainsKey(windowID) ? idLookup[windowID] : null;
|
||||
|
|
Loading…
Reference in New Issue