Compare commits
No commits in common. "178a5ea3cfa4ce4ccbcd9e0b6726a8cda791c810" and "4dbd5a2cbeab38f78274644f3b44fe1fa727f304" have entirely different histories.
178a5ea3cf
...
4dbd5a2cbe
|
@ -26,8 +26,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\fullscreen.vert.refresh">
|
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\video_fullscreen.vert.refresh">
|
||||||
<LogicalName>MoonWorks.Graphics.StockShaders.Fullscreen.vert.refresh</LogicalName>
|
<LogicalName>MoonWorks.Graphics.StockShaders.VideoFullscreen.vert.refresh</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\video_yuv2rgba.frag.refresh">
|
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\video_yuv2rgba.frag.refresh">
|
||||||
<LogicalName>MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.refresh</LogicalName>
|
<LogicalName>MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.refresh</LogicalName>
|
||||||
|
@ -38,8 +38,5 @@
|
||||||
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\text_msdf.frag.refresh">
|
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\text_msdf.frag.refresh">
|
||||||
<LogicalName>MoonWorks.Graphics.StockShaders.TextMSDF.frag.refresh</LogicalName>
|
<LogicalName>MoonWorks.Graphics.StockShaders.TextMSDF.frag.refresh</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="src\Graphics\StockShaders\Binary\blit.frag.refresh">
|
|
||||||
<LogicalName>MoonWorks.Graphics.StockShaders.Blit.frag.refresh</LogicalName>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2e346d84016fb7b26dbe7c5b6c485109571c30f4
|
Subproject commit b5325e6d0329eeb35b074091a569a5f679852d28
|
|
@ -35,8 +35,6 @@ namespace MoonWorks.Audio
|
||||||
RoomSize = FAudio.FAUDIOFX_REVERB_DEFAULT_ROOM_SIZE
|
RoomSize = FAudio.FAUDIOFX_REVERB_DEFAULT_ROOM_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
public FAudio.FAudioFXReverbParameters Params { get; private set; }
|
|
||||||
|
|
||||||
public ReverbEffect(AudioDevice audioDevice, uint processingStage) : base(audioDevice, 1, audioDevice.DeviceDetails.OutputFormat.Format.nSamplesPerSec, processingStage)
|
public ReverbEffect(AudioDevice audioDevice, uint processingStage) : base(audioDevice, 1, audioDevice.DeviceDetails.OutputFormat.Format.nSamplesPerSec, processingStage)
|
||||||
{
|
{
|
||||||
/* Init reverb */
|
/* Init reverb */
|
||||||
|
@ -66,8 +64,6 @@ namespace MoonWorks.Audio
|
||||||
|
|
||||||
public void SetParams(in FAudio.FAudioFXReverbParameters reverbParams)
|
public void SetParams(in FAudio.FAudioFXReverbParameters reverbParams)
|
||||||
{
|
{
|
||||||
Params = reverbParams;
|
|
||||||
|
|
||||||
fixed (FAudio.FAudioFXReverbParameters* reverbParamsPtr = &reverbParams)
|
fixed (FAudio.FAudioFXReverbParameters* reverbParamsPtr = &reverbParams)
|
||||||
{
|
{
|
||||||
FAudio.FAudioVoice_SetEffectParameters(
|
FAudio.FAudioVoice_SetEffectParameters(
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct BufferBinding
|
public struct BufferBinding
|
||||||
{
|
{
|
||||||
public GpuBuffer Buffer;
|
public Buffer Buffer;
|
||||||
public ulong Offset;
|
public ulong Offset;
|
||||||
|
|
||||||
public BufferBinding(GpuBuffer buffer, ulong offset)
|
public BufferBinding(Buffer buffer, ulong offset)
|
||||||
{
|
{
|
||||||
Buffer = buffer;
|
Buffer = buffer;
|
||||||
Offset = offset;
|
Offset = offset;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,34 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
|
||||||
{
|
|
||||||
internal class CommandBufferPool
|
|
||||||
{
|
|
||||||
private GraphicsDevice GraphicsDevice;
|
|
||||||
private ConcurrentQueue<CommandBuffer> CommandBuffers = new ConcurrentQueue<CommandBuffer>();
|
|
||||||
|
|
||||||
public CommandBufferPool(GraphicsDevice graphicsDevice)
|
|
||||||
{
|
|
||||||
GraphicsDevice = graphicsDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuffer Obtain()
|
|
||||||
{
|
|
||||||
if (CommandBuffers.TryDequeue(out var commandBuffer))
|
|
||||||
{
|
|
||||||
return commandBuffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new CommandBuffer(GraphicsDevice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Return(CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
commandBuffer.Handle = IntPtr.Zero;
|
|
||||||
CommandBuffers.Enqueue(commandBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -47,26 +47,8 @@ namespace MoonWorks.Graphics.Font
|
||||||
out float distanceRange
|
out float distanceRange
|
||||||
);
|
);
|
||||||
|
|
||||||
var imagePath = Path.ChangeExtension(fontPath, ".png");
|
var texture = Texture.FromImageFile(graphicsDevice, commandBuffer, 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
|
|
||||||
);
|
|
||||||
|
|
||||||
commandBuffer.BeginCopyPass();
|
|
||||||
commandBuffer.UploadToTexture(
|
|
||||||
transferBuffer,
|
|
||||||
texture
|
|
||||||
);
|
|
||||||
commandBuffer.EndCopyPass();
|
|
||||||
|
|
||||||
transferBuffer.Dispose();
|
|
||||||
NativeMemory.Free(fontFileByteBuffer);
|
NativeMemory.Free(fontFileByteBuffer);
|
||||||
NativeMemory.Free(atlasFileByteBuffer);
|
NativeMemory.Free(atlasFileByteBuffer);
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,10 @@ namespace MoonWorks.Graphics.Font
|
||||||
private GraphicsDevice GraphicsDevice { get; }
|
private GraphicsDevice GraphicsDevice { get; }
|
||||||
public IntPtr Handle { get; }
|
public IntPtr Handle { get; }
|
||||||
|
|
||||||
public GpuBuffer VertexBuffer { get; protected set; } = null;
|
public Buffer VertexBuffer { get; protected set; } = null;
|
||||||
public GpuBuffer IndexBuffer { get; protected set; } = null;
|
public Buffer IndexBuffer { get; protected set; } = null;
|
||||||
public uint PrimitiveCount { get; protected set; }
|
public uint PrimitiveCount { get; protected set; }
|
||||||
|
|
||||||
private TransferBuffer TransferBuffer;
|
|
||||||
|
|
||||||
public Font CurrentFont { get; private set; }
|
public Font CurrentFont { get; private set; }
|
||||||
|
|
||||||
private byte* StringBytes;
|
private byte* StringBytes;
|
||||||
|
@ -32,10 +30,8 @@ namespace MoonWorks.Graphics.Font
|
||||||
StringBytesLength = 128;
|
StringBytesLength = 128;
|
||||||
StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength);
|
StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength);
|
||||||
|
|
||||||
VertexBuffer = GpuBuffer.Create<Vertex>(GraphicsDevice, BufferUsageFlags.Vertex, INITIAL_VERTEX_COUNT);
|
VertexBuffer = Buffer.Create<Vertex>(GraphicsDevice, BufferUsageFlags.Vertex, INITIAL_VERTEX_COUNT);
|
||||||
IndexBuffer = GpuBuffer.Create<uint>(GraphicsDevice, BufferUsageFlags.Index, INITIAL_INDEX_COUNT);
|
IndexBuffer = Buffer.Create<uint>(GraphicsDevice, BufferUsageFlags.Index, INITIAL_INDEX_COUNT);
|
||||||
|
|
||||||
TransferBuffer = TransferBuffer.Create<byte>(GraphicsDevice, VertexBuffer.Size + IndexBuffer.Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this to initialize or reset the batch.
|
// Call this to initialize or reset the batch.
|
||||||
|
@ -97,38 +93,22 @@ namespace MoonWorks.Graphics.Font
|
||||||
out uint indexDataLengthInBytes
|
out uint indexDataLengthInBytes
|
||||||
);
|
);
|
||||||
|
|
||||||
var vertexSpan = new Span<byte>((void*) vertexDataPointer, (int) vertexDataLengthInBytes);
|
|
||||||
var indexSpan = new Span<byte>((void*) indexDataPointer, (int) indexDataLengthInBytes);
|
|
||||||
|
|
||||||
var newTransferBufferNeeded = false;
|
|
||||||
|
|
||||||
if (VertexBuffer.Size < vertexDataLengthInBytes)
|
if (VertexBuffer.Size < vertexDataLengthInBytes)
|
||||||
{
|
{
|
||||||
VertexBuffer.Dispose();
|
VertexBuffer.Dispose();
|
||||||
VertexBuffer = new GpuBuffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes);
|
VertexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes);
|
||||||
newTransferBufferNeeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IndexBuffer.Size < indexDataLengthInBytes)
|
if (IndexBuffer.Size < indexDataLengthInBytes)
|
||||||
{
|
{
|
||||||
IndexBuffer.Dispose();
|
IndexBuffer.Dispose();
|
||||||
IndexBuffer = new GpuBuffer(GraphicsDevice, BufferUsageFlags.Index, vertexDataLengthInBytes);
|
IndexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes);
|
||||||
newTransferBufferNeeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newTransferBufferNeeded)
|
|
||||||
{
|
|
||||||
TransferBuffer.Dispose();
|
|
||||||
TransferBuffer = new TransferBuffer(GraphicsDevice, VertexBuffer.Size + IndexBuffer.Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
|
if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
|
||||||
{
|
{
|
||||||
TransferBuffer.SetData(vertexSpan, SetDataOptions.Discard);
|
commandBuffer.SetBufferData(VertexBuffer, vertexDataPointer, 0, vertexDataLengthInBytes);
|
||||||
TransferBuffer.SetData(indexSpan, (uint) vertexSpan.Length, SetDataOptions.Overwrite);
|
commandBuffer.SetBufferData(IndexBuffer, indexDataPointer, 0, indexDataLengthInBytes);
|
||||||
|
|
||||||
commandBuffer.UploadToBuffer(TransferBuffer, VertexBuffer, new BufferCopy(0, 0, (uint) vertexSpan.Length));
|
|
||||||
commandBuffer.UploadToBuffer(TransferBuffer, IndexBuffer, new BufferCopy((uint) vertexSpan.Length, 0, (uint) indexSpan.Length));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimitiveCount = vertexCount / 2;
|
PrimitiveCount = vertexCount / 2;
|
||||||
|
@ -143,12 +123,12 @@ namespace MoonWorks.Graphics.Font
|
||||||
));
|
));
|
||||||
commandBuffer.BindVertexBuffers(VertexBuffer);
|
commandBuffer.BindVertexBuffers(VertexBuffer);
|
||||||
commandBuffer.BindIndexBuffer(IndexBuffer, IndexElementSize.ThirtyTwo);
|
commandBuffer.BindIndexBuffer(IndexBuffer, IndexElementSize.ThirtyTwo);
|
||||||
commandBuffer.PushVertexShaderUniforms(transformMatrix);
|
|
||||||
commandBuffer.PushFragmentShaderUniforms(CurrentFont.DistanceRange);
|
|
||||||
commandBuffer.DrawIndexedPrimitives(
|
commandBuffer.DrawIndexedPrimitives(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
PrimitiveCount
|
PrimitiveCount,
|
||||||
|
commandBuffer.PushVertexShaderUniforms(transformMatrix),
|
||||||
|
commandBuffer.PushFragmentShaderUniforms(CurrentFont.DistanceRange)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,6 @@ namespace MoonWorks.Graphics
|
||||||
// Built-in video pipeline
|
// Built-in video pipeline
|
||||||
internal GraphicsPipeline VideoPipeline { get; }
|
internal GraphicsPipeline VideoPipeline { get; }
|
||||||
|
|
||||||
// Built-in blit pipeline
|
|
||||||
internal GraphicsPipeline BlitPipeline { get; }
|
|
||||||
|
|
||||||
// Built-in text shader info
|
// Built-in text shader info
|
||||||
public GraphicsShaderInfo TextVertexShaderInfo { get; }
|
public GraphicsShaderInfo TextVertexShaderInfo { get; }
|
||||||
public GraphicsShaderInfo TextFragmentShaderInfo { get; }
|
public GraphicsShaderInfo TextFragmentShaderInfo { get; }
|
||||||
|
@ -38,7 +35,6 @@ namespace MoonWorks.Graphics
|
||||||
|
|
||||||
private readonly HashSet<GCHandle> resources = new HashSet<GCHandle>();
|
private readonly HashSet<GCHandle> resources = new HashSet<GCHandle>();
|
||||||
private FencePool FencePool;
|
private FencePool FencePool;
|
||||||
private CommandBufferPool CommandBufferPool;
|
|
||||||
|
|
||||||
internal GraphicsDevice(
|
internal GraphicsDevice(
|
||||||
Backend preferredBackend,
|
Backend preferredBackend,
|
||||||
|
@ -60,43 +56,32 @@ namespace MoonWorks.Graphics
|
||||||
// Check for replacement stock shaders
|
// Check for replacement stock shaders
|
||||||
string basePath = System.AppContext.BaseDirectory;
|
string basePath = System.AppContext.BaseDirectory;
|
||||||
|
|
||||||
string fullscreenVertPath = Path.Combine(basePath, "fullscreen.vert.refresh");
|
string videoVertPath = Path.Combine(basePath, "video_fullscreen.vert.refresh");
|
||||||
|
string videoFragPath = Path.Combine(basePath, "video_yuv2rgba.frag.refresh");
|
||||||
|
|
||||||
string textVertPath = Path.Combine(basePath, "text_transform.vert.refresh");
|
string textVertPath = Path.Combine(basePath, "text_transform.vert.refresh");
|
||||||
string textFragPath = Path.Combine(basePath, "text_msdf.frag.refresh");
|
string textFragPath = Path.Combine(basePath, "text_msdf.frag.refresh");
|
||||||
|
|
||||||
string videoFragPath = Path.Combine(basePath, "video_yuv2rgba.frag.refresh");
|
ShaderModule videoVertShader;
|
||||||
string blitFragPath = Path.Combine(basePath, "blit.frag.refresh");
|
ShaderModule videoFragShader;
|
||||||
|
|
||||||
ShaderModule fullscreenVertShader;
|
|
||||||
|
|
||||||
ShaderModule textVertShader;
|
ShaderModule textVertShader;
|
||||||
ShaderModule textFragShader;
|
ShaderModule textFragShader;
|
||||||
|
|
||||||
ShaderModule videoFragShader;
|
if (File.Exists(videoVertPath) && File.Exists(videoFragPath))
|
||||||
ShaderModule blitFragShader;
|
|
||||||
|
|
||||||
if (File.Exists(fullscreenVertPath))
|
|
||||||
{
|
|
||||||
fullscreenVertShader = new ShaderModule(this, fullscreenVertPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// use defaults
|
|
||||||
var assembly = typeof(GraphicsDevice).Assembly;
|
|
||||||
using var vertStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.Fullscreen.vert.refresh");
|
|
||||||
fullscreenVertShader = new ShaderModule(this, vertStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(videoFragPath))
|
|
||||||
{
|
{
|
||||||
|
videoVertShader = new ShaderModule(this, videoVertPath);
|
||||||
videoFragShader = new ShaderModule(this, videoFragPath);
|
videoFragShader = new ShaderModule(this, videoFragPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// use defaults
|
// use defaults
|
||||||
var assembly = typeof(GraphicsDevice).Assembly;
|
var assembly = typeof(GraphicsDevice).Assembly;
|
||||||
|
|
||||||
|
using var vertStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.VideoFullscreen.vert.refresh");
|
||||||
using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.refresh");
|
using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.refresh");
|
||||||
|
|
||||||
|
videoVertShader = new ShaderModule(this, vertStream);
|
||||||
videoFragShader = new ShaderModule(this, fragStream);
|
videoFragShader = new ShaderModule(this, fragStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,19 +102,6 @@ namespace MoonWorks.Graphics
|
||||||
textFragShader = new ShaderModule(this, fragStream);
|
textFragShader = new ShaderModule(this, fragStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (File.Exists(blitFragPath))
|
|
||||||
{
|
|
||||||
blitFragShader = new ShaderModule(this, blitFragPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// use defaults
|
|
||||||
var assembly = typeof(GraphicsDevice).Assembly;
|
|
||||||
|
|
||||||
using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.Blit.frag.refresh");
|
|
||||||
blitFragShader = new ShaderModule(this, fragStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoPipeline = new GraphicsPipeline(
|
VideoPipeline = new GraphicsPipeline(
|
||||||
this,
|
this,
|
||||||
new GraphicsPipelineCreateInfo
|
new GraphicsPipelineCreateInfo
|
||||||
|
@ -142,7 +114,7 @@ namespace MoonWorks.Graphics
|
||||||
),
|
),
|
||||||
DepthStencilState = DepthStencilState.Disable,
|
DepthStencilState = DepthStencilState.Disable,
|
||||||
VertexShaderInfo = GraphicsShaderInfo.Create(
|
VertexShaderInfo = GraphicsShaderInfo.Create(
|
||||||
fullscreenVertShader,
|
videoVertShader,
|
||||||
"main",
|
"main",
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
|
@ -158,34 +130,6 @@ namespace MoonWorks.Graphics
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
BlitPipeline = new GraphicsPipeline(
|
|
||||||
this,
|
|
||||||
new GraphicsPipelineCreateInfo
|
|
||||||
{
|
|
||||||
AttachmentInfo = new GraphicsPipelineAttachmentInfo(
|
|
||||||
new ColorAttachmentDescription(
|
|
||||||
TextureFormat.R8G8B8A8,
|
|
||||||
ColorAttachmentBlendState.None
|
|
||||||
)
|
|
||||||
),
|
|
||||||
DepthStencilState = DepthStencilState.Disable,
|
|
||||||
VertexShaderInfo = GraphicsShaderInfo.Create(
|
|
||||||
fullscreenVertShader,
|
|
||||||
"main",
|
|
||||||
0
|
|
||||||
),
|
|
||||||
FragmentShaderInfo = GraphicsShaderInfo.Create(
|
|
||||||
blitFragShader,
|
|
||||||
"main",
|
|
||||||
1
|
|
||||||
),
|
|
||||||
VertexInputState = VertexInputState.Empty,
|
|
||||||
RasterizerState = RasterizerState.CCW_CullNone,
|
|
||||||
PrimitiveType = PrimitiveType.TriangleList,
|
|
||||||
MultisampleState = MultisampleState.None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
TextVertexShaderInfo = GraphicsShaderInfo.Create<Math.Float.Matrix4x4>(textVertShader, "main", 0);
|
TextVertexShaderInfo = GraphicsShaderInfo.Create<Math.Float.Matrix4x4>(textVertShader, "main", 0);
|
||||||
TextFragmentShaderInfo = GraphicsShaderInfo.Create<float>(textFragShader, "main", 1);
|
TextFragmentShaderInfo = GraphicsShaderInfo.Create<float>(textFragShader, "main", 1);
|
||||||
TextVertexInputState = VertexInputState.CreateSingleBinding<Font.Vertex>();
|
TextVertexInputState = VertexInputState.CreateSingleBinding<Font.Vertex>();
|
||||||
|
@ -194,7 +138,6 @@ namespace MoonWorks.Graphics
|
||||||
LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp);
|
LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp);
|
||||||
|
|
||||||
FencePool = new FencePool(this);
|
FencePool = new FencePool(this);
|
||||||
CommandBufferPool = new CommandBufferPool(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -224,7 +167,7 @@ namespace MoonWorks.Graphics
|
||||||
window.SwapchainFormat = GetSwapchainFormat(window);
|
window.SwapchainFormat = GetSwapchainFormat(window);
|
||||||
if (window.SwapchainTexture == null)
|
if (window.SwapchainTexture == null)
|
||||||
{
|
{
|
||||||
window.SwapchainTexture = new Texture(this, window.SwapchainFormat);
|
window.SwapchainTexture = new Texture(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,12 +221,7 @@ namespace MoonWorks.Graphics
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public CommandBuffer AcquireCommandBuffer()
|
public CommandBuffer AcquireCommandBuffer()
|
||||||
{
|
{
|
||||||
var commandBuffer = CommandBufferPool.Obtain();
|
return new CommandBuffer(this, Refresh.Refresh_AcquireCommandBuffer(Handle));
|
||||||
commandBuffer.SetHandle(Refresh.Refresh_AcquireCommandBuffer(Handle));
|
|
||||||
#if DEBUG
|
|
||||||
commandBuffer.ResetStateTracking();
|
|
||||||
#endif
|
|
||||||
return commandBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -291,23 +229,10 @@ namespace MoonWorks.Graphics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Submit(CommandBuffer commandBuffer)
|
public void Submit(CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
if (commandBuffer.Submitted)
|
|
||||||
{
|
|
||||||
throw new System.InvalidOperationException("Command buffer already submitted!");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Refresh.Refresh_Submit(
|
Refresh.Refresh_Submit(
|
||||||
Handle,
|
Handle,
|
||||||
commandBuffer.Handle
|
commandBuffer.Handle
|
||||||
);
|
);
|
||||||
|
|
||||||
CommandBufferPool.Return(commandBuffer);
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
commandBuffer.Submitted = true;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,501 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using RefreshCS;
|
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
|
||||||
{
|
|
||||||
public static class ImageUtils
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets pointer to pixel data from compressed image byte data.
|
|
||||||
///
|
|
||||||
/// The returned pointer must be freed by calling FreePixelData.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe IntPtr GetPixelDataFromBytes(
|
|
||||||
Span<byte> data,
|
|
||||||
out uint width,
|
|
||||||
out uint height,
|
|
||||||
out uint sizeInBytes
|
|
||||||
) {
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
var pixelData =
|
|
||||||
Refresh.Refresh_Image_Load(
|
|
||||||
(nint) ptr,
|
|
||||||
data.Length,
|
|
||||||
out var w,
|
|
||||||
out var h,
|
|
||||||
out var len
|
|
||||||
);
|
|
||||||
|
|
||||||
width = (uint) w;
|
|
||||||
height = (uint) h;
|
|
||||||
sizeInBytes = (uint) len;
|
|
||||||
|
|
||||||
return pixelData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets pointer to pixel data from a compressed image stream.
|
|
||||||
///
|
|
||||||
/// The returned pointer must be freed by calling FreePixelData.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe IntPtr GetPixelDataFromStream(
|
|
||||||
Stream stream,
|
|
||||||
out uint width,
|
|
||||||
out uint height,
|
|
||||||
out uint sizeInBytes
|
|
||||||
) {
|
|
||||||
var length = stream.Length;
|
|
||||||
var buffer = NativeMemory.Alloc((nuint) length);
|
|
||||||
var span = new Span<byte>(buffer, (int) length);
|
|
||||||
stream.ReadExactly(span);
|
|
||||||
|
|
||||||
var pixelData = GetPixelDataFromBytes(span, out width, out height, out sizeInBytes);
|
|
||||||
|
|
||||||
NativeMemory.Free(buffer);
|
|
||||||
|
|
||||||
return pixelData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets pointer to pixel data from a compressed image file.
|
|
||||||
///
|
|
||||||
/// The returned pointer must be freed by calling FreePixelData.
|
|
||||||
/// </summary>
|
|
||||||
public static IntPtr GetPixelDataFromFile(
|
|
||||||
string path,
|
|
||||||
out uint width,
|
|
||||||
out uint height,
|
|
||||||
out uint sizeInBytes
|
|
||||||
) {
|
|
||||||
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
|
||||||
return GetPixelDataFromStream(fileStream, out width, out height, out sizeInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get metadata from compressed image bytes.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe bool ImageInfoFromBytes(
|
|
||||||
Span<byte> data,
|
|
||||||
out uint width,
|
|
||||||
out uint height,
|
|
||||||
out uint sizeInBytes
|
|
||||||
) {
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
var result =
|
|
||||||
Refresh.Refresh_Image_Info(
|
|
||||||
(nint) ptr,
|
|
||||||
data.Length,
|
|
||||||
out var w,
|
|
||||||
out var h,
|
|
||||||
out var len
|
|
||||||
);
|
|
||||||
|
|
||||||
width = (uint) w;
|
|
||||||
height = (uint) h;
|
|
||||||
sizeInBytes = (uint) len;
|
|
||||||
|
|
||||||
return Conversions.ByteToBool(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get metadata from a compressed image stream.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe bool ImageInfoFromStream(
|
|
||||||
Stream stream,
|
|
||||||
out uint width,
|
|
||||||
out uint height,
|
|
||||||
out uint sizeInBytes
|
|
||||||
) {
|
|
||||||
var length = stream.Length;
|
|
||||||
var buffer = NativeMemory.Alloc((nuint) length);
|
|
||||||
var span = new Span<byte>(buffer, (int) length);
|
|
||||||
stream.ReadExactly(span);
|
|
||||||
|
|
||||||
var result = ImageInfoFromBytes(span, out width, out height, out sizeInBytes);
|
|
||||||
|
|
||||||
NativeMemory.Free(buffer);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get metadata from a compressed image file.
|
|
||||||
/// </summary>
|
|
||||||
public static bool ImageInfoFromFile(
|
|
||||||
string path,
|
|
||||||
out uint width,
|
|
||||||
out uint height,
|
|
||||||
out uint sizeInBytes
|
|
||||||
) {
|
|
||||||
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
|
||||||
return ImageInfoFromStream(fileStream, out width, out height, out sizeInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees pixel data obtained from GetPixelData methods.
|
|
||||||
/// </summary>
|
|
||||||
public static void FreePixelData(IntPtr pixels)
|
|
||||||
{
|
|
||||||
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>
|
|
||||||
public static unsafe void SavePNG(
|
|
||||||
string path,
|
|
||||||
TransferBuffer transferBuffer,
|
|
||||||
uint bufferOffsetInBytes,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
bool bgra
|
|
||||||
) {
|
|
||||||
var sizeInBytes = width * height * 4;
|
|
||||||
|
|
||||||
var pixelsPtr = NativeMemory.Alloc((nuint) sizeInBytes);
|
|
||||||
var pixelsSpan = new Span<byte>(pixelsPtr, sizeInBytes);
|
|
||||||
|
|
||||||
transferBuffer.GetData(pixelsSpan, bufferOffsetInBytes);
|
|
||||||
|
|
||||||
if (bgra)
|
|
||||||
{
|
|
||||||
// if data is bgra, we have to swap the R and B channels
|
|
||||||
var rgbaPtr = NativeMemory.Alloc((nuint) sizeInBytes);
|
|
||||||
var rgbaSpan = new Span<byte>(rgbaPtr, sizeInBytes);
|
|
||||||
|
|
||||||
for (var i = 0; i < sizeInBytes; i += 4)
|
|
||||||
{
|
|
||||||
rgbaSpan[i] = pixelsSpan[i + 2];
|
|
||||||
rgbaSpan[i + 1] = pixelsSpan[i + 1];
|
|
||||||
rgbaSpan[i + 2] = pixelsSpan[i];
|
|
||||||
rgbaSpan[i + 3] = pixelsSpan[i + 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeMemory.Free(pixelsPtr);
|
|
||||||
pixelsPtr = rgbaPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh.Refresh_Image_SavePNG(path, (nint) pixelsPtr, width, height);
|
|
||||||
NativeMemory.Free(pixelsPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DDS loading extension, based on MojoDDS
|
|
||||||
// Taken from https://github.com/FNA-XNA/FNA/blob/1e49f868f595f62bc6385db45949a03186a7cd7f/src/Graphics/Texture.cs#L194
|
|
||||||
public static void ParseDDS(
|
|
||||||
BinaryReader reader,
|
|
||||||
out TextureFormat format,
|
|
||||||
out int width,
|
|
||||||
out int height,
|
|
||||||
out int levels,
|
|
||||||
out bool isCube
|
|
||||||
) {
|
|
||||||
// A whole bunch of magic numbers, yay DDS!
|
|
||||||
const uint DDS_MAGIC = 0x20534444;
|
|
||||||
const uint DDS_HEADERSIZE = 124;
|
|
||||||
const uint DDS_PIXFMTSIZE = 32;
|
|
||||||
const uint DDSD_HEIGHT = 0x2;
|
|
||||||
const uint DDSD_WIDTH = 0x4;
|
|
||||||
const uint DDSD_PITCH = 0x8;
|
|
||||||
const uint DDSD_LINEARSIZE = 0x80000;
|
|
||||||
const uint DDSD_REQ = (
|
|
||||||
DDSD_HEIGHT | DDSD_WIDTH
|
|
||||||
);
|
|
||||||
const uint DDSCAPS_MIPMAP = 0x400000;
|
|
||||||
const uint DDSCAPS_TEXTURE = 0x1000;
|
|
||||||
const uint DDSCAPS2_CUBEMAP = 0x200;
|
|
||||||
const uint DDPF_FOURCC = 0x4;
|
|
||||||
const uint DDPF_RGB = 0x40;
|
|
||||||
const uint FOURCC_DXT1 = 0x31545844;
|
|
||||||
const uint FOURCC_DXT3 = 0x33545844;
|
|
||||||
const uint FOURCC_DXT5 = 0x35545844;
|
|
||||||
const uint FOURCC_DX10 = 0x30315844;
|
|
||||||
const uint pitchAndLinear = (
|
|
||||||
DDSD_PITCH | DDSD_LINEARSIZE
|
|
||||||
);
|
|
||||||
|
|
||||||
// File should start with 'DDS '
|
|
||||||
if (reader.ReadUInt32() != DDS_MAGIC)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Not a DDS!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Texture info
|
|
||||||
uint size = reader.ReadUInt32();
|
|
||||||
if (size != DDS_HEADERSIZE)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Invalid DDS header!");
|
|
||||||
}
|
|
||||||
uint flags = reader.ReadUInt32();
|
|
||||||
if ((flags & DDSD_REQ) != DDSD_REQ)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Invalid DDS flags!");
|
|
||||||
}
|
|
||||||
if ((flags & pitchAndLinear) == pitchAndLinear)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Invalid DDS flags!");
|
|
||||||
}
|
|
||||||
height = reader.ReadInt32();
|
|
||||||
width = reader.ReadInt32();
|
|
||||||
reader.ReadUInt32(); // dwPitchOrLinearSize, unused
|
|
||||||
reader.ReadUInt32(); // dwDepth, unused
|
|
||||||
levels = reader.ReadInt32();
|
|
||||||
|
|
||||||
// "Reserved"
|
|
||||||
reader.ReadBytes(4 * 11);
|
|
||||||
|
|
||||||
// Format info
|
|
||||||
uint formatSize = reader.ReadUInt32();
|
|
||||||
if (formatSize != DDS_PIXFMTSIZE)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Bogus PIXFMTSIZE!");
|
|
||||||
}
|
|
||||||
uint formatFlags = reader.ReadUInt32();
|
|
||||||
uint formatFourCC = reader.ReadUInt32();
|
|
||||||
uint formatRGBBitCount = reader.ReadUInt32();
|
|
||||||
uint formatRBitMask = reader.ReadUInt32();
|
|
||||||
uint formatGBitMask = reader.ReadUInt32();
|
|
||||||
uint formatBBitMask = reader.ReadUInt32();
|
|
||||||
uint formatABitMask = reader.ReadUInt32();
|
|
||||||
|
|
||||||
// dwCaps "stuff"
|
|
||||||
uint caps = reader.ReadUInt32();
|
|
||||||
if ((caps & DDSCAPS_TEXTURE) == 0)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Not a texture!");
|
|
||||||
}
|
|
||||||
|
|
||||||
isCube = false;
|
|
||||||
|
|
||||||
uint caps2 = reader.ReadUInt32();
|
|
||||||
if (caps2 != 0)
|
|
||||||
{
|
|
||||||
if ((caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
|
|
||||||
{
|
|
||||||
isCube = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Invalid caps2!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.ReadUInt32(); // dwCaps3, unused
|
|
||||||
reader.ReadUInt32(); // dwCaps4, unused
|
|
||||||
|
|
||||||
// "Reserved"
|
|
||||||
reader.ReadUInt32();
|
|
||||||
|
|
||||||
// Mipmap sanity check
|
|
||||||
if ((caps & DDSCAPS_MIPMAP) != DDSCAPS_MIPMAP)
|
|
||||||
{
|
|
||||||
levels = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine texture format
|
|
||||||
if ((formatFlags & DDPF_FOURCC) == DDPF_FOURCC)
|
|
||||||
{
|
|
||||||
switch (formatFourCC)
|
|
||||||
{
|
|
||||||
case 0x71: // D3DFMT_A16B16G16R16F
|
|
||||||
format = TextureFormat.R16G16B16A16_SFLOAT;
|
|
||||||
break;
|
|
||||||
case 0x74: // D3DFMT_A32B32G32R32F
|
|
||||||
format = TextureFormat.R32G32B32A32_SFLOAT;
|
|
||||||
break;
|
|
||||||
case FOURCC_DXT1:
|
|
||||||
format = TextureFormat.BC1;
|
|
||||||
break;
|
|
||||||
case FOURCC_DXT3:
|
|
||||||
format = TextureFormat.BC2;
|
|
||||||
break;
|
|
||||||
case FOURCC_DXT5:
|
|
||||||
format = TextureFormat.BC3;
|
|
||||||
break;
|
|
||||||
case FOURCC_DX10:
|
|
||||||
// If the fourCC is DX10, there is an extra header with additional format information.
|
|
||||||
uint dxgiFormat = reader.ReadUInt32();
|
|
||||||
|
|
||||||
// These values are taken from the DXGI_FORMAT enum.
|
|
||||||
switch (dxgiFormat)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
format = TextureFormat.R32G32B32A32_SFLOAT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 10:
|
|
||||||
format = TextureFormat.R16G16B16A16_SFLOAT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 71:
|
|
||||||
format = TextureFormat.BC1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 74:
|
|
||||||
format = TextureFormat.BC2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 77:
|
|
||||||
format = TextureFormat.BC3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 98:
|
|
||||||
format = TextureFormat.BC7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException(
|
|
||||||
"Unsupported DDS texture format"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint resourceDimension = reader.ReadUInt32();
|
|
||||||
|
|
||||||
// These values are taken from the D3D10_RESOURCE_DIMENSION enum.
|
|
||||||
switch (resourceDimension)
|
|
||||||
{
|
|
||||||
case 0: // Unknown
|
|
||||||
case 1: // Buffer
|
|
||||||
throw new NotSupportedException(
|
|
||||||
"Unsupported DDS texture format"
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This flag seemingly only indicates if the texture is a cube map.
|
|
||||||
* This is already determined above. Cool!
|
|
||||||
*/
|
|
||||||
uint miscFlag = reader.ReadUInt32();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates the number of elements in the texture array.
|
|
||||||
* We don't support texture arrays so just throw if it's greater than 1.
|
|
||||||
*/
|
|
||||||
uint arraySize = reader.ReadUInt32();
|
|
||||||
|
|
||||||
if (arraySize > 1)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException(
|
|
||||||
"Unsupported DDS texture format"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.ReadUInt32(); // reserved
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException(
|
|
||||||
"Unsupported DDS texture format"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((formatFlags & DDPF_RGB) == DDPF_RGB)
|
|
||||||
{
|
|
||||||
if ( formatRGBBitCount != 32 ||
|
|
||||||
formatRBitMask != 0x00FF0000 ||
|
|
||||||
formatGBitMask != 0x0000FF00 ||
|
|
||||||
formatBBitMask != 0x000000FF ||
|
|
||||||
formatABitMask != 0xFF000000 )
|
|
||||||
{
|
|
||||||
throw new NotSupportedException(
|
|
||||||
"Unsupported DDS texture format"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
format = TextureFormat.B8G8R8A8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotSupportedException(
|
|
||||||
"Unsupported DDS texture format"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int CalculateDDSLevelSize(
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
TextureFormat format
|
|
||||||
) {
|
|
||||||
if (format == TextureFormat.R8G8B8A8)
|
|
||||||
{
|
|
||||||
return (((width * 32) + 7) / 8) * height;
|
|
||||||
}
|
|
||||||
else if (format == TextureFormat.R16G16B16A16_SFLOAT)
|
|
||||||
{
|
|
||||||
return (((width * 64) + 7) / 8) * height;
|
|
||||||
}
|
|
||||||
else if (format == TextureFormat.R32G32B32A32_SFLOAT)
|
|
||||||
{
|
|
||||||
return (((width * 128) + 7) / 8) * height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int blockSize = 16;
|
|
||||||
if (format == TextureFormat.BC1)
|
|
||||||
{
|
|
||||||
blockSize = 8;
|
|
||||||
}
|
|
||||||
width = System.Math.Max(width, 1);
|
|
||||||
height = System.Math.Max(height, 1);
|
|
||||||
return (
|
|
||||||
((width + 3) / 4) *
|
|
||||||
((height + 3) / 4) *
|
|
||||||
blockSize
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -297,12 +297,6 @@ namespace MoonWorks.Graphics
|
||||||
IntOpaqueWhite
|
IntOpaqueWhite
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SetDataOptions
|
|
||||||
{
|
|
||||||
Discard,
|
|
||||||
Overwrite
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Backend
|
public enum Backend
|
||||||
{
|
{
|
||||||
DontCare,
|
DontCare,
|
||||||
|
|
|
@ -127,12 +127,12 @@ namespace MoonWorks.Graphics
|
||||||
public uint Stride;
|
public uint Stride;
|
||||||
public VertexInputRate InputRate;
|
public VertexInputRate InputRate;
|
||||||
|
|
||||||
public static VertexBinding Create<T>(uint binding = 0, VertexInputRate inputRate = VertexInputRate.Vertex) where T : unmanaged
|
public static VertexBinding Create<T>(uint binding = 0) where T : unmanaged
|
||||||
{
|
{
|
||||||
return new VertexBinding
|
return new VertexBinding
|
||||||
{
|
{
|
||||||
Binding = binding,
|
Binding = binding,
|
||||||
InputRate = inputRate,
|
InputRate = VertexInputRate.Vertex,
|
||||||
Stride = (uint) Marshal.SizeOf<T>()
|
Stride = (uint) Marshal.SizeOf<T>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -354,60 +354,4 @@ namespace MoonWorks.Graphics
|
||||||
FirstInstance = firstInstance;
|
FirstInstance = firstInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct BufferCopy
|
|
||||||
{
|
|
||||||
public uint SrcOffset;
|
|
||||||
public uint DstOffset;
|
|
||||||
public uint Size;
|
|
||||||
|
|
||||||
public BufferCopy(
|
|
||||||
uint srcOffset,
|
|
||||||
uint dstOffset,
|
|
||||||
uint size
|
|
||||||
) {
|
|
||||||
SrcOffset = srcOffset;
|
|
||||||
DstOffset = dstOffset;
|
|
||||||
Size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Refresh.BufferCopy ToRefresh()
|
|
||||||
{
|
|
||||||
return new Refresh.BufferCopy
|
|
||||||
{
|
|
||||||
srcOffset = SrcOffset,
|
|
||||||
dstOffset = DstOffset,
|
|
||||||
size = Size
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[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
|
|
||||||
) {
|
|
||||||
BufferOffset = bufferOffset;
|
|
||||||
BufferStride = bufferStride;
|
|
||||||
BufferImageHeight = bufferImageHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Refresh.BufferImageCopy ToRefresh()
|
|
||||||
{
|
|
||||||
return new Refresh.BufferImageCopy
|
|
||||||
{
|
|
||||||
bufferOffset = BufferOffset,
|
|
||||||
bufferStride = BufferStride,
|
|
||||||
bufferImageHeight = BufferImageHeight
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,342 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A convenience structure for creating resources and uploading their data.
|
|
||||||
///
|
|
||||||
/// Note that Upload or UploadAndWait must be called after the Create methods for the data to actually be uploaded.
|
|
||||||
///
|
|
||||||
/// Note that this structure does not magically keep memory usage down -
|
|
||||||
/// you may want to stagger uploads over multiple submissions to minimize memory usage.
|
|
||||||
/// </summary>
|
|
||||||
public unsafe class ResourceUploader : GraphicsResource
|
|
||||||
{
|
|
||||||
TransferBuffer TransferBuffer;
|
|
||||||
|
|
||||||
byte* data;
|
|
||||||
uint dataOffset = 0;
|
|
||||||
uint dataSize = 1024;
|
|
||||||
|
|
||||||
List<(GpuBuffer, BufferCopy)> BufferUploads = new List<(GpuBuffer, BufferCopy)>();
|
|
||||||
List<(TextureSlice, uint)> TextureUploads = new List<(TextureSlice, uint)>();
|
|
||||||
|
|
||||||
public ResourceUploader(GraphicsDevice device) : base(device)
|
|
||||||
{
|
|
||||||
data = (byte*) NativeMemory.Alloc(dataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffers
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a GpuBuffer with data to be uploaded.
|
|
||||||
/// </summary>
|
|
||||||
public GpuBuffer CreateBuffer<T>(Span<T> data, BufferUsageFlags usageFlags) where T : unmanaged
|
|
||||||
{
|
|
||||||
var lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length);
|
|
||||||
var gpuBuffer = new GpuBuffer(Device, usageFlags, lengthInBytes);
|
|
||||||
|
|
||||||
SetBufferData(gpuBuffer, 0, data);
|
|
||||||
|
|
||||||
return gpuBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepares upload of data into a GpuBuffer.
|
|
||||||
/// </summary>
|
|
||||||
public void SetBufferData<T>(GpuBuffer buffer, uint bufferOffsetInElements, Span<T> data) where T : unmanaged
|
|
||||||
{
|
|
||||||
uint elementSize = (uint) Marshal.SizeOf<T>();
|
|
||||||
uint offsetInBytes = elementSize * bufferOffsetInElements;
|
|
||||||
uint lengthInBytes = (uint) (elementSize * data.Length);
|
|
||||||
|
|
||||||
uint resourceOffset;
|
|
||||||
fixed (void* spanPtr = data)
|
|
||||||
{
|
|
||||||
resourceOffset = CopyData(spanPtr, lengthInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
var bufferCopyParams = new BufferCopy(resourceOffset, offsetInBytes, lengthInBytes);
|
|
||||||
BufferUploads.Add((buffer, bufferCopyParams));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Textures
|
|
||||||
|
|
||||||
public Texture CreateTexture2D(Span<byte> pixelData, uint width, uint height)
|
|
||||||
{
|
|
||||||
var texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
|
|
||||||
SetTextureData(texture, pixelData);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a 2D Texture from compressed image data to be uploaded.
|
|
||||||
/// </summary>
|
|
||||||
public Texture CreateTexture2DFromCompressed(Span<byte> compressedImageData)
|
|
||||||
{
|
|
||||||
ImageUtils.ImageInfoFromBytes(compressedImageData, out var width, out var height, out var _);
|
|
||||||
var texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
|
|
||||||
SetTextureDataFromCompressed(texture, compressedImageData);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a 2D Texture from a compressed image stream to be uploaded.
|
|
||||||
/// </summary>
|
|
||||||
public Texture CreateTexture2DFromCompressed(Stream compressedImageStream)
|
|
||||||
{
|
|
||||||
var length = compressedImageStream.Length;
|
|
||||||
var buffer = NativeMemory.Alloc((nuint) length);
|
|
||||||
var span = new Span<byte>(buffer, (int) length);
|
|
||||||
compressedImageStream.ReadExactly(span);
|
|
||||||
|
|
||||||
var texture = CreateTexture2DFromCompressed(span);
|
|
||||||
|
|
||||||
NativeMemory.Free(buffer);
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a 2D Texture from a compressed image file to be uploaded.
|
|
||||||
/// </summary>
|
|
||||||
public Texture CreateTexture2DFromCompressed(string compressedImageFilePath)
|
|
||||||
{
|
|
||||||
var fileStream = new FileStream(compressedImageFilePath, FileMode.Open, FileAccess.Read);
|
|
||||||
return CreateTexture2DFromCompressed(fileStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a texture from a DDS stream.
|
|
||||||
/// </summary>
|
|
||||||
public Texture CreateTextureFromDDS(Stream stream)
|
|
||||||
{
|
|
||||||
using var reader = new BinaryReader(stream);
|
|
||||||
Texture texture;
|
|
||||||
int faces;
|
|
||||||
ImageUtils.ParseDDS(reader, out var format, out var width, out var height, out var levels, out var isCube);
|
|
||||||
|
|
||||||
if (isCube)
|
|
||||||
{
|
|
||||||
texture = Texture.CreateTextureCube(Device, (uint) width, format, TextureUsageFlags.Sampler, (uint) levels);
|
|
||||||
faces = 6;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texture = Texture.CreateTexture2D(Device, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, (uint) levels);
|
|
||||||
faces = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int face = 0; face < faces; face += 1)
|
|
||||||
{
|
|
||||||
for (int level = 0; level < levels; level += 1)
|
|
||||||
{
|
|
||||||
var levelWidth = width >> level;
|
|
||||||
var levelHeight = height >> level;
|
|
||||||
|
|
||||||
var levelSize = ImageUtils.CalculateDDSLevelSize(levelWidth, levelHeight, format);
|
|
||||||
var byteBuffer = NativeMemory.Alloc((nuint) levelSize);
|
|
||||||
var byteSpan = new Span<byte>(byteBuffer, levelSize);
|
|
||||||
stream.ReadExactly(byteSpan);
|
|
||||||
|
|
||||||
var textureSlice = new TextureSlice
|
|
||||||
{
|
|
||||||
Texture = texture,
|
|
||||||
MipLevel = (uint) level,
|
|
||||||
BaseLayer = (uint) face,
|
|
||||||
LayerCount = 1,
|
|
||||||
X = 0,
|
|
||||||
Y = 0,
|
|
||||||
Z = 0,
|
|
||||||
Width = (uint) levelWidth,
|
|
||||||
Height = (uint) levelHeight,
|
|
||||||
Depth = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
SetTextureData(textureSlice, byteSpan);
|
|
||||||
|
|
||||||
NativeMemory.Free(byteBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a texture from a DDS file.
|
|
||||||
/// </summary>
|
|
||||||
public Texture CreateTextureFromDDS(string path)
|
|
||||||
{
|
|
||||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
|
||||||
return CreateTextureFromDDS(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTextureDataFromCompressed(TextureSlice textureSlice, 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);
|
|
||||||
|
|
||||||
ImageUtils.FreePixelData(pixelData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTextureDataFromCompressed(TextureSlice textureSlice, 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);
|
|
||||||
NativeMemory.Free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTextureDataFromCompressed(TextureSlice textureSlice, string compressedImageFilePath)
|
|
||||||
{
|
|
||||||
var fileStream = new FileStream(compressedImageFilePath, FileMode.Open, FileAccess.Read);
|
|
||||||
SetTextureDataFromCompressed(textureSlice, fileStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepares upload of pixel data into a TextureSlice.
|
|
||||||
/// </summary>
|
|
||||||
public void SetTextureData<T>(TextureSlice textureSlice, Span<T> data) where T : unmanaged
|
|
||||||
{
|
|
||||||
var elementSize = Marshal.SizeOf<T>();
|
|
||||||
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
|
||||||
|
|
||||||
uint resourceOffset;
|
|
||||||
fixed (T* dataPtr = data)
|
|
||||||
{
|
|
||||||
resourceOffset = CopyDataAligned(dataPtr, dataLengthInBytes, Texture.TexelSize(textureSlice.Texture.Format));
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureUploads.Add((textureSlice, resourceOffset));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Uploads all the data corresponding to the created resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Upload()
|
|
||||||
{
|
|
||||||
CopyToTransferBuffer();
|
|
||||||
|
|
||||||
var commandBuffer = Device.AcquireCommandBuffer();
|
|
||||||
RecordUploadCommands(commandBuffer);
|
|
||||||
Device.Submit(commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Uploads and then blocks until the upload is finished.
|
|
||||||
/// This is useful for keeping memory usage down during threaded upload.
|
|
||||||
/// </summary>
|
|
||||||
public void UploadAndWait()
|
|
||||||
{
|
|
||||||
CopyToTransferBuffer();
|
|
||||||
|
|
||||||
var commandBuffer = Device.AcquireCommandBuffer();
|
|
||||||
RecordUploadCommands(commandBuffer);
|
|
||||||
var fence = Device.SubmitAndAcquireFence(commandBuffer);
|
|
||||||
Device.WaitForFences(fence);
|
|
||||||
Device.ReleaseFence(fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper methods
|
|
||||||
|
|
||||||
private void CopyToTransferBuffer()
|
|
||||||
{
|
|
||||||
if (TransferBuffer == null || TransferBuffer.Size < dataSize)
|
|
||||||
{
|
|
||||||
TransferBuffer?.Dispose();
|
|
||||||
TransferBuffer = new TransferBuffer(Device, dataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
var dataSpan = new Span<byte>(data, (int) dataSize);
|
|
||||||
TransferBuffer.SetData(dataSpan, SetDataOptions.Discard);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RecordUploadCommands(CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
commandBuffer.BeginCopyPass();
|
|
||||||
|
|
||||||
foreach (var (gpuBuffer, bufferCopyParams) in BufferUploads)
|
|
||||||
{
|
|
||||||
commandBuffer.UploadToBuffer(
|
|
||||||
TransferBuffer,
|
|
||||||
gpuBuffer,
|
|
||||||
bufferCopyParams
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (textureSlice, offset) in TextureUploads)
|
|
||||||
{
|
|
||||||
commandBuffer.UploadToTexture(
|
|
||||||
TransferBuffer,
|
|
||||||
textureSlice,
|
|
||||||
new BufferImageCopy(
|
|
||||||
offset,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
commandBuffer.EndCopyPass();
|
|
||||||
|
|
||||||
BufferUploads.Clear();
|
|
||||||
TextureUploads.Clear();
|
|
||||||
dataOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint CopyData(void* ptr, uint lengthInBytes)
|
|
||||||
{
|
|
||||||
if (dataOffset + lengthInBytes >= dataSize)
|
|
||||||
{
|
|
||||||
dataSize = dataOffset + lengthInBytes;
|
|
||||||
data = (byte*) NativeMemory.Realloc(data, dataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourceOffset = dataOffset;
|
|
||||||
|
|
||||||
NativeMemory.Copy(ptr, data + dataOffset, lengthInBytes);
|
|
||||||
dataOffset += lengthInBytes;
|
|
||||||
|
|
||||||
return resourceOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint CopyDataAligned(void* ptr, uint lengthInBytes, uint alignment)
|
|
||||||
{
|
|
||||||
dataOffset = RoundToAlignment(dataOffset, alignment);
|
|
||||||
return CopyData(ptr, lengthInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint RoundToAlignment(uint value, uint alignment)
|
|
||||||
{
|
|
||||||
return alignment * ((value + alignment - 1) / alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispose
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// It is valid to immediately call Dispose after calling Upload.
|
|
||||||
/// </summary>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!IsDisposed)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
TransferBuffer?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeMemory.Free(data);
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using RefreshCS;
|
||||||
|
|
||||||
|
namespace MoonWorks.Graphics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Buffers are generic data containers that can be used by the GPU.
|
||||||
|
/// </summary>
|
||||||
|
public class Buffer : RefreshResource
|
||||||
|
{
|
||||||
|
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public uint Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a buffer of appropriate size given a type and element count.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
||||||
|
/// <param name="device">The GraphicsDevice.</param>
|
||||||
|
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
||||||
|
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public unsafe static Buffer Create<T>(
|
||||||
|
GraphicsDevice device,
|
||||||
|
BufferUsageFlags usageFlags,
|
||||||
|
uint elementCount
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
return new Buffer(
|
||||||
|
device,
|
||||||
|
usageFlags,
|
||||||
|
(uint) Marshal.SizeOf<T>() * elementCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">An initialized GraphicsDevice.</param>
|
||||||
|
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
||||||
|
/// <param name="sizeInBytes">The length of the array. Cannot be resized.</param>
|
||||||
|
public Buffer(
|
||||||
|
GraphicsDevice device,
|
||||||
|
BufferUsageFlags usageFlags,
|
||||||
|
uint sizeInBytes
|
||||||
|
) : base(device)
|
||||||
|
{
|
||||||
|
Handle = Refresh.Refresh_CreateBuffer(
|
||||||
|
device.Handle,
|
||||||
|
(Refresh.BufferUsageFlags) usageFlags,
|
||||||
|
sizeInBytes
|
||||||
|
);
|
||||||
|
Size = sizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data out of a buffer and into a span.
|
||||||
|
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The span that data will be copied to.</param>
|
||||||
|
/// <param name="dataLengthInBytes">The length of the data to read.</param>
|
||||||
|
public unsafe void GetData<T>(
|
||||||
|
Span<T> data,
|
||||||
|
uint dataLengthInBytes
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (dataLengthInBytes > Size)
|
||||||
|
{
|
||||||
|
Logger.LogWarn("Requested too many bytes from buffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataLengthInBytes > data.Length * Marshal.SizeOf<T>())
|
||||||
|
{
|
||||||
|
Logger.LogWarn("Data length is larger than the provided Span!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fixed (T* ptr = data)
|
||||||
|
{
|
||||||
|
Refresh.Refresh_GetBufferData(
|
||||||
|
Device.Handle,
|
||||||
|
Handle,
|
||||||
|
(IntPtr) ptr,
|
||||||
|
dataLengthInBytes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data out of a buffer and into an array.
|
||||||
|
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The span that data will be copied to.</param>
|
||||||
|
/// <param name="dataLengthInBytes">The length of the data to read.</param>
|
||||||
|
public unsafe void GetData<T>(
|
||||||
|
T[] data,
|
||||||
|
uint dataLengthInBytes
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
GetData(new Span<T>(data), dataLengthInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data out of a buffer and into a span.
|
||||||
|
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
||||||
|
/// Fills the span with as much data from the buffer as it can.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The span that data will be copied to.</param>
|
||||||
|
public unsafe void GetData<T>(
|
||||||
|
Span<T> data
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
var lengthInBytes = System.Math.Min(data.Length * Marshal.SizeOf<T>(), Size);
|
||||||
|
GetData(data, (uint) lengthInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data out of a buffer and into an array.
|
||||||
|
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
||||||
|
/// Fills the array with as much data from the buffer as it can.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The span that data will be copied to.</param>
|
||||||
|
public unsafe void GetData<T>(
|
||||||
|
T[] data
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
var lengthInBytes = System.Math.Min(data.Length * Marshal.SizeOf<T>(), Size);
|
||||||
|
GetData(new Span<T>(data), (uint) lengthInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator BufferBinding(Buffer b)
|
||||||
|
{
|
||||||
|
return new BufferBinding(b, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using RefreshCS;
|
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// GpuBuffers are generic data containers that can be used by the GPU.
|
|
||||||
/// </summary>
|
|
||||||
public class GpuBuffer : RefreshResource
|
|
||||||
{
|
|
||||||
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyGpuBuffer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Size in bytes.
|
|
||||||
/// </summary>
|
|
||||||
public uint Size { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a buffer of appropriate size given a type and element count.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
|
||||||
/// <param name="device">The GraphicsDevice.</param>
|
|
||||||
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
|
||||||
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public unsafe static GpuBuffer Create<T>(
|
|
||||||
GraphicsDevice device,
|
|
||||||
BufferUsageFlags usageFlags,
|
|
||||||
uint elementCount
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
return new GpuBuffer(
|
|
||||||
device,
|
|
||||||
usageFlags,
|
|
||||||
(uint) Marshal.SizeOf<T>() * elementCount
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">An initialized GraphicsDevice.</param>
|
|
||||||
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
|
||||||
/// <param name="sizeInBytes">The length of the array. Cannot be resized.</param>
|
|
||||||
public GpuBuffer(
|
|
||||||
GraphicsDevice device,
|
|
||||||
BufferUsageFlags usageFlags,
|
|
||||||
uint sizeInBytes
|
|
||||||
) : base(device)
|
|
||||||
{
|
|
||||||
Handle = Refresh.Refresh_CreateGpuBuffer(
|
|
||||||
device.Handle,
|
|
||||||
(Refresh.BufferUsageFlags) usageFlags,
|
|
||||||
sizeInBytes
|
|
||||||
);
|
|
||||||
Size = sizeInBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator BufferBinding(GpuBuffer b)
|
|
||||||
{
|
|
||||||
return new BufferBinding(b, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -61,11 +61,12 @@ namespace MoonWorks.Graphics
|
||||||
refreshGraphicsPipelineCreateInfo.blendConstants[2] = blendConstants.B;
|
refreshGraphicsPipelineCreateInfo.blendConstants[2] = blendConstants.B;
|
||||||
refreshGraphicsPipelineCreateInfo.blendConstants[3] = blendConstants.A;
|
refreshGraphicsPipelineCreateInfo.blendConstants[3] = blendConstants.A;
|
||||||
|
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilState = depthStencilState.StencilState.ToRefresh();
|
refreshGraphicsPipelineCreateInfo.depthStencilState.backStencilState = depthStencilState.BackStencilState.ToRefresh();
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.compareOp = (Refresh.CompareOp) depthStencilState.CompareOp;
|
refreshGraphicsPipelineCreateInfo.depthStencilState.compareOp = (Refresh.CompareOp) depthStencilState.CompareOp;
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthBoundsTestEnable = Conversions.BoolToByte(depthStencilState.DepthBoundsTestEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.depthBoundsTestEnable = Conversions.BoolToByte(depthStencilState.DepthBoundsTestEnable);
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthTestEnable = Conversions.BoolToByte(depthStencilState.DepthTestEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.depthTestEnable = Conversions.BoolToByte(depthStencilState.DepthTestEnable);
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthWriteEnable = Conversions.BoolToByte(depthStencilState.DepthWriteEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.depthWriteEnable = Conversions.BoolToByte(depthStencilState.DepthWriteEnable);
|
||||||
|
refreshGraphicsPipelineCreateInfo.depthStencilState.frontStencilState = depthStencilState.FrontStencilState.ToRefresh();
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.maxDepthBounds = depthStencilState.MaxDepthBounds;
|
refreshGraphicsPipelineCreateInfo.depthStencilState.maxDepthBounds = depthStencilState.MaxDepthBounds;
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.minDepthBounds = depthStencilState.MinDepthBounds;
|
refreshGraphicsPipelineCreateInfo.depthStencilState.minDepthBounds = depthStencilState.MinDepthBounds;
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilTestEnable = Conversions.BoolToByte(depthStencilState.StencilTestEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilTestEnable = Conversions.BoolToByte(depthStencilState.StencilTestEnable);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using RefreshCS;
|
using RefreshCS;
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
namespace MoonWorks.Graphics
|
||||||
|
@ -17,11 +18,166 @@ namespace MoonWorks.Graphics
|
||||||
public uint LevelCount { get; }
|
public uint LevelCount { get; }
|
||||||
public SampleCount SampleCount { get; }
|
public SampleCount SampleCount { get; }
|
||||||
public TextureUsageFlags UsageFlags { get; }
|
public TextureUsageFlags UsageFlags { get; }
|
||||||
public uint Size { get; }
|
|
||||||
|
|
||||||
// FIXME: this allocates a delegate instance
|
// FIXME: this allocates a delegate instance
|
||||||
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
|
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a 2D Texture using PNG or QOI data from raw byte data.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe Texture FromImageBytes(
|
||||||
|
GraphicsDevice device,
|
||||||
|
CommandBuffer commandBuffer,
|
||||||
|
Span<byte> data
|
||||||
|
) {
|
||||||
|
Texture texture;
|
||||||
|
|
||||||
|
fixed (byte *dataPtr = data)
|
||||||
|
{
|
||||||
|
var pixels = Refresh.Refresh_Image_Load((nint) dataPtr, data.Length, out var width, out var height, out var len);
|
||||||
|
|
||||||
|
TextureCreateInfo textureCreateInfo = new TextureCreateInfo();
|
||||||
|
textureCreateInfo.Width = (uint) width;
|
||||||
|
textureCreateInfo.Height = (uint) height;
|
||||||
|
textureCreateInfo.Depth = 1;
|
||||||
|
textureCreateInfo.Format = TextureFormat.R8G8B8A8;
|
||||||
|
textureCreateInfo.IsCube = false;
|
||||||
|
textureCreateInfo.LevelCount = 1;
|
||||||
|
textureCreateInfo.SampleCount = SampleCount.One;
|
||||||
|
textureCreateInfo.UsageFlags = TextureUsageFlags.Sampler;
|
||||||
|
|
||||||
|
texture = new Texture(device, textureCreateInfo);
|
||||||
|
commandBuffer.SetTextureData(texture, pixels, (uint) len);
|
||||||
|
|
||||||
|
Refresh.Refresh_Image_Free(pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a 2D Texture using PNG or QOI data from a stream.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe Texture FromImageStream(
|
||||||
|
GraphicsDevice device,
|
||||||
|
CommandBuffer commandBuffer,
|
||||||
|
Stream stream
|
||||||
|
) {
|
||||||
|
var length = stream.Length;
|
||||||
|
var buffer = NativeMemory.Alloc((nuint) length);
|
||||||
|
var span = new Span<byte>(buffer, (int) length);
|
||||||
|
stream.ReadExactly(span);
|
||||||
|
|
||||||
|
var texture = FromImageBytes(device, commandBuffer, span);
|
||||||
|
|
||||||
|
NativeMemory.Free((void*) buffer);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a 2D Texture using PNG or QOI data from a file.
|
||||||
|
/// </summary>
|
||||||
|
public static Texture FromImageFile(
|
||||||
|
GraphicsDevice device,
|
||||||
|
CommandBuffer commandBuffer,
|
||||||
|
string path
|
||||||
|
) {
|
||||||
|
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
|
return FromImageStream(device, commandBuffer, fileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe void SetDataFromImageBytes(
|
||||||
|
CommandBuffer commandBuffer,
|
||||||
|
TextureSlice textureSlice,
|
||||||
|
Span<byte> data
|
||||||
|
) {
|
||||||
|
fixed (byte* ptr = data)
|
||||||
|
{
|
||||||
|
var pixels = Refresh.Refresh_Image_Load(
|
||||||
|
(nint) ptr,
|
||||||
|
(int) data.Length,
|
||||||
|
out var w,
|
||||||
|
out var h,
|
||||||
|
out var len
|
||||||
|
);
|
||||||
|
|
||||||
|
commandBuffer.SetTextureData(textureSlice, pixels, (uint) len);
|
||||||
|
|
||||||
|
Refresh.Refresh_Image_Free(pixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets data for a texture slice using PNG or QOI data from a stream.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe void SetDataFromImageStream(
|
||||||
|
CommandBuffer commandBuffer,
|
||||||
|
TextureSlice textureSlice,
|
||||||
|
Stream stream
|
||||||
|
) {
|
||||||
|
var length = stream.Length;
|
||||||
|
var buffer = NativeMemory.Alloc((nuint) length);
|
||||||
|
var span = new Span<byte>(buffer, (int) length);
|
||||||
|
stream.ReadExactly(span);
|
||||||
|
|
||||||
|
SetDataFromImageBytes(commandBuffer, textureSlice, span);
|
||||||
|
|
||||||
|
NativeMemory.Free((void*) buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets data for a texture slice using PNG or QOI data from a file.
|
||||||
|
/// </summary>
|
||||||
|
public static void SetDataFromImageFile(
|
||||||
|
CommandBuffer commandBuffer,
|
||||||
|
TextureSlice textureSlice,
|
||||||
|
string path
|
||||||
|
) {
|
||||||
|
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
|
SetDataFromImageStream(commandBuffer, textureSlice, fileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe static Texture LoadDDS(GraphicsDevice graphicsDevice, CommandBuffer commandBuffer, System.IO.Stream stream)
|
||||||
|
{
|
||||||
|
using var reader = new BinaryReader(stream);
|
||||||
|
Texture texture;
|
||||||
|
int faces;
|
||||||
|
ParseDDS(reader, out var format, out var width, out var height, out var levels, out var isCube);
|
||||||
|
|
||||||
|
if (isCube)
|
||||||
|
{
|
||||||
|
texture = CreateTextureCube(graphicsDevice, (uint) width, format, TextureUsageFlags.Sampler, (uint) levels);
|
||||||
|
faces = 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture = CreateTexture2D(graphicsDevice, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, (uint) levels);
|
||||||
|
faces = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < faces; i += 1)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < levels; j += 1)
|
||||||
|
{
|
||||||
|
var levelWidth = width >> j;
|
||||||
|
var levelHeight = height >> j;
|
||||||
|
|
||||||
|
var levelSize = CalculateDDSLevelSize(levelWidth, levelHeight, format);
|
||||||
|
var byteBuffer = NativeMemory.Alloc((nuint) levelSize);
|
||||||
|
var byteSpan = new Span<byte>(byteBuffer, levelSize);
|
||||||
|
stream.ReadExactly(byteSpan);
|
||||||
|
|
||||||
|
var textureSlice = new TextureSlice(texture, new Rect(0, 0, levelWidth, levelHeight), 0, (uint) i, (uint) j);
|
||||||
|
commandBuffer.SetTextureData(textureSlice, (nint) byteBuffer, (uint) levelSize);
|
||||||
|
|
||||||
|
NativeMemory.Free(byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a 2D texture.
|
/// Creates a 2D texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -140,7 +296,6 @@ namespace MoonWorks.Graphics
|
||||||
LevelCount = textureCreateInfo.LevelCount;
|
LevelCount = textureCreateInfo.LevelCount;
|
||||||
SampleCount = textureCreateInfo.SampleCount;
|
SampleCount = textureCreateInfo.SampleCount;
|
||||||
UsageFlags = textureCreateInfo.UsageFlags;
|
UsageFlags = textureCreateInfo.UsageFlags;
|
||||||
Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator TextureSlice(Texture t) => new TextureSlice(t);
|
public static implicit operator TextureSlice(Texture t) => new TextureSlice(t);
|
||||||
|
@ -148,13 +303,12 @@ namespace MoonWorks.Graphics
|
||||||
// Used by AcquireSwapchainTexture.
|
// Used by AcquireSwapchainTexture.
|
||||||
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
||||||
internal Texture(
|
internal Texture(
|
||||||
GraphicsDevice device,
|
GraphicsDevice device
|
||||||
TextureFormat format
|
|
||||||
) : base(device)
|
) : base(device)
|
||||||
{
|
{
|
||||||
Handle = IntPtr.Zero;
|
Handle = IntPtr.Zero;
|
||||||
|
|
||||||
Format = format;
|
Format = TextureFormat.R8G8B8A8;
|
||||||
Width = 0;
|
Width = 0;
|
||||||
Height = 0;
|
Height = 0;
|
||||||
Depth = 1;
|
Depth = 1;
|
||||||
|
@ -162,113 +316,333 @@ namespace MoonWorks.Graphics
|
||||||
LevelCount = 1;
|
LevelCount = 1;
|
||||||
SampleCount = SampleCount.One;
|
SampleCount = SampleCount.One;
|
||||||
UsageFlags = TextureUsageFlags.ColorTarget;
|
UsageFlags = TextureUsageFlags.ColorTarget;
|
||||||
Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint BytesPerPixel(TextureFormat format)
|
// DDS loading extension, based on MojoDDS
|
||||||
{
|
// Taken from https://github.com/FNA-XNA/FNA/blob/1e49f868f595f62bc6385db45949a03186a7cd7f/src/Graphics/Texture.cs#L194
|
||||||
switch (format)
|
private static void ParseDDS(
|
||||||
|
BinaryReader reader,
|
||||||
|
out TextureFormat format,
|
||||||
|
out int width,
|
||||||
|
out int height,
|
||||||
|
out int levels,
|
||||||
|
out bool isCube
|
||||||
|
) {
|
||||||
|
// A whole bunch of magic numbers, yay DDS!
|
||||||
|
const uint DDS_MAGIC = 0x20534444;
|
||||||
|
const uint DDS_HEADERSIZE = 124;
|
||||||
|
const uint DDS_PIXFMTSIZE = 32;
|
||||||
|
const uint DDSD_HEIGHT = 0x2;
|
||||||
|
const uint DDSD_WIDTH = 0x4;
|
||||||
|
const uint DDSD_PITCH = 0x8;
|
||||||
|
const uint DDSD_LINEARSIZE = 0x80000;
|
||||||
|
const uint DDSD_REQ = (
|
||||||
|
DDSD_HEIGHT | DDSD_WIDTH
|
||||||
|
);
|
||||||
|
const uint DDSCAPS_MIPMAP = 0x400000;
|
||||||
|
const uint DDSCAPS_TEXTURE = 0x1000;
|
||||||
|
const uint DDSCAPS2_CUBEMAP = 0x200;
|
||||||
|
const uint DDPF_FOURCC = 0x4;
|
||||||
|
const uint DDPF_RGB = 0x40;
|
||||||
|
const uint FOURCC_DXT1 = 0x31545844;
|
||||||
|
const uint FOURCC_DXT3 = 0x33545844;
|
||||||
|
const uint FOURCC_DXT5 = 0x35545844;
|
||||||
|
const uint FOURCC_DX10 = 0x30315844;
|
||||||
|
const uint pitchAndLinear = (
|
||||||
|
DDSD_PITCH | DDSD_LINEARSIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
// File should start with 'DDS '
|
||||||
|
if (reader.ReadUInt32() != DDS_MAGIC)
|
||||||
{
|
{
|
||||||
case TextureFormat.R8:
|
throw new NotSupportedException("Not a DDS!");
|
||||||
case TextureFormat.R8_UINT:
|
}
|
||||||
return 1;
|
|
||||||
case TextureFormat.R5G6B5:
|
// Texture info
|
||||||
case TextureFormat.B4G4R4A4:
|
uint size = reader.ReadUInt32();
|
||||||
case TextureFormat.A1R5G5B5:
|
if (size != DDS_HEADERSIZE)
|
||||||
case TextureFormat.R16_SFLOAT:
|
{
|
||||||
case TextureFormat.R8G8_SNORM:
|
throw new NotSupportedException("Invalid DDS header!");
|
||||||
case TextureFormat.R8G8_UINT:
|
}
|
||||||
case TextureFormat.R16_UINT:
|
uint flags = reader.ReadUInt32();
|
||||||
case TextureFormat.D16:
|
if ((flags & DDSD_REQ) != DDSD_REQ)
|
||||||
return 2;
|
{
|
||||||
case TextureFormat.D16S8:
|
throw new NotSupportedException("Invalid DDS flags!");
|
||||||
return 3;
|
}
|
||||||
case TextureFormat.R8G8B8A8:
|
if ((flags & pitchAndLinear) == pitchAndLinear)
|
||||||
case TextureFormat.B8G8R8A8:
|
{
|
||||||
case TextureFormat.R32_SFLOAT:
|
throw new NotSupportedException("Invalid DDS flags!");
|
||||||
case TextureFormat.R16G16:
|
}
|
||||||
case TextureFormat.R16G16_SFLOAT:
|
height = reader.ReadInt32();
|
||||||
case TextureFormat.R8G8B8A8_SNORM:
|
width = reader.ReadInt32();
|
||||||
case TextureFormat.A2R10G10B10:
|
reader.ReadUInt32(); // dwPitchOrLinearSize, unused
|
||||||
case TextureFormat.R8G8B8A8_UINT:
|
reader.ReadUInt32(); // dwDepth, unused
|
||||||
case TextureFormat.R16G16_UINT:
|
levels = reader.ReadInt32();
|
||||||
case TextureFormat.D32:
|
|
||||||
return 4;
|
// "Reserved"
|
||||||
case TextureFormat.D32S8:
|
reader.ReadBytes(4 * 11);
|
||||||
return 5;
|
|
||||||
case TextureFormat.R16G16B16A16_SFLOAT:
|
// Format info
|
||||||
case TextureFormat.R16G16B16A16:
|
uint formatSize = reader.ReadUInt32();
|
||||||
case TextureFormat.R32G32_SFLOAT:
|
if (formatSize != DDS_PIXFMTSIZE)
|
||||||
case TextureFormat.R16G16B16A16_UINT:
|
{
|
||||||
case TextureFormat.BC1:
|
throw new NotSupportedException("Bogus PIXFMTSIZE!");
|
||||||
return 8;
|
}
|
||||||
case TextureFormat.R32G32B32A32_SFLOAT:
|
uint formatFlags = reader.ReadUInt32();
|
||||||
case TextureFormat.BC2:
|
uint formatFourCC = reader.ReadUInt32();
|
||||||
case TextureFormat.BC3:
|
uint formatRGBBitCount = reader.ReadUInt32();
|
||||||
case TextureFormat.BC7:
|
uint formatRBitMask = reader.ReadUInt32();
|
||||||
return 16;
|
uint formatGBitMask = reader.ReadUInt32();
|
||||||
default:
|
uint formatBBitMask = reader.ReadUInt32();
|
||||||
Logger.LogError("Texture format not recognized!");
|
uint formatABitMask = reader.ReadUInt32();
|
||||||
return 0;
|
|
||||||
|
// dwCaps "stuff"
|
||||||
|
uint caps = reader.ReadUInt32();
|
||||||
|
if ((caps & DDSCAPS_TEXTURE) == 0)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Not a texture!");
|
||||||
|
}
|
||||||
|
|
||||||
|
isCube = false;
|
||||||
|
|
||||||
|
uint caps2 = reader.ReadUInt32();
|
||||||
|
if (caps2 != 0)
|
||||||
|
{
|
||||||
|
if ((caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
|
||||||
|
{
|
||||||
|
isCube = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Invalid caps2!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadUInt32(); // dwCaps3, unused
|
||||||
|
reader.ReadUInt32(); // dwCaps4, unused
|
||||||
|
|
||||||
|
// "Reserved"
|
||||||
|
reader.ReadUInt32();
|
||||||
|
|
||||||
|
// Mipmap sanity check
|
||||||
|
if ((caps & DDSCAPS_MIPMAP) != DDSCAPS_MIPMAP)
|
||||||
|
{
|
||||||
|
levels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine texture format
|
||||||
|
if ((formatFlags & DDPF_FOURCC) == DDPF_FOURCC)
|
||||||
|
{
|
||||||
|
switch (formatFourCC)
|
||||||
|
{
|
||||||
|
case 0x71: // D3DFMT_A16B16G16R16F
|
||||||
|
format = TextureFormat.R16G16B16A16_SFLOAT;
|
||||||
|
break;
|
||||||
|
case 0x74: // D3DFMT_A32B32G32R32F
|
||||||
|
format = TextureFormat.R32G32B32A32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case FOURCC_DXT1:
|
||||||
|
format = TextureFormat.BC1;
|
||||||
|
break;
|
||||||
|
case FOURCC_DXT3:
|
||||||
|
format = TextureFormat.BC2;
|
||||||
|
break;
|
||||||
|
case FOURCC_DXT5:
|
||||||
|
format = TextureFormat.BC3;
|
||||||
|
break;
|
||||||
|
case FOURCC_DX10:
|
||||||
|
// If the fourCC is DX10, there is an extra header with additional format information.
|
||||||
|
uint dxgiFormat = reader.ReadUInt32();
|
||||||
|
|
||||||
|
// These values are taken from the DXGI_FORMAT enum.
|
||||||
|
switch (dxgiFormat)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
format = TextureFormat.R32G32B32A32_SFLOAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10:
|
||||||
|
format = TextureFormat.R16G16B16A16_SFLOAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 71:
|
||||||
|
format = TextureFormat.BC1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 74:
|
||||||
|
format = TextureFormat.BC2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 77:
|
||||||
|
format = TextureFormat.BC3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 98:
|
||||||
|
format = TextureFormat.BC7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Unsupported DDS texture format"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint resourceDimension = reader.ReadUInt32();
|
||||||
|
|
||||||
|
// These values are taken from the D3D10_RESOURCE_DIMENSION enum.
|
||||||
|
switch (resourceDimension)
|
||||||
|
{
|
||||||
|
case 0: // Unknown
|
||||||
|
case 1: // Buffer
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Unsupported DDS texture format"
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This flag seemingly only indicates if the texture is a cube map.
|
||||||
|
* This is already determined above. Cool!
|
||||||
|
*/
|
||||||
|
uint miscFlag = reader.ReadUInt32();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicates the number of elements in the texture array.
|
||||||
|
* We don't support texture arrays so just throw if it's greater than 1.
|
||||||
|
*/
|
||||||
|
uint arraySize = reader.ReadUInt32();
|
||||||
|
|
||||||
|
if (arraySize > 1)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Unsupported DDS texture format"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadUInt32(); // reserved
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Unsupported DDS texture format"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((formatFlags & DDPF_RGB) == DDPF_RGB)
|
||||||
|
{
|
||||||
|
if ( formatRGBBitCount != 32 ||
|
||||||
|
formatRBitMask != 0x00FF0000 ||
|
||||||
|
formatGBitMask != 0x0000FF00 ||
|
||||||
|
formatBBitMask != 0x000000FF ||
|
||||||
|
formatABitMask != 0xFF000000 )
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Unsupported DDS texture format"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
format = TextureFormat.B8G8R8A8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Unsupported DDS texture format"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint TexelSize(TextureFormat format)
|
private static int CalculateDDSLevelSize(
|
||||||
{
|
int width,
|
||||||
switch (format)
|
int height,
|
||||||
|
TextureFormat format
|
||||||
|
) {
|
||||||
|
if (format == TextureFormat.R8G8B8A8)
|
||||||
{
|
{
|
||||||
case TextureFormat.BC2:
|
return (((width * 32) + 7) / 8) * height;
|
||||||
case TextureFormat.BC3:
|
}
|
||||||
case TextureFormat.BC7:
|
else if (format == TextureFormat.R16G16B16A16_SFLOAT)
|
||||||
return 16;
|
{
|
||||||
case TextureFormat.BC1:
|
return (((width * 64) + 7) / 8) * height;
|
||||||
return 8;
|
}
|
||||||
default:
|
else if (format == TextureFormat.R32G32B32A32_SFLOAT)
|
||||||
return 1;
|
{
|
||||||
|
return (((width * 128) + 7) / 8) * height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int blockSize = 16;
|
||||||
|
if (format == TextureFormat.BC1)
|
||||||
|
{
|
||||||
|
blockSize = 8;
|
||||||
|
}
|
||||||
|
width = System.Math.Max(width, 1);
|
||||||
|
height = System.Math.Max(height, 1);
|
||||||
|
return (
|
||||||
|
((width + 3) / 4) *
|
||||||
|
((height + 3) / 4) *
|
||||||
|
blockSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint BlockSizeSquared(TextureFormat format)
|
/// <summary>
|
||||||
|
/// Asynchronously saves RGBA or BGRA pixel data to a file in PNG format. <br/>
|
||||||
|
/// Warning: this is expensive and will block to wait for data download from GPU! <br/>
|
||||||
|
/// You can avoid blocking by calling this method from a thread.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe void SavePNG(string path)
|
||||||
{
|
{
|
||||||
switch (format)
|
#if DEBUG
|
||||||
|
if (Format != TextureFormat.R8G8B8A8 && Format != TextureFormat.B8G8R8A8)
|
||||||
{
|
{
|
||||||
case TextureFormat.BC1:
|
throw new ArgumentException("Texture format must be RGBA or BGRA!", "format");
|
||||||
case TextureFormat.BC2:
|
|
||||||
case TextureFormat.BC3:
|
|
||||||
case TextureFormat.BC7:
|
|
||||||
return 16;
|
|
||||||
case TextureFormat.R8G8B8A8:
|
|
||||||
case TextureFormat.B8G8R8A8:
|
|
||||||
case TextureFormat.R5G6B5:
|
|
||||||
case TextureFormat.A1R5G5B5:
|
|
||||||
case TextureFormat.B4G4R4A4:
|
|
||||||
case TextureFormat.A2R10G10B10:
|
|
||||||
case TextureFormat.R16G16:
|
|
||||||
case TextureFormat.R16G16B16A16:
|
|
||||||
case TextureFormat.R8:
|
|
||||||
case TextureFormat.R8G8_SNORM:
|
|
||||||
case TextureFormat.R8G8B8A8_SNORM:
|
|
||||||
case TextureFormat.R16_SFLOAT:
|
|
||||||
case TextureFormat.R16G16_SFLOAT:
|
|
||||||
case TextureFormat.R16G16B16A16_SFLOAT:
|
|
||||||
case TextureFormat.R32_SFLOAT:
|
|
||||||
case TextureFormat.R32G32_SFLOAT:
|
|
||||||
case TextureFormat.R32G32B32A32_SFLOAT:
|
|
||||||
case TextureFormat.R8_UINT:
|
|
||||||
case TextureFormat.R8G8_UINT:
|
|
||||||
case TextureFormat.R8G8B8A8_UINT:
|
|
||||||
case TextureFormat.R16_UINT:
|
|
||||||
case TextureFormat.R16G16_UINT:
|
|
||||||
case TextureFormat.R16G16B16A16_UINT:
|
|
||||||
case TextureFormat.D16:
|
|
||||||
case TextureFormat.D32:
|
|
||||||
case TextureFormat.D16S8:
|
|
||||||
case TextureFormat.D32S8:
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
Logger.LogError("Texture format not recognized!");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var buffer = new Buffer(Device, 0, Width * Height * 4); // this creates garbage... oh well
|
||||||
|
|
||||||
|
// immediately request the data copy
|
||||||
|
var commandBuffer = Device.AcquireCommandBuffer();
|
||||||
|
commandBuffer.CopyTextureToBuffer(this, buffer);
|
||||||
|
var fence = Device.SubmitAndAcquireFence(commandBuffer);
|
||||||
|
|
||||||
|
var byteCount = buffer.Size;
|
||||||
|
|
||||||
|
var pixelsPtr = NativeMemory.Alloc((nuint) byteCount);
|
||||||
|
var pixelsSpan = new Span<byte>(pixelsPtr, (int) byteCount);
|
||||||
|
|
||||||
|
Device.WaitForFences(fence); // make sure the data transfer is done...
|
||||||
|
Device.ReleaseFence(fence); // and then release the fence
|
||||||
|
|
||||||
|
buffer.GetData(pixelsSpan);
|
||||||
|
|
||||||
|
if (Format == TextureFormat.B8G8R8A8)
|
||||||
|
{
|
||||||
|
var rgbaPtr = NativeMemory.Alloc((nuint) byteCount);
|
||||||
|
var rgbaSpan = new Span<byte>(rgbaPtr, (int) byteCount);
|
||||||
|
|
||||||
|
for (var i = 0; i < byteCount; i += 4)
|
||||||
|
{
|
||||||
|
rgbaSpan[i] = pixelsSpan[i + 2];
|
||||||
|
rgbaSpan[i + 1] = pixelsSpan[i + 1];
|
||||||
|
rgbaSpan[i + 2] = pixelsSpan[i];
|
||||||
|
rgbaSpan[i + 3] = pixelsSpan[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
Refresh.Refresh_Image_SavePNG(path, (nint) rgbaPtr, (int) Width, (int) Height);
|
||||||
|
|
||||||
|
NativeMemory.Free((void*) rgbaPtr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixed (byte* ptr = pixelsSpan)
|
||||||
|
{
|
||||||
|
Refresh.Refresh_Image_SavePNG(path, (nint) ptr, (int) Width, (int) Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMemory.Free(pixelsPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using RefreshCS;
|
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
|
||||||
{
|
|
||||||
public unsafe class TransferBuffer : RefreshResource
|
|
||||||
{
|
|
||||||
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTransferBuffer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Size in bytes.
|
|
||||||
/// </summary>
|
|
||||||
public uint Size { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a buffer of requested size given a type and element count.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
|
||||||
/// <param name="device">The GraphicsDevice.</param>
|
|
||||||
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public unsafe static TransferBuffer Create<T>(
|
|
||||||
GraphicsDevice device,
|
|
||||||
uint elementCount
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
return new TransferBuffer(
|
|
||||||
device,
|
|
||||||
(uint) Marshal.SizeOf<T>() * elementCount
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a TransferBuffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">An initialized GraphicsDevice.</param>
|
|
||||||
/// <param name="sizeInBytes">The length of the buffer. Cannot be resized.</param>
|
|
||||||
public TransferBuffer(
|
|
||||||
GraphicsDevice device,
|
|
||||||
uint sizeInBytes
|
|
||||||
) : base(device)
|
|
||||||
{
|
|
||||||
Handle = Refresh.Refresh_CreateTransferBuffer(
|
|
||||||
device.Handle,
|
|
||||||
sizeInBytes
|
|
||||||
);
|
|
||||||
Size = sizeInBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Immediately copies data from a Span to the TransferBuffer.
|
|
||||||
/// Returns the length of the copy in bytes.
|
|
||||||
///
|
|
||||||
/// If setDataOption is DISCARD and this TransferBuffer was used in an Upload command,
|
|
||||||
/// that command will still use the correct data at the cost of increased memory usage.
|
|
||||||
///
|
|
||||||
/// If setDataOption is OVERWRITE and this TransferBuffer was used in an Upload command,
|
|
||||||
/// the data will be overwritten immediately, which could cause a data race.
|
|
||||||
/// </summary>
|
|
||||||
public unsafe uint SetData<T>(
|
|
||||||
Span<T> data,
|
|
||||||
uint bufferOffsetInBytes,
|
|
||||||
SetDataOptions setDataOption
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
var elementSize = Marshal.SizeOf<T>();
|
|
||||||
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
AssertBufferBoundsCheck(Size, bufferOffsetInBytes, dataLengthInBytes);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fixed (T* dataPtr = data)
|
|
||||||
{
|
|
||||||
Refresh.Refresh_SetData(
|
|
||||||
Device.Handle,
|
|
||||||
(nint) dataPtr,
|
|
||||||
Handle,
|
|
||||||
new Refresh.BufferCopy
|
|
||||||
{
|
|
||||||
srcOffset = 0,
|
|
||||||
dstOffset = bufferOffsetInBytes,
|
|
||||||
size = dataLengthInBytes
|
|
||||||
},
|
|
||||||
(Refresh.SetDataOptions) setDataOption
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataLengthInBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Immediately copies data from a Span to the TransferBuffer.
|
|
||||||
/// Returns the length of the copy in bytes.
|
|
||||||
///
|
|
||||||
/// If setDataOption is DISCARD and this TransferBuffer was used in an Upload command,
|
|
||||||
/// that command will still use the correct data at the cost of increased memory usage.
|
|
||||||
///
|
|
||||||
/// If setDataOption is OVERWRITE and this TransferBuffer was used in an Upload command,
|
|
||||||
/// the data will be overwritten immediately, which could cause a data race.
|
|
||||||
/// </summary>
|
|
||||||
public unsafe uint SetData<T>(
|
|
||||||
Span<T> data,
|
|
||||||
SetDataOptions setDataOption
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
return SetData(data, 0, setDataOption);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Immediately copies data from the TransferBuffer into a Span.
|
|
||||||
/// </summary>
|
|
||||||
public unsafe void GetData<T>(
|
|
||||||
Span<T> data,
|
|
||||||
uint bufferOffsetInBytes = 0
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
var elementSize = Marshal.SizeOf<T>();
|
|
||||||
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
AssertBufferBoundsCheck(Size, bufferOffsetInBytes, dataLengthInBytes);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fixed (T* dataPtr = data)
|
|
||||||
{
|
|
||||||
Refresh.Refresh_GetData(
|
|
||||||
Device.Handle,
|
|
||||||
Handle,
|
|
||||||
(nint) dataPtr,
|
|
||||||
new Refresh.BufferCopy
|
|
||||||
{
|
|
||||||
srcOffset = bufferOffsetInBytes,
|
|
||||||
dstOffset = 0,
|
|
||||||
size = dataLengthInBytes
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
private void AssertBufferBoundsCheck(uint bufferLengthInBytes, uint offsetInBytes, uint copyLengthInBytes)
|
|
||||||
{
|
|
||||||
if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"SetData overflow! Transfer buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,9 +11,14 @@
|
||||||
public bool DepthTestEnable;
|
public bool DepthTestEnable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the stencil operation.
|
/// Describes the stencil operation for back-facing primitives.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StencilOpState StencilState;
|
public StencilOpState BackStencilState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes the stencil operation for front-facing primitives.
|
||||||
|
/// </summary>
|
||||||
|
public StencilOpState FrontStencilState;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The comparison operator used in the depth test.
|
/// The comparison operator used in the depth test.
|
||||||
|
|
Binary file not shown.
|
@ -1,12 +0,0 @@
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout (location = 0) in vec2 TexCoord;
|
|
||||||
|
|
||||||
layout (location = 0) out vec4 FragColor;
|
|
||||||
|
|
||||||
layout (binding = 0, set = 1) uniform sampler2D TexSampler;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
FragColor = texture(TexSampler, TexCoord);
|
|
||||||
}
|
|
|
@ -8,31 +8,34 @@ namespace MoonWorks.Graphics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct TextureSlice
|
public struct TextureSlice
|
||||||
{
|
{
|
||||||
public Texture Texture;
|
public Texture Texture { get; }
|
||||||
public uint MipLevel;
|
public Rect Rectangle { get; }
|
||||||
public uint BaseLayer;
|
public uint Depth { get; }
|
||||||
public uint LayerCount;
|
public uint Layer { get; }
|
||||||
public uint X;
|
public uint Level { get; }
|
||||||
public uint Y;
|
|
||||||
public uint Z;
|
|
||||||
public uint Width;
|
|
||||||
public uint Height;
|
|
||||||
public uint Depth;
|
|
||||||
|
|
||||||
public uint Size => (Width * Height * Depth * LayerCount * Texture.BytesPerPixel(Texture.Format) / Texture.BlockSizeSquared(Texture.Format)) >> (int) MipLevel;
|
|
||||||
|
|
||||||
public TextureSlice(Texture texture)
|
public TextureSlice(Texture texture)
|
||||||
{
|
{
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
MipLevel = 0;
|
Rectangle = new Rect
|
||||||
BaseLayer = 0;
|
{
|
||||||
LayerCount = (uint) (texture.IsCube ? 6 : 1);
|
X = 0,
|
||||||
X = 0;
|
Y = 0,
|
||||||
Y = 0;
|
W = (int) texture.Width,
|
||||||
Z = 0;
|
H = (int) texture.Height
|
||||||
Width = texture.Width;
|
};
|
||||||
Height = texture.Height;
|
Depth = 0;
|
||||||
Depth = texture.Depth;
|
Layer = 0;
|
||||||
|
Level = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureSlice(Texture texture, Rect rectangle, uint depth = 0, uint layer = 0, uint level = 0)
|
||||||
|
{
|
||||||
|
Texture = texture;
|
||||||
|
Rectangle = rectangle;
|
||||||
|
Depth = depth;
|
||||||
|
Layer = layer;
|
||||||
|
Level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Refresh.TextureSlice ToRefreshTextureSlice()
|
public Refresh.TextureSlice ToRefreshTextureSlice()
|
||||||
|
@ -40,15 +43,10 @@ namespace MoonWorks.Graphics
|
||||||
Refresh.TextureSlice textureSlice = new Refresh.TextureSlice
|
Refresh.TextureSlice textureSlice = new Refresh.TextureSlice
|
||||||
{
|
{
|
||||||
texture = Texture.Handle,
|
texture = Texture.Handle,
|
||||||
mipLevel = MipLevel,
|
rectangle = Rectangle.ToRefresh(),
|
||||||
baseLayer = BaseLayer,
|
depth = Depth,
|
||||||
layerCount = LayerCount,
|
layer = Layer,
|
||||||
x = X,
|
level = Level
|
||||||
y = Y,
|
|
||||||
z = Z,
|
|
||||||
w = Width,
|
|
||||||
h = Height,
|
|
||||||
d = Depth
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return textureSlice;
|
return textureSlice;
|
||||||
|
|
|
@ -14,9 +14,9 @@ namespace MoonWorks.Graphics
|
||||||
VertexAttributes = attributes;
|
VertexAttributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VertexBindingAndAttributes Create<T>(uint bindingIndex, uint locationOffset = 0, VertexInputRate inputRate = VertexInputRate.Vertex) where T : unmanaged, IVertexType
|
public static VertexBindingAndAttributes Create<T>(uint bindingIndex) where T : unmanaged, IVertexType
|
||||||
{
|
{
|
||||||
VertexBinding binding = VertexBinding.Create<T>(bindingIndex, inputRate);
|
VertexBinding binding = VertexBinding.Create<T>(bindingIndex);
|
||||||
VertexAttribute[] attributes = new VertexAttribute[T.Formats.Length];
|
VertexAttribute[] attributes = new VertexAttribute[T.Formats.Length];
|
||||||
uint offset = 0;
|
uint offset = 0;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace MoonWorks.Graphics
|
||||||
attributes[i] = new VertexAttribute
|
attributes[i] = new VertexAttribute
|
||||||
{
|
{
|
||||||
Binding = bindingIndex,
|
Binding = bindingIndex,
|
||||||
Location = locationOffset + i,
|
Location = i,
|
||||||
Format = format,
|
Format = format,
|
||||||
Offset = offset
|
Offset = offset
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonWorks.Input
|
namespace MoonWorks.Input
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -14,9 +16,9 @@ namespace MoonWorks.Input
|
||||||
KeyCode = keyCode;
|
KeyCode = keyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal unsafe override bool CheckPressed()
|
internal override bool CheckPressed()
|
||||||
{
|
{
|
||||||
return Conversions.ByteToBool(((byte*) Parent.State)[(int) KeyCode]);
|
return Conversions.ByteToBool(Marshal.ReadByte(Parent.State, (int) KeyCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace MoonWorks.Math
|
||||||
{
|
{
|
||||||
return Interp(start, hold, time, attackDuration, Function.Get(attackEasingFunction));
|
return Interp(start, hold, time, attackDuration, Function.Get(attackEasingFunction));
|
||||||
}
|
}
|
||||||
else if (time >= attackDuration && time < attackDuration + holdDuration)
|
else if (time >= attackDuration && time < holdDuration)
|
||||||
{
|
{
|
||||||
return hold;
|
return hold;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ namespace MoonWorks.Math
|
||||||
{
|
{
|
||||||
return Interp(start, hold, time, attackDuration, Function.Get(attackEasingFunction));
|
return Interp(start, hold, time, attackDuration, Function.Get(attackEasingFunction));
|
||||||
}
|
}
|
||||||
else if (time >= attackDuration && time < attackDuration + holdDuration)
|
else if (time >= attackDuration && time < holdDuration)
|
||||||
{
|
{
|
||||||
return hold;
|
return hold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,12 @@ namespace MoonWorks.Video
|
||||||
private Task ResetStreamATask;
|
private Task ResetStreamATask;
|
||||||
private Task ResetStreamBTask;
|
private Task ResetStreamBTask;
|
||||||
|
|
||||||
|
private GraphicsDevice GraphicsDevice;
|
||||||
private Texture yTexture = null;
|
private Texture yTexture = null;
|
||||||
private Texture uTexture = null;
|
private Texture uTexture = null;
|
||||||
private Texture vTexture = null;
|
private Texture vTexture = null;
|
||||||
private Sampler LinearSampler;
|
private Sampler LinearSampler;
|
||||||
|
|
||||||
private TransferBuffer TransferBuffer;
|
|
||||||
|
|
||||||
private int currentFrame;
|
private int currentFrame;
|
||||||
|
|
||||||
private Stopwatch timer;
|
private Stopwatch timer;
|
||||||
|
@ -37,6 +36,8 @@ namespace MoonWorks.Video
|
||||||
|
|
||||||
public VideoPlayer(GraphicsDevice device) : base(device)
|
public VideoPlayer(GraphicsDevice device) : base(device)
|
||||||
{
|
{
|
||||||
|
GraphicsDevice = device;
|
||||||
|
|
||||||
LinearSampler = new Sampler(device, SamplerCreateInfo.LinearClamp);
|
LinearSampler = new Sampler(device, SamplerCreateInfo.LinearClamp);
|
||||||
|
|
||||||
timer = new Stopwatch();
|
timer = new Stopwatch();
|
||||||
|
@ -54,46 +55,46 @@ namespace MoonWorks.Video
|
||||||
|
|
||||||
if (RenderTexture == null)
|
if (RenderTexture == null)
|
||||||
{
|
{
|
||||||
RenderTexture = CreateRenderTexture(Device, video.Width, video.Height);
|
RenderTexture = CreateRenderTexture(GraphicsDevice, video.Width, video.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yTexture == null)
|
if (yTexture == null)
|
||||||
{
|
{
|
||||||
yTexture = CreateSubTexture(Device, video.Width, video.Height);
|
yTexture = CreateSubTexture(GraphicsDevice, video.Width, video.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uTexture == null)
|
if (uTexture == null)
|
||||||
{
|
{
|
||||||
uTexture = CreateSubTexture(Device, video.UVWidth, video.UVHeight);
|
uTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vTexture == null)
|
if (vTexture == null)
|
||||||
{
|
{
|
||||||
vTexture = CreateSubTexture(Device, video.UVWidth, video.UVHeight);
|
vTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.Width != RenderTexture.Width || video.Height != RenderTexture.Height)
|
if (video.Width != RenderTexture.Width || video.Height != RenderTexture.Height)
|
||||||
{
|
{
|
||||||
RenderTexture.Dispose();
|
RenderTexture.Dispose();
|
||||||
RenderTexture = CreateRenderTexture(Device, video.Width, video.Height);
|
RenderTexture = CreateRenderTexture(GraphicsDevice, video.Width, video.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.Width != yTexture.Width || video.Height != yTexture.Height)
|
if (video.Width != yTexture.Width || video.Height != yTexture.Height)
|
||||||
{
|
{
|
||||||
yTexture.Dispose();
|
yTexture.Dispose();
|
||||||
yTexture = CreateSubTexture(Device, video.Width, video.Height);
|
yTexture = CreateSubTexture(GraphicsDevice, video.Width, video.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.UVWidth != uTexture.Width || video.UVHeight != uTexture.Height)
|
if (video.UVWidth != uTexture.Width || video.UVHeight != uTexture.Height)
|
||||||
{
|
{
|
||||||
uTexture.Dispose();
|
uTexture.Dispose();
|
||||||
uTexture = CreateSubTexture(Device, video.UVWidth, video.UVHeight);
|
uTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.UVWidth != vTexture.Width || video.UVHeight != vTexture.Height)
|
if (video.UVWidth != vTexture.Width || video.UVHeight != vTexture.Height)
|
||||||
{
|
{
|
||||||
vTexture.Dispose();
|
vTexture.Dispose();
|
||||||
vTexture = CreateSubTexture(Device, video.UVWidth, video.UVHeight);
|
vTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Video = video;
|
Video = video;
|
||||||
|
@ -232,73 +233,37 @@ namespace MoonWorks.Video
|
||||||
{
|
{
|
||||||
lock (CurrentStream)
|
lock (CurrentStream)
|
||||||
{
|
{
|
||||||
var commandBuffer = Device.AcquireCommandBuffer();
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
||||||
|
|
||||||
var ySpan = new Span<byte>((void*) CurrentStream.yDataHandle, (int) CurrentStream.yDataLength);
|
commandBuffer.SetTextureDataYUV(
|
||||||
var uSpan = new Span<byte>((void*) CurrentStream.uDataHandle, (int) CurrentStream.uvDataLength);
|
|
||||||
var vSpan = new Span<byte>((void*) CurrentStream.vDataHandle, (int) CurrentStream.uvDataLength);
|
|
||||||
|
|
||||||
if (TransferBuffer == null || TransferBuffer.Size < ySpan.Length + uSpan.Length + vSpan.Length)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
commandBuffer.BeginCopyPass();
|
|
||||||
|
|
||||||
commandBuffer.UploadToTexture(
|
|
||||||
TransferBuffer,
|
|
||||||
yTexture,
|
yTexture,
|
||||||
new BufferImageCopy
|
|
||||||
{
|
|
||||||
BufferOffset = 0,
|
|
||||||
BufferStride = CurrentStream.yStride,
|
|
||||||
BufferImageHeight = yTexture.Height
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
commandBuffer.UploadToTexture(
|
|
||||||
TransferBuffer,
|
|
||||||
uTexture,
|
uTexture,
|
||||||
new BufferImageCopy{
|
|
||||||
BufferOffset = (uint) ySpan.Length,
|
|
||||||
BufferStride = CurrentStream.uvStride,
|
|
||||||
BufferImageHeight = uTexture.Height
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
commandBuffer.UploadToTexture(
|
|
||||||
TransferBuffer,
|
|
||||||
vTexture,
|
vTexture,
|
||||||
new BufferImageCopy
|
CurrentStream.yDataHandle,
|
||||||
{
|
CurrentStream.uDataHandle,
|
||||||
BufferOffset = (uint) (ySpan.Length + uSpan.Length),
|
CurrentStream.vDataHandle,
|
||||||
BufferStride = CurrentStream.uvStride,
|
CurrentStream.yDataLength,
|
||||||
BufferImageHeight = vTexture.Height
|
CurrentStream.uvDataLength,
|
||||||
}
|
CurrentStream.yStride,
|
||||||
|
CurrentStream.uvStride
|
||||||
);
|
);
|
||||||
|
|
||||||
commandBuffer.EndCopyPass();
|
|
||||||
|
|
||||||
commandBuffer.BeginRenderPass(
|
commandBuffer.BeginRenderPass(
|
||||||
new ColorAttachmentInfo(RenderTexture, Color.Black)
|
new ColorAttachmentInfo(RenderTexture, Color.Black)
|
||||||
);
|
);
|
||||||
|
|
||||||
commandBuffer.BindGraphicsPipeline(Device.VideoPipeline);
|
commandBuffer.BindGraphicsPipeline(GraphicsDevice.VideoPipeline);
|
||||||
commandBuffer.BindFragmentSamplers(
|
commandBuffer.BindFragmentSamplers(
|
||||||
new TextureSamplerBinding(yTexture, LinearSampler),
|
new TextureSamplerBinding(yTexture, LinearSampler),
|
||||||
new TextureSamplerBinding(uTexture, LinearSampler),
|
new TextureSamplerBinding(uTexture, LinearSampler),
|
||||||
new TextureSamplerBinding(vTexture, LinearSampler)
|
new TextureSamplerBinding(vTexture, LinearSampler)
|
||||||
);
|
);
|
||||||
|
|
||||||
commandBuffer.DrawPrimitives(0, 1);
|
commandBuffer.DrawPrimitives(0, 1, 0, 0);
|
||||||
|
|
||||||
commandBuffer.EndRenderPass();
|
commandBuffer.EndRenderPass();
|
||||||
|
|
||||||
Device.Submit(commandBuffer);
|
GraphicsDevice.Submit(commandBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue