Make specialization constants work (#780)

* Add new template parameters for GraphicsPipelineBuilder

* Add support for the specialization constants in build()

* Fix SpecializationConstants fields being private

* Fix lifetime problem in SpecializationConstants::descriptors()

* Run rustfmt on builder.rs
This commit is contained in:
tomaka 2017-08-27 10:04:18 +02:00 committed by GitHub
parent a54281f8ec
commit 2cbdb288d4
3 changed files with 334 additions and 232 deletions

View File

@ -122,17 +122,19 @@ impl Default for SpecializationConstants {{
unsafe impl SpecConstsTrait for SpecializationConstants {{ unsafe impl SpecConstsTrait for SpecializationConstants {{
fn descriptors() -> &'static [SpecializationMapEntry] {{ fn descriptors() -> &'static [SpecializationMapEntry] {{
&[ static DESCRIPTORS: [SpecializationMapEntry; {num_map_entries}] = [
{map_entries} {map_entries}
] ];
&DESCRIPTORS
}} }}
}} }}
"#, "#,
struct_def = spec_consts.iter().map(|c| format!("{}: {}", c.name, c.rust_ty)) struct_def = spec_consts.iter().map(|c| format!("pub {}: {}", c.name, c.rust_ty))
.collect::<Vec<_>>().join(", "), .collect::<Vec<_>>().join(", "),
def_vals = spec_consts.iter().map(|c| format!("{}: {}", c.name, c.default_value)) def_vals = spec_consts.iter().map(|c| format!("{}: {}", c.name, c.default_value))
.collect::<Vec<_>>().join(", "), .collect::<Vec<_>>().join(", "),
num_map_entries = map_entries.len(),
map_entries = map_entries.join(", ") map_entries = map_entries.join(", ")
) )
} }

View File

@ -29,8 +29,8 @@ use pipeline::depth_stencil::Compare;
use pipeline::depth_stencil::DepthBounds; use pipeline::depth_stencil::DepthBounds;
use pipeline::depth_stencil::DepthStencil; use pipeline::depth_stencil::DepthStencil;
use pipeline::graphics_pipeline::GraphicsPipeline; use pipeline::graphics_pipeline::GraphicsPipeline;
use pipeline::graphics_pipeline::Inner as GraphicsPipelineInner;
use pipeline::graphics_pipeline::GraphicsPipelineCreationError; use pipeline::graphics_pipeline::GraphicsPipelineCreationError;
use pipeline::graphics_pipeline::Inner as GraphicsPipelineInner;
use pipeline::input_assembly::InputAssembly; use pipeline::input_assembly::InputAssembly;
use pipeline::input_assembly::PrimitiveTopology; use pipeline::input_assembly::PrimitiveTopology;
use pipeline::multisample::Multisample; use pipeline::multisample::Multisample;
@ -43,6 +43,7 @@ use pipeline::shader::EmptyEntryPointDummy;
use pipeline::shader::GraphicsEntryPointAbstract; use pipeline::shader::GraphicsEntryPointAbstract;
use pipeline::shader::GraphicsShaderType; use pipeline::shader::GraphicsShaderType;
use pipeline::shader::ShaderInterfaceDefMatch; use pipeline::shader::ShaderInterfaceDefMatch;
use pipeline::shader::SpecializationConstants;
use pipeline::vertex::SingleBufferDefinition; use pipeline::vertex::SingleBufferDefinition;
use pipeline::vertex::VertexDefinition; use pipeline::vertex::VertexDefinition;
use pipeline::viewport::Scissor; use pipeline::viewport::Scissor;
@ -58,24 +59,16 @@ use vk;
/// Prototype for a `GraphicsPipeline`. /// Prototype for a `GraphicsPipeline`.
// TODO: we can optimize this by filling directly the raw vk structs // TODO: we can optimize this by filling directly the raw vk structs
pub struct GraphicsPipelineBuilder< pub struct GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> {
Vdef,
Vs,
Tcs,
Tes,
Gs,
Fs,
Rp>
{
vertex_input: Vdef, vertex_input: Vdef,
vertex_shader: Option<Vs>, vertex_shader: Option<(Vs, Vss)>,
input_assembly: InputAssembly, input_assembly: InputAssembly,
tessellation: Option<TessInfo<Tcs, Tes>>, tessellation: Option<TessInfo<Tcs, Tcss, Tes, Tess>>,
geometry_shader: Option<Gs>, geometry_shader: Option<(Gs, Gss)>,
viewport: Option<ViewportsState>, viewport: Option<ViewportsState>,
raster: Rasterization, raster: Rasterization,
multisample: Multisample, multisample: Multisample,
fragment_shader: Option<Fs>, fragment_shader: Option<(Fs, Fss)>,
depth_stencil: DepthStencil, depth_stencil: DepthStencil,
blend: Blend, blend: Blend,
render_pass: Option<Subpass<Rp>>, render_pass: Option<Subpass<Rp>>,
@ -83,18 +76,24 @@ pub struct GraphicsPipelineBuilder<
// Additional parameters if tessellation is used. // Additional parameters if tessellation is used.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct TessInfo<Tcs, Tes> { struct TessInfo<Tcs, Tcss, Tes, Tess> {
tessellation_control_shader: Tcs, tessellation_control_shader: (Tcs, Tcss),
tessellation_evaluation_shader: Tes, tessellation_evaluation_shader: (Tes, Tess),
} }
impl GraphicsPipelineBuilder<SingleBufferDefinition<()>, impl
EmptyEntryPointDummy, GraphicsPipelineBuilder<SingleBufferDefinition<()>,
EmptyEntryPointDummy, EmptyEntryPointDummy,
EmptyEntryPointDummy, (),
EmptyEntryPointDummy, EmptyEntryPointDummy,
EmptyEntryPointDummy, (),
()> { EmptyEntryPointDummy,
(),
EmptyEntryPointDummy,
(),
EmptyEntryPointDummy,
(),
()> {
/// Builds a new empty builder. /// Builds a new empty builder.
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
@ -114,26 +113,19 @@ impl GraphicsPipelineBuilder<SingleBufferDefinition<()>,
} }
} }
impl<Vdef, impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
Vs, GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
Tcs,
Tes,
Gs,
Fs,
Rp>
GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tes,
Gs,
Fs,
Rp>
where Vdef: VertexDefinition<Vs::InputDefinition>, where Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract, Vs: GraphicsEntryPointAbstract,
Fs: GraphicsEntryPointAbstract, Fs: GraphicsEntryPointAbstract,
Gs: GraphicsEntryPointAbstract, Gs: GraphicsEntryPointAbstract,
Tcs: GraphicsEntryPointAbstract, Tcs: GraphicsEntryPointAbstract,
Tes: GraphicsEntryPointAbstract, Tes: GraphicsEntryPointAbstract,
Vss: SpecializationConstants,
Tcss: SpecializationConstants,
Tess: SpecializationConstants,
Gss: SpecializationConstants,
Fss: SpecializationConstants,
Vs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required Vs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
Fs::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 Tcs::PipelineLayout: Clone + 'static + Send + Sync, // TODO: shouldn't be required
@ -141,10 +133,11 @@ impl<Vdef,
Gs::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>, Tcs::InputDefinition: ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Tes::InputDefinition: ShaderInterfaceDefMatch<Tcs::OutputDefinition>, Tes::InputDefinition: ShaderInterfaceDefMatch<Tcs::OutputDefinition>,
Gs::InputDefinition: ShaderInterfaceDefMatch<Tes::OutputDefinition> + ShaderInterfaceDefMatch<Vs::OutputDefinition>, Gs::InputDefinition: ShaderInterfaceDefMatch<Tes::OutputDefinition>
+ ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Fs::InputDefinition: ShaderInterfaceDefMatch<Gs::OutputDefinition> Fs::InputDefinition: ShaderInterfaceDefMatch<Gs::OutputDefinition>
+ ShaderInterfaceDefMatch<Tes::OutputDefinition> + ShaderInterfaceDefMatch<Tes::OutputDefinition>
+ ShaderInterfaceDefMatch<Vs::OutputDefinition>, + ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fs::OutputDefinition> Rp: RenderPassAbstract + RenderPassSubpassInterface<Fs::OutputDefinition>
{ {
/// Builds the graphics pipeline. /// Builds the graphics pipeline.
@ -161,126 +154,165 @@ impl<Vdef,
if let Some(ref tess) = self.tessellation { if let Some(ref tess) = self.tessellation {
if let Some(ref gs) = self.geometry_shader { if let Some(ref gs) = self.geometry_shader {
if let Err(err) = tess.tessellation_control_shader if let Err(err) = tess.tessellation_control_shader
.0
.input() .input()
.matches(self.vertex_shader.as_ref().unwrap().output()) .matches(self.vertex_shader.as_ref().unwrap().0.output())
{ {
return Err(GraphicsPipelineCreationError::VertexTessControlStagesMismatch(err)); return Err(GraphicsPipelineCreationError::VertexTessControlStagesMismatch(err));
} }
if let Err(err) = tess.tessellation_evaluation_shader if let Err(err) = tess.tessellation_evaluation_shader
.0
.input() .input()
.matches(tess.tessellation_control_shader.output()) .matches(tess.tessellation_control_shader.0.output())
{ {
return Err(GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(err)); return Err(GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(err));
} }
if let Err(err) = gs.input() if let Err(err) = gs.0
.matches(tess.tessellation_evaluation_shader.output()) .input()
.matches(tess.tessellation_evaluation_shader.0.output())
{ {
return Err(GraphicsPipelineCreationError::TessEvalGeometryStagesMismatch(err)); return Err(GraphicsPipelineCreationError::TessEvalGeometryStagesMismatch(err));
} }
if let Err(err) = self.fragment_shader.as_ref().unwrap().input().matches(gs.output()) { if let Err(err) = self.fragment_shader
.as_ref()
.unwrap()
.0
.input()
.matches(gs.0.output())
{
return Err(GraphicsPipelineCreationError::GeometryFragmentStagesMismatch(err)); return Err(GraphicsPipelineCreationError::GeometryFragmentStagesMismatch(err));
} }
pipeline_layout = Box::new(self.vertex_shader.as_ref().unwrap().layout().clone() pipeline_layout = Box::new(self.vertex_shader.as_ref().unwrap().0.layout().clone()
.union(self.fragment_shader.as_ref().unwrap().layout().clone()) .union(self.fragment_shader.as_ref().unwrap().0.layout().clone())
.union(self.tessellation.as_ref().unwrap().tessellation_control_shader.layout().clone()) // FIXME: unwrap() .union(self.tessellation.as_ref().unwrap().tessellation_control_shader.0.layout().clone()) // FIXME: unwrap()
.union(self.tessellation.as_ref().unwrap().tessellation_evaluation_shader.layout().clone()) // FIXME: unwrap() .union(self.tessellation.as_ref().unwrap().tessellation_evaluation_shader.0.layout().clone()) // FIXME: unwrap()
.union(self.geometry_shader.as_ref().unwrap().layout().clone()) // FIXME: unwrap() .union(self.geometry_shader.as_ref().unwrap().0.layout().clone()) // FIXME: unwrap()
.build(device.clone()).unwrap()) as Box<_>; // TODO: error .build(device.clone()).unwrap()) as Box<_>; // TODO: error
} else { } else {
if let Err(err) = tess.tessellation_control_shader if let Err(err) = tess.tessellation_control_shader
.0
.input() .input()
.matches(self.vertex_shader.as_ref().unwrap().output()) .matches(self.vertex_shader.as_ref().unwrap().0.output())
{ {
return Err(GraphicsPipelineCreationError::VertexTessControlStagesMismatch(err)); return Err(GraphicsPipelineCreationError::VertexTessControlStagesMismatch(err));
} }
if let Err(err) = tess.tessellation_evaluation_shader if let Err(err) = tess.tessellation_evaluation_shader
.0
.input() .input()
.matches(tess.tessellation_control_shader.output()) .matches(tess.tessellation_control_shader.0.output())
{ {
return Err(GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(err)); return Err(GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(err));
} }
if let Err(err) = self if let Err(err) = self.fragment_shader
.fragment_shader .as_ref()
.as_ref().unwrap() .unwrap()
.0
.input() .input()
.matches(tess.tessellation_evaluation_shader.output()) .matches(tess.tessellation_evaluation_shader.0.output())
{ {
return Err(GraphicsPipelineCreationError::TessEvalFragmentStagesMismatch(err)); return Err(GraphicsPipelineCreationError::TessEvalFragmentStagesMismatch(err));
} }
pipeline_layout = Box::new(self.vertex_shader.as_ref().unwrap().layout().clone() pipeline_layout = Box::new(self.vertex_shader.as_ref().unwrap().0.layout().clone()
.union(self.fragment_shader.as_ref().unwrap().layout().clone()) .union(self.fragment_shader.as_ref().unwrap().0.layout().clone())
.union(self.tessellation.as_ref().unwrap().tessellation_control_shader.layout().clone()) // FIXME: unwrap() .union(self.tessellation.as_ref().unwrap().tessellation_control_shader.0.layout().clone()) // FIXME: unwrap()
.union(self.tessellation.as_ref().unwrap().tessellation_evaluation_shader.layout().clone()) // FIXME: unwrap() .union(self.tessellation.as_ref().unwrap().tessellation_evaluation_shader.0.layout().clone()) // FIXME: unwrap()
.build(device.clone()).unwrap()) as Box<_>; // TODO: error .build(device.clone()).unwrap()) as Box<_>; // TODO: error
} }
} else { } else {
if let Some(ref geometry_shader) = self.geometry_shader { if let Some(ref geometry_shader) = self.geometry_shader {
if let Err(err) = geometry_shader if let Err(err) = geometry_shader
.0
.input() .input()
.matches(self.vertex_shader.as_ref().unwrap().output()) .matches(self.vertex_shader.as_ref().unwrap().0.output())
{ {
return Err(GraphicsPipelineCreationError::VertexGeometryStagesMismatch(err)); return Err(GraphicsPipelineCreationError::VertexGeometryStagesMismatch(err));
} }
if let Err(err) = self if let Err(err) = self.fragment_shader
.fragment_shader .as_ref()
.as_ref().unwrap() .unwrap()
.0
.input() .input()
.matches(geometry_shader.output()) .matches(geometry_shader.0.output())
{ {
return Err(GraphicsPipelineCreationError::GeometryFragmentStagesMismatch(err)); return Err(GraphicsPipelineCreationError::GeometryFragmentStagesMismatch(err));
} }
pipeline_layout = Box::new(self.vertex_shader.as_ref().unwrap().layout().clone() pipeline_layout = Box::new(self.vertex_shader.as_ref().unwrap().0.layout().clone()
.union(self.fragment_shader.as_ref().unwrap().layout().clone()) .union(self.fragment_shader.as_ref().unwrap().0.layout().clone())
.union(self.geometry_shader.as_ref().unwrap().layout().clone()) // FIXME: unwrap() .union(self.geometry_shader.as_ref().unwrap().0.layout().clone()) // FIXME: unwrap()
.build(device.clone()).unwrap()) as Box<_>; // TODO: error .build(device.clone()).unwrap()) as Box<_>; // TODO: error
} else { } else {
if let Err(err) = self if let Err(err) = self.fragment_shader
.fragment_shader .as_ref()
.as_ref().unwrap() .unwrap()
.0
.input() .input()
.matches(self.vertex_shader.as_ref().unwrap().output()) .matches(self.vertex_shader.as_ref().unwrap().0.output())
{ {
return Err(GraphicsPipelineCreationError::VertexFragmentStagesMismatch(err)); return Err(GraphicsPipelineCreationError::VertexFragmentStagesMismatch(err));
} }
pipeline_layout = Box::new(self pipeline_layout =
.vertex_shader Box::new(self.vertex_shader
.as_ref().unwrap() .as_ref()
.layout() .unwrap()
.clone() .0
.union(self.fragment_shader.as_ref().unwrap().layout().clone()) .layout()
.build(device.clone()) .clone()
.unwrap()) as Box<_>; // TODO: error .union(self.fragment_shader.as_ref().unwrap().0.layout().clone())
.build(device.clone())
.unwrap()) as Box<_>; // TODO: error
} }
} }
// Checking that the pipeline layout matches the shader stages. // Checking that the pipeline layout matches the shader stages.
// TODO: more details in the errors // TODO: more details in the errors
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout, PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
self.vertex_shader.as_ref().unwrap().layout())?; self.vertex_shader
.as_ref()
.unwrap()
.0
.layout())?;
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout, PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
self.fragment_shader.as_ref().unwrap().layout())?; self.fragment_shader
.as_ref()
.unwrap()
.0
.layout())?;
if let Some(ref geometry_shader) = self.geometry_shader { if let Some(ref geometry_shader) = self.geometry_shader {
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout, geometry_shader.layout())?; PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
geometry_shader.0.layout())?;
} }
if let Some(ref tess) = self.tessellation { if let Some(ref tess) = self.tessellation {
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout, PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
tess.tessellation_control_shader.layout())?; tess.tessellation_control_shader
.0
.layout())?;
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout, PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
tess.tessellation_evaluation_shader tess.tessellation_evaluation_shader
.0
.layout())?; .layout())?;
} }
// Check that the subpass can accept the output of the fragment shader. // Check that the subpass can accept the output of the fragment shader.
if !RenderPassSubpassInterface::is_compatible_with(&self.render_pass.as_ref().unwrap().render_pass(), if !RenderPassSubpassInterface::is_compatible_with(&self.render_pass
self.render_pass.as_ref().unwrap().index(), .as_ref()
self.fragment_shader.as_ref().unwrap().output()) .unwrap()
.render_pass(),
self.render_pass
.as_ref()
.unwrap()
.index(),
self.fragment_shader
.as_ref()
.unwrap()
.0
.output())
{ {
return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible); return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible);
} }
@ -288,11 +320,70 @@ impl<Vdef,
// Will contain the list of dynamic states. Filled throughout this function. // Will contain the list of dynamic states. Filled throughout this function.
let mut dynamic_states: SmallVec<[vk::DynamicState; 8]> = SmallVec::new(); let mut dynamic_states: SmallVec<[vk::DynamicState; 8]> = SmallVec::new();
// Creating the specialization constants of the various stages.
let vertex_shader_specialization = {
let spec_descriptors = Vss::descriptors();
let constants = &self.vertex_shader.as_ref().unwrap().1;
vk::SpecializationInfo {
mapEntryCount: spec_descriptors.len() as u32,
pMapEntries: spec_descriptors.as_ptr() as *const _,
dataSize: mem::size_of_val(constants),
pData: constants as *const Vss as *const _,
}
};
let tess_shader_specialization = if let Some(ref tess) = self.tessellation {
let tcs_spec = {
let spec_descriptors = Tcss::descriptors();
let constants = &tess.tessellation_control_shader.1;
vk::SpecializationInfo {
mapEntryCount: spec_descriptors.len() as u32,
pMapEntries: spec_descriptors.as_ptr() as *const _,
dataSize: mem::size_of_val(constants),
pData: constants as *const Tcss as *const _,
}
};
let tes_spec = {
let spec_descriptors = Tess::descriptors();
let constants = &tess.tessellation_evaluation_shader.1;
vk::SpecializationInfo {
mapEntryCount: spec_descriptors.len() as u32,
pMapEntries: spec_descriptors.as_ptr() as *const _,
dataSize: mem::size_of_val(constants),
pData: constants as *const Tess as *const _,
}
};
Some((tcs_spec, tes_spec))
} else {
None
};
let geometry_shader_specialization = if let Some(ref gs) = self.geometry_shader {
let spec_descriptors = Gss::descriptors();
let constants = &gs.1;
Some(vk::SpecializationInfo {
mapEntryCount: spec_descriptors.len() as u32,
pMapEntries: spec_descriptors.as_ptr() as *const _,
dataSize: mem::size_of_val(constants),
pData: constants as *const Gss as *const _,
})
} else {
None
};
let fragment_shader_specialization = {
let spec_descriptors = Fss::descriptors();
let constants = &self.fragment_shader.as_ref().unwrap().1;
vk::SpecializationInfo {
mapEntryCount: spec_descriptors.len() as u32,
pMapEntries: spec_descriptors.as_ptr() as *const _,
dataSize: mem::size_of_val(constants),
pData: constants as *const Fss as *const _,
}
};
// List of shader stages. // List of shader stages.
let stages = { let stages = {
let mut stages = SmallVec::<[_; 5]>::new(); let mut stages = SmallVec::<[_; 5]>::new();
match self.vertex_shader.as_ref().unwrap().ty() { match self.vertex_shader.as_ref().unwrap().0.ty() {
GraphicsShaderType::Vertex => {}, GraphicsShaderType::Vertex => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType), _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}; };
@ -302,12 +393,17 @@ impl<Vdef,
pNext: ptr::null(), pNext: ptr::null(),
flags: 0, // reserved flags: 0, // reserved
stage: vk::SHADER_STAGE_VERTEX_BIT, stage: vk::SHADER_STAGE_VERTEX_BIT,
module: self.vertex_shader.as_ref().unwrap().module().internal_object(), module: self.vertex_shader
pName: self.vertex_shader.as_ref().unwrap().name().as_ptr(), .as_ref()
pSpecializationInfo: ptr::null(), // TODO: .unwrap()
.0
.module()
.internal_object(),
pName: self.vertex_shader.as_ref().unwrap().0.name().as_ptr(),
pSpecializationInfo: &vertex_shader_specialization as *const _,
}); });
match self.fragment_shader.as_ref().unwrap().ty() { match self.fragment_shader.as_ref().unwrap().0.ty() {
GraphicsShaderType::Fragment => {}, GraphicsShaderType::Fragment => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType), _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}; };
@ -317,9 +413,14 @@ impl<Vdef,
pNext: ptr::null(), pNext: ptr::null(),
flags: 0, // reserved flags: 0, // reserved
stage: vk::SHADER_STAGE_FRAGMENT_BIT, stage: vk::SHADER_STAGE_FRAGMENT_BIT,
module: self.fragment_shader.as_ref().unwrap().module().internal_object(), module: self.fragment_shader
pName: self.fragment_shader.as_ref().unwrap().name().as_ptr(), .as_ref()
pSpecializationInfo: ptr::null(), // TODO: .unwrap()
.0
.module()
.internal_object(),
pName: self.fragment_shader.as_ref().unwrap().0.name().as_ptr(),
pSpecializationInfo: &fragment_shader_specialization as *const _,
}); });
if let Some(ref gs) = self.geometry_shader { if let Some(ref gs) = self.geometry_shader {
@ -332,9 +433,12 @@ impl<Vdef,
pNext: ptr::null(), pNext: ptr::null(),
flags: 0, // reserved flags: 0, // reserved
stage: vk::SHADER_STAGE_GEOMETRY_BIT, stage: vk::SHADER_STAGE_GEOMETRY_BIT,
module: gs.module().internal_object(), module: gs.0.module().internal_object(),
pName: gs.name().as_ptr(), pName: gs.0.name().as_ptr(),
pSpecializationInfo: ptr::null(), // TODO: pSpecializationInfo: geometry_shader_specialization
.as_ref()
.unwrap() as
*const _,
}); });
} }
@ -345,12 +449,12 @@ impl<Vdef,
return Err(GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled); return Err(GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled);
} }
match tess.tessellation_control_shader.ty() { match tess.tessellation_control_shader.0.ty() {
GraphicsShaderType::TessellationControl => {}, GraphicsShaderType::TessellationControl => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType), _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}; };
match tess.tessellation_evaluation_shader.ty() { match tess.tessellation_evaluation_shader.0.ty() {
GraphicsShaderType::TessellationControl => {}, GraphicsShaderType::TessellationControl => {},
_ => return Err(GraphicsPipelineCreationError::WrongShaderType), _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}; };
@ -360,9 +464,16 @@ impl<Vdef,
pNext: ptr::null(), pNext: ptr::null(),
flags: 0, // reserved flags: 0, // reserved
stage: vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT, stage: vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT,
module: tess.tessellation_control_shader.module().internal_object(), module: tess.tessellation_control_shader
pName: tess.tessellation_control_shader.name().as_ptr(), .0
pSpecializationInfo: ptr::null(), // TODO: .module()
.internal_object(),
pName: tess.tessellation_control_shader.0.name().as_ptr(),
pSpecializationInfo: &tess_shader_specialization
.as_ref()
.unwrap()
.0 as
*const _,
}); });
stages.push(vk::PipelineShaderStageCreateInfo { stages.push(vk::PipelineShaderStageCreateInfo {
@ -371,10 +482,15 @@ impl<Vdef,
flags: 0, // reserved flags: 0, // reserved
stage: vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT, stage: vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
module: tess.tessellation_evaluation_shader module: tess.tessellation_evaluation_shader
.0
.module() .module()
.internal_object(), .internal_object(),
pName: tess.tessellation_evaluation_shader.name().as_ptr(), pName: tess.tessellation_evaluation_shader.0.name().as_ptr(),
pSpecializationInfo: ptr::null(), // TODO: pSpecializationInfo: &tess_shader_specialization
.as_ref()
.unwrap()
.1 as
*const _,
}); });
} }
@ -384,9 +500,8 @@ impl<Vdef,
// Vertex bindings. // Vertex bindings.
let (binding_descriptions, attribute_descriptions) = { let (binding_descriptions, attribute_descriptions) = {
let (buffers_iter, attribs_iter) = let (buffers_iter, attribs_iter) =
self self.vertex_input
.vertex_input .definition(self.vertex_shader.as_ref().unwrap().0.input())?;
.definition(self.vertex_shader.as_ref().unwrap().input())?;
let mut binding_descriptions = SmallVec::<[_; 8]>::new(); let mut binding_descriptions = SmallVec::<[_; 8]>::new();
for (num, stride, rate) in buffers_iter { for (num, stride, rate) in buffers_iter {
@ -494,7 +609,7 @@ impl<Vdef,
// TODO: should check from the tess eval shader instead of the input assembly // TODO: should check from the tess eval shader instead of the input assembly
if let Some(ref gs) = self.geometry_shader { if let Some(ref gs) = self.geometry_shader {
match gs.ty() { match gs.0.ty() {
GraphicsShaderType::Geometry(primitives) => { GraphicsShaderType::Geometry(primitives) => {
if !primitives.matches(self.input_assembly.topology) { if !primitives.matches(self.input_assembly.topology) {
return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader); return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader);
@ -760,7 +875,9 @@ impl<Vdef,
_ => return Err(GraphicsPipelineCreationError::WrongStencilState), _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
}; };
if self.depth_stencil.depth_write && !self.render_pass.as_ref().unwrap().has_writable_depth() { if self.depth_stencil.depth_write &&
!self.render_pass.as_ref().unwrap().has_writable_depth()
{
return Err(GraphicsPipelineCreationError::NoDepthAttachment); return Err(GraphicsPipelineCreationError::NoDepthAttachment);
} }
@ -809,13 +926,11 @@ impl<Vdef,
passOp: self.depth_stencil.stencil_front.pass_op as u32, passOp: self.depth_stencil.stencil_front.pass_op as u32,
depthFailOp: self.depth_stencil.stencil_front.depth_fail_op as u32, depthFailOp: self.depth_stencil.stencil_front.depth_fail_op as u32,
compareOp: self.depth_stencil.stencil_front.compare as u32, compareOp: self.depth_stencil.stencil_front.compare as u32,
compareMask: self compareMask: self.depth_stencil
.depth_stencil
.stencil_front .stencil_front
.compare_mask .compare_mask
.unwrap_or(u32::MAX), .unwrap_or(u32::MAX),
writeMask: self writeMask: self.depth_stencil
.depth_stencil
.stencil_front .stencil_front
.write_mask .write_mask
.unwrap_or(u32::MAX), .unwrap_or(u32::MAX),
@ -826,13 +941,11 @@ impl<Vdef,
passOp: self.depth_stencil.stencil_back.pass_op as u32, passOp: self.depth_stencil.stencil_back.pass_op as u32,
depthFailOp: self.depth_stencil.stencil_back.depth_fail_op as u32, depthFailOp: self.depth_stencil.stencil_back.depth_fail_op as u32,
compareOp: self.depth_stencil.stencil_back.compare as u32, compareOp: self.depth_stencil.stencil_back.compare as u32,
compareMask: self compareMask: self.depth_stencil
.depth_stencil
.stencil_back .stencil_back
.compare_mask .compare_mask
.unwrap_or(u32::MAX), .unwrap_or(u32::MAX),
writeMask: self writeMask: self.depth_stencil
.depth_stencil
.stencil_back .stencil_back
.write_mask .write_mask
.unwrap_or(u32::MAX), .unwrap_or(u32::MAX),
@ -848,7 +961,9 @@ impl<Vdef,
match self.blend.attachments { match self.blend.attachments {
AttachmentsBlend::Collective(blend) => { AttachmentsBlend::Collective(blend) => {
(0 .. num_atch).map(|_| blend.clone().into_vulkan_state()).collect() (0 .. num_atch)
.map(|_| blend.clone().into_vulkan_state())
.collect()
}, },
AttachmentsBlend::Individual(blend) => { AttachmentsBlend::Individual(blend) => {
if blend.len() != num_atch as usize { if blend.len() != num_atch as usize {
@ -859,7 +974,10 @@ impl<Vdef,
return Err(GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled); return Err(GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled);
} }
blend.iter().map(|b| b.clone().into_vulkan_state()).collect() blend
.iter()
.map(|b| b.clone().into_vulkan_state())
.collect()
}, },
} }
}; };
@ -922,7 +1040,12 @@ impl<Vdef,
.map(|s| s as *const _) .map(|s| s as *const _)
.unwrap_or(ptr::null()), .unwrap_or(ptr::null()),
layout: PipelineLayoutAbstract::sys(&pipeline_layout).internal_object(), layout: PipelineLayoutAbstract::sys(&pipeline_layout).internal_object(),
renderPass: self.render_pass.as_ref().unwrap().render_pass().inner().internal_object(), renderPass: self.render_pass
.as_ref()
.unwrap()
.render_pass()
.inner()
.internal_object(),
subpass: self.render_pass.as_ref().unwrap().index(), subpass: self.render_pass.as_ref().unwrap().index(),
basePipelineHandle: 0, // TODO: basePipelineHandle: 0, // TODO:
basePipelineIndex: -1, // TODO: basePipelineIndex: -1, // TODO:
@ -941,64 +1064,43 @@ impl<Vdef,
let (render_pass, render_pass_subpass) = self.render_pass.take().unwrap().into(); let (render_pass, render_pass_subpass) = self.render_pass.take().unwrap().into();
Ok(GraphicsPipeline { Ok(GraphicsPipeline {
inner: GraphicsPipelineInner { inner: GraphicsPipelineInner {
device: device.clone(), device: device.clone(),
pipeline: pipeline, pipeline: pipeline,
}, },
layout: pipeline_layout, layout: pipeline_layout,
vertex_definition: self.vertex_input, vertex_definition: self.vertex_input,
render_pass: render_pass, render_pass: render_pass,
render_pass_subpass: render_pass_subpass, render_pass_subpass: render_pass_subpass,
dynamic_line_width: self.raster.line_width.is_none(), dynamic_line_width: self.raster.line_width.is_none(),
dynamic_viewport: self.viewport.as_ref().unwrap().dynamic_viewports(), dynamic_viewport: self.viewport.as_ref().unwrap().dynamic_viewports(),
dynamic_scissor: self.viewport.as_ref().unwrap().dynamic_scissors(), dynamic_scissor: self.viewport.as_ref().unwrap().dynamic_scissors(),
dynamic_depth_bias: self.raster.depth_bias.is_dynamic(), dynamic_depth_bias: self.raster.depth_bias.is_dynamic(),
dynamic_depth_bounds: self.depth_stencil.depth_bounds_test.is_dynamic(), dynamic_depth_bounds: self.depth_stencil.depth_bounds_test.is_dynamic(),
dynamic_stencil_compare_mask: self dynamic_stencil_compare_mask: self.depth_stencil.stencil_back.compare_mask.is_none(),
.depth_stencil dynamic_stencil_write_mask: self.depth_stencil.stencil_back.write_mask.is_none(),
.stencil_back dynamic_stencil_reference: self.depth_stencil.stencil_back.reference.is_none(),
.compare_mask dynamic_blend_constants: self.blend.blend_constants.is_none(),
.is_none(),
dynamic_stencil_write_mask: self.depth_stencil.stencil_back.write_mask.is_none(),
dynamic_stencil_reference: self.depth_stencil.stencil_back.reference.is_none(),
dynamic_blend_constants: self.blend.blend_constants.is_none(),
num_viewports: self.viewport.as_ref().unwrap().num_viewports(), num_viewports: self.viewport.as_ref().unwrap().num_viewports(),
}) })
} }
// TODO: add build_with_cache method // TODO: add build_with_cache method
} }
impl<Vdef, impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
Vs, GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> {
Tcs,
Tes,
Gs,
Fs,
Rp>
GraphicsPipelineBuilder<Vdef,
Vs,
Tcs,
Tes,
Gs,
Fs,
Rp> {
// TODO: add pipeline derivate system // TODO: add pipeline derivate system
/// Sets the vertex input. /// Sets the vertex input.
#[inline] #[inline]
pub fn vertex_input<T>(self, vertex_input: T) pub fn vertex_input<T>(
-> GraphicsPipelineBuilder<T, self, vertex_input: T)
Vs, -> GraphicsPipelineBuilder<T, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> {
Tcs,
Tes,
Gs,
Fs,
Rp> {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
vertex_input: vertex_input, vertex_input: vertex_input,
vertex_shader: self.vertex_shader, vertex_shader: self.vertex_shader,
@ -1023,10 +1125,15 @@ impl<Vdef,
pub fn vertex_input_single_buffer<V>(self) pub fn vertex_input_single_buffer<V>(self)
-> GraphicsPipelineBuilder<SingleBufferDefinition<V>, -> GraphicsPipelineBuilder<SingleBufferDefinition<V>,
Vs, Vs,
Vss,
Tcs, Tcs,
Tcss,
Tes, Tes,
Tess,
Gs, Gs,
Gss,
Fs, Fs,
Fss,
Rp> { Rp> {
self.vertex_input(SingleBufferDefinition::<V>::new()) self.vertex_input(SingleBufferDefinition::<V>::new())
} }
@ -1034,21 +1141,15 @@ impl<Vdef,
/// Sets the vertex shader to use. /// Sets the vertex shader to use.
// TODO: correct specialization constants // TODO: correct specialization constants
#[inline] #[inline]
pub fn vertex_shader<Vs2>(self, pub fn vertex_shader<Vs2, Vss2>(
shader: Vs2, self, shader: Vs2, specialization_constants: Vss2)
specialization_constants: ()) -> GraphicsPipelineBuilder<Vdef, Vs2, Vss2, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
-> GraphicsPipelineBuilder<Vdef, where Vs2: GraphicsEntryPointAbstract<SpecializationConstants = Vss2>,
Vs2, Vss2: SpecializationConstants
Tcs,
Tes,
Gs,
Fs,
Rp>
where Vs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{ {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
vertex_input: self.vertex_input, vertex_input: self.vertex_input,
vertex_shader: Some(shader), vertex_shader: Some((shader, specialization_constants)),
input_assembly: self.input_assembly, input_assembly: self.input_assembly,
tessellation: self.tessellation, tessellation: self.tessellation,
geometry_shader: self.geometry_shader, geometry_shader: self.geometry_shader,
@ -1179,22 +1280,27 @@ impl<Vdef,
/// Sets the tessellation shaders to use. /// Sets the tessellation shaders to use.
// TODO: correct specialization constants // TODO: correct specialization constants
#[inline] #[inline]
pub fn tessellation_shaders<Tcs2, Tes2>(self, pub fn tessellation_shaders<Tcs2, Tcss2, Tes2, Tess2>(
tessellation_control_shader: Tcs2, self, tessellation_control_shader: Tcs2,
tessellation_control_shader_spec_constants: (), tessellation_control_shader_spec_constants: Tcss2, tessellation_evaluation_shader: Tes2,
tessellation_evaluation_shader: Tes2, tessellation_evaluation_shader_spec_constants: Tess2)
tessellation_evaluation_shader_spec_constants: ()) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs2, Tcss2, Tes2, Tess2, Gs, Gss, Fs, Fss, Rp>
-> GraphicsPipelineBuilder<Vdef, Vs, Tcs2, Tes2, Gs, Fs, Rp> where Tcs2: GraphicsEntryPointAbstract<SpecializationConstants = Tcss2>,
where Tcs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>, Tes2: GraphicsEntryPointAbstract<SpecializationConstants = Tess2>,
Tes2: GraphicsEntryPointAbstract<SpecializationConstants = ()>, Tcss2: SpecializationConstants,
Tess2: SpecializationConstants
{ {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
vertex_input: self.vertex_input, vertex_input: self.vertex_input,
vertex_shader: self.vertex_shader, vertex_shader: self.vertex_shader,
input_assembly: self.input_assembly, input_assembly: self.input_assembly,
tessellation: Some(TessInfo { tessellation: Some(TessInfo {
tessellation_control_shader: tessellation_control_shader, tessellation_control_shader:
tessellation_evaluation_shader: tessellation_evaluation_shader, (tessellation_control_shader,
tessellation_control_shader_spec_constants),
tessellation_evaluation_shader:
(tessellation_evaluation_shader,
tessellation_evaluation_shader_spec_constants),
}), }),
geometry_shader: self.geometry_shader, geometry_shader: self.geometry_shader,
viewport: self.viewport, viewport: self.viewport,
@ -1217,24 +1323,18 @@ impl<Vdef,
/// Sets the geometry shader to use. /// Sets the geometry shader to use.
// TODO: correct specialization constants // TODO: correct specialization constants
#[inline] #[inline]
pub fn geometry_shader<Gs2>(self, pub fn geometry_shader<Gs2, Gss2>(
shader: Gs2, self, shader: Gs2, specialization_constants: Gss2)
specialization_constants: ()) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs2, Gss2, Fs, Fss, Rp>
-> GraphicsPipelineBuilder<Vdef, where Gs2: GraphicsEntryPointAbstract<SpecializationConstants = Gss2>,
Vs, Gss2: SpecializationConstants
Tcs,
Tes,
Gs2,
Fs,
Rp>
where Gs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{ {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
vertex_input: self.vertex_input, vertex_input: self.vertex_input,
vertex_shader: self.vertex_shader, vertex_shader: self.vertex_shader,
input_assembly: self.input_assembly, input_assembly: self.input_assembly,
tessellation: self.tessellation, tessellation: self.tessellation,
geometry_shader: Some(shader), geometry_shader: Some((shader, specialization_constants)),
viewport: self.viewport, viewport: self.viewport,
raster: self.raster, raster: self.raster,
multisample: self.multisample, multisample: self.multisample,
@ -1425,17 +1525,11 @@ impl<Vdef,
/// The fragment shader is run once for each pixel that is covered by each primitive. /// The fragment shader is run once for each pixel that is covered by each primitive.
// TODO: correct specialization constants // TODO: correct specialization constants
#[inline] #[inline]
pub fn fragment_shader<Fs2>(self, pub fn fragment_shader<Fs2, Fss2>(
shader: Fs2, self, shader: Fs2, specialization_constants: Fss2)
specialization_constants: ()) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs2, Fss2, Rp>
-> GraphicsPipelineBuilder<Vdef, where Fs2: GraphicsEntryPointAbstract<SpecializationConstants = Fss2>,
Vs, Fss2: SpecializationConstants
Tcs,
Tes,
Gs,
Fs2,
Rp>
where Fs2: GraphicsEntryPointAbstract<SpecializationConstants = ()>,
{ {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
vertex_input: self.vertex_input, vertex_input: self.vertex_input,
@ -1446,7 +1540,7 @@ impl<Vdef,
viewport: self.viewport, viewport: self.viewport,
raster: self.raster, raster: self.raster,
multisample: self.multisample, multisample: self.multisample,
fragment_shader: Some(shader), fragment_shader: Some((shader, specialization_constants)),
depth_stencil: self.depth_stencil, depth_stencil: self.depth_stencil,
blend: self.blend, blend: self.blend,
render_pass: self.render_pass, render_pass: self.render_pass,
@ -1549,14 +1643,9 @@ impl<Vdef,
/// Sets the render pass subpass to use. /// Sets the render pass subpass to use.
#[inline] #[inline]
pub fn render_pass<Rp2>(self, subpass: Subpass<Rp2>) pub fn render_pass<Rp2>(
-> GraphicsPipelineBuilder<Vdef, self, subpass: Subpass<Rp2>)
Vs, -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp2> {
Tcs,
Tes,
Gs,
Fs,
Rp2> {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {
vertex_input: self.vertex_input, vertex_input: self.vertex_input,
vertex_shader: self.vertex_shader, vertex_shader: self.vertex_shader,
@ -1574,9 +1663,20 @@ impl<Vdef,
} }
} }
impl<Vdef, Vs, Tcs, Tes, Gs, Fs, Rp> Clone for impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> Clone
GraphicsPipelineBuilder<Vdef, Vs, Tcs, Tes, Gs, Fs, Rp> for GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
where Vdef: Clone, Vs: Clone, Tcs: Clone, Tes: Clone, Gs: Clone, Fs: Clone, Rp: Clone where Vdef: Clone,
Vs: Clone,
Vss: Clone,
Tcs: Clone,
Tcss: Clone,
Tes: Clone,
Tess: Clone,
Gs: Clone,
Gss: Clone,
Fs: Clone,
Fss: Clone,
Rp: Clone
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
GraphicsPipelineBuilder { GraphicsPipelineBuilder {

View File

@ -84,11 +84,11 @@ impl GraphicsPipeline<(), (), ()> {
/// fill with the various parameters. /// fill with the various parameters.
pub fn start<'a>() pub fn start<'a>()
-> GraphicsPipelineBuilder<SingleBufferDefinition<()>, -> GraphicsPipelineBuilder<SingleBufferDefinition<()>,
EmptyEntryPointDummy, EmptyEntryPointDummy, (),
EmptyEntryPointDummy, EmptyEntryPointDummy, (),
EmptyEntryPointDummy, EmptyEntryPointDummy, (),
EmptyEntryPointDummy, EmptyEntryPointDummy, (),
EmptyEntryPointDummy, EmptyEntryPointDummy, (),
()> ()>
{ {
GraphicsPipelineBuilder::new() GraphicsPipelineBuilder::new()