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

View File

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