#![allow(deprecated)]
use crate::check_errors;
use crate::descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutCreateInfo};
use crate::device::Device;
use crate::format::NumericType;
use crate::pipeline::cache::PipelineCache;
use crate::pipeline::graphics::color_blend::{
AttachmentBlend, ColorBlendAttachmentState, ColorBlendState, ColorComponents, LogicOp,
};
use crate::pipeline::graphics::depth_stencil::DepthStencilState;
use crate::pipeline::graphics::discard_rectangle::DiscardRectangleState;
use crate::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use crate::pipeline::graphics::multisample::MultisampleState;
use crate::pipeline::graphics::rasterization::{
CullMode, FrontFace, PolygonMode, RasterizationState,
};
use crate::pipeline::graphics::tessellation::TessellationState;
use crate::pipeline::graphics::vertex_input::{
BuffersDefinition, Vertex, VertexDefinition, VertexInputState,
};
use crate::pipeline::graphics::viewport::{Scissor, Viewport, ViewportState};
use crate::pipeline::graphics::{GraphicsPipeline, GraphicsPipelineCreationError};
use crate::pipeline::layout::{PipelineLayout, PipelineLayoutCreateInfo, PushConstantRange};
use crate::pipeline::{DynamicState, PartialStateMode, StateMode};
use crate::render_pass::Subpass;
use crate::shader::{
DescriptorRequirements, EntryPoint, ShaderExecution, ShaderStage, SpecializationConstants,
SpecializationMapEntry,
};
use crate::DeviceSize;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::collections::{hash_map::Entry, HashMap};
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use std::u32;
#[derive(Debug)]
pub struct GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> {
subpass: Option<Subpass>,
cache: Option<Arc<PipelineCache>>,
vertex_shader: Option<(EntryPoint<'vs>, Vss)>,
tessellation_shaders: Option<TessellationShaders<'tcs, 'tes, Tcss, Tess>>,
geometry_shader: Option<(EntryPoint<'gs>, Gss)>,
fragment_shader: Option<(EntryPoint<'fs>, Fss)>,
vertex_input_state: Vdef,
input_assembly_state: InputAssemblyState,
tessellation_state: TessellationState,
viewport_state: ViewportState,
discard_rectangle_state: DiscardRectangleState,
rasterization_state: RasterizationState,
multisample_state: MultisampleState,
depth_stencil_state: DepthStencilState,
color_blend_state: ColorBlendState,
}
#[derive(Clone, Debug)]
struct TessellationShaders<'tcs, 'tes, Tcss, Tess> {
control: (EntryPoint<'tcs>, Tcss),
evaluation: (EntryPoint<'tes>, Tess),
}
impl
GraphicsPipelineBuilder<
'static,
'static,
'static,
'static,
'static,
VertexInputState,
(),
(),
(),
(),
(),
>
{
pub(super) fn new() -> Self {
GraphicsPipelineBuilder {
subpass: None,
cache: None,
vertex_shader: None,
tessellation_shaders: None,
geometry_shader: None,
fragment_shader: None,
vertex_input_state: Default::default(),
input_assembly_state: Default::default(),
tessellation_state: Default::default(),
viewport_state: Default::default(),
discard_rectangle_state: Default::default(),
rasterization_state: Default::default(),
multisample_state: Default::default(),
depth_stencil_state: Default::default(),
color_blend_state: Default::default(),
}
}
}
impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
where
Vdef: VertexDefinition,
Vss: SpecializationConstants,
Tcss: SpecializationConstants,
Tess: SpecializationConstants,
Gss: SpecializationConstants,
Fss: SpecializationConstants,
{
pub fn build(
self,
device: Arc<Device>,
) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> {
self.with_auto_layout(device, |_| {})
}
pub fn with_auto_layout<F>(
self,
device: Arc<Device>,
func: F,
) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError>
where
F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
{
let (set_layout_create_infos, push_constant_ranges) = {
let stages: SmallVec<[&EntryPoint; 5]> = [
self.vertex_shader.as_ref().map(|s| &s.0),
self.tessellation_shaders.as_ref().map(|s| &s.control.0),
self.tessellation_shaders.as_ref().map(|s| &s.evaluation.0),
self.geometry_shader.as_ref().map(|s| &s.0),
self.fragment_shader.as_ref().map(|s| &s.0),
]
.into_iter()
.flatten()
.collect();
let mut descriptor_requirements: HashMap<(u32, u32), DescriptorRequirements> =
HashMap::default();
for (loc, reqs) in stages
.iter()
.map(|shader| shader.descriptor_requirements())
.flatten()
{
match descriptor_requirements.entry(loc) {
Entry::Occupied(entry) => {
let previous = entry.into_mut();
*previous = previous.intersection(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
}
Entry::Vacant(entry) => {
entry.insert(reqs.clone());
}
}
}
let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
descriptor_requirements
.iter()
.map(|(&loc, reqs)| (loc, reqs)),
);
func(&mut set_layout_create_infos);
let mut range_map = HashMap::new();
for stage in stages.iter() {
if let Some(range) = stage.push_constant_requirements() {
match range_map.entry((range.offset, range.size)) {
Entry::Vacant(entry) => {
entry.insert(range.stages);
}
Entry::Occupied(mut entry) => {
*entry.get_mut() = *entry.get() | range.stages;
}
}
}
}
let push_constant_ranges: Vec<_> = range_map
.iter()
.map(|((offset, size), stages)| PushConstantRange {
stages: *stages,
offset: *offset,
size: *size,
})
.collect();
(set_layout_create_infos, push_constant_ranges)
};
let set_layouts = set_layout_create_infos
.into_iter()
.map(|desc| DescriptorSetLayout::new(device.clone(), desc))
.collect::<Result<Vec<_>, _>>()?;
let pipeline_layout = PipelineLayout::new(
device.clone(),
PipelineLayoutCreateInfo {
set_layouts,
push_constant_ranges,
..Default::default()
},
)
.unwrap();
self.with_pipeline_layout(device, pipeline_layout)
}
pub fn with_pipeline_layout(
mut self,
device: Arc<Device>,
pipeline_layout: Arc<PipelineLayout>,
) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> {
let fns = device.fns();
let subpass = self.subpass.take().expect("Missing subpass");
let self_vertex_input_state = self
.vertex_input_state
.definition(self.vertex_shader.as_ref().unwrap().0.input_interface())?;
if let Some(vertex_shader) = &self.vertex_shader {
match self.vertex_shader.as_ref().unwrap().0.execution() {
ShaderExecution::Vertex => (),
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}
for element in vertex_shader.0.input_interface().elements() {
assert!(!element.ty.is_64bit); let location_range =
element.location..element.location + element.ty.num_locations();
for location in location_range {
let attribute_desc = match self_vertex_input_state.attributes.get(&location) {
Some(attribute_desc) => attribute_desc,
None => {
return Err(
GraphicsPipelineCreationError::VertexInputAttributeMissing {
location,
},
)
}
};
let shader_type = element.ty.to_format().type_color().unwrap();
let attribute_type = attribute_desc.format.type_color().unwrap();
if !matches!(
(shader_type, attribute_type),
(
NumericType::SFLOAT
| NumericType::UFLOAT
| NumericType::SNORM
| NumericType::UNORM
| NumericType::SSCALED
| NumericType::USCALED
| NumericType::SRGB,
NumericType::SFLOAT
| NumericType::UFLOAT
| NumericType::SNORM
| NumericType::UNORM
| NumericType::SSCALED
| NumericType::USCALED
| NumericType::SRGB,
) | (NumericType::SINT, NumericType::SINT)
| (NumericType::UINT, NumericType::UINT)
) {
return Err(
GraphicsPipelineCreationError::VertexInputAttributeIncompatibleFormat {
location,
shader_type,
attribute_type,
},
);
}
}
}
} else {
panic!("Missing vertex shader"); }
if let Some(tessellation_shaders) = &self.tessellation_shaders {
if !device.enabled_features().tessellation_shader {
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "tessellation_shader",
reason: "a tessellation shader was provided",
});
}
match tessellation_shaders.control.0.execution() {
ShaderExecution::TessellationControl => (),
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}
match tessellation_shaders.evaluation.0.execution() {
ShaderExecution::TessellationEvaluation => (),
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}
if subpass.render_pass().views_used() != 0
&& !device.enabled_features().multiview_tessellation_shader
{
return Err(
GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "multiview_tessellation_shader",
reason: "a tessellation shader was provided, and the render pass has multiview enabled with more than zero layers used",
},
);
}
}
if let Some(geometry_shader) = &self.geometry_shader {
if !device.enabled_features().geometry_shader {
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "geometry_shader",
reason: "a geometry shader was provided",
});
}
let input = match geometry_shader.0.execution() {
ShaderExecution::Geometry(execution) => execution.input,
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
};
if let PartialStateMode::Fixed(topology) = self.input_assembly_state.topology {
if !input.is_compatible_with(topology) {
return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader);
}
}
if subpass.render_pass().views_used() != 0
&& !device.enabled_features().multiview_geometry_shader
{
return Err(
GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "multiview_geometry_shader",
reason: "a geometry shader was provided, and the render pass has multiview enabled with more than zero layers used",
},
);
}
}
if let Some(fragment_shader) = &self.fragment_shader {
match fragment_shader.0.execution() {
ShaderExecution::Fragment => (),
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}
if !subpass.is_compatible_with(fragment_shader.0.output_interface()) {
return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible);
}
} else {
}
struct ShaderStageInfo<'a> {
entry_point: &'a EntryPoint<'a>,
specialization_map_entries: &'a [SpecializationMapEntry],
specialization_data: &'a [u8],
}
let stages_info: SmallVec<[ShaderStageInfo; 5]> = [
self.vertex_shader
.as_ref()
.map(|(entry_point, spec_consts)| ShaderStageInfo {
entry_point,
specialization_map_entries: Vss::descriptors(),
specialization_data: unsafe {
std::slice::from_raw_parts(
spec_consts as *const _ as *const u8,
std::mem::size_of_val(spec_consts),
)
},
}),
self.tessellation_shaders.as_ref().map(
|TessellationShaders {
control: (entry_point, spec_consts),
..
}| ShaderStageInfo {
entry_point,
specialization_map_entries: Tcss::descriptors(),
specialization_data: unsafe {
std::slice::from_raw_parts(
spec_consts as *const _ as *const u8,
std::mem::size_of_val(spec_consts),
)
},
},
),
self.tessellation_shaders.as_ref().map(
|TessellationShaders {
evaluation: (entry_point, spec_consts),
..
}| ShaderStageInfo {
entry_point,
specialization_map_entries: Tess::descriptors(),
specialization_data: unsafe {
std::slice::from_raw_parts(
spec_consts as *const _ as *const u8,
std::mem::size_of_val(spec_consts),
)
},
},
),
self.geometry_shader
.as_ref()
.map(|(entry_point, spec_consts)| ShaderStageInfo {
entry_point,
specialization_map_entries: Gss::descriptors(),
specialization_data: unsafe {
std::slice::from_raw_parts(
spec_consts as *const _ as *const u8,
std::mem::size_of_val(spec_consts),
)
},
}),
self.fragment_shader
.as_ref()
.map(|(entry_point, spec_consts)| ShaderStageInfo {
entry_point,
specialization_map_entries: Fss::descriptors(),
specialization_data: unsafe {
std::slice::from_raw_parts(
spec_consts as *const _ as *const u8,
std::mem::size_of_val(spec_consts),
)
},
}),
]
.into_iter()
.flatten()
.collect();
let mut descriptor_requirements: HashMap<(u32, u32), DescriptorRequirements> =
HashMap::default();
for stage_info in &stages_info {
pipeline_layout.ensure_compatible_with_shader(
stage_info.entry_point.descriptor_requirements(),
stage_info.entry_point.push_constant_requirements(),
)?;
for (loc, reqs) in stage_info.entry_point.descriptor_requirements() {
match descriptor_requirements.entry(loc) {
Entry::Occupied(entry) => {
let previous = entry.into_mut();
*previous = previous.intersection(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
}
Entry::Vacant(entry) => {
entry.insert(reqs.clone());
}
}
}
}
let num_used_descriptor_sets = descriptor_requirements
.keys()
.map(|loc| loc.0)
.max()
.map(|x| x + 1)
.unwrap_or(0);
for (output, input) in stages_info.iter().zip(stages_info.iter().skip(1)) {
if let Err(err) = input
.entry_point
.input_interface()
.matches(output.entry_point.output_interface())
{
return Err(GraphicsPipelineCreationError::ShaderStagesMismatch(err));
}
}
let specialization: SmallVec<[_; 5]> = stages_info
.iter()
.map(|stage_info| {
for (constant_id, reqs) in stage_info
.entry_point
.specialization_constant_requirements()
{
let map_entry = stage_info
.specialization_map_entries
.iter()
.find(|desc| desc.constant_id == constant_id)
.ok_or(
GraphicsPipelineCreationError::IncompatibleSpecializationConstants,
)?;
if map_entry.size as DeviceSize != reqs.size {
return Err(
GraphicsPipelineCreationError::IncompatibleSpecializationConstants,
);
}
}
Ok(ash::vk::SpecializationInfo {
map_entry_count: stage_info.specialization_map_entries.len() as u32,
p_map_entries: stage_info.specialization_map_entries.as_ptr() as *const _,
data_size: stage_info.specialization_data.len(),
p_data: stage_info.specialization_data.as_ptr() as *const _,
})
})
.collect::<Result<_, _>>()?;
debug_assert_eq!(specialization.len(), stages_info.len());
let stages: SmallVec<[_; 5]> = stages_info
.iter()
.zip(&specialization)
.map(|(stage_info, specialization)| {
let stage = ShaderStage::from(*stage_info.entry_point.execution());
ash::vk::PipelineShaderStageCreateInfo {
flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
stage: stage.into(),
module: stage_info.entry_point.module().internal_object(),
p_name: stage_info.entry_point.name().as_ptr(),
p_specialization_info: specialization as *const _,
..Default::default()
}
})
.collect();
debug_assert_eq!(stages.len(), stages_info.len());
let mut dynamic_state_modes: HashMap<DynamicState, bool> = HashMap::default();
let binding_descriptions = self_vertex_input_state.to_vulkan_bindings(&device)?;
let attribute_descriptions = self_vertex_input_state.to_vulkan_attributes(&device)?;
let binding_divisor_descriptions =
self_vertex_input_state.to_vulkan_binding_divisors(&device)?;
let binding_divisor_state = self_vertex_input_state
.to_vulkan_binding_divisor_state(binding_divisor_descriptions.as_ref());
let vertex_input_state = Some(self_vertex_input_state.to_vulkan(
&device,
&mut dynamic_state_modes,
&binding_descriptions,
&attribute_descriptions,
binding_divisor_state.as_ref(),
));
let input_assembly_state = if self.vertex_shader.is_some() {
Some(
self.input_assembly_state
.to_vulkan(&device, &mut dynamic_state_modes)?,
)
} else {
None
};
let tessellation_state = if self.tessellation_shaders.is_some() {
Some(self.tessellation_state.to_vulkan(
&device,
&mut dynamic_state_modes,
&self.input_assembly_state,
)?)
} else {
None
};
let (viewport_count, viewports, scissor_count, scissors) = self
.viewport_state
.to_vulkan_viewports_scissors(&device, &mut dynamic_state_modes)?;
let viewport_state = Some(self.viewport_state.to_vulkan(
&device,
&mut dynamic_state_modes,
viewport_count,
&viewports,
scissor_count,
&scissors,
)?);
let discard_rectangles = self
.discard_rectangle_state
.to_vulkan_rectangles(&device, &mut dynamic_state_modes)?;
let mut discard_rectangle_state = self.discard_rectangle_state.to_vulkan(
&device,
&mut dynamic_state_modes,
&discard_rectangles,
)?;
let mut rasterization_line_state = self
.rasterization_state
.to_vulkan_line_state(&device, &mut dynamic_state_modes)?;
let rasterization_state = Some(self.rasterization_state.to_vulkan(
&device,
&mut dynamic_state_modes,
rasterization_line_state.as_mut(),
)?);
let has_fragment_shader_state =
self.rasterization_state.rasterizer_discard_enable != StateMode::Fixed(true);
let multisample_state = if has_fragment_shader_state {
Some(
self.multisample_state
.to_vulkan(&device, &mut dynamic_state_modes, &subpass)?,
)
} else {
None
};
let depth_stencil_state = if has_fragment_shader_state
&& subpass.subpass_desc().depth_stencil_attachment.is_some()
{
Some(
self.depth_stencil_state
.to_vulkan(&device, &mut dynamic_state_modes, &subpass)?,
)
} else {
None
};
let (color_blend_attachments, color_write_enables) = self
.color_blend_state
.to_vulkan_attachments(&device, &mut dynamic_state_modes, &subpass)?;
let mut color_write = self.color_blend_state.to_vulkan_color_write(
&device,
&mut dynamic_state_modes,
&color_write_enables,
)?;
let color_blend_state = if has_fragment_shader_state {
Some(self.color_blend_state.to_vulkan(
&device,
&mut dynamic_state_modes,
&color_blend_attachments,
color_write.as_mut(),
)?)
} else {
None
};
let dynamic_state_list: Vec<ash::vk::DynamicState> = dynamic_state_modes
.iter()
.filter(|(_, d)| **d)
.map(|(&state, _)| state.into())
.collect();
let dynamic_state = if !dynamic_state_list.is_empty() {
Some(ash::vk::PipelineDynamicStateCreateInfo {
flags: ash::vk::PipelineDynamicStateCreateFlags::empty(),
dynamic_state_count: dynamic_state_list.len() as u32,
p_dynamic_states: dynamic_state_list.as_ptr(),
..Default::default()
})
} else {
None
};
let handle = unsafe {
let mut create_info = ash::vk::GraphicsPipelineCreateInfo {
flags: ash::vk::PipelineCreateFlags::empty(), stage_count: stages.len() as u32,
p_stages: stages.as_ptr(),
p_vertex_input_state: vertex_input_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_input_assembly_state: input_assembly_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_tessellation_state: tessellation_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_viewport_state: viewport_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_rasterization_state: rasterization_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_multisample_state: multisample_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_depth_stencil_state: depth_stencil_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_color_blend_state: color_blend_state
.as_ref()
.map(|p| p as *const _)
.unwrap_or(ptr::null()),
p_dynamic_state: dynamic_state
.as_ref()
.map(|s| s as *const _)
.unwrap_or(ptr::null()),
layout: pipeline_layout.internal_object(),
render_pass: subpass.render_pass().internal_object(),
subpass: subpass.index(),
base_pipeline_handle: ash::vk::Pipeline::null(), base_pipeline_index: -1, ..Default::default()
};
if let Some(discard_rectangle_state) = discard_rectangle_state.as_mut() {
discard_rectangle_state.p_next = create_info.p_next;
create_info.p_next = discard_rectangle_state as *const _ as *const _;
}
let cache_handle = match self.cache.as_ref() {
Some(cache) => cache.internal_object(),
None => ash::vk::PipelineCache::null(),
};
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.create_graphics_pipelines(
device.internal_object(),
cache_handle,
1,
&create_info,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
if handle == ash::vk::Pipeline::null() {
panic!("vkCreateGraphicsPipelines provided a NULL handle");
}
Ok(Arc::new(GraphicsPipeline {
handle,
device: device.clone(),
layout: pipeline_layout,
subpass,
shaders: stages_info
.iter()
.map(|stage_info| (ShaderStage::from(*stage_info.entry_point.execution()), ()))
.collect(),
descriptor_requirements,
num_used_descriptor_sets,
vertex_input_state: self_vertex_input_state, input_assembly_state: self.input_assembly_state, tessellation_state: if tessellation_state.is_some() {
Some(self.tessellation_state)
} else {
None
},
viewport_state: if viewport_state.is_some() {
Some(self.viewport_state)
} else {
None
},
discard_rectangle_state: if discard_rectangle_state.is_some() {
Some(self.discard_rectangle_state)
} else {
None
},
rasterization_state: self.rasterization_state,
multisample_state: if multisample_state.is_some() {
Some(self.multisample_state)
} else {
None
},
depth_stencil_state: if depth_stencil_state.is_some() {
Some(self.depth_stencil_state)
} else {
None
},
color_blend_state: if color_blend_state.is_some() {
Some(self.color_blend_state)
} else {
None
},
dynamic_state: dynamic_state_modes,
}))
}
}
impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
{
#[inline]
pub fn vertex_shader<'vs2, Vss2>(
self,
shader: EntryPoint<'vs2>,
specialization_constants: Vss2,
) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss>
where
Vss2: SpecializationConstants,
{
GraphicsPipelineBuilder {
subpass: self.subpass,
cache: self.cache,
vertex_shader: Some((shader, specialization_constants)),
tessellation_shaders: self.tessellation_shaders,
geometry_shader: self.geometry_shader,
fragment_shader: self.fragment_shader,
vertex_input_state: self.vertex_input_state,
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state,
discard_rectangle_state: self.discard_rectangle_state,
rasterization_state: self.rasterization_state,
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state,
color_blend_state: self.color_blend_state,
}
}
#[inline]
pub fn tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>(
self,
control_shader: EntryPoint<'tcs2>,
control_specialization_constants: Tcss2,
evaluation_shader: EntryPoint<'tes2>,
evaluation_specialization_constants: Tess2,
) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss>
where
Tcss2: SpecializationConstants,
Tess2: SpecializationConstants,
{
GraphicsPipelineBuilder {
subpass: self.subpass,
cache: self.cache,
vertex_shader: self.vertex_shader,
tessellation_shaders: Some(TessellationShaders {
control: (control_shader, control_specialization_constants),
evaluation: (evaluation_shader, evaluation_specialization_constants),
}),
geometry_shader: self.geometry_shader,
fragment_shader: self.fragment_shader,
vertex_input_state: self.vertex_input_state,
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state,
discard_rectangle_state: self.discard_rectangle_state,
rasterization_state: self.rasterization_state,
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state,
color_blend_state: self.color_blend_state,
}
}
#[inline]
pub fn geometry_shader<'gs2, Gss2>(
self,
shader: EntryPoint<'gs2>,
specialization_constants: Gss2,
) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss>
where
Gss2: SpecializationConstants,
{
GraphicsPipelineBuilder {
subpass: self.subpass,
cache: self.cache,
vertex_shader: self.vertex_shader,
tessellation_shaders: self.tessellation_shaders,
geometry_shader: Some((shader, specialization_constants)),
fragment_shader: self.fragment_shader,
vertex_input_state: self.vertex_input_state,
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state,
discard_rectangle_state: self.discard_rectangle_state,
rasterization_state: self.rasterization_state,
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state,
color_blend_state: self.color_blend_state,
}
}
#[inline]
pub fn fragment_shader<'fs2, Fss2>(
self,
shader: EntryPoint<'fs2>,
specialization_constants: Fss2,
) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2>
where
Fss2: SpecializationConstants,
{
GraphicsPipelineBuilder {
subpass: self.subpass,
cache: self.cache,
vertex_shader: self.vertex_shader,
tessellation_shaders: self.tessellation_shaders,
geometry_shader: self.geometry_shader,
fragment_shader: Some((shader, specialization_constants)),
vertex_input_state: self.vertex_input_state,
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state,
discard_rectangle_state: self.discard_rectangle_state,
rasterization_state: self.rasterization_state,
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state,
color_blend_state: self.color_blend_state,
}
}
#[inline]
pub fn vertex_input_state<T>(
self,
vertex_input_state: T,
) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss>
where
T: VertexDefinition,
{
GraphicsPipelineBuilder {
subpass: self.subpass,
cache: self.cache,
vertex_shader: self.vertex_shader,
tessellation_shaders: self.tessellation_shaders,
geometry_shader: self.geometry_shader,
fragment_shader: self.fragment_shader,
vertex_input_state,
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state,
discard_rectangle_state: self.discard_rectangle_state,
rasterization_state: self.rasterization_state,
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state,
color_blend_state: self.color_blend_state,
}
}
#[inline]
pub fn input_assembly_state(mut self, input_assembly_state: InputAssemblyState) -> Self {
self.input_assembly_state = input_assembly_state;
self
}
#[inline]
pub fn tessellation_state(mut self, tessellation_state: TessellationState) -> Self {
self.tessellation_state = tessellation_state;
self
}
#[inline]
pub fn viewport_state(mut self, viewport_state: ViewportState) -> Self {
self.viewport_state = viewport_state;
self
}
#[inline]
pub fn discard_rectangle_state(
mut self,
discard_rectangle_state: DiscardRectangleState,
) -> Self {
self.discard_rectangle_state = discard_rectangle_state;
self
}
#[inline]
pub fn rasterization_state(mut self, rasterization_state: RasterizationState) -> Self {
self.rasterization_state = rasterization_state;
self
}
#[inline]
pub fn multisample_state(mut self, multisample_state: MultisampleState) -> Self {
self.multisample_state = multisample_state;
self
}
#[inline]
pub fn depth_stencil_state(mut self, depth_stencil_state: DepthStencilState) -> Self {
self.depth_stencil_state = depth_stencil_state;
self
}
#[inline]
pub fn color_blend_state(mut self, color_blend_state: ColorBlendState) -> Self {
self.color_blend_state = color_blend_state;
self
}
#[deprecated(since = "0.27")]
#[inline]
pub fn tessellation_shaders_disabled(mut self) -> Self {
self.tessellation_shaders = None;
self
}
#[deprecated(since = "0.27")]
#[inline]
pub fn geometry_shader_disabled(mut self) -> Self {
self.geometry_shader = None;
self
}
#[deprecated(since = "0.27", note = "Use `vertex_input_state` instead")]
#[inline]
pub fn vertex_input_single_buffer<V: Vertex>(
self,
) -> GraphicsPipelineBuilder<
'vs,
'tcs,
'tes,
'gs,
'fs,
BuffersDefinition,
Vss,
Tcss,
Tess,
Gss,
Fss,
> {
self.vertex_input_state(BuffersDefinition::new().vertex::<V>())
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn primitive_restart(mut self, enabled: bool) -> Self {
self.input_assembly_state.primitive_restart_enable = StateMode::Fixed(enabled);
self
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn primitive_topology(mut self, topology: PrimitiveTopology) -> Self {
self.input_assembly_state.topology = PartialStateMode::Fixed(topology);
self
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn point_list(self) -> Self {
self.primitive_topology(PrimitiveTopology::PointList)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn line_list(self) -> Self {
self.primitive_topology(PrimitiveTopology::LineList)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn line_strip(self) -> Self {
self.primitive_topology(PrimitiveTopology::LineStrip)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn triangle_list(self) -> Self {
self.primitive_topology(PrimitiveTopology::TriangleList)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn triangle_strip(self) -> Self {
self.primitive_topology(PrimitiveTopology::TriangleStrip)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn triangle_fan(self) -> Self {
self.primitive_topology(PrimitiveTopology::TriangleFan)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn line_list_with_adjacency(self) -> Self {
self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn line_strip_with_adjacency(self) -> Self {
self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn triangle_list_with_adjacency(self) -> Self {
self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn triangle_strip_with_adjacency(self) -> Self {
self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)
}
#[deprecated(since = "0.27", note = "Use `input_assembly_state` instead")]
#[inline]
pub fn patch_list(self) -> Self {
self.primitive_topology(PrimitiveTopology::PatchList)
}
#[deprecated(since = "0.27", note = "Use `viewport_state` instead")]
#[inline]
pub fn viewports<I>(self, viewports: I) -> Self
where
I: IntoIterator<Item = Viewport>,
{
self.viewports_scissors(viewports.into_iter().map(|v| (v, Scissor::irrelevant())))
}
#[deprecated(since = "0.27", note = "Use `viewport_state` instead")]
#[inline]
pub fn viewports_scissors<I>(mut self, viewports: I) -> Self
where
I: IntoIterator<Item = (Viewport, Scissor)>,
{
self.viewport_state = ViewportState::Fixed {
data: viewports.into_iter().collect(),
};
self
}
#[deprecated(since = "0.27", note = "Use `viewport_state` instead")]
#[inline]
pub fn viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self
where
I: IntoIterator<Item = Scissor>,
{
self.viewport_state = ViewportState::FixedScissor {
scissors: scissors.into_iter().collect(),
viewport_count_dynamic: false,
};
self
}
#[deprecated(since = "0.27", note = "Use `viewport_state` instead")]
#[inline]
pub fn viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self {
self.viewport_state = ViewportState::FixedScissor {
scissors: (0..num).map(|_| Scissor::irrelevant()).collect(),
viewport_count_dynamic: false,
};
self
}
#[deprecated(since = "0.27", note = "Use `viewport_state` instead")]
#[inline]
pub fn viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self
where
I: IntoIterator<Item = Viewport>,
{
self.viewport_state = ViewportState::FixedViewport {
viewports: viewports.into_iter().collect(),
scissor_count_dynamic: false,
};
self
}
#[deprecated(since = "0.27", note = "Use `viewport_state` instead")]
#[inline]
pub fn viewports_scissors_dynamic(mut self, count: u32) -> Self {
self.viewport_state = ViewportState::Dynamic {
count,
viewport_count_dynamic: false,
scissor_count_dynamic: false,
};
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn depth_clamp(mut self, clamp: bool) -> Self {
self.rasterization_state.depth_clamp_enable = clamp;
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn front_face_counter_clockwise(mut self) -> Self {
self.rasterization_state.front_face = StateMode::Fixed(FrontFace::CounterClockwise);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn front_face_clockwise(mut self) -> Self {
self.rasterization_state.front_face = StateMode::Fixed(FrontFace::Clockwise);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn cull_mode_disabled(mut self) -> Self {
self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::None);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn cull_mode_front(mut self) -> Self {
self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::Front);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn cull_mode_back(mut self) -> Self {
self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::Back);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn cull_mode_front_and_back(mut self) -> Self {
self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::FrontAndBack);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn polygon_mode_fill(mut self) -> Self {
self.rasterization_state.polygon_mode = PolygonMode::Fill;
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn polygon_mode_line(mut self) -> Self {
self.rasterization_state.polygon_mode = PolygonMode::Line;
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn polygon_mode_point(mut self) -> Self {
self.rasterization_state.polygon_mode = PolygonMode::Point;
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn line_width(mut self, value: f32) -> Self {
self.rasterization_state.line_width = StateMode::Fixed(value);
self
}
#[deprecated(since = "0.27", note = "Use `rasterization_state` instead")]
#[inline]
pub fn line_width_dynamic(mut self) -> Self {
self.rasterization_state.line_width = StateMode::Dynamic;
self
}
#[deprecated(since = "0.27", note = "Use `multisample_state` instead")]
#[inline]
pub fn sample_shading_disabled(mut self) -> Self {
self.multisample_state.sample_shading = None;
self
}
#[deprecated(since = "0.27", note = "Use `multisample_state` instead")]
#[inline]
pub fn sample_shading_enabled(mut self, min_fract: f32) -> Self {
assert!(min_fract >= 0.0 && min_fract <= 1.0);
self.multisample_state.sample_shading = Some(min_fract);
self
}
#[deprecated(since = "0.27", note = "Use `multisample_state` instead")]
pub fn alpha_to_coverage_disabled(mut self) -> Self {
self.multisample_state.alpha_to_coverage_enable = false;
self
}
#[deprecated(since = "0.27", note = "Use `multisample_state` instead")]
pub fn alpha_to_coverage_enabled(mut self) -> Self {
self.multisample_state.alpha_to_coverage_enable = true;
self
}
#[deprecated(since = "0.27", note = "Use `multisample_state` instead")]
#[inline]
pub fn alpha_to_one_disabled(mut self) -> Self {
self.multisample_state.alpha_to_one_enable = false;
self
}
#[deprecated(since = "0.27", note = "Use `multisample_state` instead")]
#[inline]
pub fn alpha_to_one_enabled(mut self) -> Self {
self.multisample_state.alpha_to_one_enable = true;
self
}
#[deprecated(since = "0.27", note = "Use `depth_stencil_state` instead")]
#[inline]
pub fn depth_stencil(self, depth_stencil_state: DepthStencilState) -> Self {
self.depth_stencil_state(depth_stencil_state)
}
#[deprecated(since = "0.27", note = "Use `depth_stencil_state` instead")]
#[inline]
pub fn depth_stencil_disabled(mut self) -> Self {
self.depth_stencil_state = DepthStencilState::disabled();
self
}
#[deprecated(since = "0.27", note = "Use `depth_stencil_state` instead")]
#[inline]
pub fn depth_stencil_simple_depth(mut self) -> Self {
self.depth_stencil_state = DepthStencilState::simple_depth_test();
self
}
#[deprecated(since = "0.27", note = "Use `depth_stencil_state` instead")]
#[inline]
pub fn depth_write(mut self, write: bool) -> Self {
let depth_state = self
.depth_stencil_state
.depth
.get_or_insert(Default::default());
depth_state.write_enable = StateMode::Fixed(write);
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_collective(mut self, blend: AttachmentBlend) -> Self {
self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
blend: Some(blend),
color_write_mask: ColorComponents::all(),
color_write_enable: StateMode::Fixed(true),
}];
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_individual<I>(mut self, blend: I) -> Self
where
I: IntoIterator<Item = AttachmentBlend>,
{
self.color_blend_state.attachments = blend
.into_iter()
.map(|x| ColorBlendAttachmentState {
blend: Some(x),
color_write_mask: ColorComponents::all(),
color_write_enable: StateMode::Fixed(true),
})
.collect();
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_pass_through(mut self) -> Self {
self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
blend: None,
color_write_mask: ColorComponents::all(),
color_write_enable: StateMode::Fixed(true),
}];
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_alpha_blending(mut self) -> Self {
self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
blend: Some(AttachmentBlend::alpha()),
color_write_mask: ColorComponents::all(),
color_write_enable: StateMode::Fixed(true),
}];
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_logic_op(mut self, logic_op: LogicOp) -> Self {
self.color_blend_state.logic_op = Some(StateMode::Fixed(logic_op));
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_logic_op_disabled(mut self) -> Self {
self.color_blend_state.logic_op = None;
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_constants(mut self, constants: [f32; 4]) -> Self {
self.color_blend_state.blend_constants = StateMode::Fixed(constants);
self
}
#[deprecated(since = "0.27", note = "Use `color_blend_state` instead")]
#[inline]
pub fn blend_constants_dynamic(mut self) -> Self {
self.color_blend_state.blend_constants = StateMode::Dynamic;
self
}
#[inline]
pub fn render_pass(self, subpass: Subpass) -> Self {
GraphicsPipelineBuilder {
subpass: Some(subpass),
cache: self.cache,
vertex_shader: self.vertex_shader,
tessellation_shaders: self.tessellation_shaders,
geometry_shader: self.geometry_shader,
fragment_shader: self.fragment_shader,
vertex_input_state: self.vertex_input_state,
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state,
rasterization_state: self.rasterization_state,
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state,
color_blend_state: self.color_blend_state,
discard_rectangle_state: self.discard_rectangle_state,
}
}
#[inline]
pub fn build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self {
self.cache = Some(pipeline_cache);
self
}
}
impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> Clone
for GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
where
Vdef: Clone,
Vss: Clone,
Tcss: Clone,
Tess: Clone,
Gss: Clone,
Fss: Clone,
{
fn clone(&self) -> Self {
GraphicsPipelineBuilder {
subpass: self.subpass.clone(),
cache: self.cache.clone(),
vertex_shader: self.vertex_shader.clone(),
tessellation_shaders: self.tessellation_shaders.clone(),
geometry_shader: self.geometry_shader.clone(),
fragment_shader: self.fragment_shader.clone(),
vertex_input_state: self.vertex_input_state.clone(),
input_assembly_state: self.input_assembly_state,
tessellation_state: self.tessellation_state,
viewport_state: self.viewport_state.clone(),
rasterization_state: self.rasterization_state.clone(),
multisample_state: self.multisample_state,
depth_stencil_state: self.depth_stencil_state.clone(),
color_blend_state: self.color_blend_state.clone(),
discard_rectangle_state: self.discard_rectangle_state.clone(),
}
}
}