mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 14:24:18 +00:00
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:
parent
a54281f8ec
commit
2cbdb288d4
@ -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(", ")
|
||||
)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user