Render Pass Streamlining (#14)

Changes as per a531fb8593

Reviewed-on: MoonsideGames/MoonWorks#14
Co-authored-by: cosmonaut <evan@moonside.games>
Co-committed-by: cosmonaut <evan@moonside.games>
main
cosmonaut 2022-02-25 05:34:36 +00:00
parent 8a3d93d2dc
commit 1064bae828
10 changed files with 264 additions and 325 deletions

@ -1 +1 @@
Subproject commit 1e8abe379a0ccc891ce0f4d90793feac59d30948
Subproject commit cb949b8205eb2454dd0c9f4c84d41c6647802408

View File

@ -27,169 +27,187 @@ namespace MoonWorks.Graphics
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderPass">The render pass object to begin.</param>
/// <param name="framebuffer">The framebuffer used by the render pass.</param>
/// <param name="colorAttachmentInfos">The color attachments to use in the render pass.</param>
public unsafe void BeginRenderPass(
RenderPass renderPass,
Framebuffer framebuffer
params ColorAttachmentInfo[] colorAttachmentInfos
)
{
var renderArea = new Rect
#if DEBUG
if (colorAttachmentInfos.Length == 0)
{
X = 0,
Y = 0,
W = (int) framebuffer.Width,
H = (int) framebuffer.Height
};
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderPass.Handle,
framebuffer.Handle,
renderArea.ToRefresh(),
IntPtr.Zero,
0,
IntPtr.Zero
);
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderPass">The render pass object to begin.</param>
/// <param name="framebuffer">The framebuffer used by the render pass.</param>
/// <param name="renderArea">The screen area of the render pass.</param>
public unsafe void BeginRenderPass(
RenderPass renderPass,
Framebuffer framebuffer,
in Rect renderArea
)
{
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderPass.Handle,
framebuffer.Handle,
renderArea.ToRefresh(),
IntPtr.Zero,
0,
IntPtr.Zero
);
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderPass">The render pass object to begin.</param>
/// <param name="framebuffer">The framebuffer used by the render pass.</param>
/// <param name="renderArea">The screen area of the render pass.</param>
/// <param name="clearColors">Color clear values for each render target in the framebuffer.</param>
public unsafe void BeginRenderPass(
RenderPass renderPass,
Framebuffer framebuffer,
in Rect renderArea,
params Vector4[] clearColors
)
{
Refresh.Vec4* colors = stackalloc Refresh.Vec4[clearColors.Length];
for (var i = 0; i < clearColors.Length; i++)
{
colors[i] = new Refresh.Vec4
{
x = clearColors[i].X,
y = clearColors[i].Y,
z = clearColors[i].Z,
w = clearColors[i].W
};
Logger.LogError("Render pass must contain at least one attachment!");
return;
}
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderPass.Handle,
framebuffer.Handle,
renderArea.ToRefresh(),
(IntPtr) colors,
(uint) clearColors.Length,
IntPtr.Zero
);
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderPass">The render pass object to begin.</param>
/// <param name="framebuffer">The framebuffer used by the render pass.</param>
/// <param name="renderArea">The screen area of the render pass.</param>
/// <param name="depthStencilClearValue">Clear values for the depth/stencil buffer. This is ignored if the render pass does not clear.</param>
public unsafe void BeginRenderPass(
RenderPass renderPass,
Framebuffer framebuffer,
in Rect renderArea,
in DepthStencilValue depthStencilClearValue
)
{
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderPass.Handle,
framebuffer.Handle,
renderArea.ToRefresh(),
IntPtr.Zero,
0,
depthStencilClearValue.ToRefresh()
);
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderPass">The render pass object to begin.</param>
/// <param name="framebuffer">The framebuffer used by the render pass.</param>
/// <param name="renderArea">The screen area of the render pass.</param>
/// <param name="depthStencilClearValue">Clear values for the depth/stencil buffer. This is ignored if the render pass does not clear.</param>
/// <param name="clearColors">Color clear values for each render target in the framebuffer.</param>
public unsafe void BeginRenderPass(
RenderPass renderPass,
Framebuffer framebuffer,
in Rect renderArea,
in DepthStencilValue depthStencilClearValue,
params Vector4[] clearColors
)
{
Refresh.Vec4* colors = stackalloc Refresh.Vec4[clearColors.Length];
for (var i = 0; i < clearColors.Length; i++)
if (colorAttachmentInfos.Length > 4)
{
colors[i] = new Refresh.Vec4
{
x = clearColors[i].X,
y = clearColors[i].Y,
z = clearColors[i].Z,
w = clearColors[i].W
};
Logger.LogError("Render pass cannot have more than 4 color attachments!");
return;
}
#endif
var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length];
for (var i = 0; i < colorAttachmentInfos.Length; i += 1)
{
refreshColorAttachmentInfos[i] = colorAttachmentInfos[i].ToRefresh();
}
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderPass.Handle,
framebuffer.Handle,
renderArea.ToRefresh(),
(IntPtr) colors,
(uint) clearColors.Length,
depthStencilClearValue.ToRefresh()
);
fixed (Refresh.ColorAttachmentInfo* pColorAttachmentInfos = refreshColorAttachmentInfos)
{
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
colorAttachmentInfos[0].renderTarget.TextureSlice.Rectangle.ToRefresh(),
(IntPtr) pColorAttachmentInfos,
(uint) colorAttachmentInfos.Length,
IntPtr.Zero
);
}
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="depthStencilAttachmentInfo">The depth stencil attachment to use in the render pass.</param>
/// <param name="colorAttachmentInfos">The color attachments to use in the render pass.</param>
public unsafe void BeginRenderPass(
DepthStencilAttachmentInfo depthStencilAttachmentInfo,
params ColorAttachmentInfo[] colorAttachmentInfos
)
{
#if DEBUG
if (colorAttachmentInfos.Length == 0)
{
Logger.LogError("Render pass must contain at least one attachment!");
return;
}
if (colorAttachmentInfos.Length > 4)
{
Logger.LogError("Render pass cannot have more than 4 color attachments!");
return;
}
#endif
var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length];
for (var i = 0; i < colorAttachmentInfos.Length; i += 1)
{
refreshColorAttachmentInfos[i] = colorAttachmentInfos[i].ToRefresh();
}
var refreshDepthStencilAttachmentInfo = depthStencilAttachmentInfo.ToRefresh();
fixed (Refresh.ColorAttachmentInfo* pColorAttachmentInfos = refreshColorAttachmentInfos)
{
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
colorAttachmentInfos[0].renderTarget.TextureSlice.Rectangle.ToRefresh(),
pColorAttachmentInfos,
(uint) colorAttachmentInfos.Length,
&refreshDepthStencilAttachmentInfo
);
}
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderArea">The rectangle that should be drawn to on the attachments.</param>
/// <param name="colorAttachmentInfos">The color attachments to use in the render pass.</param>
public unsafe void BeginRenderPass(
in Rect renderArea,
params ColorAttachmentInfo[] colorAttachmentInfos
)
{
#if DEBUG
if (colorAttachmentInfos.Length == 0)
{
Logger.LogError("Render pass must contain at least one attachment!");
return;
}
if (colorAttachmentInfos.Length > 4)
{
Logger.LogError("Render pass cannot have more than 4 color attachments!");
return;
}
#endif
var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length];
for (var i = 0; i < colorAttachmentInfos.Length; i += 1)
{
refreshColorAttachmentInfos[i] = colorAttachmentInfos[i].ToRefresh();
}
fixed (Refresh.ColorAttachmentInfo* pColorAttachmentInfos = refreshColorAttachmentInfos)
{
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderArea.ToRefresh(),
(IntPtr) pColorAttachmentInfos,
(uint) colorAttachmentInfos.Length,
IntPtr.Zero
);
}
}
/// <summary>
/// Begins a render pass.
/// All render state, resource binding, and draw commands must be made within a render pass.
/// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass.
/// </summary>
/// <param name="renderArea">The rectangle that should be drawn to on the attachments.</param>
/// <param name="depthStencilAttachmentInfo">The depth stencil attachment to use in the render pass.</param>
/// <param name="colorAttachmentInfos">The color attachments to use in the render pass.</param>
public unsafe void BeginRenderPass(
in Rect renderArea,
DepthStencilAttachmentInfo depthStencilAttachmentInfo,
params ColorAttachmentInfo[] colorAttachmentInfos
)
{
#if DEBUG
if (colorAttachmentInfos.Length == 0)
{
Logger.LogError("Render pass must contain at least one attachment!");
return;
}
if (colorAttachmentInfos.Length > 4)
{
Logger.LogError("Render pass cannot have more than 4 color attachments!");
return;
}
#endif
var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length];
for (var i = 0; i < colorAttachmentInfos.Length; i += 1)
{
refreshColorAttachmentInfos[i] = colorAttachmentInfos[i].ToRefresh();
}
var refreshDepthStencilAttachmentInfo = depthStencilAttachmentInfo.ToRefresh();
fixed (Refresh.ColorAttachmentInfo* pColorAttachmentInfos = refreshColorAttachmentInfos)
{
Refresh.Refresh_BeginRenderPass(
Device.Handle,
Handle,
renderArea.ToRefresh(),
pColorAttachmentInfos,
(uint) colorAttachmentInfos.Length,
&refreshDepthStencilAttachmentInfo
);
}
}
/// <summary>

View File

@ -72,25 +72,6 @@ namespace MoonWorks.Graphics
public uint Offset;
}
[StructLayout(LayoutKind.Sequential)]
public struct ColorTargetDescription
{
public TextureFormat Format;
public SampleCount MultisampleCount;
public LoadOp LoadOp;
public StoreOp StoreOp;
}
[StructLayout(LayoutKind.Sequential)]
public struct DepthStencilTargetDescription
{
public TextureFormat Format;
public LoadOp LoadOp;
public StoreOp StoreOp;
public LoadOp StencilLoadOp;
public StoreOp StencilStoreOp;
}
[StructLayout(LayoutKind.Sequential)]
public struct StencilOpState
{
@ -117,4 +98,61 @@ namespace MoonWorks.Graphics
};
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ColorAttachmentInfo
{
public RenderTarget renderTarget;
public Color clearColor;
public LoadOp loadOp;
public StoreOp storeOp;
public Refresh.ColorAttachmentInfo ToRefresh()
{
return new Refresh.ColorAttachmentInfo
{
renderTarget = renderTarget.Handle,
clearColor = new Refresh.Vec4
{
x = clearColor.R,
y = clearColor.G,
z = clearColor.B,
w = clearColor.A
},
loadOp = (Refresh.LoadOp) loadOp,
storeOp = (Refresh.StoreOp) storeOp
};
}
}
[StructLayout(LayoutKind.Sequential)]
public struct DepthStencilAttachmentInfo
{
public RenderTarget depthStencilTarget;
public DepthStencilValue depthStencilValue;
public LoadOp loadOp;
public StoreOp storeOp;
public LoadOp stencilLoadOp;
public StoreOp stencilStoreOp;
public Refresh.DepthStencilAttachmentInfo ToRefresh()
{
return new Refresh.DepthStencilAttachmentInfo
{
depthStencilTarget = depthStencilTarget.Handle,
depthStencilValue = depthStencilValue.ToRefresh(),
loadOp = (Refresh.LoadOp) loadOp,
storeOp = (Refresh.StoreOp) storeOp,
stencilLoadOp = (Refresh.LoadOp) stencilLoadOp,
stencilStoreOp = (Refresh.StoreOp) stencilStoreOp
};
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ColorAttachmentDescription
{
public TextureFormat format;
public SampleCount sampleCount;
}
}

View File

@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using RefreshCS;
namespace MoonWorks.Graphics
{
/// <summary>
/// A framebuffer is a collection of render targets that is rendered to during a render pass.
/// </summary>
public class Framebuffer : GraphicsResource
{
protected override Action<IntPtr, IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyFramebuffer;
public RenderTarget DepthStencilTarget { get; }
private RenderTarget[] colorTargets { get; }
public IEnumerable<RenderTarget> ColorTargets => colorTargets;
public RenderPass RenderPass { get; }
public uint Width { get; }
public uint Height { get; }
/// <summary>
/// Creates a framebuffer.
/// </summary>
/// <param name="device">An initialized GraphicsDevice.</param>
/// <param name="width">The width of the framebuffer.</param>
/// <param name="height">The height of the framebuffer.</param>
/// <param name="renderPass">The reference render pass for the framebuffer.</param>
/// <param name="depthStencilTarget">The depth stencil target. Can be null.</param>
/// <param name="colorTargets">Anywhere from 0-4 color targets can be provided.</param>
public unsafe Framebuffer(
GraphicsDevice device,
uint width,
uint height,
RenderPass renderPass,
RenderTarget depthStencilTarget,
params RenderTarget[] colorTargets
) : base(device)
{
IntPtr[] colorTargetHandles = new IntPtr[colorTargets.Length];
for (var i = 0; i < colorTargets.Length; i += 1)
{
colorTargetHandles[i] = colorTargets[i].Handle;
}
IntPtr depthStencilTargetHandle;
if (depthStencilTarget == null)
{
depthStencilTargetHandle = IntPtr.Zero;
}
else
{
depthStencilTargetHandle = depthStencilTarget.Handle;
}
fixed (IntPtr* colorTargetHandlesPtr = colorTargetHandles)
{
Refresh.FramebufferCreateInfo framebufferCreateInfo = new Refresh.FramebufferCreateInfo
{
width = width,
height = height,
colorTargetCount = (uint) colorTargets.Length,
pColorTargets = (IntPtr) colorTargetHandlesPtr,
depthStencilTarget = depthStencilTargetHandle,
renderPass = renderPass.Handle
};
Handle = Refresh.Refresh_CreateFramebuffer(device.Handle, framebufferCreateInfo);
}
DepthStencilTarget = depthStencilTarget;
this.colorTargets = new RenderTarget[colorTargets.Length];
for (var i = 0; i < colorTargets.Length; i++)
{
this.colorTargets[i] = colorTargets[i];
}
RenderPass = renderPass;
Width = width;
Height = height;
}
}
}

View File

@ -14,7 +14,6 @@ namespace MoonWorks.Graphics
public ShaderStageState VertexShaderState { get; }
public ShaderStageState FragmentShaderState { get; }
public RenderPass RenderPass { get; }
public unsafe GraphicsPipeline(
GraphicsDevice device,
@ -31,7 +30,7 @@ namespace MoonWorks.Graphics
PrimitiveType primitiveType = graphicsPipelineCreateInfo.PrimitiveType;
VertexInputState vertexInputState = graphicsPipelineCreateInfo.VertexInputState;
ViewportState viewportState = graphicsPipelineCreateInfo.ViewportState;
RenderPass renderPass = graphicsPipelineCreateInfo.RenderPass;
GraphicsPipelineAttachmentInfo attachmentInfo = graphicsPipelineCreateInfo.AttachmentInfo;
var vertexAttributesHandle = GCHandle.Alloc(
vertexInputState.VertexAttributes,
@ -59,6 +58,16 @@ namespace MoonWorks.Graphics
colorTargetBlendStates[i] = colorBlendState.ColorTargetBlendStates[i].ToRefreshColorTargetBlendState();
}
var colorAttachmentDescriptions = stackalloc Refresh.ColorAttachmentDescription[
(int) attachmentInfo.colorAttachmentCount
];
for (var i = 0; i < attachmentInfo.colorAttachmentCount; i += 1)
{
colorAttachmentDescriptions[i].format = (Refresh.TextureFormat) attachmentInfo.colorAttachmentDescriptions[i].format;
colorAttachmentDescriptions[i].sampleCount = (Refresh.SampleCount) attachmentInfo.colorAttachmentDescriptions[i].sampleCount;
}
Refresh.GraphicsPipelineCreateInfo refreshGraphicsPipelineCreateInfo;
refreshGraphicsPipelineCreateInfo.colorBlendState.logicOpEnable = Conversions.BoolToByte(colorBlendState.LogicOpEnable);
@ -115,7 +124,11 @@ namespace MoonWorks.Graphics
refreshGraphicsPipelineCreateInfo.viewportState.scissorCount = (uint) viewportState.Scissors.Length;
refreshGraphicsPipelineCreateInfo.primitiveType = (Refresh.PrimitiveType) primitiveType;
refreshGraphicsPipelineCreateInfo.renderPass = renderPass.Handle;
refreshGraphicsPipelineCreateInfo.attachmentInfo.colorAttachmentCount = attachmentInfo.colorAttachmentCount;
refreshGraphicsPipelineCreateInfo.attachmentInfo.colorAttachmentDescriptions = (IntPtr) colorAttachmentDescriptions;
refreshGraphicsPipelineCreateInfo.attachmentInfo.depthStencilFormat = (Refresh.TextureFormat) attachmentInfo.depthStencilFormat;
refreshGraphicsPipelineCreateInfo.attachmentInfo.hasDepthStencilAttachment = Conversions.BoolToByte(attachmentInfo.hasDepthStencilAttachment);
Handle = Refresh.Refresh_CreateGraphicsPipeline(device.Handle, refreshGraphicsPipelineCreateInfo);
@ -126,7 +139,6 @@ namespace MoonWorks.Graphics
VertexShaderState = vertexShaderState;
FragmentShaderState = fragmentShaderState;
RenderPass = renderPass;
}
}
}

View File

@ -1,59 +0,0 @@
using System;
using RefreshCS;
namespace MoonWorks.Graphics
{
/// <summary>
/// A render pass describes the kind of render targets that will be used in rendering.
/// </summary>
public class RenderPass : GraphicsResource
{
protected override Action<IntPtr, IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyRenderPass;
/// <summary>
/// Creates a render pass using color target descriptions.
/// </summary>
/// <param name="device">An initialized GraphicsDevice.</param>
/// <param name="colorTargetDescriptions">Up to 4 color target descriptions may be provided.</param>
public unsafe RenderPass(
GraphicsDevice device,
params ColorTargetDescription[] colorTargetDescriptions
) : base(device)
{
fixed (ColorTargetDescription* ptr = colorTargetDescriptions)
{
Refresh.RenderPassCreateInfo renderPassCreateInfo;
renderPassCreateInfo.colorTargetCount = (uint) colorTargetDescriptions.Length;
renderPassCreateInfo.colorTargetDescriptions = (IntPtr) ptr;
renderPassCreateInfo.depthStencilTargetDescription = IntPtr.Zero;
Handle = Refresh.Refresh_CreateRenderPass(device.Handle, renderPassCreateInfo);
}
}
/// <summary>
/// Creates a render pass using a depth/stencil target description and optional color target descriptions.
/// </summary>
/// <param name="device">An initialized GraphicsDevice.</param>
/// <param name="depthStencilTargetDescription">A depth/stencil target description.</param>
/// <param name="colorTargetDescriptions">Up to 4 color target descriptions may be provided.</param>
public unsafe RenderPass(
GraphicsDevice device,
in DepthStencilTargetDescription depthStencilTargetDescription,
params ColorTargetDescription[] colorTargetDescriptions
) : base(device)
{
fixed (DepthStencilTargetDescription* depthStencilPtr = &depthStencilTargetDescription)
fixed (ColorTargetDescription* colorPtr = colorTargetDescriptions)
{
Refresh.RenderPassCreateInfo renderPassCreateInfo;
renderPassCreateInfo.colorTargetCount = (uint) colorTargetDescriptions.Length;
renderPassCreateInfo.colorTargetDescriptions = (IntPtr) colorPtr;
renderPassCreateInfo.depthStencilTargetDescription = (IntPtr) depthStencilPtr;
Handle = Refresh.Refresh_CreateRenderPass(device.Handle, renderPassCreateInfo);
}
}
}
}

View File

@ -11,6 +11,9 @@ namespace MoonWorks.Graphics
public TextureSlice TextureSlice { get; }
public TextureFormat Format => TextureSlice.Texture.Format;
public uint Width => (uint) TextureSlice.Rectangle.W;
public uint Height => (uint) TextureSlice.Rectangle.H;
protected override Action<IntPtr, IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyRenderTarget;
/// <summary>

View File

@ -0,0 +1,13 @@
namespace MoonWorks.Graphics
{
/// <summary>
/// Describes the kind of attachments that will be used with this pipeline.
/// </summary>
public struct GraphicsPipelineAttachmentInfo
{
public ColorAttachmentDescription[] colorAttachmentDescriptions;
public uint colorAttachmentCount;
public bool hasDepthStencilAttachment;
public TextureFormat depthStencilFormat;
}
}

View File

@ -12,6 +12,6 @@
public PrimitiveType PrimitiveType;
public VertexInputState VertexInputState;
public ViewportState ViewportState;
public RenderPass RenderPass;
public GraphicsPipelineAttachmentInfo AttachmentInfo;
}
}

View File

@ -9,7 +9,7 @@
public static bool ByteToBool(byte b)
{
return b == 0 ? false : true;
return b != 0;
}
}
}