use std::marker;
use std::sync::Arc;
use crate::image::Region2D;
use crate::pipeline::graphics::shader::{FragmentShaderData, VertexShaderData};
use crate::pipeline::graphics::{
Blending, DepthTest, FragmentShader, PrimitiveAssembly, StencilTest,
TransformFeedbackLayoutDescriptor, TypedTransformFeedbackLayout, TypedVertexInputLayout,
Untyped, VertexInputLayoutDescriptor, VertexShader, Viewport,
};
use crate::pipeline::resources::{
ResourceBindingsLayoutDescriptor, TypedResourceBindingsLayout,
TypedResourceBindingsLayoutDescriptor,
};
#[derive(Clone, Debug)]
pub(crate) enum ResourceBindingsLayoutKind {
Minimal(ResourceBindingsLayoutDescriptor),
Typed(TypedResourceBindingsLayoutDescriptor),
}
impl ResourceBindingsLayoutKind {
pub(crate) fn key(&self) -> u64 {
match self {
ResourceBindingsLayoutKind::Minimal(descriptor) => descriptor.key(),
ResourceBindingsLayoutKind::Typed(descriptor) => descriptor.key(),
}
}
}
pub struct GraphicsPipelineDescriptor<V, R, Tf> {
_vertex_attribute_layout: marker::PhantomData<V>,
_resource_layout: marker::PhantomData<R>,
_transform_feedback: marker::PhantomData<Tf>,
pub(crate) vertex_shader_data: Arc<VertexShaderData>,
pub(crate) fragment_shader_data: Arc<FragmentShaderData>,
pub(crate) vertex_attribute_layout: VertexInputLayoutDescriptor,
pub(crate) transform_feedback_layout: Option<TransformFeedbackLayoutDescriptor>,
pub(crate) resource_bindings_layout: ResourceBindingsLayoutKind,
pub(crate) primitive_assembly: PrimitiveAssembly,
pub(crate) depth_test: Option<DepthTest>,
pub(crate) stencil_test: Option<StencilTest>,
pub(crate) scissor_region: Region2D,
pub(crate) blending: Option<Blending>,
pub(crate) viewport: Viewport,
}
impl GraphicsPipelineDescriptor<(), (), ()> {
pub fn begin() -> GraphicsPipelineDescriptorBuilder<(), (), (), (), (), ()> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: None,
fragment_shader: None,
vertex_input_layout: ().into(),
transform_feedback_layout: None,
resource_bindings_layout: ResourceBindingsLayoutKind::Typed(
TypedResourceBindingsLayoutDescriptor::empty(),
),
primitive_assembly: None,
depth_test: None,
stencil_test: None,
scissor_region: Region2D::Fill,
blending: None,
viewport: Viewport::Auto,
}
}
}
pub struct GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, V, R, Tf> {
_vertex_shader: marker::PhantomData<Vs>,
_primitive_assembly: marker::PhantomData<Pa>,
_fragment_shader: marker::PhantomData<Fs>,
_transform_feedback: marker::PhantomData<Tf>,
_vertex_attribute_layout: marker::PhantomData<V>,
_resource_layout: marker::PhantomData<R>,
vertex_shader: Option<Arc<VertexShaderData>>,
vertex_input_layout: VertexInputLayoutDescriptor,
transform_feedback_layout: Option<TransformFeedbackLayoutDescriptor>,
resource_bindings_layout: ResourceBindingsLayoutKind,
fragment_shader: Option<Arc<FragmentShaderData>>,
primitive_assembly: Option<PrimitiveAssembly>,
depth_test: Option<DepthTest>,
stencil_test: Option<StencilTest>,
scissor_region: Region2D,
blending: Option<Blending>,
viewport: Viewport,
}
impl<Vs, Pa, Fs, V, R, Tf> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, V, R, Tf> {
pub fn vertex_shader(
self,
vertex_shader: &VertexShader,
) -> GraphicsPipelineDescriptorBuilder<VertexShader, Pa, Fs, V, R, Tf> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: Some(vertex_shader.data().clone()),
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn primitive_assembly(
self,
primitive_assembly: PrimitiveAssembly,
) -> GraphicsPipelineDescriptorBuilder<Vs, PrimitiveAssembly, Fs, V, R, Tf> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: Some(primitive_assembly),
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn fragment_shader(
self,
fragment_shader: &FragmentShader,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, FragmentShader, V, R, Tf> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly,
fragment_shader: Some(fragment_shader.data().clone()),
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn typed_vertex_attribute_layout<T>(
self,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, T, R, Tf>
where
T: TypedVertexInputLayout,
{
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: T::LAYOUT_DESCRIPTION.into(),
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn untyped_vertex_attribute_layout(
self,
vertex_attribute_layout: VertexInputLayoutDescriptor,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, Untyped, R, Tf> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: vertex_attribute_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn typed_transform_feedback_layout<T>(
self,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, V, R, T>
where
T: TypedTransformFeedbackLayout,
{
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: Some(T::LAYOUT_DESCRIPTION.into()),
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn untyped_transform_feedback_layout(
self,
transform_feedback_layout: TransformFeedbackLayoutDescriptor,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, V, R, Untyped> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: Some(transform_feedback_layout),
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn typed_resource_bindings_layout<T>(
self,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, V, T, Tf>
where
T: TypedResourceBindingsLayout,
{
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: ResourceBindingsLayoutKind::Typed(T::LAYOUT.into()),
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn untyped_resource_bindings_layout(
self,
layout: ResourceBindingsLayoutDescriptor,
) -> GraphicsPipelineDescriptorBuilder<Vs, Pa, Fs, V, Untyped, Tf> {
GraphicsPipelineDescriptorBuilder {
_vertex_shader: marker::PhantomData,
_primitive_assembly: marker::PhantomData,
_fragment_shader: marker::PhantomData,
_transform_feedback: marker::PhantomData,
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
vertex_shader: self.vertex_shader,
vertex_input_layout: self.vertex_input_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: ResourceBindingsLayoutKind::Minimal(layout),
primitive_assembly: self.primitive_assembly,
fragment_shader: self.fragment_shader,
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
pub fn enable_depth_test(self, depth_test: DepthTest) -> Self {
GraphicsPipelineDescriptorBuilder {
depth_test: Some(depth_test),
..self
}
}
pub fn enable_stencil_test(self, stencil_test: StencilTest) -> Self {
GraphicsPipelineDescriptorBuilder {
stencil_test: Some(stencil_test),
..self
}
}
pub fn scissor_region(self, scissor_region: Region2D) -> Self {
GraphicsPipelineDescriptorBuilder {
scissor_region,
..self
}
}
pub fn enable_blending(self, blending: Blending) -> Self {
GraphicsPipelineDescriptorBuilder {
blending: Some(blending),
..self
}
}
pub fn viewport(self, viewport: Viewport) -> Self {
GraphicsPipelineDescriptorBuilder { viewport, ..self }
}
}
impl<V, R, Tf>
GraphicsPipelineDescriptorBuilder<VertexShader, PrimitiveAssembly, FragmentShader, V, R, Tf>
{
pub fn finish(self) -> GraphicsPipelineDescriptor<V, R, Tf> {
GraphicsPipelineDescriptor {
_vertex_attribute_layout: marker::PhantomData,
_resource_layout: marker::PhantomData,
_transform_feedback: marker::PhantomData,
vertex_shader_data: self.vertex_shader.unwrap(),
fragment_shader_data: self.fragment_shader.unwrap(),
vertex_attribute_layout: self.vertex_input_layout,
transform_feedback_layout: self.transform_feedback_layout,
resource_bindings_layout: self.resource_bindings_layout,
primitive_assembly: self.primitive_assembly.unwrap(),
depth_test: self.depth_test,
stencil_test: self.stencil_test,
scissor_region: self.scissor_region,
blending: self.blending,
viewport: self.viewport,
}
}
}