diff --git a/MoonWorks.csproj b/MoonWorks.csproj
index 2e0eb18..a1e1f4e 100644
--- a/MoonWorks.csproj
+++ b/MoonWorks.csproj
@@ -26,8 +26,8 @@
-
- MoonWorks.Graphics.StockShaders.VideoFullscreen.vert.refresh
+
+ MoonWorks.Graphics.StockShaders.Fullscreen.vert.refresh
MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.refresh
@@ -38,5 +38,8 @@
MoonWorks.Graphics.StockShaders.TextMSDF.frag.refresh
+
+ MoonWorks.Graphics.StockShaders.Blit.frag.refresh
+
diff --git a/src/Graphics/CommandBuffer.cs b/src/Graphics/CommandBuffer.cs
index c53d5d0..e44d53b 100644
--- a/src/Graphics/CommandBuffer.cs
+++ b/src/Graphics/CommandBuffer.cs
@@ -87,6 +87,7 @@ namespace MoonWorks.Graphics
) {
#if DEBUG
AssertNotSubmitted();
+ AssertNotInPass("Cannot begin a render pass inside another pass!");
AssertTextureNotNull(colorAttachmentInfo);
AssertColorTarget(colorAttachmentInfo);
#endif
@@ -528,6 +529,7 @@ namespace MoonWorks.Graphics
public void BeginComputePass()
{
#if DEBUG
+ AssertNotSubmitted();
AssertNotInPass("Cannot begin compute pass while in another pass!");
computePassActive = true;
#endif
@@ -1844,6 +1846,25 @@ namespace MoonWorks.Graphics
#endif
}
+ ///
+ /// Blits a texture to another texture with the specified filter.
+ ///
+ /// This operation cannot be performed inside any pass.
+ ///
+ public void Blit(
+ Texture source,
+ Texture destination,
+ Filter filter
+ ) {
+ var sampler = filter == Filter.Linear ? Device.LinearSampler : Device.PointSampler;
+
+ BeginRenderPass(new ColorAttachmentInfo(destination));
+ BindGraphicsPipeline(Device.BlitPipeline);
+ BindFragmentSamplers(new TextureSamplerBinding(source, sampler));
+ DrawPrimitives(0, 2);
+ EndRenderPass();
+ }
+
///
/// Acquires a swapchain texture.
/// This texture will be presented to the given window when the command buffer is submitted.
diff --git a/src/Graphics/GraphicsDevice.cs b/src/Graphics/GraphicsDevice.cs
index 7293f02..ce7c865 100644
--- a/src/Graphics/GraphicsDevice.cs
+++ b/src/Graphics/GraphicsDevice.cs
@@ -22,6 +22,9 @@ namespace MoonWorks.Graphics
// Built-in video pipeline
internal GraphicsPipeline VideoPipeline { get; }
+ // Built-in blit pipeline
+ internal GraphicsPipeline BlitPipeline { get; }
+
// Built-in text shader info
public GraphicsShaderInfo TextVertexShaderInfo { get; }
public GraphicsShaderInfo TextFragmentShaderInfo { get; }
@@ -57,32 +60,43 @@ namespace MoonWorks.Graphics
// Check for replacement stock shaders
string basePath = System.AppContext.BaseDirectory;
- string videoVertPath = Path.Combine(basePath, "video_fullscreen.vert.refresh");
- string videoFragPath = Path.Combine(basePath, "video_yuv2rgba.frag.refresh");
+ string fullscreenVertPath = Path.Combine(basePath, "fullscreen.vert.refresh");
string textVertPath = Path.Combine(basePath, "text_transform.vert.refresh");
string textFragPath = Path.Combine(basePath, "text_msdf.frag.refresh");
- ShaderModule videoVertShader;
- ShaderModule videoFragShader;
+ string videoFragPath = Path.Combine(basePath, "video_yuv2rgba.frag.refresh");
+ string blitFragPath = Path.Combine(basePath, "blit.frag.refresh");
+
+ ShaderModule fullscreenVertShader;
ShaderModule textVertShader;
ShaderModule textFragShader;
- if (File.Exists(videoVertPath) && File.Exists(videoFragPath))
+ ShaderModule videoFragShader;
+ 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);
}
else
{
// use defaults
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");
-
- videoVertShader = new ShaderModule(this, vertStream);
videoFragShader = new ShaderModule(this, fragStream);
}
@@ -103,6 +117,19 @@ namespace MoonWorks.Graphics
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(
this,
new GraphicsPipelineCreateInfo
@@ -115,7 +142,7 @@ namespace MoonWorks.Graphics
),
DepthStencilState = DepthStencilState.Disable,
VertexShaderInfo = GraphicsShaderInfo.Create(
- videoVertShader,
+ fullscreenVertShader,
"main",
0
),
@@ -131,6 +158,34 @@ 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(textVertShader, "main", 0);
TextFragmentShaderInfo = GraphicsShaderInfo.Create(textFragShader, "main", 1);
TextVertexInputState = VertexInputState.CreateSingleBinding();
diff --git a/src/Graphics/Resources/TransferBuffer.cs b/src/Graphics/Resources/TransferBuffer.cs
index b93200d..bb94aa2 100644
--- a/src/Graphics/Resources/TransferBuffer.cs
+++ b/src/Graphics/Resources/TransferBuffer.cs
@@ -113,7 +113,7 @@ namespace MoonWorks.Graphics
///
public unsafe void GetData(
Span data,
- uint bufferOffsetInBytes
+ uint bufferOffsetInBytes = 0
) where T : unmanaged
{
var elementSize = Marshal.SizeOf();
diff --git a/src/Graphics/StockShaders/Binary/blit.frag.refresh b/src/Graphics/StockShaders/Binary/blit.frag.refresh
new file mode 100644
index 0000000..ac3850a
Binary files /dev/null and b/src/Graphics/StockShaders/Binary/blit.frag.refresh differ
diff --git a/src/Graphics/StockShaders/Binary/video_fullscreen.vert.refresh b/src/Graphics/StockShaders/Binary/fullscreen.vert.refresh
similarity index 100%
rename from src/Graphics/StockShaders/Binary/video_fullscreen.vert.refresh
rename to src/Graphics/StockShaders/Binary/fullscreen.vert.refresh
diff --git a/src/Graphics/StockShaders/Source/blit.frag b/src/Graphics/StockShaders/Source/blit.frag
new file mode 100644
index 0000000..de32fd1
--- /dev/null
+++ b/src/Graphics/StockShaders/Source/blit.frag
@@ -0,0 +1,12 @@
+#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);
+}
diff --git a/src/Graphics/StockShaders/Source/video_fullscreen.vert b/src/Graphics/StockShaders/Source/fullscreen.vert
similarity index 100%
rename from src/Graphics/StockShaders/Source/video_fullscreen.vert
rename to src/Graphics/StockShaders/Source/fullscreen.vert