Rework shader entry points (#708)

This commit is contained in:
tomaka 2017-08-02 10:42:30 +02:00 committed by GitHub
parent a4589e7a16
commit bf82214ec1
6 changed files with 441 additions and 950 deletions

View File

@ -39,6 +39,7 @@ use vulkano::format;
use vulkano::framebuffer::Framebuffer;
use vulkano::framebuffer::Subpass;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::shader::GraphicsShaderType;
use vulkano::pipeline::shader::ShaderInterfaceDef;
use vulkano::pipeline::shader::ShaderInterfaceDefEntry;
use vulkano::pipeline::shader::ShaderModule;
@ -374,18 +375,20 @@ fn main() {
// You must be extra careful to specify correct entry point, or program will
// crash at runtime outside of rust and you will get NO meaningful error
// information!
let vert_main = unsafe { vs.vertex_shader_entry_point(
let vert_main = unsafe { vs.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
VertInput,
VertOutput,
VertLayout(ShaderStages { vertex: true, ..ShaderStages::none() })
VertLayout(ShaderStages { vertex: true, ..ShaderStages::none() }),
GraphicsShaderType::Vertex
) };
let frag_main = unsafe { fs.fragment_shader_entry_point(
let frag_main = unsafe { fs.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
FragInput,
FragOutput,
FragLayout(ShaderStages { fragment: true, ..ShaderStages::none() })
FragLayout(ShaderStages { fragment: true, ..ShaderStages::none() }),
GraphicsShaderType::Fragment
) };
let graphics_pipeline = Arc::new(

View File

@ -54,92 +54,73 @@ pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -
_ => false,
});
let (ty, f_call) = match *execution {
enums::ExecutionModel::ExecutionModelVertex => {
let t = format!("::vulkano::pipeline::shader::VertexShaderEntryPoint<(), {0}Input, \
{0}Output, Layout>",
capitalized_ep_name);
let f = format!("vertex_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() \
as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ vertex: \
true, .. ShaderStages::none() }}))",
capitalized_ep_name);
(t, f)
},
let (ty, f_call) = {
if let enums::ExecutionModel::ExecutionModelGLCompute = *execution {
(format!("::vulkano::pipeline::shader::ComputeEntryPoint<(), Layout>"),
format!("compute_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as \
*const _), Layout(ShaderStages {{ compute: true, .. ShaderStages::none() \
}}))"))
enums::ExecutionModel::ExecutionModelTessellationControl => {
let t = format!("::vulkano::pipeline::shader::TessControlShaderEntryPoint<(), \
{0}Input, {0}Output, Layout>",
capitalized_ep_name);
let f = format!("tess_control_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
tessellation_control: true, .. ShaderStages::none() }}))",
capitalized_ep_name);
(t, f)
},
} else {
let ty = match *execution {
enums::ExecutionModel::ExecutionModelVertex => {
"::vulkano::pipeline::shader::GraphicsShaderType::Vertex".to_owned()
},
enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
let t = format!("::vulkano::pipeline::shader::TessEvaluationShaderEntryPoint<(), \
{0}Input, {0}Output, Layout>",
capitalized_ep_name);
let f = format!("tess_evaluation_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
tessellation_evaluation: true, .. ShaderStages::none() }}))",
capitalized_ep_name);
(t, f)
},
enums::ExecutionModel::ExecutionModelTessellationControl => {
"::vulkano::pipeline::shader::GraphicsShaderType::TessellationControl".to_owned()
},
enums::ExecutionModel::ExecutionModelGeometry => {
let mut execution_mode = None;
for instruction in doc.instructions.iter() {
if let &parse::Instruction::ExecutionMode { target_id, ref mode, .. } = instruction {
if target_id != id {
continue;
enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
"::vulkano::pipeline::shader::GraphicsShaderType::TessellationEvaluation".to_owned()
},
enums::ExecutionModel::ExecutionModelGeometry => {
let mut execution_mode = None;
for instruction in doc.instructions.iter() {
if let &parse::Instruction::ExecutionMode { target_id, ref mode, .. } = instruction {
if target_id != id {
continue;
}
execution_mode = match mode {
&enums::ExecutionMode::ExecutionModeInputPoints => Some("Points"),
&enums::ExecutionMode::ExecutionModeInputLines => Some("Lines"),
&enums::ExecutionMode::ExecutionModeInputLinesAdjacency => Some("LinesWithAdjacency"),
&enums::ExecutionMode::ExecutionModeTriangles => Some("Triangles"),
&enums::ExecutionMode::ExecutionModeInputTrianglesAdjacency => Some("TrianglesWithAdjacency"),
_ => continue,
};
break;
}
}
execution_mode = match mode {
&enums::ExecutionMode::ExecutionModeInputPoints => Some("Points"),
&enums::ExecutionMode::ExecutionModeInputLines => Some("Lines"),
&enums::ExecutionMode::ExecutionModeInputLinesAdjacency => Some("LinesWithAdjacency"),
&enums::ExecutionMode::ExecutionModeTriangles => Some("Triangles"),
&enums::ExecutionMode::ExecutionModeInputTrianglesAdjacency => Some("TrianglesWithAdjacency"),
_ => continue,
};
break;
}
}
let execution_mode = format!("::vulkano::pipeline::shader::GeometryShaderExecutionMode::{0}", execution_mode.unwrap());
let t = format!("::vulkano::pipeline::shader::GeometryShaderEntryPoint<(), {0}Input, \
{0}Output, Layout>",
format!("::vulkano::pipeline::shader::GraphicsShaderType::Geometry(
::vulkano::pipeline::shader::GeometryShaderExecutionMode::{0}
)", execution_mode.unwrap())
},
enums::ExecutionModel::ExecutionModelFragment => {
"::vulkano::pipeline::shader::GraphicsShaderType::Fragment".to_owned()
},
enums::ExecutionModel::ExecutionModelGLCompute => {
unreachable!()
},
enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
};
let t = format!("::vulkano::pipeline::shader::GraphicsEntryPoint<(), {0}Input, \
{0}Output, Layout>",
capitalized_ep_name);
let f = format!("geometry_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
as_ptr() as *const _), {1}, {0}Input, {0}Output, Layout(ShaderStages {{ \
geometry: true, .. ShaderStages::none() }}))",
capitalized_ep_name,
execution_mode);
let f = format!("graphics_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() \
as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ vertex: \
true, .. ShaderStages::none() }}), {1})",
capitalized_ep_name, ty);
(t, f)
},
enums::ExecutionModel::ExecutionModelFragment => {
let t = format!("::vulkano::pipeline::shader::FragmentShaderEntryPoint<(), {0}Input, \
{0}Output, Layout>",
capitalized_ep_name);
let f = format!("fragment_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
fragment: true, .. ShaderStages::none() }}))",
capitalized_ep_name);
(t, f)
},
enums::ExecutionModel::ExecutionModelGLCompute => {
(format!("::vulkano::pipeline::shader::ComputeShaderEntryPoint<(), Layout>"),
format!("compute_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as \
*const _), Layout(ShaderStages {{ compute: true, .. ShaderStages::none() \
}}))"))
},
enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
}
};
let entry_point = format!(

View File

@ -25,7 +25,7 @@ use descriptor::pipeline_layout::PipelineLayoutDescPcRange;
use descriptor::pipeline_layout::PipelineLayoutNotSupersetError;
use descriptor::pipeline_layout::PipelineLayoutSuperset;
use descriptor::pipeline_layout::PipelineLayoutSys;
use pipeline::shader::ComputeShaderEntryPoint;
use pipeline::shader::EntryPointAbstract;
use pipeline::shader::SpecializationConstants;
use Error;
@ -56,11 +56,11 @@ struct Inner {
impl ComputePipeline<()> {
/// Builds a new `ComputePipeline`.
pub fn new<Css, Csl>(
device: Arc<Device>, shader: &ComputeShaderEntryPoint<Css, Csl>, specialization: &Css)
-> Result<ComputePipeline<PipelineLayout<Csl>>, ComputePipelineCreationError>
where Csl: PipelineLayoutDescNames + Clone,
Css: SpecializationConstants
pub fn new<Cs>(
device: Arc<Device>, shader: &Cs, specialization: &Cs::SpecializationConstants)
-> Result<ComputePipeline<PipelineLayout<Cs::PipelineLayout>>, ComputePipelineCreationError>
where Cs::PipelineLayout: Clone,
Cs: EntryPointAbstract
{
unsafe {
let pipeline_layout = shader.layout().clone().build(device.clone())?;
@ -77,12 +77,12 @@ impl<Pl> ComputePipeline<Pl> {
///
/// An error will be returned if the pipeline layout isn't a superset of what the shader
/// uses.
pub fn with_pipeline_layout<Css, Csl>(
device: Arc<Device>, shader: &ComputeShaderEntryPoint<Css, Csl>, specialization: &Css,
pub fn with_pipeline_layout<Cs>(
device: Arc<Device>, shader: &Cs, specialization: &Cs::SpecializationConstants,
pipeline_layout: Pl)
-> Result<ComputePipeline<Pl>, ComputePipelineCreationError>
where Csl: PipelineLayoutDescNames + Clone,
Css: SpecializationConstants,
where Cs::PipelineLayout: Clone,
Cs: EntryPointAbstract,
Pl: PipelineLayoutAbstract
{
unsafe {
@ -96,23 +96,23 @@ impl<Pl> ComputePipeline<Pl> {
/// Same as `with_pipeline_layout`, but doesn't check whether the pipeline layout is a
/// superset of what the shader expects.
pub unsafe fn with_unchecked_pipeline_layout<Css, Csl>(
device: Arc<Device>, shader: &ComputeShaderEntryPoint<Css, Csl>, specialization: &Css,
pub unsafe fn with_unchecked_pipeline_layout<Cs>(
device: Arc<Device>, shader: &Cs, specialization: &Cs::SpecializationConstants,
pipeline_layout: Pl)
-> Result<ComputePipeline<Pl>, ComputePipelineCreationError>
where Csl: PipelineLayoutDescNames + Clone,
Css: SpecializationConstants,
where Cs::PipelineLayout: Clone,
Cs: EntryPointAbstract,
Pl: PipelineLayoutAbstract
{
let vk = device.pointers();
let pipeline = {
let spec_descriptors = <Css as SpecializationConstants>::descriptors();
let spec_descriptors = Cs::SpecializationConstants::descriptors();
let specialization = vk::SpecializationInfo {
mapEntryCount: spec_descriptors.len() as u32,
pMapEntries: spec_descriptors.as_ptr() as *const _,
dataSize: mem::size_of_val(specialization),
pData: specialization as *const Css as *const _,
pData: specialization as *const Cs::SpecializationConstants as *const _,
};
let stage = vk::PipelineShaderStageCreateInfo {

View File

@ -11,9 +11,7 @@
// to avoid duplicating code, so we hide the warnings for now
#![allow(deprecated)]
use descriptor::pipeline_layout::EmptyPipelineDesc;
use descriptor::pipeline_layout::PipelineLayoutAbstract;
use descriptor::pipeline_layout::PipelineLayoutDescNames;
use device::Device;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassSubpassInterface;
@ -34,14 +32,9 @@ use pipeline::raster::CullMode;
use pipeline::raster::FrontFace;
use pipeline::raster::PolygonMode;
use pipeline::raster::Rasterization;
use pipeline::shader::EmptyShaderInterfaceDef;
use pipeline::shader::FragmentShaderEntryPoint;
use pipeline::shader::GeometryShaderEntryPoint;
use pipeline::shader::ShaderInterfaceDef;
use pipeline::shader::EmptyEntryPointDummy;
use pipeline::shader::GraphicsEntryPointAbstract;
use pipeline::shader::ShaderInterfaceDefMatch;
use pipeline::shader::TessControlShaderEntryPoint;
use pipeline::shader::TessEvaluationShaderEntryPoint;
use pipeline::shader::VertexShaderEntryPoint;
use pipeline::vertex::SingleBufferDefinition;
use pipeline::vertex::VertexDefinition;
use pipeline::viewport::Scissor;
@ -51,68 +44,36 @@ use std::sync::Arc;
/// Prototype for a `GraphicsPipeline`.
// TODO: we can optimize this by filling directly the raw vk structs
pub struct GraphicsPipelineBuilder<'a,
pub struct GraphicsPipelineBuilder<
Vdef,
Vsp,
Vi,
Vo,
Vl,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp>
{
vertex_input: Vdef,
vertex_shader: Option<VertexShaderEntryPoint<'a, Vsp, Vi, Vo, Vl>>,
vertex_shader: Option<Vs>,
input_assembly: InputAssembly,
tessellation: Option<GraphicsPipelineParamsTess<'a, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel>>,
geometry_shader: Option<GeometryShaderEntryPoint<'a, Gs, Gi, Go, Gl>>,
tessellation: Option<GraphicsPipelineParamsTess<Tcs, Tes>>,
geometry_shader: Option<Gs>,
viewport: Option<ViewportsState>,
raster: Rasterization,
multisample: Multisample,
fragment_shader: Option<FragmentShaderEntryPoint<'a, Fs, Fi, Fo, Fl>>,
fragment_shader: Option<Fs>,
depth_stencil: DepthStencil,
blend: Blend,
render_pass: Option<Subpass<Rp>>,
}
impl<'a>
GraphicsPipelineBuilder<'a,
SingleBufferDefinition<()>,
(),
(),
(),
(),
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
()> {
impl GraphicsPipelineBuilder<SingleBufferDefinition<()>,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
()> {
/// Builds a new empty builder.
pub(super) fn new() -> Self {
GraphicsPipelineBuilder {
@ -132,70 +93,38 @@ impl<'a>
}
}
impl<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
impl<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp>
GraphicsPipelineBuilder<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp>
where Vdef: VertexDefinition<Vi>,
Vl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Fl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Tcl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Tel: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Gl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Tci: ShaderInterfaceDefMatch<Vo>,
Tei: ShaderInterfaceDefMatch<Tco>,
Gi: ShaderInterfaceDefMatch<Teo> + ShaderInterfaceDefMatch<Vo>,
Vo: ShaderInterfaceDef,
Tco: ShaderInterfaceDef,
Teo: ShaderInterfaceDef,
Go: ShaderInterfaceDef,
Fi: ShaderInterfaceDefMatch<Go>
+ ShaderInterfaceDefMatch<Teo>
+ ShaderInterfaceDefMatch<Vo>,
Fo: ShaderInterfaceDef,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fo>
where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract,
Gs: GraphicsEntryPointAbstract,
Tcs: GraphicsEntryPointAbstract,
Tes: GraphicsEntryPointAbstract,
Vs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Fs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Tcs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Tes::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Gs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Tcs::InputDefinition: ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Tes::InputDefinition: ShaderInterfaceDefMatch<Tcs::OutputDefinition>,
Gs::InputDefinition: ShaderInterfaceDefMatch<Tes::OutputDefinition> + ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Fs::InputDefinition: ShaderInterfaceDefMatch<Gs::OutputDefinition>
+ ShaderInterfaceDefMatch<Tes::OutputDefinition>
+ ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fs::OutputDefinition>
{
/// Builds the graphics pipeline.
// TODO: replace Box<PipelineLayoutAbstract> with a PipelineUnion struct without template params
@ -239,79 +168,31 @@ impl<'a,
// TODO: add build_with_cache method
}
impl<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
impl<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp>
GraphicsPipelineBuilder<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp> {
// TODO: add pipeline derivate system
/// Sets the vertex input.
#[inline]
pub fn vertex_input<T>(self, vertex_input: T)
-> GraphicsPipelineBuilder<'a,
T,
Vsp,
Vi,
Vo,
Vl,
-> GraphicsPipelineBuilder<T,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp> {
GraphicsPipelineBuilder {
vertex_input: vertex_input,
@ -335,28 +216,12 @@ impl<'a,
/// vertex.
#[inline]
pub fn vertex_input_single_buffer<V>(self)
-> GraphicsPipelineBuilder<'a,
SingleBufferDefinition<V>,
Vsp,
Vi,
Vo,
Vl,
-> GraphicsPipelineBuilder<SingleBufferDefinition<V>,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp> {
self.vertex_input(SingleBufferDefinition::<V>::new())
}
@ -364,32 +229,18 @@ impl<'a,
/// Sets the vertex shader to use.
// TODO: correct specialization constants
#[inline]
pub fn vertex_shader<Vi2, Vo2, Vl2>(self,
shader: VertexShaderEntryPoint<'a, (), Vi2, Vo2, Vl2>,
specialization_constants: ())
-> GraphicsPipelineBuilder<'a,
Vdef,
(),
Vi2,
Vo2,
Vl2,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp> {
pub fn vertex_shader<Vs2>(self,
shader: Vs2,
specialization_constants: ())
-> GraphicsPipelineBuilder<Vdef,
Vs2,
Tcs,
Tes,
Gs,
Fs,
Rp>
where Vs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{
GraphicsPipelineBuilder {
vertex_input: self.vertex_input,
vertex_shader: Some(shader),
@ -523,13 +374,14 @@ impl<'a,
/// Sets the tessellation shaders to use.
// TODO: correct specialization constants
#[inline]
pub fn tessellation_shaders<Tci2, Tco2, Tcl2, Tei2, Teo2, Tel2>(self,
tessellation_control_shader: TessControlShaderEntryPoint<'a, (), Tci2, Tco2, Tcl2>,
pub fn tessellation_shaders<Tcs2, Tes2>(self,
tessellation_control_shader: Tcs2,
tessellation_control_shader_spec_constants: (),
tessellation_evaluation_shader: TessEvaluationShaderEntryPoint<'a, (), Tei2, Teo2, Tel2>,
tessellation_evaluation_shader: Tes2,
tessellation_evaluation_shader_spec_constants: ())
-> GraphicsPipelineBuilder<'a, Vdef, Vsp, Vi, Vo, Vl, (), Tci2, Tco2,
Tcl2, (), Tei2, Teo2, Tel2, Gs, Gi, Go, Gl, Fs, Fi, Fo, Fl, Rp>
-> GraphicsPipelineBuilder<Vdef, Vs, Tcs2, Tes2, Gs, Fs, Rp>
where Tcs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
Tes2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{
GraphicsPipelineBuilder {
vertex_input: self.vertex_input,
@ -560,32 +412,18 @@ impl<'a,
/// Sets the geometry shader to use.
// TODO: correct specialization constants
#[inline]
pub fn geometry_shader<Gi2, Go2, Gl2>(self,
shader: GeometryShaderEntryPoint<'a, (), Gi2, Go2, Gl2>,
specialization_constants: ())
-> GraphicsPipelineBuilder<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
(),
Gi2,
Go2,
Gl2,
Fs,
Fi,
Fo,
Fl,
Rp> {
pub fn geometry_shader<Gs2>(self,
shader: Gs2,
specialization_constants: ())
-> GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tes,
Gs2,
Fs,
Rp>
where Gs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{
GraphicsPipelineBuilder {
vertex_input: self.vertex_input,
vertex_shader: self.vertex_shader,
@ -782,32 +620,18 @@ impl<'a,
/// The fragment shader is run once for each pixel that is covered by each primitive.
// TODO: correct specialization constants
#[inline]
pub fn fragment_shader<Fi2, Fo2, Fl2>(self,
shader: FragmentShaderEntryPoint<'a, (), Fi2, Fo2, Fl2>,
specialization_constants: ())
-> GraphicsPipelineBuilder<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
(),
Fi2,
Fo2,
Fl2,
Rp> {
pub fn fragment_shader<Fs2>(self,
shader: Fs2,
specialization_constants: ())
-> GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tes,
Gs,
Fs2,
Rp>
where Fs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{
GraphicsPipelineBuilder {
vertex_input: self.vertex_input,
vertex_shader: self.vertex_shader,
@ -921,28 +745,12 @@ impl<'a,
/// Sets the render pass subpass to use.
#[inline]
pub fn render_pass<Rp2>(self, subpass: Subpass<Rp2>)
-> GraphicsPipelineBuilder<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
-> GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp2> {
GraphicsPipelineBuilder {
vertex_input: self.vertex_input,

View File

@ -29,7 +29,6 @@ use check_errors;
use descriptor::PipelineLayoutAbstract;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::pipeline_layout::EmptyPipelineDesc;
use descriptor::pipeline_layout::PipelineLayout;
use descriptor::pipeline_layout::PipelineLayoutDesc;
use descriptor::pipeline_layout::PipelineLayoutDescNames;
@ -63,15 +62,11 @@ use pipeline::multisample::Multisample;
use pipeline::raster::DepthBiasControl;
use pipeline::raster::PolygonMode;
use pipeline::raster::Rasterization;
use pipeline::shader::EmptyShaderInterfaceDef;
use pipeline::shader::FragmentShaderEntryPoint;
use pipeline::shader::GeometryShaderEntryPoint;
use pipeline::shader::ShaderInterfaceDef;
use pipeline::shader::EmptyEntryPointDummy;
use pipeline::shader::GraphicsEntryPointAbstract;
use pipeline::shader::GraphicsShaderType;
use pipeline::shader::ShaderInterfaceDefMatch;
use pipeline::shader::ShaderInterfaceMismatchError;
use pipeline::shader::TessControlShaderEntryPoint;
use pipeline::shader::TessEvaluationShaderEntryPoint;
use pipeline::shader::VertexShaderEntryPoint;
use pipeline::vertex::IncompatibleVertexDefinitionError;
use pipeline::vertex::SingleBufferDefinition;
use pipeline::vertex::VertexDefinition;
@ -86,28 +81,13 @@ mod builder;
/// Description of a `GraphicsPipeline`.
#[deprecated = "Use the GraphicsPipelineBuilder instead"]
pub struct GraphicsPipelineParams<'a,
pub struct GraphicsPipelineParams<
Vdef,
Vsp,
Vi,
Vo,
Vl,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gs,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl,
Rp>
{
/// Describes the layout of the vertex input.
@ -119,7 +99,7 @@ pub struct GraphicsPipelineParams<'a,
pub vertex_input: Vdef,
/// The entry point of the vertex shader that will be run on the vertex input.
pub vertex_shader: VertexShaderEntryPoint<'a, Vsp, Vi, Vo, Vl>,
pub vertex_shader: Vs,
/// Describes how vertices should be assembled into primitives. Essentially contains the type
/// of primitives.
@ -127,12 +107,11 @@ pub struct GraphicsPipelineParams<'a,
/// Parameters of the tessellation stage. `None` if you don't want to use tessellation.
/// If you use tessellation, you must enable the `tessellation_shader` feature on the device.
pub tessellation:
Option<GraphicsPipelineParamsTess<'a, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel>>,
pub tessellation: Option<GraphicsPipelineParamsTess<Tcs, Tes>>,
/// The entry point of the geometry shader. `None` if you don't want a geometry shader.
/// If you use a geometry shader, you must enable the `geometry_shader` feature on the device.
pub geometry_shader: Option<GeometryShaderEntryPoint<'a, Gs, Gi, Go, Gl>>,
pub geometry_shader: Option<Gs>,
/// Describes the subsection of the framebuffer attachments where the scene will be drawn.
/// You can use one or multiple viewports, but using multiple viewports is only relevant with
@ -146,7 +125,7 @@ pub struct GraphicsPipelineParams<'a,
pub multisample: Multisample,
/// The entry point of the fragment shader that will be run on the pixels.
pub fragment_shader: FragmentShaderEntryPoint<'a, Fs, Fi, Fo, Fl>,
pub fragment_shader: Fs,
/// Describes how the implementation should perform the depth and stencil tests.
pub depth_stencil: DepthStencil,
@ -162,11 +141,11 @@ pub struct GraphicsPipelineParams<'a,
/// Additional parameters if you use tessellation.
#[deprecated = "Use the GraphicsPipelineBuilder instead"]
pub struct GraphicsPipelineParamsTess<'a, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel> {
pub struct GraphicsPipelineParamsTess<Tcs, Tes> {
/// The entry point of the tessellation control shader.
pub tessellation_control_shader: TessControlShaderEntryPoint<'a, Tcs, Tci, Tco, Tcl>,
pub tessellation_control_shader: Tcs,
/// The entry point of the tessellation evaluation shader.
pub tessellation_evaluation_shader: TessEvaluationShaderEntryPoint<'a, Tes, Tei, Teo, Tel>,
pub tessellation_evaluation_shader: Tes,
}
/// Defines how the implementation should perform a draw operation.
@ -204,28 +183,12 @@ impl GraphicsPipeline<(), (), ()> {
/// Starts the building process of a graphics pipeline. Returns a builder object that you can
/// fill with the various parameters.
pub fn start<'a>()
-> GraphicsPipelineBuilder<'a,
SingleBufferDefinition<()>,
(),
(),
(),
(),
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
(),
EmptyShaderInterfaceDef,
EmptyShaderInterfaceDef,
EmptyPipelineDesc,
-> GraphicsPipelineBuilder<SingleBufferDefinition<()>,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
()>
{
GraphicsPipelineBuilder::new()
@ -244,19 +207,17 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
/// the other constructors for other possibilities.
#[inline]
#[deprecated = "Use the GraphicsPipelineBuilder instead"]
pub fn new<'a, Vsp, Vi, Vo, Vl, Fs, Fi, Fo, Fl>
pub fn new<Vs, Fs>
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, (), (), (), EmptyPipelineDesc,
(), (), (), EmptyPipelineDesc, (), (), (), EmptyPipelineDesc,
Fs, Fi, Fo, Fl, Rp>)
-> Result<GraphicsPipeline<Vdef, PipelineLayout<PipelineLayoutDescUnion<Vl, Fl>>, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vi>,
Vl: PipelineLayoutDescNames + Clone,
Fl: PipelineLayoutDescNames + Clone,
Fi: ShaderInterfaceDefMatch<Vo>,
Fo: ShaderInterfaceDef,
Vo: ShaderInterfaceDef,
Rp: RenderPassSubpassInterface<Fo>,
params: GraphicsPipelineParams<Vdef, Vs, EmptyEntryPointDummy, EmptyEntryPointDummy, EmptyEntryPointDummy, Fs, Rp>)
-> Result<GraphicsPipeline<Vdef, PipelineLayout<PipelineLayoutDescUnion<Vs::PipelineLayout, Fs::PipelineLayout>>, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract,
Vs::PipelineLayout: Clone,
Fs::PipelineLayout: Clone,
Fs::InputDefinition: ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassSubpassInterface<Fs::OutputDefinition>,
{
if let Err(err) = params
.fragment_shader
@ -275,24 +236,9 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
.unwrap(); // TODO: error
GraphicsPipeline::new_inner::<_,
_,
_,
_,
(),
(),
(),
EmptyPipelineDesc,
(),
(),
(),
EmptyPipelineDesc,
(),
(),
(),
EmptyPipelineDesc,
_,
_,
_,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
EmptyEntryPointDummy,
_>(device, params, pl)
}
@ -305,22 +251,20 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
/// shader. See the other constructors for other possibilities.
#[inline]
#[deprecated = "Use the GraphicsPipelineBuilder instead"]
pub fn with_geometry_shader<'a, Vsp, Vi, Vo, Vl, Gsp, Gi, Go, Gl, Fs, Fi, Fo, Fl>
pub fn with_geometry_shader<Vs, Gs, Fs>
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, (), (), (), EmptyPipelineDesc,
(), (), (), EmptyPipelineDesc, Gsp, Gi, Go, Gl, Fs, Fi,
Fo, Fl, Rp>)
-> Result<GraphicsPipeline<Vdef, PipelineLayout<PipelineLayoutDescUnion<PipelineLayoutDescUnion<Vl, Fl>, Gl>>, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vi>,
Vl: PipelineLayoutDescNames + Clone,
Fl: PipelineLayoutDescNames + Clone,
Gl: PipelineLayoutDescNames + Clone,
Gi: ShaderInterfaceDefMatch<Vo>,
Vo: ShaderInterfaceDef,
Fi: ShaderInterfaceDefMatch<Go> + ShaderInterfaceDefMatch<Vo>,
Fo: ShaderInterfaceDef,
Go: ShaderInterfaceDef,
Rp: RenderPassSubpassInterface<Fo>,
params: GraphicsPipelineParams<Vdef, Vs, EmptyEntryPointDummy, EmptyEntryPointDummy, Gs, Fs, Rp>)
-> Result<GraphicsPipeline<Vdef, PipelineLayout<PipelineLayoutDescUnion<PipelineLayoutDescUnion<Vs::PipelineLayout, Fs::PipelineLayout>, Gs::PipelineLayout>>, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract,
Gs: GraphicsEntryPointAbstract,
Vs::PipelineLayout: Clone,
Fs::PipelineLayout: Clone,
Gs::PipelineLayout: Clone,
Gs::InputDefinition: ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Fs::InputDefinition: ShaderInterfaceDefMatch<Gs::OutputDefinition> + ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassSubpassInterface<Fs::OutputDefinition>,
{
if let Some(ref geometry_shader) = params.geometry_shader {
if let Err(err) = geometry_shader
@ -365,26 +309,23 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
/// possibilities.
#[inline]
#[deprecated = "Use the GraphicsPipelineBuilder instead"]
pub fn with_tessellation<'a, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel, Fs, Fi,
Fo, Fl>
pub fn with_tessellation<Vs, Tcs, Tes, Fs>
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes,
Tei, Teo, Tel, (), (), (), EmptyPipelineDesc, Fs, Fi,
Fo, Fl, Rp>)
-> Result<GraphicsPipeline<Vdef, PipelineLayout<PipelineLayoutDescUnion<PipelineLayoutDescUnion<PipelineLayoutDescUnion<Vl, Fl>, Tcl>, Tel>>, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vi>,
Vl: PipelineLayoutDescNames + Clone,
Fl: PipelineLayoutDescNames + Clone,
Tcl: PipelineLayoutDescNames + Clone,
Tel: PipelineLayoutDescNames + Clone,
Tci: ShaderInterfaceDefMatch<Vo>,
Tei: ShaderInterfaceDefMatch<Tco>,
Vo: ShaderInterfaceDef,
Tco: ShaderInterfaceDef,
Teo: ShaderInterfaceDef,
Fi: ShaderInterfaceDefMatch<Teo> + ShaderInterfaceDefMatch<Vo>,
Fo: ShaderInterfaceDef,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fo>,
params: GraphicsPipelineParams<Vdef, Vs, Tcs, Tes, EmptyEntryPointDummy, Fs, Rp>)
-> Result<GraphicsPipeline<Vdef, PipelineLayout<PipelineLayoutDescUnion<PipelineLayoutDescUnion<PipelineLayoutDescUnion<Vs::PipelineLayout, Fs::PipelineLayout>, Tcs::PipelineLayout>, Tes::PipelineLayout>>, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract,
Tcs: GraphicsEntryPointAbstract,
Tes: GraphicsEntryPointAbstract,
Vs::PipelineLayout: Clone,
Fs::PipelineLayout: Clone,
Tcs::PipelineLayout: Clone,
Tes::PipelineLayout: Clone,
Tcs::InputDefinition: ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Tes::InputDefinition: ShaderInterfaceDefMatch<Tcs::OutputDefinition>,
Fs::InputDefinition: ShaderInterfaceDefMatch<Tes::OutputDefinition> + ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fs::OutputDefinition>,
{
if let Some(ref tess) = params.tessellation {
if let Err(err) = tess.tessellation_control_shader
@ -437,71 +378,39 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
// TODO: replace Box<PipelineLayoutAbstract> with a PipelineUnion struct without template params
#[inline]
#[deprecated = "Use the GraphicsPipelineBuilder instead"]
pub fn with_tessellation_and_geometry<'a,
Vsp,
Vi,
Vo,
Vl,
pub fn with_tessellation_and_geometry<Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gsp,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl>(
Gs,
Fs>(
device: Arc<Device>,
params: GraphicsPipelineParams<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
params: GraphicsPipelineParams<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gsp,
Gi,
Go,
Gl,
Gs,
Fs,
Fi,
Fo,
Fl,
Rp>)
-> Result<GraphicsPipeline<Vdef, Box<PipelineLayoutAbstract + Send + Sync>, Rp>,
GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vi>,
Vl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Fl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Tcl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Tel: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Gl: PipelineLayoutDescNames + Clone + 'static + Send + Sync, // TODO: Clone + 'static + Send + Sync shouldn't be required
Tci: ShaderInterfaceDefMatch<Vo>,
Tei: ShaderInterfaceDefMatch<Tco>,
Gi: ShaderInterfaceDefMatch<Teo> + ShaderInterfaceDefMatch<Vo>,
Vo: ShaderInterfaceDef,
Tco: ShaderInterfaceDef,
Teo: ShaderInterfaceDef,
Go: ShaderInterfaceDef,
Fi: ShaderInterfaceDefMatch<Go>
+ ShaderInterfaceDefMatch<Teo>
+ ShaderInterfaceDefMatch<Vo>,
Fo: ShaderInterfaceDef,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fo>
where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract,
Gs: GraphicsEntryPointAbstract,
Tcs: GraphicsEntryPointAbstract,
Tes: GraphicsEntryPointAbstract,
Vs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Fs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Tcs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Tes::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Gs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Tcs::InputDefinition: ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Tes::InputDefinition: ShaderInterfaceDefMatch<Tcs::OutputDefinition>,
Gs::InputDefinition: ShaderInterfaceDefMatch<Tes::OutputDefinition> + ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Fs::InputDefinition: ShaderInterfaceDefMatch<Gs::OutputDefinition>
+ ShaderInterfaceDefMatch<Tes::OutputDefinition>
+ ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fs::OutputDefinition>
{
let pl;
@ -610,61 +519,28 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
where L: PipelineLayoutAbstract
{
fn new_inner<'a,
Vsp,
Vi,
Vo,
Vl,
fn new_inner<Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gsp,
Gi,
Go,
Gl,
Fs,
Fi,
Fo,
Fl>(
Gs,
Fs>(
device: Arc<Device>,
params: GraphicsPipelineParams<'a,
Vdef,
Vsp,
Vi,
Vo,
Vl,
params: GraphicsPipelineParams<Vdef,
Vs,
Tcs,
Tci,
Tco,
Tcl,
Tes,
Tei,
Teo,
Tel,
Gsp,
Gi,
Go,
Gl,
Gs,
Fs,
Fi,
Fo,
Fl,
Rp>,
pipeline_layout: L)
-> Result<GraphicsPipeline<Vdef, L, Rp>, GraphicsPipelineCreationError>
where Vdef: VertexDefinition<Vi>,
Fo: ShaderInterfaceDef,
Vl: PipelineLayoutDescNames,
Fl: PipelineLayoutDescNames,
Gl: PipelineLayoutDescNames,
Tcl: PipelineLayoutDescNames,
Tel: PipelineLayoutDescNames,
Rp: RenderPassAbstract + RenderPassDesc + RenderPassSubpassInterface<Fo>
where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract,
Gs: GraphicsEntryPointAbstract,
Tcs: GraphicsEntryPointAbstract,
Tes: GraphicsEntryPointAbstract,
Rp: RenderPassAbstract + RenderPassDesc + RenderPassSubpassInterface<Fs::OutputDefinition>
{
let vk = device.pointers();
@ -700,6 +576,11 @@ impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
let stages = {
let mut stages = SmallVec::<[_; 5]>::new();
match params.vertex_shader.ty() {
GraphicsShaderType::Vertex => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
};
stages.push(vk::PipelineShaderStageCreateInfo {
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
pNext: ptr::null(),
@ -710,6 +591,11 @@ impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
pSpecializationInfo: ptr::null(), // TODO:
});
match params.fragment_shader.ty() {
GraphicsShaderType::Fragment => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
};
stages.push(vk::PipelineShaderStageCreateInfo {
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
pNext: ptr::null(),
@ -743,6 +629,16 @@ impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
return Err(GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled);
}
match tess.tessellation_control_shader.ty() {
GraphicsShaderType::TessellationControl => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
};
match tess.tessellation_evaluation_shader.ty() {
GraphicsShaderType::TessellationControl => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
};
stages.push(vk::PipelineShaderStageCreateInfo {
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
pNext: ptr::null(),
@ -774,7 +670,7 @@ impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
let (buffers_iter, attribs_iter) =
params
.vertex_input
.definition(params.vertex_shader.input_definition())?;
.definition(params.vertex_shader.input())?;
let mut binding_descriptions = SmallVec::<[_; 8]>::new();
for (num, stride, rate) in buffers_iter {
@ -882,8 +778,13 @@ impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
// TODO: should check from the tess eval shader instead of the input assembly
if let Some(ref gs) = params.geometry_shader {
if !gs.primitives().matches(params.input_assembly.topology) {
return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader);
match gs.ty() {
GraphicsShaderType::Geometry(primitives) => {
if !primitives.matches(params.input_assembly.topology) {
return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader);
}
},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}
}
@ -1922,6 +1823,11 @@ pub enum GraphicsPipelineCreationError {
/// The `maxTessellationPatchSize` limit was exceeded.
MaxTessellationPatchSizeExceeded,
/// The wrong type of shader has been passed.
///
/// For example you passed a vertex shader as the fragment shader.
WrongShaderType,
}
impl error::Error for GraphicsPipelineCreationError {
@ -2050,6 +1956,9 @@ impl error::Error for GraphicsPipelineCreationError {
GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded => {
"the maximum tessellation patch size was exceeded"
},
GraphicsPipelineCreationError::WrongShaderType => {
"the wrong type of shader has been passed"
},
}
}

View File

@ -29,11 +29,12 @@ use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use descriptor::pipeline_layout::EmptyPipelineDesc;
use descriptor::pipeline_layout::PipelineLayoutDescNames;
use format::Format;
use pipeline::input_assembly::PrimitiveTopology;
use OomError;
use SafeDeref;
use VulkanObject;
use check_errors;
use device::Device;
@ -44,18 +45,14 @@ use vk;
/// Note that it is advised to wrap around a `ShaderModule` with a struct that is different for
/// each shader.
#[derive(Debug)]
pub struct ShaderModule<P = Arc<Device>>
where P: SafeDeref<Target = Device>
{
pub struct ShaderModule {
// The module.
module: vk::ShaderModule,
// Pointer to the device.
device: P,
device: Arc<Device>,
}
impl<P> ShaderModule<P>
where P: SafeDeref<Target = Device>
{
impl ShaderModule {
/// Builds a new shader module from SPIR-V.
///
/// # Safety
@ -64,7 +61,7 @@ impl<P> ShaderModule<P>
/// - The SPIR-V code may require some features that are not enabled. This isn't checked by
/// this function either.
///
pub unsafe fn new(device: P, spirv: &[u8]) -> Result<Arc<ShaderModule<P>>, OomError> {
pub unsafe fn new(device: Arc<Device>, spirv: &[u8]) -> Result<Arc<ShaderModule>, OomError> {
debug_assert!((spirv.len() % 4) == 0);
let module = {
@ -103,117 +100,17 @@ impl<P> ShaderModule<P>
/// - The input, output and layout must correctly describe the input, output and layout used
/// by this stage.
///
pub unsafe fn vertex_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> VertexShaderEntryPoint<'a, S, I, O, L, P> {
VertexShaderEntryPoint {
pub unsafe fn graphics_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, input: I, output: O,
layout: L, ty: GraphicsShaderType)
-> GraphicsEntryPoint<'a, S, I, O, L>
{
GraphicsEntryPoint {
module: self,
name: name,
input: input,
output: output,
layout: layout,
marker: PhantomData,
}
}
/// Gets access to an entry point contained in this module.
///
/// This is purely a *logical* operation. It returns a struct that *represents* the entry
/// point but doesn't actually do anything.
///
/// # Safety
///
/// - The user must check that the entry point exists in the module, as this is not checked
/// by Vulkan.
/// - The input, output and layout must correctly describe the input, output and layout used
/// by this stage.
///
pub unsafe fn tess_control_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> TessControlShaderEntryPoint<'a, S, I, O, L, P> {
TessControlShaderEntryPoint {
module: self,
name: name,
layout: layout,
input: input,
output: output,
marker: PhantomData,
}
}
/// Gets access to an entry point contained in this module.
///
/// This is purely a *logical* operation. It returns a struct that *represents* the entry
/// point but doesn't actually do anything.
///
/// # Safety
///
/// - The user must check that the entry point exists in the module, as this is not checked
/// by Vulkan.
/// - The input, output and layout must correctly describe the input, output and layout used
/// by this stage.
///
pub unsafe fn tess_evaluation_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> TessEvaluationShaderEntryPoint<'a, S, I, O, L, P> {
TessEvaluationShaderEntryPoint {
module: self,
name: name,
layout: layout,
input: input,
output: output,
marker: PhantomData,
}
}
/// Gets access to an entry point contained in this module.
///
/// This is purely a *logical* operation. It returns a struct that *represents* the entry
/// point but doesn't actually do anything.
///
/// # Safety
///
/// - The user must check that the entry point exists in the module, as this is not checked
/// by Vulkan.
/// - The input, output and layout must correctly describe the input, output and layout used
/// by this stage.
///
pub unsafe fn geometry_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, primitives: GeometryShaderExecutionMode, input: I, output: O,
layout: L)
-> GeometryShaderEntryPoint<'a, S, I, O, L, P> {
GeometryShaderEntryPoint {
module: self,
name: name,
layout: layout,
primitives: primitives,
input: input,
output: output,
marker: PhantomData,
}
}
/// Gets access to an entry point contained in this module.
///
/// This is purely a *logical* operation. It returns a struct that *represents* the entry
/// point but doesn't actually do anything.
///
/// # Safety
///
/// - The user must check that the entry point exists in the module, as this is not checked
/// by Vulkan.
/// - The input, output and layout must correctly describe the input, output and layout used
/// by this stage.
///
pub unsafe fn fragment_shader_entry_point<'a, S, I, O, L>(
&'a self, name: &'a CStr, input: I, output: O, layout: L)
-> FragmentShaderEntryPoint<'a, S, I, O, L, P> {
FragmentShaderEntryPoint {
module: self,
name: name,
layout: layout,
input: input,
output: output,
ty: ty,
marker: PhantomData,
}
}
@ -230,9 +127,9 @@ impl<P> ShaderModule<P>
/// - The layout must correctly describe the layout used by this stage.
///
#[inline]
pub unsafe fn compute_shader_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
-> ComputeShaderEntryPoint<'a, S, L, P> {
ComputeShaderEntryPoint {
pub unsafe fn compute_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
-> ComputeEntryPoint<'a, S, L> {
ComputeEntryPoint {
module: self,
name: name,
layout: layout,
@ -241,9 +138,7 @@ impl<P> ShaderModule<P>
}
}
unsafe impl<P> VulkanObject for ShaderModule<P>
where P: SafeDeref<Target = Device>
{
unsafe impl VulkanObject for ShaderModule {
type Object = vk::ShaderModule;
#[inline]
@ -252,9 +147,7 @@ unsafe impl<P> VulkanObject for ShaderModule<P>
}
}
impl<P> Drop for ShaderModule<P>
where P: SafeDeref<Target = Device>
{
impl Drop for ShaderModule {
#[inline]
fn drop(&mut self) {
unsafe {
@ -264,213 +157,95 @@ impl<P> Drop for ShaderModule<P>
}
}
/// Represents the entry point of a vertex shader in a shader module.
pub unsafe trait GraphicsEntryPointAbstract: EntryPointAbstract {
type InputDefinition: ShaderInterfaceDef;
type OutputDefinition: ShaderInterfaceDef;
/// Returns the input attributes used by the shader stage.
fn input(&self) -> &Self::InputDefinition;
/// Returns the output attributes used by the shader stage.
fn output(&self) -> &Self::OutputDefinition;
/// Returns the type of shader.
fn ty(&self) -> GraphicsShaderType;
}
/// Represents a shader entry point in a shader module.
///
/// Can be obtained by calling `vertex_shader_entry_point()` on the shader module.
/// Can be obtained by calling `entry_point()` on the shader module.
#[derive(Debug, Copy, Clone)]
pub struct VertexShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
pub struct GraphicsEntryPoint<'a, S, I, O, L> {
module: &'a ShaderModule,
name: &'a CStr,
input: I,
layout: L,
output: O,
ty: GraphicsShaderType,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> VertexShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
unsafe impl<'a, S, I, O, L> EntryPointAbstract for GraphicsEntryPoint<'a, S, I, O, L>
where L: PipelineLayoutDescNames,
I: ShaderInterfaceDef,
O: ShaderInterfaceDef,
S: SpecializationConstants,
{
/// Returns the module this entry point comes from.
type PipelineLayout = L;
type SpecializationConstants = S;
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
fn module(&self) -> &ShaderModule {
self.module
}
/// Returns the name of the entry point.
#[inline]
pub fn name(&self) -> &'a CStr {
fn name(&self) -> &CStr {
self.name
}
/// Returns the pipeline layout used by the shader stage.
#[inline]
pub fn layout(&self) -> &L {
fn layout(&self) -> &L {
&self.layout
}
}
unsafe impl<'a, S, I, O, L> GraphicsEntryPointAbstract for GraphicsEntryPoint<'a, S, I, O, L>
where L: PipelineLayoutDescNames,
I: ShaderInterfaceDef,
O: ShaderInterfaceDef,
S: SpecializationConstants,
{
type InputDefinition = I;
type OutputDefinition = O;
/// Returns the input attributes used by the shader stage.
// TODO: rename "input" for consistency
#[inline]
pub fn input_definition(&self) -> &I {
fn input(&self) -> &I {
&self.input
}
/// Returns the output attributes used by the shader stage.
#[inline]
pub fn output(&self) -> &O {
fn output(&self) -> &O {
&self.output
}
}
/// Represents the entry point of a tessellation control shader in a shader module.
///
/// Can be obtained by calling `tess_control_shader_entry_point()` on the shader module.
#[derive(Debug, Copy, Clone)]
pub struct TessControlShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> TessControlShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
/// Returns the module this entry point comes from.
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
/// Returns the name of the entry point.
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
/// Returns the pipeline layout used by the shader stage.
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
/// Returns the input attributes used by the shader stage.
#[inline]
pub fn input(&self) -> &I {
&self.input
}
/// Returns the output attributes used by the shader stage.
#[inline]
pub fn output(&self) -> &O {
&self.output
fn ty(&self) -> GraphicsShaderType {
self.ty
}
}
/// Represents the entry point of a tessellation evaluation shader in a shader module.
///
/// Can be obtained by calling `tess_evaluation_shader_entry_point()` on the shader module.
#[derive(Debug, Copy, Clone)]
pub struct TessEvaluationShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> TessEvaluationShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
/// Returns the module this entry point comes from.
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
/// Returns the name of the entry point.
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
/// Returns the pipeline layout used by the shader stage.
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
/// Returns the input attributes used by the shader stage.
#[inline]
pub fn input(&self) -> &I {
&self.input
}
/// Returns the output attributes used by the shader stage.
#[inline]
pub fn output(&self) -> &O {
&self.output
}
}
/// Represents the entry point of a geometry shader in a shader module.
///
/// Can be obtained by calling `geometry_shader_entry_point()` on the shader module.
#[derive(Debug, Copy, Clone)]
pub struct GeometryShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
primitives: GeometryShaderExecutionMode,
input: I,
output: O,
marker: PhantomData<S>,
}
impl<'a, S, I, O, L, P> GeometryShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
/// Returns the module this entry point comes from.
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
/// Returns the name of the entry point.
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
/// Returns the kind of primitives expected by the geometry shader.
#[inline]
pub fn primitives(&self) -> GeometryShaderExecutionMode {
self.primitives
}
/// Returns the pipeline layout used by the shader stage.
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
/// Returns the input attributes used by the shader stage.
#[inline]
pub fn input(&self) -> &I {
&self.input
}
/// Returns the output attributes used by the shader stage.
#[inline]
pub fn output(&self) -> &O {
&self.output
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum GraphicsShaderType {
Vertex,
TessellationControl,
TessellationEvaluation,
Geometry(GeometryShaderExecutionMode),
Fragment,
}
/// Declares which type of primitives are expected by the geometry shader.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[doc(hidden)]
pub enum GeometryShaderExecutionMode {
Points,
Lines,
@ -503,90 +278,105 @@ impl GeometryShaderExecutionMode {
}
}
/// Represents the entry point of a fragment shader in a shader module.
///
/// Can be obtained by calling `fragment_shader_entry_point()` on the shader module.
#[derive(Debug, Copy, Clone)]
pub struct FragmentShaderEntryPoint<'a, S, I, O, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
name: &'a CStr,
layout: L,
input: I,
output: O,
marker: PhantomData<S>,
}
pub unsafe trait EntryPointAbstract {
type PipelineLayout: PipelineLayoutDescNames;
type SpecializationConstants: SpecializationConstants;
impl<'a, S, I, O, L, P> FragmentShaderEntryPoint<'a, S, I, O, L, P>
where P: 'a + SafeDeref<Target = Device>
{
/// Returns the module this entry point comes from.
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
self.module
}
fn module(&self) -> &ShaderModule;
/// Returns the name of the entry point.
#[inline]
pub fn name(&self) -> &'a CStr {
self.name
}
fn name(&self) -> &CStr;
/// Returns the pipeline layout used by the shader stage.
#[inline]
pub fn layout(&self) -> &L {
&self.layout
}
/// Returns the input attributes used by the shader stage.
#[inline]
pub fn input(&self) -> &I {
&self.input
}
/// Returns the output attributes used by the shader stage.
#[inline]
pub fn output(&self) -> &O {
&self.output
}
fn layout(&self) -> &Self::PipelineLayout;
}
/// Represents the entry point of a compute shader in a shader module.
///
/// Can be obtained by calling `compute_shader_entry_point()` on the shader module.
#[derive(Debug, Copy, Clone)]
pub struct ComputeShaderEntryPoint<'a, S, L, P = Arc<Device>>
where P: 'a + SafeDeref<Target = Device>
{
module: &'a ShaderModule<P>,
pub struct ComputeEntryPoint<'a, S, L> {
module: &'a ShaderModule,
name: &'a CStr,
layout: L,
marker: PhantomData<S>,
}
impl<'a, S, L, P> ComputeShaderEntryPoint<'a, S, L, P>
where P: 'a + SafeDeref<Target = Device>
unsafe impl<'a, S, L> EntryPointAbstract for ComputeEntryPoint<'a, S, L>
where L: PipelineLayoutDescNames,
S: SpecializationConstants,
{
/// Returns the module this entry point comes from.
type PipelineLayout = L;
type SpecializationConstants = S;
#[inline]
pub fn module(&self) -> &'a ShaderModule<P> {
fn module(&self) -> &ShaderModule {
self.module
}
/// Returns the name of the entry point.
#[inline]
pub fn name(&self) -> &'a CStr {
fn name(&self) -> &CStr {
self.name
}
/// Returns the pipeline layout used by the shader stage.
#[inline]
pub fn layout(&self) -> &L {
fn layout(&self) -> &L {
&self.layout
}
}
/// A dummy that implements `GraphicsEntryPointAbstract` and `EntryPointAbstract`.
///
/// When a function has a signature like: `fn foo<S: EntryPointAbstract>(shader: Option<S>)`, you
/// can pass `None::<EmptyEntryPointDummy>`.
///
/// This object is meant to be a replacement to `!` before it is stabilized.
// TODO: ^
#[derive(Debug, Copy, Clone)]
pub enum EmptyEntryPointDummy {
}
unsafe impl EntryPointAbstract for EmptyEntryPointDummy {
type PipelineLayout = EmptyPipelineDesc;
type SpecializationConstants = ();
#[inline]
fn module(&self) -> &ShaderModule {
unreachable!()
}
#[inline]
fn name(&self) -> &CStr {
unreachable!()
}
#[inline]
fn layout(&self) -> &EmptyPipelineDesc {
unreachable!()
}
}
unsafe impl GraphicsEntryPointAbstract for EmptyEntryPointDummy {
type InputDefinition = EmptyShaderInterfaceDef;
type OutputDefinition = EmptyShaderInterfaceDef;
#[inline]
fn input(&self) -> &EmptyShaderInterfaceDef {
unreachable!()
}
#[inline]
fn output(&self) -> &EmptyShaderInterfaceDef {
unreachable!()
}
#[inline]
fn ty(&self) -> GraphicsShaderType {
unreachable!()
}
}
/// Types that contain the definition of an interface between two shader stages, or between
/// the outside and a shader stage.
///