mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
Continue cleanup of the graphics pipeline builder code (#777)
* Move GraphicsPipeline::new_inner() as GraphicsPipelineBuilder::build() * Move GraphicsPipelineCreationError to a separate module * Remove GraphicsPipelineParams Signed-off-by: tomaka <pierre.krieger1708@gmail.com> * Remove GraphicsPipelineParamsTess Signed-off-by: tomaka <pierre.krieger1708@gmail.com>
This commit is contained in:
parent
5207f8a703
commit
a8058022bd
@ -11,36 +11,50 @@
|
||||
// to avoid duplicating code, so we hide the warnings for now
|
||||
#![allow(deprecated)]
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::u32;
|
||||
|
||||
use descriptor::pipeline_layout::PipelineLayoutAbstract;
|
||||
use device::Device;
|
||||
use framebuffer::RenderPassAbstract;
|
||||
use framebuffer::RenderPassSubpassInterface;
|
||||
use framebuffer::Subpass;
|
||||
use pipeline::blend::AttachmentBlend;
|
||||
use pipeline::blend::AttachmentsBlend;
|
||||
use pipeline::blend::Blend;
|
||||
use pipeline::blend::LogicOp;
|
||||
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::GraphicsPipelineParams;
|
||||
use pipeline::graphics_pipeline::GraphicsPipelineParamsTess;
|
||||
use pipeline::input_assembly::InputAssembly;
|
||||
use pipeline::input_assembly::PrimitiveTopology;
|
||||
use pipeline::multisample::Multisample;
|
||||
use pipeline::raster::CullMode;
|
||||
use pipeline::raster::DepthBiasControl;
|
||||
use pipeline::raster::FrontFace;
|
||||
use pipeline::raster::PolygonMode;
|
||||
use pipeline::raster::Rasterization;
|
||||
use pipeline::shader::EmptyEntryPointDummy;
|
||||
use pipeline::shader::GraphicsEntryPointAbstract;
|
||||
use pipeline::shader::GraphicsShaderType;
|
||||
use pipeline::shader::ShaderInterfaceDefMatch;
|
||||
use pipeline::vertex::SingleBufferDefinition;
|
||||
use pipeline::vertex::VertexDefinition;
|
||||
use pipeline::viewport::Scissor;
|
||||
use pipeline::viewport::Viewport;
|
||||
use pipeline::viewport::ViewportsState;
|
||||
use std::sync::Arc;
|
||||
|
||||
use VulkanObject;
|
||||
use check_errors;
|
||||
use descriptor::pipeline_layout::PipelineLayoutDesc;
|
||||
use descriptor::pipeline_layout::PipelineLayoutSuperset;
|
||||
use framebuffer::RenderPassSubpassInterface;
|
||||
use vk;
|
||||
|
||||
/// Prototype for a `GraphicsPipeline`.
|
||||
// TODO: we can optimize this by filling directly the raw vk structs
|
||||
@ -56,7 +70,7 @@ pub struct GraphicsPipelineBuilder<
|
||||
vertex_input: Vdef,
|
||||
vertex_shader: Option<Vs>,
|
||||
input_assembly: InputAssembly,
|
||||
tessellation: Option<GraphicsPipelineParamsTess<Tcs, Tes>>,
|
||||
tessellation: Option<TessInfo<Tcs, Tes>>,
|
||||
geometry_shader: Option<Gs>,
|
||||
viewport: Option<ViewportsState>,
|
||||
raster: Rasterization,
|
||||
@ -67,6 +81,13 @@ pub struct GraphicsPipelineBuilder<
|
||||
render_pass: Option<Subpass<Rp>>,
|
||||
}
|
||||
|
||||
// Additional parameters if tessellation is used.
|
||||
#[derive(Copy, Clone)]
|
||||
struct TessInfo<Tcs, Tes> {
|
||||
tessellation_control_shader: Tcs,
|
||||
tessellation_evaluation_shader: Tes,
|
||||
}
|
||||
|
||||
impl GraphicsPipelineBuilder<SingleBufferDefinition<()>,
|
||||
EmptyEntryPointDummy,
|
||||
EmptyEntryPointDummy,
|
||||
@ -128,41 +149,825 @@ impl<Vdef,
|
||||
{
|
||||
/// Builds the graphics pipeline.
|
||||
// TODO: replace Box<PipelineLayoutAbstract> with a PipelineUnion struct without template params
|
||||
pub fn build(self, device: Arc<Device>)
|
||||
pub fn build(mut self, device: Arc<Device>)
|
||||
-> Result<GraphicsPipeline<Vdef, Box<PipelineLayoutAbstract + Send + Sync>, Rp>,
|
||||
GraphicsPipelineCreationError> {
|
||||
// TODO: return errors instead of panicking if missing param
|
||||
GraphicsPipeline::with_tessellation_and_geometry(device,
|
||||
GraphicsPipelineParams {
|
||||
vertex_input: self.vertex_input,
|
||||
vertex_shader:
|
||||
self.vertex_shader
|
||||
.expect("Vertex shader not \
|
||||
specified in the \
|
||||
builder"),
|
||||
input_assembly: self.input_assembly,
|
||||
tessellation: self.tessellation,
|
||||
geometry_shader: self.geometry_shader,
|
||||
viewport:
|
||||
self.viewport
|
||||
.expect("Viewport state not \
|
||||
specified in the \
|
||||
builder"),
|
||||
raster: self.raster,
|
||||
multisample: self.multisample,
|
||||
fragment_shader:
|
||||
self.fragment_shader
|
||||
.expect("Fragment shader not \
|
||||
specified in the \
|
||||
builder"),
|
||||
depth_stencil: self.depth_stencil,
|
||||
blend: self.blend,
|
||||
render_pass:
|
||||
self.render_pass
|
||||
.expect("Render pass not \
|
||||
specified in the \
|
||||
builder"),
|
||||
})
|
||||
|
||||
let vk = device.pointers();
|
||||
|
||||
let pipeline_layout;
|
||||
|
||||
if let Some(ref tess) = self.tessellation {
|
||||
if let Some(ref gs) = self.geometry_shader {
|
||||
if let Err(err) = tess.tessellation_control_shader
|
||||
.input()
|
||||
.matches(self.vertex_shader.as_ref().unwrap().output())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::VertexTessControlStagesMismatch(err));
|
||||
}
|
||||
if let Err(err) = tess.tessellation_evaluation_shader
|
||||
.input()
|
||||
.matches(tess.tessellation_control_shader.output())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(err));
|
||||
}
|
||||
if let Err(err) = gs.input()
|
||||
.matches(tess.tessellation_evaluation_shader.output())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::TessEvalGeometryStagesMismatch(err));
|
||||
}
|
||||
if let Err(err) = self.fragment_shader.as_ref().unwrap().input().matches(gs.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()
|
||||
.build(device.clone()).unwrap()) as Box<_>; // TODO: error
|
||||
|
||||
} else {
|
||||
if let Err(err) = tess.tessellation_control_shader
|
||||
.input()
|
||||
.matches(self.vertex_shader.as_ref().unwrap().output())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::VertexTessControlStagesMismatch(err));
|
||||
}
|
||||
if let Err(err) = tess.tessellation_evaluation_shader
|
||||
.input()
|
||||
.matches(tess.tessellation_control_shader.output())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(err));
|
||||
}
|
||||
if let Err(err) = self
|
||||
.fragment_shader
|
||||
.as_ref().unwrap()
|
||||
.input()
|
||||
.matches(tess.tessellation_evaluation_shader.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()
|
||||
.build(device.clone()).unwrap()) as Box<_>; // TODO: error
|
||||
}
|
||||
|
||||
} else {
|
||||
if let Some(ref geometry_shader) = self.geometry_shader {
|
||||
if let Err(err) = geometry_shader
|
||||
.input()
|
||||
.matches(self.vertex_shader.as_ref().unwrap().output())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::VertexGeometryStagesMismatch(err));
|
||||
}
|
||||
if let Err(err) = self
|
||||
.fragment_shader
|
||||
.as_ref().unwrap()
|
||||
.input()
|
||||
.matches(geometry_shader.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()
|
||||
.build(device.clone()).unwrap()) as Box<_>; // TODO: error
|
||||
|
||||
} else {
|
||||
if let Err(err) = self
|
||||
.fragment_shader
|
||||
.as_ref().unwrap()
|
||||
.input()
|
||||
.matches(self.vertex_shader.as_ref().unwrap().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
|
||||
}
|
||||
}
|
||||
|
||||
// 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())?;
|
||||
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
|
||||
self.fragment_shader.as_ref().unwrap().layout())?;
|
||||
if let Some(ref geometry_shader) = self.geometry_shader {
|
||||
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout, geometry_shader.layout())?;
|
||||
}
|
||||
if let Some(ref tess) = self.tessellation {
|
||||
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
|
||||
tess.tessellation_control_shader.layout())?;
|
||||
PipelineLayoutSuperset::ensure_superset_of(&pipeline_layout,
|
||||
tess.tessellation_evaluation_shader
|
||||
.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())
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible);
|
||||
}
|
||||
|
||||
// Will contain the list of dynamic states. Filled throughout this function.
|
||||
let mut dynamic_states: SmallVec<[vk::DynamicState; 8]> = SmallVec::new();
|
||||
|
||||
// List of shader stages.
|
||||
let stages = {
|
||||
let mut stages = SmallVec::<[_; 5]>::new();
|
||||
|
||||
match self.vertex_shader.as_ref().unwrap().ty() {
|
||||
GraphicsShaderType::Vertex => {},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
|
||||
};
|
||||
|
||||
stages.push(vk::PipelineShaderStageCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
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:
|
||||
});
|
||||
|
||||
match self.fragment_shader.as_ref().unwrap().ty() {
|
||||
GraphicsShaderType::Fragment => {},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
|
||||
};
|
||||
|
||||
stages.push(vk::PipelineShaderStageCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
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:
|
||||
});
|
||||
|
||||
if let Some(ref gs) = self.geometry_shader {
|
||||
if !device.enabled_features().geometry_shader {
|
||||
return Err(GraphicsPipelineCreationError::GeometryShaderFeatureNotEnabled);
|
||||
}
|
||||
|
||||
stages.push(vk::PipelineShaderStageCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
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:
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(ref tess) = self.tessellation {
|
||||
// FIXME: must check that the control shader and evaluation shader are compatible
|
||||
|
||||
if !device.enabled_features().tessellation_shader {
|
||||
return Err(GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled);
|
||||
}
|
||||
|
||||
match tess.tessellation_control_shader.ty() {
|
||||
GraphicsShaderType::TessellationControl => {},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
|
||||
};
|
||||
|
||||
match tess.tessellation_evaluation_shader.ty() {
|
||||
GraphicsShaderType::TessellationControl => {},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
|
||||
};
|
||||
|
||||
stages.push(vk::PipelineShaderStageCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
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:
|
||||
});
|
||||
|
||||
stages.push(vk::PipelineShaderStageCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
stage: vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
|
||||
module: tess.tessellation_evaluation_shader
|
||||
.module()
|
||||
.internal_object(),
|
||||
pName: tess.tessellation_evaluation_shader.name().as_ptr(),
|
||||
pSpecializationInfo: ptr::null(), // TODO:
|
||||
});
|
||||
}
|
||||
|
||||
stages
|
||||
};
|
||||
|
||||
// Vertex bindings.
|
||||
let (binding_descriptions, attribute_descriptions) = {
|
||||
let (buffers_iter, attribs_iter) =
|
||||
self
|
||||
.vertex_input
|
||||
.definition(self.vertex_shader.as_ref().unwrap().input())?;
|
||||
|
||||
let mut binding_descriptions = SmallVec::<[_; 8]>::new();
|
||||
for (num, stride, rate) in buffers_iter {
|
||||
if stride >
|
||||
device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_vertex_input_binding_stride() as usize
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
|
||||
binding: num as usize,
|
||||
max: device.physical_device().limits().max_vertex_input_binding_stride() as usize,
|
||||
obtained: stride,
|
||||
});
|
||||
}
|
||||
|
||||
binding_descriptions.push(vk::VertexInputBindingDescription {
|
||||
binding: num as u32,
|
||||
stride: stride as u32,
|
||||
inputRate: rate as u32,
|
||||
});
|
||||
}
|
||||
|
||||
let mut attribute_descriptions = SmallVec::<[_; 8]>::new();
|
||||
for (loc, binding, info) in attribs_iter {
|
||||
// TODO: check attribute format support
|
||||
|
||||
if info.offset >
|
||||
device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_vertex_input_attribute_offset() as usize
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
|
||||
max: device.physical_device().limits().max_vertex_input_attribute_offset() as usize,
|
||||
obtained: info.offset,
|
||||
});
|
||||
}
|
||||
|
||||
debug_assert!(binding_descriptions
|
||||
.iter()
|
||||
.find(|b| b.binding == binding)
|
||||
.is_some());
|
||||
|
||||
attribute_descriptions.push(vk::VertexInputAttributeDescription {
|
||||
location: loc as u32,
|
||||
binding: binding as u32,
|
||||
format: info.format as u32,
|
||||
offset: info.offset as u32,
|
||||
});
|
||||
}
|
||||
|
||||
(binding_descriptions, attribute_descriptions)
|
||||
};
|
||||
|
||||
if binding_descriptions.len() >
|
||||
device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_vertex_input_bindings() as usize
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
|
||||
max: device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_vertex_input_bindings() as
|
||||
usize,
|
||||
obtained: binding_descriptions.len(),
|
||||
});
|
||||
}
|
||||
|
||||
if attribute_descriptions.len() >
|
||||
device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_vertex_input_attributes() as usize
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
|
||||
max: device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_vertex_input_attributes() as
|
||||
usize,
|
||||
obtained: attribute_descriptions.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
vertexBindingDescriptionCount: binding_descriptions.len() as u32,
|
||||
pVertexBindingDescriptions: binding_descriptions.as_ptr(),
|
||||
vertexAttributeDescriptionCount: attribute_descriptions.len() as u32,
|
||||
pVertexAttributeDescriptions: attribute_descriptions.as_ptr(),
|
||||
};
|
||||
|
||||
if self.input_assembly.primitive_restart_enable &&
|
||||
!self.input_assembly.topology.supports_primitive_restart()
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart {
|
||||
primitive: self.input_assembly.topology,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: should check from the tess eval shader instead of the input assembly
|
||||
if let Some(ref gs) = self.geometry_shader {
|
||||
match gs.ty() {
|
||||
GraphicsShaderType::Geometry(primitives) => {
|
||||
if !primitives.matches(self.input_assembly.topology) {
|
||||
return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader);
|
||||
}
|
||||
},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
|
||||
}
|
||||
}
|
||||
|
||||
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
topology: self.input_assembly.topology.into(),
|
||||
primitiveRestartEnable: if self.input_assembly.primitive_restart_enable {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
};
|
||||
|
||||
let tessellation = match self.input_assembly.topology {
|
||||
PrimitiveTopology::PatchList { vertices_per_patch } => {
|
||||
if self.tessellation.is_none() {
|
||||
return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
|
||||
}
|
||||
if vertices_per_patch >
|
||||
device
|
||||
.physical_device()
|
||||
.limits()
|
||||
.max_tessellation_patch_size()
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded);
|
||||
}
|
||||
|
||||
Some(vk::PipelineTessellationStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved,
|
||||
patchControlPoints: vertices_per_patch,
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
if self.tessellation.is_some() {
|
||||
return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
let (vp_vp, vp_sc, vp_num) = match *self.viewport.as_ref().unwrap() {
|
||||
ViewportsState::Fixed { ref data } => (data.iter()
|
||||
.map(|e| e.0.clone().into_vulkan_viewport())
|
||||
.collect::<SmallVec<[vk::Viewport; 4]>>(),
|
||||
data.iter()
|
||||
.map(|e| e.1.clone().into_vulkan_rect())
|
||||
.collect::<SmallVec<[vk::Rect2D; 4]>>(),
|
||||
data.len() as u32),
|
||||
ViewportsState::DynamicViewports { ref scissors } => {
|
||||
let num = scissors.len() as u32;
|
||||
let scissors = scissors
|
||||
.iter()
|
||||
.map(|e| e.clone().into_vulkan_rect())
|
||||
.collect::<SmallVec<[vk::Rect2D; 4]>>();
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_VIEWPORT);
|
||||
(SmallVec::new(), scissors, num)
|
||||
},
|
||||
ViewportsState::DynamicScissors { ref viewports } => {
|
||||
let num = viewports.len() as u32;
|
||||
let viewports = viewports
|
||||
.iter()
|
||||
.map(|e| e.clone().into_vulkan_viewport())
|
||||
.collect::<SmallVec<[vk::Viewport; 4]>>();
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_SCISSOR);
|
||||
(viewports, SmallVec::new(), num)
|
||||
},
|
||||
ViewportsState::Dynamic { num } => {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_VIEWPORT);
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_SCISSOR);
|
||||
(SmallVec::new(), SmallVec::new(), num)
|
||||
},
|
||||
};
|
||||
|
||||
if vp_num > 1 && !device.enabled_features().multi_viewport {
|
||||
return Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled);
|
||||
}
|
||||
|
||||
if vp_num > device.physical_device().limits().max_viewports() {
|
||||
return Err(GraphicsPipelineCreationError::MaxViewportsExceeded {
|
||||
obtained: vp_num,
|
||||
max: device.physical_device().limits().max_viewports(),
|
||||
});
|
||||
}
|
||||
|
||||
for vp in vp_vp.iter() {
|
||||
if vp.width > device.physical_device().limits().max_viewport_dimensions()[0] as f32 ||
|
||||
vp.height > device.physical_device().limits().max_viewport_dimensions()[1] as f32
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::MaxViewportDimensionsExceeded);
|
||||
}
|
||||
|
||||
if vp.x < device.physical_device().limits().viewport_bounds_range()[0] ||
|
||||
vp.x + vp.width > device.physical_device().limits().viewport_bounds_range()[1] ||
|
||||
vp.y < device.physical_device().limits().viewport_bounds_range()[0] ||
|
||||
vp.y + vp.height > device.physical_device().limits().viewport_bounds_range()[1]
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
|
||||
}
|
||||
}
|
||||
|
||||
let viewport_info = vk::PipelineViewportStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
viewportCount: vp_num,
|
||||
pViewports: if vp_vp.is_empty() {
|
||||
ptr::null()
|
||||
} else {
|
||||
vp_vp.as_ptr()
|
||||
}, // validation layer crashes if you just pass the pointer
|
||||
scissorCount: vp_num,
|
||||
pScissors: if vp_sc.is_empty() {
|
||||
ptr::null()
|
||||
} else {
|
||||
vp_sc.as_ptr()
|
||||
}, // validation layer crashes if you just pass the pointer
|
||||
};
|
||||
|
||||
if let Some(line_width) = self.raster.line_width {
|
||||
if line_width != 1.0 && !device.enabled_features().wide_lines {
|
||||
return Err(GraphicsPipelineCreationError::WideLinesFeatureNotEnabled);
|
||||
}
|
||||
} else {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_LINE_WIDTH);
|
||||
}
|
||||
|
||||
let (db_enable, db_const, db_clamp, db_slope) = match self.raster.depth_bias {
|
||||
DepthBiasControl::Dynamic => {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_DEPTH_BIAS);
|
||||
(vk::TRUE, 0.0, 0.0, 0.0)
|
||||
},
|
||||
DepthBiasControl::Disabled => {
|
||||
(vk::FALSE, 0.0, 0.0, 0.0)
|
||||
},
|
||||
DepthBiasControl::Static(bias) => {
|
||||
if bias.clamp != 0.0 && !device.enabled_features().depth_bias_clamp {
|
||||
return Err(GraphicsPipelineCreationError::DepthBiasClampFeatureNotEnabled);
|
||||
}
|
||||
|
||||
(vk::TRUE, bias.constant_factor, bias.clamp, bias.slope_factor)
|
||||
},
|
||||
};
|
||||
|
||||
if self.raster.depth_clamp && !device.enabled_features().depth_clamp {
|
||||
return Err(GraphicsPipelineCreationError::DepthClampFeatureNotEnabled);
|
||||
}
|
||||
|
||||
if self.raster.polygon_mode != PolygonMode::Fill &&
|
||||
!device.enabled_features().fill_mode_non_solid
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FillModeNonSolidFeatureNotEnabled);
|
||||
}
|
||||
|
||||
let rasterization = vk::PipelineRasterizationStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
depthClampEnable: if self.raster.depth_clamp {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
rasterizerDiscardEnable: if self.raster.rasterizer_discard {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
polygonMode: self.raster.polygon_mode as u32,
|
||||
cullMode: self.raster.cull_mode as u32,
|
||||
frontFace: self.raster.front_face as u32,
|
||||
depthBiasEnable: db_enable,
|
||||
depthBiasConstantFactor: db_const,
|
||||
depthBiasClamp: db_clamp,
|
||||
depthBiasSlopeFactor: db_slope,
|
||||
lineWidth: self.raster.line_width.unwrap_or(1.0),
|
||||
};
|
||||
|
||||
assert!(self.multisample.rasterization_samples >= 1);
|
||||
// FIXME: check that rasterization_samples is equal to what's in the renderpass
|
||||
if let Some(s) = self.multisample.sample_shading {
|
||||
assert!(s >= 0.0 && s <= 1.0);
|
||||
}
|
||||
let multisample = vk::PipelineMultisampleStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
rasterizationSamples: self.multisample.rasterization_samples,
|
||||
sampleShadingEnable: if self.multisample.sample_shading.is_some() {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
minSampleShading: self.multisample.sample_shading.unwrap_or(1.0),
|
||||
pSampleMask: ptr::null(), //self.multisample.sample_mask.as_ptr(), // FIXME:
|
||||
alphaToCoverageEnable: if self.multisample.alpha_to_coverage {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
alphaToOneEnable: if self.multisample.alpha_to_one {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
};
|
||||
|
||||
let depth_stencil = {
|
||||
let db = match self.depth_stencil.depth_bounds_test {
|
||||
DepthBounds::Disabled => (vk::FALSE, 0.0, 0.0),
|
||||
DepthBounds::Fixed(ref range) => {
|
||||
if !device.enabled_features().depth_bounds {
|
||||
return Err(GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled);
|
||||
}
|
||||
|
||||
(vk::TRUE, range.start, range.end)
|
||||
},
|
||||
DepthBounds::Dynamic => {
|
||||
if !device.enabled_features().depth_bounds {
|
||||
return Err(GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled);
|
||||
}
|
||||
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_DEPTH_BOUNDS);
|
||||
|
||||
(vk::TRUE, 0.0, 1.0)
|
||||
},
|
||||
};
|
||||
|
||||
match (self.depth_stencil.stencil_front.compare_mask,
|
||||
self.depth_stencil.stencil_back.compare_mask) {
|
||||
(Some(_), Some(_)) => (),
|
||||
(None, None) => {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_STENCIL_COMPARE_MASK);
|
||||
},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongStencilState),
|
||||
};
|
||||
|
||||
match (self.depth_stencil.stencil_front.write_mask,
|
||||
self.depth_stencil.stencil_back.write_mask) {
|
||||
(Some(_), Some(_)) => (),
|
||||
(None, None) => {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
||||
},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongStencilState),
|
||||
};
|
||||
|
||||
match (self.depth_stencil.stencil_front.reference,
|
||||
self.depth_stencil.stencil_back.reference) {
|
||||
(Some(_), Some(_)) => (),
|
||||
(None, None) => {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_STENCIL_REFERENCE);
|
||||
},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongStencilState),
|
||||
};
|
||||
|
||||
if self.depth_stencil.depth_write && !self.render_pass.as_ref().unwrap().has_writable_depth() {
|
||||
return Err(GraphicsPipelineCreationError::NoDepthAttachment);
|
||||
}
|
||||
|
||||
if self.depth_stencil.depth_compare != Compare::Always &&
|
||||
!self.render_pass.as_ref().unwrap().has_depth()
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::NoDepthAttachment);
|
||||
}
|
||||
|
||||
if (!self.depth_stencil.stencil_front.always_keep() ||
|
||||
!self.depth_stencil.stencil_back.always_keep()) &&
|
||||
!self.render_pass.as_ref().unwrap().has_stencil()
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::NoStencilAttachment);
|
||||
}
|
||||
|
||||
// FIXME: stencil writability
|
||||
|
||||
vk::PipelineDepthStencilStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
depthTestEnable: if !self.depth_stencil.depth_write &&
|
||||
self.depth_stencil.depth_compare == Compare::Always
|
||||
{
|
||||
vk::FALSE
|
||||
} else {
|
||||
vk::TRUE
|
||||
},
|
||||
depthWriteEnable: if self.depth_stencil.depth_write {
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
depthCompareOp: self.depth_stencil.depth_compare as u32,
|
||||
depthBoundsTestEnable: db.0,
|
||||
stencilTestEnable: if self.depth_stencil.stencil_front.always_keep() &&
|
||||
self.depth_stencil.stencil_back.always_keep()
|
||||
{
|
||||
vk::FALSE
|
||||
} else {
|
||||
vk::TRUE
|
||||
},
|
||||
front: vk::StencilOpState {
|
||||
failOp: self.depth_stencil.stencil_front.fail_op as u32,
|
||||
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
|
||||
.stencil_front
|
||||
.compare_mask
|
||||
.unwrap_or(u32::MAX),
|
||||
writeMask: self
|
||||
.depth_stencil
|
||||
.stencil_front
|
||||
.write_mask
|
||||
.unwrap_or(u32::MAX),
|
||||
reference: self.depth_stencil.stencil_front.reference.unwrap_or(0),
|
||||
},
|
||||
back: vk::StencilOpState {
|
||||
failOp: self.depth_stencil.stencil_back.fail_op as u32,
|
||||
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
|
||||
.stencil_back
|
||||
.compare_mask
|
||||
.unwrap_or(u32::MAX),
|
||||
writeMask: self
|
||||
.depth_stencil
|
||||
.stencil_back
|
||||
.write_mask
|
||||
.unwrap_or(u32::MAX),
|
||||
reference: self.depth_stencil.stencil_back.reference.unwrap_or(0),
|
||||
},
|
||||
minDepthBounds: db.1,
|
||||
maxDepthBounds: db.2,
|
||||
}
|
||||
};
|
||||
|
||||
let blend_atch: SmallVec<[vk::PipelineColorBlendAttachmentState; 8]> = {
|
||||
let num_atch = self.render_pass.as_ref().unwrap().num_color_attachments();
|
||||
|
||||
match self.blend.attachments {
|
||||
AttachmentsBlend::Collective(blend) => {
|
||||
(0 .. num_atch).map(|_| blend.clone().into_vulkan_state()).collect()
|
||||
},
|
||||
AttachmentsBlend::Individual(blend) => {
|
||||
if blend.len() != num_atch as usize {
|
||||
return Err(GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount);
|
||||
}
|
||||
|
||||
if !device.enabled_features().independent_blend {
|
||||
return Err(GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled);
|
||||
}
|
||||
|
||||
blend.iter().map(|b| b.clone().into_vulkan_state()).collect()
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let blend = vk::PipelineColorBlendStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
logicOpEnable: if self.blend.logic_op.is_some() {
|
||||
if !device.enabled_features().logic_op {
|
||||
return Err(GraphicsPipelineCreationError::LogicOpFeatureNotEnabled);
|
||||
}
|
||||
vk::TRUE
|
||||
} else {
|
||||
vk::FALSE
|
||||
},
|
||||
logicOp: self.blend.logic_op.unwrap_or(Default::default()) as u32,
|
||||
attachmentCount: blend_atch.len() as u32,
|
||||
pAttachments: blend_atch.as_ptr(),
|
||||
blendConstants: if let Some(c) = self.blend.blend_constants {
|
||||
c
|
||||
} else {
|
||||
dynamic_states.push(vk::DYNAMIC_STATE_BLEND_CONSTANTS);
|
||||
[0.0, 0.0, 0.0, 0.0]
|
||||
},
|
||||
};
|
||||
|
||||
let dynamic_states = if !dynamic_states.is_empty() {
|
||||
Some(vk::PipelineDynamicStateCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
dynamicStateCount: dynamic_states.len() as u32,
|
||||
pDynamicStates: dynamic_states.as_ptr(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let pipeline = unsafe {
|
||||
let infos = vk::GraphicsPipelineCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // TODO: some flags are available but none are critical
|
||||
stageCount: stages.len() as u32,
|
||||
pStages: stages.as_ptr(),
|
||||
pVertexInputState: &vertex_input_state,
|
||||
pInputAssemblyState: &input_assembly,
|
||||
pTessellationState: tessellation
|
||||
.as_ref()
|
||||
.map(|t| t as *const _)
|
||||
.unwrap_or(ptr::null()),
|
||||
pViewportState: &viewport_info,
|
||||
pRasterizationState: &rasterization,
|
||||
pMultisampleState: &multisample,
|
||||
pDepthStencilState: &depth_stencil,
|
||||
pColorBlendState: &blend,
|
||||
pDynamicState: dynamic_states
|
||||
.as_ref()
|
||||
.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(),
|
||||
subpass: self.render_pass.as_ref().unwrap().index(),
|
||||
basePipelineHandle: 0, // TODO:
|
||||
basePipelineIndex: -1, // TODO:
|
||||
};
|
||||
|
||||
let mut output = mem::uninitialized();
|
||||
check_errors(vk.CreateGraphicsPipelines(device.internal_object(),
|
||||
0,
|
||||
1,
|
||||
&infos,
|
||||
ptr::null(),
|
||||
&mut output))?;
|
||||
output
|
||||
};
|
||||
|
||||
let (render_pass, render_pass_subpass) = self.render_pass.take().unwrap().into();
|
||||
|
||||
Ok(GraphicsPipeline {
|
||||
inner: GraphicsPipelineInner {
|
||||
device: device.clone(),
|
||||
pipeline: pipeline,
|
||||
},
|
||||
layout: pipeline_layout,
|
||||
|
||||
vertex_definition: self.vertex_input,
|
||||
|
||||
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(),
|
||||
|
||||
num_viewports: self.viewport.as_ref().unwrap().num_viewports(),
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: add build_with_cache method
|
||||
@ -387,7 +1192,7 @@ impl<Vdef,
|
||||
vertex_input: self.vertex_input,
|
||||
vertex_shader: self.vertex_shader,
|
||||
input_assembly: self.input_assembly,
|
||||
tessellation: Some(GraphicsPipelineParamsTess {
|
||||
tessellation: Some(TessInfo {
|
||||
tessellation_control_shader: tessellation_control_shader,
|
||||
tessellation_evaluation_shader: tessellation_evaluation_shader,
|
||||
}),
|
||||
|
372
vulkano/src/pipeline/graphics_pipeline/creation_error.rs
Normal file
372
vulkano/src/pipeline/graphics_pipeline/creation_error.rs
Normal file
@ -0,0 +1,372 @@
|
||||
// Copyright (c) 2017 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
|
||||
use Error;
|
||||
use OomError;
|
||||
use descriptor::pipeline_layout::PipelineLayoutNotSupersetError;
|
||||
use pipeline::input_assembly::PrimitiveTopology;
|
||||
use pipeline::shader::ShaderInterfaceMismatchError;
|
||||
use pipeline::vertex::IncompatibleVertexDefinitionError;
|
||||
|
||||
/// Error that can happen when creating a graphics pipeline.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum GraphicsPipelineCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
|
||||
/// The pipeline layout is not compatible with what the shaders expect.
|
||||
IncompatiblePipelineLayout(PipelineLayoutNotSupersetError),
|
||||
|
||||
/// The interface between the vertex shader and the geometry shader mismatches.
|
||||
VertexGeometryStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The interface between the vertex shader and the tessellation control shader mismatches.
|
||||
VertexTessControlStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The interface between the vertex shader and the fragment shader mismatches.
|
||||
VertexFragmentStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The interface between the tessellation control shader and the tessellation evaluation
|
||||
/// shader mismatches.
|
||||
TessControlTessEvalStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The interface between the tessellation evaluation shader and the geometry shader
|
||||
/// mismatches.
|
||||
TessEvalGeometryStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The interface between the tessellation evaluation shader and the fragment shader
|
||||
/// mismatches.
|
||||
TessEvalFragmentStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The interface between the geometry shader and the fragment shader mismatches.
|
||||
GeometryFragmentStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The output of the fragment shader is not compatible with what the render pass subpass
|
||||
/// expects.
|
||||
FragmentShaderRenderPassIncompatible,
|
||||
|
||||
/// The vertex definition is not compatible with the input of the vertex shader.
|
||||
IncompatibleVertexDefinition(IncompatibleVertexDefinitionError),
|
||||
|
||||
/// The maximum stride value for vertex input (ie. the distance between two vertex elements)
|
||||
/// has been exceeded.
|
||||
MaxVertexInputBindingStrideExceeded {
|
||||
/// Index of the faulty binding.
|
||||
binding: usize,
|
||||
/// Maximum allowed value.
|
||||
max: usize,
|
||||
/// Value that was passed.
|
||||
obtained: usize,
|
||||
},
|
||||
|
||||
/// The maximum number of vertex sources has been exceeded.
|
||||
MaxVertexInputBindingsExceeded {
|
||||
/// Maximum allowed value.
|
||||
max: usize,
|
||||
/// Value that was passed.
|
||||
obtained: usize,
|
||||
},
|
||||
|
||||
/// The maximum offset for a vertex attribute has been exceeded. This means that your vertex
|
||||
/// struct is too large.
|
||||
MaxVertexInputAttributeOffsetExceeded {
|
||||
/// Maximum allowed value.
|
||||
max: usize,
|
||||
/// Value that was passed.
|
||||
obtained: usize,
|
||||
},
|
||||
|
||||
/// The maximum number of vertex attributes has been exceeded.
|
||||
MaxVertexInputAttributesExceeded {
|
||||
/// Maximum allowed value.
|
||||
max: usize,
|
||||
/// Value that was passed.
|
||||
obtained: usize,
|
||||
},
|
||||
|
||||
/// The user requested to use primitive restart, but the primitive topology doesn't support it.
|
||||
PrimitiveDoesntSupportPrimitiveRestart {
|
||||
/// The topology that doesn't support primitive restart.
|
||||
primitive: PrimitiveTopology,
|
||||
},
|
||||
|
||||
/// The `multi_viewport` feature must be enabled in order to use multiple viewports at once.
|
||||
MultiViewportFeatureNotEnabled,
|
||||
|
||||
/// The maximum number of viewports has been exceeded.
|
||||
MaxViewportsExceeded {
|
||||
/// Maximum allowed value.
|
||||
max: u32,
|
||||
/// Value that was passed.
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// The maximum dimensions of viewports has been exceeded.
|
||||
MaxViewportDimensionsExceeded,
|
||||
|
||||
/// The minimum or maximum bounds of viewports have been exceeded.
|
||||
ViewportBoundsExceeded,
|
||||
|
||||
/// The `wide_lines` feature must be enabled in order to use a line width superior to 1.0.
|
||||
WideLinesFeatureNotEnabled,
|
||||
|
||||
/// The `depth_clamp` feature must be enabled in order to use depth clamping.
|
||||
DepthClampFeatureNotEnabled,
|
||||
|
||||
/// The `depth_bias_clamp` feature must be enabled in order to use a depth bias clamp different
|
||||
/// from 0.0.
|
||||
DepthBiasClampFeatureNotEnabled,
|
||||
|
||||
/// The `fill_mode_non_solid` feature must be enabled in order to use a polygon mode different
|
||||
/// from `Fill`.
|
||||
FillModeNonSolidFeatureNotEnabled,
|
||||
|
||||
/// The `depth_bounds` feature must be enabled in order to use depth bounds testing.
|
||||
DepthBoundsFeatureNotEnabled,
|
||||
|
||||
/// The requested stencil test is invalid.
|
||||
WrongStencilState,
|
||||
|
||||
/// The primitives topology does not match what the geometry shader expects.
|
||||
TopologyNotMatchingGeometryShader,
|
||||
|
||||
/// The `geometry_shader` feature must be enabled in order to use geometry shaders.
|
||||
GeometryShaderFeatureNotEnabled,
|
||||
|
||||
/// The `tessellation_shader` feature must be enabled in order to use tessellation shaders.
|
||||
TessellationShaderFeatureNotEnabled,
|
||||
|
||||
/// The number of attachments specified in the blending does not match the number of
|
||||
/// attachments in the subpass.
|
||||
MismatchBlendingAttachmentsCount,
|
||||
|
||||
/// The `independent_blend` feature must be enabled in order to use different blending
|
||||
/// operations per attachment.
|
||||
IndependentBlendFeatureNotEnabled,
|
||||
|
||||
/// The `logic_op` feature must be enabled in order to use logic operations.
|
||||
LogicOpFeatureNotEnabled,
|
||||
|
||||
/// The depth test requires a depth attachment but render pass has no depth attachment, or
|
||||
/// depth writing is enabled and the depth attachment is read-only.
|
||||
NoDepthAttachment,
|
||||
|
||||
/// The stencil test requires a stencil attachment but render pass has no stencil attachment, or
|
||||
/// stencil writing is enabled and the stencil attachment is read-only.
|
||||
NoStencilAttachment,
|
||||
|
||||
/// Tried to use a patch list without a tessellation shader, or a non-patch-list with a
|
||||
/// tessellation shader.
|
||||
InvalidPrimitiveTopology,
|
||||
|
||||
/// The `maxTessellationPatchSize` limit was exceeded.
|
||||
MaxTessellationPatchSizeExceeded,
|
||||
|
||||
/// The wrong type of shader has been passed.
|
||||
///
|
||||
/// For example you passed a vertex shader as the fragment shader.
|
||||
WrongShaderType,
|
||||
}
|
||||
|
||||
impl error::Error for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
// TODO: finish
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
GraphicsPipelineCreationError::OomError(_) => "not enough memory available",
|
||||
GraphicsPipelineCreationError::VertexGeometryStagesMismatch(_) => {
|
||||
"the interface between the vertex shader and the geometry shader mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::VertexTessControlStagesMismatch(_) => {
|
||||
"the interface between the vertex shader and the tessellation control shader \
|
||||
mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::VertexFragmentStagesMismatch(_) => {
|
||||
"the interface between the vertex shader and the fragment shader mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(_) => {
|
||||
"the interface between the tessellation control shader and the tessellation \
|
||||
evaluation shader mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::TessEvalGeometryStagesMismatch(_) => {
|
||||
"the interface between the tessellation evaluation shader and the geometry \
|
||||
shader mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::TessEvalFragmentStagesMismatch(_) => {
|
||||
"the interface between the tessellation evaluation shader and the fragment \
|
||||
shader mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::GeometryFragmentStagesMismatch(_) => {
|
||||
"the interface between the geometry shader and the fragment shader mismatches"
|
||||
},
|
||||
GraphicsPipelineCreationError::IncompatiblePipelineLayout(_) => {
|
||||
"the pipeline layout is not compatible with what the shaders expect"
|
||||
},
|
||||
GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible => {
|
||||
"the output of the fragment shader is not compatible with what the render pass \
|
||||
subpass expects"
|
||||
},
|
||||
GraphicsPipelineCreationError::IncompatibleVertexDefinition(_) => {
|
||||
"the vertex definition is not compatible with the input of the vertex shader"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded { .. } => {
|
||||
"the maximum stride value for vertex input (ie. the distance between two vertex \
|
||||
elements) has been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded { .. } => {
|
||||
"the maximum number of vertex sources has been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded { .. } => {
|
||||
"the maximum offset for a vertex attribute has been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded { .. } => {
|
||||
"the maximum number of vertex attributes has been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart { .. } => {
|
||||
"the user requested to use primitive restart, but the primitive topology \
|
||||
doesn't support it"
|
||||
},
|
||||
GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled => {
|
||||
"the `multi_viewport` feature must be enabled in order to use multiple viewports \
|
||||
at once"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxViewportsExceeded { .. } => {
|
||||
"the maximum number of viewports has been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxViewportDimensionsExceeded => {
|
||||
"the maximum dimensions of viewports has been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::ViewportBoundsExceeded => {
|
||||
"the minimum or maximum bounds of viewports have been exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::WideLinesFeatureNotEnabled => {
|
||||
"the `wide_lines` feature must be enabled in order to use a line width \
|
||||
superior to 1.0"
|
||||
},
|
||||
GraphicsPipelineCreationError::DepthClampFeatureNotEnabled => {
|
||||
"the `depth_clamp` feature must be enabled in order to use depth clamping"
|
||||
},
|
||||
GraphicsPipelineCreationError::DepthBiasClampFeatureNotEnabled => {
|
||||
"the `depth_bias_clamp` feature must be enabled in order to use a depth bias \
|
||||
clamp different from 0.0."
|
||||
},
|
||||
GraphicsPipelineCreationError::FillModeNonSolidFeatureNotEnabled => {
|
||||
"the `fill_mode_non_solid` feature must be enabled in order to use a polygon mode \
|
||||
different from `Fill`"
|
||||
},
|
||||
GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled => {
|
||||
"the `depth_bounds` feature must be enabled in order to use depth bounds testing"
|
||||
},
|
||||
GraphicsPipelineCreationError::WrongStencilState => {
|
||||
"the requested stencil test is invalid"
|
||||
},
|
||||
GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader => {
|
||||
"the primitives topology does not match what the geometry shader expects"
|
||||
},
|
||||
GraphicsPipelineCreationError::GeometryShaderFeatureNotEnabled => {
|
||||
"the `geometry_shader` feature must be enabled in order to use geometry shaders"
|
||||
},
|
||||
GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled => {
|
||||
"the `tessellation_shader` feature must be enabled in order to use tessellation \
|
||||
shaders"
|
||||
},
|
||||
GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount => {
|
||||
"the number of attachments specified in the blending does not match the number of \
|
||||
attachments in the subpass"
|
||||
},
|
||||
GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled => {
|
||||
"the `independent_blend` feature must be enabled in order to use different \
|
||||
blending operations per attachment"
|
||||
},
|
||||
GraphicsPipelineCreationError::LogicOpFeatureNotEnabled => {
|
||||
"the `logic_op` feature must be enabled in order to use logic operations"
|
||||
},
|
||||
GraphicsPipelineCreationError::NoDepthAttachment => {
|
||||
"the depth attachment of the render pass does not match the depth test"
|
||||
},
|
||||
GraphicsPipelineCreationError::NoStencilAttachment => {
|
||||
"the stencil attachment of the render pass does not match the stencil test"
|
||||
},
|
||||
GraphicsPipelineCreationError::InvalidPrimitiveTopology => {
|
||||
"trying to use a patch list without a tessellation shader, or a non-patch-list \
|
||||
with a tessellation shader"
|
||||
},
|
||||
GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded => {
|
||||
"the maximum tessellation patch size was exceeded"
|
||||
},
|
||||
GraphicsPipelineCreationError::WrongShaderType => {
|
||||
"the wrong type of shader has been passed"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
GraphicsPipelineCreationError::OomError(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::VertexGeometryStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::VertexTessControlStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::VertexFragmentStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::TessControlTessEvalStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::TessEvalGeometryStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::TessEvalFragmentStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::GeometryFragmentStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::IncompatibleVertexDefinition(ref err) => Some(err),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{}", error::Error::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OomError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: OomError) -> GraphicsPipelineCreationError {
|
||||
GraphicsPipelineCreationError::OomError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutNotSupersetError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutNotSupersetError) -> GraphicsPipelineCreationError {
|
||||
GraphicsPipelineCreationError::IncompatiblePipelineLayout(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IncompatibleVertexDefinitionError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: IncompatibleVertexDefinitionError) -> GraphicsPipelineCreationError {
|
||||
GraphicsPipelineCreationError::IncompatibleVertexDefinition(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: Error) -> GraphicsPipelineCreationError {
|
||||
match err {
|
||||
err @ Error::OutOfHostMemory => {
|
||||
GraphicsPipelineCreationError::OomError(OomError::from(err))
|
||||
},
|
||||
err @ Error::OutOfDeviceMemory => {
|
||||
GraphicsPipelineCreationError::OomError(OomError::from(err))
|
||||
},
|
||||
_ => panic!("unexpected error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user