using System;
using System.Runtime.InteropServices;
using SDL2_gpuCS;
namespace MoonWorks.Graphics
{
///
/// Graphics pipelines encapsulate all of the render state in a single object.
/// These pipelines are bound before draw calls are issued.
///
public class GraphicsPipeline : SDL_GpuResource
{
protected override Action ReleaseFunction => SDL_Gpu.SDL_GpuReleaseGraphicsPipeline;
public GraphicsPipelineResourceInfo VertexShaderResourceInfo { get; }
public GraphicsPipelineResourceInfo FragmentShaderResourceInfo { get; }
public SampleCount SampleCount { get; }
#if DEBUG
internal GraphicsPipelineAttachmentInfo AttachmentInfo { get; }
#endif
public unsafe GraphicsPipeline(
GraphicsDevice device,
in GraphicsPipelineCreateInfo graphicsPipelineCreateInfo
) : base(device)
{
SDL_Gpu.GraphicsPipelineCreateInfo sdlGraphicsPipelineCreateInfo;
var vertexAttributes = (SDL_Gpu.VertexAttribute*) NativeMemory.Alloc(
(nuint) (graphicsPipelineCreateInfo.VertexInputState.VertexAttributes.Length * Marshal.SizeOf())
);
for (var i = 0; i < graphicsPipelineCreateInfo.VertexInputState.VertexAttributes.Length; i += 1)
{
vertexAttributes[i] = graphicsPipelineCreateInfo.VertexInputState.VertexAttributes[i].ToSDL();
}
var vertexBindings = (SDL_Gpu.VertexBinding*) NativeMemory.Alloc(
(nuint) (graphicsPipelineCreateInfo.VertexInputState.VertexBindings.Length * Marshal.SizeOf())
);
for (var i = 0; i < graphicsPipelineCreateInfo.VertexInputState.VertexBindings.Length; i += 1)
{
vertexBindings[i] = graphicsPipelineCreateInfo.VertexInputState.VertexBindings[i].ToSDL();
}
var colorAttachmentDescriptions = stackalloc SDL_Gpu.ColorAttachmentDescription[
graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions.Length
];
for (var i = 0; i < graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions.Length; i += 1)
{
colorAttachmentDescriptions[i].Format = (SDL_Gpu.TextureFormat) graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions[i].Format;
colorAttachmentDescriptions[i].BlendState = graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions[i].BlendState.ToSDL();
}
sdlGraphicsPipelineCreateInfo.VertexShader = graphicsPipelineCreateInfo.VertexShader.Handle;
sdlGraphicsPipelineCreateInfo.FragmentShader = graphicsPipelineCreateInfo.FragmentShader.Handle;
sdlGraphicsPipelineCreateInfo.VertexInputState.VertexAttributes = vertexAttributes;
sdlGraphicsPipelineCreateInfo.VertexInputState.VertexAttributeCount = (uint) graphicsPipelineCreateInfo.VertexInputState.VertexAttributes.Length;
sdlGraphicsPipelineCreateInfo.VertexInputState.VertexBindings = vertexBindings;
sdlGraphicsPipelineCreateInfo.VertexInputState.VertexBindingCount = (uint) graphicsPipelineCreateInfo.VertexInputState.VertexBindings.Length;
sdlGraphicsPipelineCreateInfo.PrimitiveType = (SDL_Gpu.PrimitiveType) graphicsPipelineCreateInfo.PrimitiveType;
sdlGraphicsPipelineCreateInfo.RasterizerState = graphicsPipelineCreateInfo.RasterizerState.ToSDL();
sdlGraphicsPipelineCreateInfo.MultisampleState = graphicsPipelineCreateInfo.MultisampleState.ToSDL();
sdlGraphicsPipelineCreateInfo.DepthStencilState = graphicsPipelineCreateInfo.DepthStencilState.ToSDL();
sdlGraphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentCount = (uint) graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions.Length;
sdlGraphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions = colorAttachmentDescriptions;
sdlGraphicsPipelineCreateInfo.AttachmentInfo.DepthStencilFormat = (SDL_Gpu.TextureFormat) graphicsPipelineCreateInfo.AttachmentInfo.DepthStencilFormat;
sdlGraphicsPipelineCreateInfo.AttachmentInfo.HasDepthStencilAttachment = Conversions.BoolToInt(graphicsPipelineCreateInfo.AttachmentInfo.HasDepthStencilAttachment);
sdlGraphicsPipelineCreateInfo.VertexResourceInfo = graphicsPipelineCreateInfo.VertexShaderResourceInfo.ToSDL();
sdlGraphicsPipelineCreateInfo.FragmentResourceInfo = graphicsPipelineCreateInfo.FragmentShaderResourceInfo.ToSDL();
sdlGraphicsPipelineCreateInfo.BlendConstants[0] = graphicsPipelineCreateInfo.BlendConstants.R;
sdlGraphicsPipelineCreateInfo.BlendConstants[1] = graphicsPipelineCreateInfo.BlendConstants.G;
sdlGraphicsPipelineCreateInfo.BlendConstants[2] = graphicsPipelineCreateInfo.BlendConstants.B;
sdlGraphicsPipelineCreateInfo.BlendConstants[3] = graphicsPipelineCreateInfo.BlendConstants.A;
Handle = SDL_Gpu.SDL_GpuCreateGraphicsPipeline(device.Handle, sdlGraphicsPipelineCreateInfo);
if (Handle == IntPtr.Zero)
{
throw new Exception("Could not create graphics pipeline!");
}
NativeMemory.Free(vertexAttributes);
NativeMemory.Free(vertexBindings);
VertexShaderResourceInfo = graphicsPipelineCreateInfo.VertexShaderResourceInfo;
FragmentShaderResourceInfo = graphicsPipelineCreateInfo.FragmentShaderResourceInfo;
SampleCount = graphicsPipelineCreateInfo.MultisampleState.MultisampleCount;
#if DEBUG
AttachmentInfo = graphicsPipelineCreateInfo.AttachmentInfo;
#endif
}
}
}