use vk::*;
use std::ffi::CString;
use {VkHandle, DeviceChild};
#[cfg(feature = "Implements")] use VkResultHandler;
use std::ptr::null;
use std::marker::PhantomData;
#[cfg(feature = "Implements")] use crate::vkresolve::{Resolver, ResolverInterface};
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, Hash)]
pub struct ShaderStage(pub VkShaderStageFlags);
impl ShaderStage
{
pub const EMPTY: Self = ShaderStage(0);
pub const VERTEX: Self = ShaderStage(VK_SHADER_STAGE_VERTEX_BIT);
pub const TESSELLATION_CONTROL: Self = ShaderStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
pub const TESSELLATION_EVALUATION: Self = ShaderStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
pub const GEOMETRY: Self = ShaderStage(VK_SHADER_STAGE_GEOMETRY_BIT);
pub const FRAGMENT: Self = ShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT);
pub const COMPUTE: Self = ShaderStage(VK_SHADER_STAGE_COMPUTE_BIT);
pub const ALL_GRAPHICS: Self = ShaderStage(VK_SHADER_STAGE_ALL_GRAPHICS);
pub const ALL: Self = ShaderStage(VK_SHADER_STAGE_ALL);
pub const TESSELLATION: Self = ShaderStage(Self::TESSELLATION_CONTROL.0 | Self::TESSELLATION_EVALUATION.0);
pub fn vertex(self) -> Self { ShaderStage(self.0 | Self::VERTEX.0) }
pub fn tessellation_control(self) -> Self { ShaderStage(self.0 | Self::TESSELLATION_CONTROL.0) }
pub fn tessellation_evaluation(self) -> Self { ShaderStage(self.0 | Self::TESSELLATION_EVALUATION.0) }
pub fn geometry(self) -> Self { ShaderStage(self.0 | Self::GEOMETRY.0) }
pub fn fragment(self) -> Self { ShaderStage(self.0 | Self::FRAGMENT.0) }
pub fn compute(self) -> Self { ShaderStage(self.0 | Self::COMPUTE.0) }
pub fn all_graphics(self) -> Self { ShaderStage(self.0 | Self::ALL_GRAPHICS.0) }
pub fn tessellation(self) -> Self { ShaderStage(self.0 | Self::TESSELLATION.0) }
}
#[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp
{
Never = VK_COMPARE_OP_NEVER as _,
Less = VK_COMPARE_OP_LESS as _,
Equal = VK_COMPARE_OP_EQUAL as _,
LessOrEqual = VK_COMPARE_OP_LESS_OR_EQUAL as _,
Greater = VK_COMPARE_OP_GREATER as _,
NotEqual = VK_COMPARE_OP_NOT_EQUAL as _,
GreaterOrEqual = VK_COMPARE_OP_GREATER_OR_EQUAL as _,
Always = VK_COMPARE_OP_ALWAYS as _
}
#[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StencilOp
{
Keep = VK_STENCIL_OP_KEEP as _,
Zero = VK_STENCIL_OP_ZERO as _,
Replace = VK_STENCIL_OP_REPLACE as _,
IncrementClamp = VK_STENCIL_OP_INCREMENT_AND_CLAMP as _,
DecrementClamp = VK_STENCIL_OP_DECREMENT_AND_CLAMP as _,
Invert = VK_STENCIL_OP_INVERT as _,
IncrementWrap = VK_STENCIL_OP_INCREMENT_AND_WRAP as _,
DecrementWrap = VK_STENCIL_OP_DECREMENT_AND_WRAP as _
}
#[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogicOp
{
Clear = VK_LOGIC_OP_CLEAR as _,
And = VK_LOGIC_OP_AND as _,
AndReverse = VK_LOGIC_OP_AND_REVERSE as _,
Copy = VK_LOGIC_OP_COPY as _,
AndInverted = VK_LOGIC_OP_AND_INVERTED as _,
NoOp = VK_LOGIC_OP_NO_OP as _,
Xor = VK_LOGIC_OP_XOR as _,
Or = VK_LOGIC_OP_OR as _,
Nor = VK_LOGIC_OP_NOR as _,
Equivalent = VK_LOGIC_OP_EQUIVALENT as _,
Invert = VK_LOGIC_OP_INVERT as _,
OrReverse = VK_LOGIC_OP_OR_REVERSE as _,
CopyInverted = VK_LOGIC_OP_COPY_INVERTED as _,
OrInverted = VK_LOGIC_OP_OR_INVERTED as _,
Nand = VK_LOGIC_OP_NAND as _,
Set = VK_LOGIC_OP_SET as _
}
#[repr(C)] #[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub enum StencilFaceMask
{
Front = VK_STENCIL_FACE_FRONT_BIT as _,
Back = VK_STENCIL_FACE_BACK_BIT as _,
Both = VK_STENCIL_FRONT_AND_BACK as _
}
pub struct ShaderModule(VkShaderModule, ::Device);
pub struct PipelineCache(VkPipelineCache, ::Device);
pub struct PipelineLayout(VkPipelineLayout, ::Device);
pub struct Pipeline(VkPipeline, ::Device);
#[cfg(feature = "Implements")] DeviceChildCommonDrop! {
for ShaderModule[destroy_shader_module], PipelineCache[destroy_pipeline_cache], PipelineLayout[destroy_pipeline_layout],
Pipeline[destroy_pipeline]
}
impl VkHandle for ShaderModule { type Handle = VkShaderModule; fn native_ptr(&self) -> VkShaderModule { self.0 } }
impl VkHandle for PipelineCache { type Handle = VkPipelineCache; fn native_ptr(&self) -> VkPipelineCache { self.0 } }
impl VkHandle for PipelineLayout { type Handle = VkPipelineLayout; fn native_ptr(&self) -> VkPipelineLayout { self.0 } }
impl VkHandle for Pipeline { type Handle = VkPipeline; fn native_ptr(&self) -> VkPipeline { self.0 } }
impl DeviceChild for ShaderModule { fn device(&self) -> &::Device { &self.1 } }
impl DeviceChild for PipelineCache { fn device(&self) -> &::Device { &self.1 } }
impl DeviceChild for PipelineLayout { fn device(&self) -> &::Device { &self.1 } }
impl DeviceChild for Pipeline { fn device(&self) -> &::Device { &self.1 } }
#[cfg(feature = "Implements")]
impl ShaderModule
{
pub fn from_memory<Buffer: AsRef<[u8]> + ?Sized>(device: &::Device, buffer: &Buffer) -> ::Result<Self>
{
let cinfo = VkShaderModuleCreateInfo
{
codeSize: buffer.as_ref().len() as _, pCode: buffer.as_ref().as_ptr() as *const _, .. Default::default()
};
let mut h = VK_NULL_HANDLE as _;
unsafe { Resolver::get().create_shader_module(device.native_ptr(), &cinfo, ::std::ptr::null(), &mut h) }.into_result()
.map(|_| ShaderModule(h, device.clone()))
}
pub fn from_file<FilePath: AsRef<std::path::Path> + ?Sized>(device: &crate::Device, path: &FilePath) -> Result<Self, Box<dyn std::error::Error>>
{
use std::io::prelude::Read;
let bin = ::std::fs::File::open(path).and_then(|mut fp| { let mut v = Vec::new(); fp.read_to_end(&mut v).map(|_| v) })?;
Self::from_memory(device, &bin).map_err(From::from)
}
}
#[cfg(feature = "Implements")]
impl PipelineCache
{
pub fn new<Data: AsRef<[u8]> + ?Sized>(device: &::Device, initial: &Data) -> ::Result<Self>
{
let cinfo = VkPipelineCacheCreateInfo
{
initialDataSize: initial.as_ref().len() as _, pInitialData: initial.as_ref().as_ptr() as *const _, .. Default::default()
};
let mut h = VK_NULL_HANDLE as _;
unsafe { Resolver::get().create_pipeline_cache(device.native_ptr(), &cinfo, ::std::ptr::null(), &mut h) }.into_result()
.map(|_| PipelineCache(h, device.clone()))
}
pub fn data(&self) -> ::Result<Vec<u8>>
{
let mut n = 0;
unsafe { Resolver::get().get_pipeline_cache_data(self.1.native_ptr(), self.0, &mut n, ::std::ptr::null_mut()) }.into_result()?;
let mut b = Vec::<u8>::with_capacity(n as _); unsafe { b.set_len(n as _) };
unsafe { Resolver::get().get_pipeline_cache_data(self.1.native_ptr(), self.0, &mut n, b.as_mut_ptr() as *mut _) }.into_result().map(|_| b)
}
pub fn merge_into(&self, src: &[&PipelineCache]) -> ::Result<()>
{
let srcs = src.iter().map(|x| x.0).collect::<Vec<_>>();
unsafe { Resolver::get().merge_pipeline_caches(self.1.native_ptr(), self.0, srcs.len() as _, srcs.as_ptr()) }.into_result()
}
}
#[cfg(feature = "Implements")]
impl PipelineLayout
{
pub fn new(device: &::Device, layouts: &[&::DescriptorSetLayout], push_constants: &[(ShaderStage, ::std::ops::Range<u32>)]) -> ::Result<Self>
{
let layouts = layouts.into_iter().map(|x| x.native_ptr()).collect::<Vec<_>>();
let push_constants = push_constants.iter().map(|&(sh, ref r)| VkPushConstantRange { stageFlags: sh.0, offset: r.start, size: r.end - r.start })
.collect::<Vec<_>>();
let cinfo = VkPipelineLayoutCreateInfo
{
setLayoutCount: layouts.len() as _, pSetLayouts: layouts.as_ptr(),
pushConstantRangeCount: push_constants.len() as _, pPushConstantRanges: push_constants.as_ptr(),
.. Default::default()
};
let mut h = VK_NULL_HANDLE as _;
unsafe { Resolver::get().create_pipeline_layout(device.native_ptr(), &cinfo, ::std::ptr::null(), &mut h) }.into_result()
.map(|_| PipelineLayout(h, device.clone()))
}
}
pub enum SwitchOrDynamicState<T> { Disabled, Dynamic, Static(T) }
impl<T> SwitchOrDynamicState<T>
{
fn is_dynamic(&self) -> bool { match self { SwitchOrDynamicState::Dynamic => true, _ => false } }
fn is_enabled(&self) -> bool { match self { SwitchOrDynamicState::Disabled => false, _ => true } }
}
pub use SwitchOrDynamicState::*;
#[cfg_attr(not(feature = "Implements"), allow(dead_code))] #[derive(Clone)]
pub struct DynamicDataCell<'d> { size: usize, data: *const (), ph: PhantomData<&'d ()> }
impl<'d, T> From<&'d T> for DynamicDataCell<'d>
{
fn from(d: &'d T) -> Self { DynamicDataCell { size: ::std::mem::size_of::<T>(), data: d as *const T as *const _, ph: PhantomData } }
}
impl<'d> DynamicDataCell<'d>
{
pub fn from_slice<T>(s: &'d [T]) -> Self
{
DynamicDataCell { size: ::std::mem::size_of::<T>() * s.len(), data: s.as_ptr() as *const _, ph: ::std::marker::PhantomData }
}
}
#[cfg_attr(not(feature = "Implements"), allow(dead_code))] #[derive(Clone)]
pub struct PipelineShader<'d>
{
pub module: &'d ShaderModule, pub entry_name: CString,
pub specinfo: Option<(Vec<VkSpecializationMapEntry>, DynamicDataCell<'d>)>
}
pub enum DynamicArrayState<'d, T: 'd> { Dynamic(usize), Static(&'d [T]) }
#[derive(Clone)]
struct DynamicStateFlags
{
viewport: bool, scissor: bool, line_width: bool, depth_bias: bool, blend_constants: bool, depth_bounds: bool,
stencil_compare_mask: bool, stencil_write_mask: bool, stencil_reference: bool
}
#[derive(Clone, Copy)]
pub enum BasePipeline<'d>
{
None,
Handle(&'d Pipeline),
Index(u32)
}
#[derive(Clone)]
pub struct GraphicsPipelineBuilder<'d>
{
flags: VkPipelineCreateFlags, _layout: &'d PipelineLayout, rp: &'d ::RenderPass, subpass: u32, _base: BasePipeline<'d>,
vp: Option<VertexProcessingStages<'d>>,
rasterizer_state: VkPipelineRasterizationStateCreateInfo,
tess_state: Option<Box<VkPipelineTessellationStateCreateInfo>>,
viewport_state: Option<Box<VkPipelineViewportStateCreateInfo>>,
ms_state: Option<&'d MultisampleState>,
ds_state: Option<Box<VkPipelineDepthStencilStateCreateInfo>>,
color_blending: Option<(Box<VkPipelineColorBlendStateCreateInfo>, Vec<VkPipelineColorBlendAttachmentState>)>,
dynamic_state_flags: DynamicStateFlags
}
impl<'d, T> DynamicArrayState<'d, T>
{
fn count(&self) -> usize
{
match self { DynamicArrayState::Dynamic(s) => *s, DynamicArrayState::Static(ref v) => v.len() }
}
fn as_ptr(&self) -> *const T
{
match self { DynamicArrayState::Static(ref v) => v.as_ptr(), _ => ::std::ptr::null() }
}
fn is_dynamic(&self) -> bool
{
match self { DynamicArrayState::Dynamic(_) => true, _ => false }
}
}
#[derive(Clone)] pub struct VertexProcessingStages<'d>
{
vertex: PipelineShader<'d>, vi: VkPipelineVertexInputStateCreateInfo,
ia: VkPipelineInputAssemblyStateCreateInfo,
geometry: Option<PipelineShader<'d>>, fragment: Option<PipelineShader<'d>>,
_holder: PhantomData<(&'d [VkVertexInputBindingDescription], &'d [VkVertexInputAttributeDescription])>
}
impl<'d> VertexProcessingStages<'d>
{
pub fn new(vsh: PipelineShader<'d>,
vbind: &'d [VkVertexInputBindingDescription], vattr: &'d [VkVertexInputAttributeDescription],
primitive_topo: VkPrimitiveTopology) -> Self
{
VertexProcessingStages
{
vertex: vsh, vi: VkPipelineVertexInputStateCreateInfo
{
vertexBindingDescriptionCount: vbind.len() as _,
pVertexBindingDescriptions: vbind.as_ptr(),
vertexAttributeDescriptionCount: vattr.len() as _,
pVertexAttributeDescriptions: vattr.as_ptr(), .. Default::default()
},
ia: VkPipelineInputAssemblyStateCreateInfo
{
topology: primitive_topo, .. Default::default()
},
geometry: None, fragment: None, _holder: PhantomData
}
}
pub fn vertex_shader(&mut self, vsh: PipelineShader<'d>) -> &mut Self
{
self.vertex = vsh; self
}
pub fn mod_vertex_shader(&mut self) -> &mut PipelineShader<'d> { &mut self.vertex }
pub fn geometry_shader<S: Into<Option<PipelineShader<'d>>>>(&mut self, gsh: S) -> &mut Self
{
self.geometry = gsh.into(); self
}
pub fn mod_geometry_shader(&mut self) -> Option<&mut PipelineShader<'d>> { Option::as_mut(&mut self.geometry) }
pub fn fragment_shader<S: Into<Option<PipelineShader<'d>>>>(&mut self, fsh: S) -> &mut Self
{
self.fragment = fsh.into(); self
}
pub fn mod_fragment_shader(&mut self) -> Option<&mut PipelineShader<'d>> { Option::as_mut(&mut self.fragment) }
pub fn vertex_binding(&mut self, vbind: &'d [VkVertexInputBindingDescription]) -> &mut Self
{
self.vi.vertexBindingDescriptionCount = vbind.len() as _;
self.vi.pVertexBindingDescriptions = vbind.as_ptr(); self
}
pub fn vertex_attributes(&mut self, vattr: &'d [VkVertexInputAttributeDescription]) -> &mut Self
{
self.vi.vertexAttributeDescriptionCount = vattr.len() as _;
self.vi.pVertexAttributeDescriptions = vattr.as_ptr(); self
}
pub fn vertex_input(&mut self, vbind: &'d [VkVertexInputBindingDescription],
vattr: &'d [VkVertexInputAttributeDescription]) -> &mut Self
{
self.vertex_binding(vbind).vertex_attributes(vattr)
}
pub fn vertex_processing(&mut self, vsh: PipelineShader<'d>,
vbind: &'d [VkVertexInputBindingDescription], vattr: &'d [VkVertexInputAttributeDescription]) -> &mut Self
{
self.vertex_shader(vsh).vertex_input(vbind, vattr)
}
pub fn enable_primitive_restart(&mut self, w: bool) -> &mut Self
{
self.ia.primitiveRestartEnable = w as _; self
}
pub fn primitive_topology(&mut self, topo: VkPrimitiveTopology) -> &mut Self
{
self.ia.topology = topo; self
}
}
#[derive(Clone)] pub struct MultisampleState(VkPipelineMultisampleStateCreateInfo);
impl MultisampleState
{
#[allow(clippy::new_without_default)]
pub fn new() -> Self
{
MultisampleState(VkPipelineMultisampleStateCreateInfo
{
rasterizationSamples: 1, .. Default::default()
})
}
pub fn rasterization_samples(&mut self, samples: usize) -> &mut Self
{
self.0.rasterizationSamples = samples as _; self
}
pub fn sample_mask(&mut self, mask: &[VkSampleMask]) -> &mut Self
{
if mask.is_empty()
{
self.0.pSampleMask = null();
}
else {
assert_eq!(mask.len(), (self.0.rasterizationSamples as usize + 31) / 32);
self.0.pSampleMask = mask.as_ptr();
}
self
}
pub fn sample_shading(&mut self, min_sample_shading: Option<f32>) -> &mut Self
{
self.0.sampleShadingEnable = min_sample_shading.is_some() as _;
if let Some(m) = min_sample_shading
{
assert!(0.0 <= m && m <= 1.0,
"Invalid usage: VkPipelineMultisampleStateCreateInfo::minSampleShading must be in the range [0, 1]");
self.0.minSampleShading = m as _;
}
self
}
pub fn enable_alpha_to_coverage(&mut self, w: bool) -> &mut Self
{
self.0.alphaToCoverageEnable = w as _; self
}
pub fn replace_alpha_to_one(&mut self, w: bool) -> &mut Self { self.0.alphaToOneEnable = w as _; self }
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub fn new(layout: &'d PipelineLayout, rpsp: (&'d ::RenderPass, u32)) -> Self
{
GraphicsPipelineBuilder
{
flags: 0, _layout: layout, rp: rpsp.0, subpass: rpsp.1, _base: BasePipeline::None,
vp: None, rasterizer_state: Default::default(),
tess_state: None, viewport_state: None, ms_state: None, ds_state: None, color_blending: None,
dynamic_state_flags: unsafe { ::std::mem::zeroed() }
}
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub fn vertex_processing(&mut self, vp: VertexProcessingStages<'d>) -> &mut Self
{
self.vp = Some(vp); self
}
pub fn vertex_processing_mut(&mut self) -> &mut VertexProcessingStages<'d> { self.vp.as_mut().unwrap() }
pub fn tessellation_control_shader(&mut self, _shader: PipelineShader<'d>) -> &mut Self { self }
pub fn tessellation_evaluation_shader(&mut self, _shader: PipelineShader<'d>) -> &mut Self { self }
pub fn patch_control_point_count(&mut self, count: u32) -> &mut Self
{
if self.tess_state.is_none() { self.tess_state = Some(Default::default()); }
self.tess_state.as_mut().unwrap().patchControlPoints = count; self
}
pub fn tessellator_settings(&mut self, control: PipelineShader<'d>, evaluation: PipelineShader<'d>, num_control_points: u32) -> &mut Self
{
self.tessellation_control_shader(control).tessellation_evaluation_shader(evaluation).patch_control_point_count(num_control_points)
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub unsafe fn viewports(&mut self, vps: DynamicArrayState<VkViewport>) -> &mut Self
{
if self.viewport_state.is_none() { self.viewport_state = Some(Default::default()); }
self.viewport_state.as_mut().unwrap().viewportCount = vps.count() as _;
self.viewport_state.as_mut().unwrap().pViewports = vps.as_ptr();
self.dynamic_state_flags.viewport = vps.is_dynamic();
self
}
pub unsafe fn scissors(&mut self, scs: DynamicArrayState<VkRect2D>) -> &mut Self
{
if self.viewport_state.is_none() { self.viewport_state = Some(Default::default()); }
self.viewport_state.as_mut().unwrap().scissorCount = scs.count() as _;
self.viewport_state.as_mut().unwrap().pScissors = scs.as_ptr();
self.dynamic_state_flags.scissor = scs.is_dynamic();
self
}
pub fn fixed_viewport_scissors(&mut self, vps: DynamicArrayState<VkViewport>, scissor: DynamicArrayState<VkRect2D>) -> &mut Self
{
assert_eq!(vps.count(), scissor.count());
unsafe { self.viewports(vps).scissors(scissor) }
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub fn depth_clamp_enable(&mut self, enable: bool) -> &mut Self { self.rasterizer_state.depthClampEnable = enable as _; self }
pub fn rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self { self.rasterizer_state.rasterizerDiscardEnable = enable as _; self }
pub fn polygon_mode(&mut self, mode: VkPolygonMode) -> &mut Self { self.rasterizer_state.polygonMode = mode; self }
pub fn cull_mode(&mut self, mode: VkCullModeFlags) -> &mut Self { self.rasterizer_state.cullMode = mode; self }
pub fn front_face(&mut self, face: VkFrontFace) -> &mut Self { self.rasterizer_state.frontFace = face; self }
pub fn depth_bias(&mut self, opts: SwitchOrDynamicState<(f32, f32, f32)>) -> &mut Self
{
self.rasterizer_state.depthBiasEnable = opts.is_enabled() as _;
self.dynamic_state_flags.depth_bias = opts.is_dynamic();
if let SwitchOrDynamicState::Static((cf, c, sf)) = opts
{
self.rasterizer_state.depthBiasConstantFactor = cf;
self.rasterizer_state.depthBiasClamp = c;
self.rasterizer_state.depthBiasSlopeFactor = sf;
}
self
}
pub fn line_width(&mut self, width: Option<f32>) -> &mut Self
{
self.dynamic_state_flags.line_width = width.is_none() as _;
self.rasterizer_state.lineWidth = width.unwrap_or(0.0); self
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub fn multisample_state(&mut self, state: Option<&'d MultisampleState>) -> &mut Self
{
self.ms_state = state; self
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub fn clear_depth_stencil_state(&mut self) -> &mut Self { self.ds_state = None; self }
fn dss_ref(&mut self) -> &mut VkPipelineDepthStencilStateCreateInfo
{
if self.ds_state.is_none() { self.ds_state = Some(Box::new(Default::default())); }
self.ds_state.as_mut().unwrap()
}
pub fn depth_test_enable(&mut self, enable: bool) -> &mut Self { self.dss_ref().depthTestEnable = enable as _; self }
pub fn depth_write_enable(&mut self, enable: bool) -> &mut Self { self.dss_ref().depthWriteEnable = enable as _; self }
pub fn depth_compare_op(&mut self, op: CompareOp) -> &mut Self { self.dss_ref().depthCompareOp = op as _; self }
pub fn depth_test_settings(&mut self, compare_op: Option<CompareOp>, write_enable: bool) -> &mut Self
{
if let Some(op) = compare_op { self.depth_test_enable(true).depth_compare_op(op) } else { self.depth_test_enable(false) }
.depth_write_enable(write_enable)
}
pub fn depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self { self.dss_ref().depthBoundsTestEnable = enable as _; self }
pub fn stencil_test_enable(&mut self, enable: bool) -> &mut Self { self.dss_ref().stencilTestEnable = enable as _; self }
pub fn stencil_control_front(&mut self, state: VkStencilOpState) -> &mut Self
{
self.dynamic_state_flags.stencil_compare_mask = false;
self.dynamic_state_flags.stencil_write_mask = false;
self.dynamic_state_flags.stencil_reference = false;
self.dss_ref().front = state;
self
}
pub fn stencil_control_back(&mut self, state: VkStencilOpState) -> &mut Self
{
self.dynamic_state_flags.stencil_compare_mask = false;
self.dynamic_state_flags.stencil_write_mask = false;
self.dynamic_state_flags.stencil_reference = false;
self.dss_ref().back = state;
self
}
pub fn stencil_compare_mask(&mut self, mask: Option<(u32, u32)>) -> &mut Self
{
self.dynamic_state_flags.stencil_compare_mask = if let Some((f, b)) = mask
{
self.dss_ref().front.compareMask = f;
self.dss_ref().back.compareMask = b;
false
}
else { true }; self
}
pub fn stencil_write_mask(&mut self, mask: Option<(u32, u32)>) -> &mut Self
{
self.dynamic_state_flags.stencil_write_mask = if let Some((f, b)) = mask
{
self.dss_ref().front.writeMask = f; self.dss_ref().back.writeMask = b;
false
}
else { true }; self
}
pub fn stencil_reference(&mut self, mask: Option<(u32, u32)>) -> &mut Self
{
self.dynamic_state_flags.stencil_reference = if let Some((f, b)) = mask
{
self.dss_ref().front.reference = f; self.dss_ref().back.reference = b;
false
}
else { true }; self
}
pub fn depth_bounds_range(&mut self, bounds: ::std::ops::Range<f32>) -> &mut Self
{
self.dss_ref().minDepthBounds = bounds.start; self.dss_ref().maxDepthBounds = bounds.end; self
}
pub fn depth_bounds(&mut self, bounds: SwitchOrDynamicState<::std::ops::Range<f32>>) -> &mut Self
{
self.depth_bounds_test_enable(bounds.is_enabled());
self.dynamic_state_flags.depth_bounds = bounds.is_dynamic();
if let SwitchOrDynamicState::Static(r) = bounds { self.depth_bounds_range(r) } else { self }
}
}
#[repr(C)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum BlendFactor
{
Zero = VK_BLEND_FACTOR_ZERO as _,
One = VK_BLEND_FACTOR_ONE as _,
SourceColor = VK_BLEND_FACTOR_SRC_COLOR as _,
OneMinusSourceColor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR as _,
DestColor = VK_BLEND_FACTOR_DST_COLOR as _,
OneMinusDestColor = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR as _,
SourceAlpha = VK_BLEND_FACTOR_SRC_ALPHA as _,
OneMinusSourceAlpha = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA as _,
DestAlpha = VK_BLEND_FACTOR_DST_ALPHA as _,
OneMinusDestAlpha = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA as _,
ConstantColor = VK_BLEND_FACTOR_CONSTANT_COLOR as _,
OneMinusConstantColor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR as _,
ConstantAlpha = VK_BLEND_FACTOR_CONSTANT_ALPHA as _,
OneMinusConstantAlpha = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA as _,
SrcAlphaSat = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE as _,
AltSourceColor = VK_BLEND_FACTOR_SRC1_COLOR as _,
OneMinusAltSourceColor = VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR as _,
AltSourceAlpha = VK_BLEND_FACTOR_SRC1_ALPHA as _,
OneMinusAltSourceAlpha = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA as _
}
#[repr(C)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum BlendOp
{
Add = VK_BLEND_OP_ADD as _,
Sub = VK_BLEND_OP_SUBTRACT as _,
RevSub = VK_BLEND_OP_REVERSE_SUBTRACT as _,
Min = VK_BLEND_OP_MIN as _,
Max = VK_BLEND_OP_MAX as _
}
#[derive(Clone)] pub struct AttachmentColorBlendState(VkPipelineColorBlendAttachmentState);
impl AttachmentColorBlendState
{
pub fn noblend() -> Self { AttachmentColorBlendState(Default::default()) }
pub fn premultiplied() -> Self
{
AttachmentColorBlendState(VkPipelineColorBlendAttachmentState
{
blendEnable: true as _,
srcColorBlendFactor: BlendFactor::One as _,
dstColorBlendFactor: BlendFactor::OneMinusSourceAlpha as _,
colorBlendOp: BlendOp::Add as _,
srcAlphaBlendFactor: BlendFactor::One as _,
dstAlphaBlendFactor: BlendFactor::OneMinusSourceAlpha as _,
alphaBlendOp: BlendOp::Add as _, .. Default::default()
})
}
pub fn enable(&mut self, w: bool) -> &mut Self { self.0.blendEnable = w as _; self }
pub fn color_blend_factor_src(&mut self, f: BlendFactor) -> &mut Self
{
self.0.srcColorBlendFactor = f as _; self
}
pub fn color_blend_factor_dst(&mut self, f: BlendFactor) -> &mut Self
{
self.0.dstColorBlendFactor = f as _; self
}
pub fn alpha_blend_factor_src(&mut self, f: BlendFactor) -> &mut Self
{
self.0.srcAlphaBlendFactor = f as _; self
}
pub fn alpha_blend_factor_dst(&mut self, f: BlendFactor) -> &mut Self
{
self.0.dstAlphaBlendFactor = f as _; self
}
pub fn color_blend_op(&mut self, op: BlendOp) -> &mut Self { self.0.colorBlendOp = op as _; self }
pub fn alpha_blend_op(&mut self, op: BlendOp) -> &mut Self { self.0.alphaBlendOp = op as _; self }
pub fn color_blend(&mut self, src: BlendFactor, op: BlendOp, dst: BlendFactor) -> &mut Self
{
self.color_blend_factor_src(src).color_blend_op(op).color_blend_factor_dst(dst)
}
pub fn alpha_blend(&mut self, src: BlendFactor, op: BlendOp, dst: BlendFactor) -> &mut Self
{
self.alpha_blend_factor_src(src).alpha_blend_op(op).alpha_blend_factor_dst(dst)
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
fn cb_ref(&mut self) -> &mut (Box<VkPipelineColorBlendStateCreateInfo>, Vec<VkPipelineColorBlendAttachmentState>)
{
if self.color_blending.is_none() { self.color_blending = Some((Default::default(), Vec::new())) }
self.color_blending.as_mut().unwrap()
}
pub fn logic_op(&mut self, op: Option<LogicOp>) -> &mut Self
{
self.cb_ref().0.logicOpEnable = op.is_some() as _;
self.cb_ref().0.logicOp = op.unwrap_or(LogicOp::NoOp) as _;
self
}
pub fn add_attachment_blend(&mut self, blend: AttachmentColorBlendState) -> &mut Self
{
{
let cb = self.cb_ref();
cb.1.push(blend.0); cb.0.attachmentCount = cb.1.len() as _; cb.0.pAttachments = cb.1.as_ptr();
}
self
}
pub fn clear_attachment_blends(&mut self) -> &mut Self { self.color_blending = None; self }
pub fn blend_constants(&mut self, values: Option<[f32; 4]>) -> &mut Self
{
self.dynamic_state_flags.blend_constants = values.is_none();
self.cb_ref().0.blendConstants.copy_from_slice(&values.unwrap_or([0.0; 4])); self
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub fn base(&mut self, b: BasePipeline<'d>) -> &mut Self { self._base = b; self }
pub fn layout(&mut self, l: &'d PipelineLayout) -> &mut Self { self._layout = l; self }
pub fn render_pass(&mut self, rpo: &'d ::RenderPass, subpass: u32) -> &mut Self
{
self.rp = rpo; self.subpass = subpass; self
}
pub fn enable_optimization(&mut self, opt: bool) -> &mut Self
{
if opt { self.flags &= !VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT }
else { self.flags |= VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT };
self
}
pub fn allow_derivatives(&mut self, allow: bool) -> &mut Self
{
if allow { self.flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT }
else { self.flags &= !VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT };
self
}
}
impl<'d> GraphicsPipelineBuilder<'d>
{
pub unsafe fn tessellation_state_create_info(&mut self, state: Option<Box<VkPipelineTessellationStateCreateInfo>>) -> &mut Self
{
self.tess_state = state; self
}
pub unsafe fn viewport_state_create_info(&mut self, state: Option<Box<VkPipelineViewportStateCreateInfo>>) -> &mut Self
{
self.viewport_state = state; self
}
pub unsafe fn rasterization_state_create_info(&mut self, state: VkPipelineRasterizationStateCreateInfo) -> &mut Self
{
self.rasterizer_state = state; self
}
pub unsafe fn depth_stencil_state_create_info(&mut self, state: Option<Box<VkPipelineDepthStencilStateCreateInfo>>) -> &mut Self
{
self.ds_state = state; self
}
pub unsafe fn color_blend_state_info(&mut self, state: Option<Box<VkPipelineColorBlendStateCreateInfo>>) -> &mut Self
{
self.color_blending = state.map(|x| (x, Vec::new())); self
}
}
#[cfg(feature = "Implements")]
impl<'d> PipelineShader<'d>
{
fn createinfo_native(&self, stage: ShaderStage)
-> (VkPipelineShaderStageCreateInfo, Option<Box<VkSpecializationInfo>>)
{
let specinfo = self.specinfo.as_ref().map(|&(ref m, ref d)| Box::new(VkSpecializationInfo
{
mapEntryCount: m.len() as _, pMapEntries: m.as_ptr(), dataSize: d.size as _, pData: d.data as _
}));
(VkPipelineShaderStageCreateInfo
{
stage: stage.0, module: self.module.native_ptr(), pName: self.entry_name.as_ptr(),
pSpecializationInfo: specinfo.as_ref().map(|x| &**x as *const _).unwrap_or_else(null),
.. Default::default()
}, specinfo)
}
}
#[cfg(feature = "Implements")]
impl<'d> VertexProcessingStages<'d>
{
pub fn generate_stages(&self) -> (Vec<VkPipelineShaderStageCreateInfo>, Vec<Option<Box<VkSpecializationInfo>>>)
{
let mut stages = Vec::with_capacity(3);
stages.push(self.vertex.createinfo_native(ShaderStage::VERTEX));
if let Some(ref s) = self.geometry { stages.push(s.createinfo_native(ShaderStage::GEOMETRY)); }
if let Some(ref s) = self.fragment { stages.push(s.createinfo_native(ShaderStage::FRAGMENT)); }
stages.into_iter().unzip()
}
}
#[cfg(feature = "Implements")]
impl<'d> GraphicsPipelineBuilder<'d>
{
fn rasterized(&self) -> bool { self.rasterizer_state.rasterizerDiscardEnable == false as _ }
fn ms_state_ptr(&self, default: &MultisampleState) -> *const VkPipelineMultisampleStateCreateInfo
{
self.ms_state.as_ref().map(|&x| x as *const _)
.unwrap_or_else(||if self.rasterized() { default as _ } else { null() }) as _
}
#[allow(unused_variables)]
pub fn create(&self, device: &::Device, cache: Option<&PipelineCache>) -> ::Result<Pipeline>
{
let vp = self.vp.as_ref().expect("Required the Vertex Processing Stages for Graphics Pipeline");
let (stages, _specinfo) = vp.generate_stages();
let mut dynamic_states = Vec::new();
if self.dynamic_state_flags.viewport { dynamic_states.push(VK_DYNAMIC_STATE_VIEWPORT); }
if self.dynamic_state_flags.scissor { dynamic_states.push(VK_DYNAMIC_STATE_SCISSOR); }
if self.dynamic_state_flags.line_width { dynamic_states.push(VK_DYNAMIC_STATE_LINE_WIDTH); }
if self.dynamic_state_flags.depth_bias { dynamic_states.push(VK_DYNAMIC_STATE_DEPTH_BIAS); }
if self.dynamic_state_flags.blend_constants { dynamic_states.push(VK_DYNAMIC_STATE_BLEND_CONSTANTS); }
if self.dynamic_state_flags.depth_bounds { dynamic_states.push(VK_DYNAMIC_STATE_DEPTH_BOUNDS); }
if self.dynamic_state_flags.stencil_compare_mask { dynamic_states.push(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); }
if self.dynamic_state_flags.stencil_write_mask { dynamic_states.push(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); }
if self.dynamic_state_flags.stencil_reference { dynamic_states.push(VK_DYNAMIC_STATE_STENCIL_REFERENCE); }
let ds = if !dynamic_states.is_empty()
{
Some(VkPipelineDynamicStateCreateInfo
{
dynamicStateCount: dynamic_states.len() as _, pDynamicStates: dynamic_states.as_ptr(), .. Default::default()
})
}
else { None };
let base = match self._base
{
BasePipeline::Handle(ref h) => Some(h.native_ptr()), BasePipeline::None => None,
_ => panic!("Deriving from other info in same creation is invalid for single creation of pipeline")
};
let flags = self.flags | if base.is_some() { VK_PIPELINE_CREATE_DERIVATIVE_BIT } else { 0 };
let ms_empty = MultisampleState::new();
let cinfo = VkGraphicsPipelineCreateInfo
{
stageCount: stages.len() as _, pStages: stages.as_ptr(), pVertexInputState: &vp.vi, pInputAssemblyState: &vp.ia,
pTessellationState: self.tess_state.as_ref().map(|x| &**x as *const _).unwrap_or(::std::ptr::null()),
pViewportState: self.viewport_state.as_ref().map(|x| &**x as *const _).unwrap_or(::std::ptr::null()),
pRasterizationState: &self.rasterizer_state as *const _, pMultisampleState: self.ms_state_ptr(&ms_empty),
pDepthStencilState: self.ds_state.as_ref().map(|x| &**x as *const _).unwrap_or(::std::ptr::null()),
pColorBlendState: self.color_blending.as_ref().map(|&(ref x, _)| &**x as *const _).unwrap_or(::std::ptr::null()),
pDynamicState: ds.as_ref().map(|x| x as *const _).unwrap_or(::std::ptr::null()),
layout: self._layout.native_ptr(), renderPass: self.rp.native_ptr(), subpass: self.subpass,
basePipelineHandle: if let &BasePipeline::Handle(ref h) = &self._base { h.native_ptr() } else { VK_NULL_HANDLE as _ },
basePipelineIndex: -1, flags, .. Default::default()
};
let mut h = VK_NULL_HANDLE as _;
unsafe { Resolver::get().create_graphics_pipelines(device.native_ptr(), cache.map(VkHandle::native_ptr).unwrap_or(VK_NULL_HANDLE as _),
1, &cinfo, ::std::ptr::null(), &mut h) }.into_result().map(|_| Pipeline(h, device.clone()))
}
}
#[cfg(feature = "Implements")]
impl ::Device
{
pub fn create_graphics_pipelines(&self, builders: &[GraphicsPipelineBuilder], cache: Option<&PipelineCache>) -> ::Result<Vec<Pipeline>>
{
let aggregates = builders.iter().map(|x|
{
let vp = x.vp.as_ref().expect("Required the Vertex Processing Stages for Graphics Pipeline");
let (stages, _specinfo) = vp.generate_stages();
let mut dynamic_states = Vec::new();
if x.dynamic_state_flags.viewport { dynamic_states.push(VK_DYNAMIC_STATE_VIEWPORT); }
if x.dynamic_state_flags.scissor { dynamic_states.push(VK_DYNAMIC_STATE_SCISSOR); }
if x.dynamic_state_flags.line_width { dynamic_states.push(VK_DYNAMIC_STATE_LINE_WIDTH); }
if x.dynamic_state_flags.depth_bias { dynamic_states.push(VK_DYNAMIC_STATE_DEPTH_BIAS); }
if x.dynamic_state_flags.blend_constants { dynamic_states.push(VK_DYNAMIC_STATE_BLEND_CONSTANTS); }
if x.dynamic_state_flags.depth_bounds { dynamic_states.push(VK_DYNAMIC_STATE_DEPTH_BOUNDS); }
if x.dynamic_state_flags.stencil_compare_mask { dynamic_states.push(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); }
if x.dynamic_state_flags.stencil_write_mask { dynamic_states.push(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); }
if x.dynamic_state_flags.stencil_reference { dynamic_states.push(VK_DYNAMIC_STATE_STENCIL_REFERENCE); }
let ds = if !dynamic_states.is_empty()
{
Some(VkPipelineDynamicStateCreateInfo
{
dynamicStateCount: dynamic_states.len() as _, pDynamicStates: dynamic_states.as_ptr(), .. Default::default()
})
}
else { None };
(vp, stages, ds, _specinfo, dynamic_states)
}).collect::<Vec<_>>();
let ms_empty = MultisampleState::new();
let cinfos = builders.iter().zip(aggregates.iter()).map(|(b, &(ref vp, ref stages, ref ds, _, _))|
{
let (base_handle, base_index) = match b._base
{
BasePipeline::Handle(ref h) => (h.0, -1), BasePipeline::None => (VK_NULL_HANDLE as _, -1),
BasePipeline::Index(x) => (VK_NULL_HANDLE as _, x as i32)
};
let flags = b.flags | if base_handle != VK_NULL_HANDLE as _ || base_index >= 0 { VK_PIPELINE_CREATE_DERIVATIVE_BIT } else { 0 };
VkGraphicsPipelineCreateInfo
{
stageCount: stages.len() as _, pStages: stages.as_ptr(), pVertexInputState: &vp.vi, pInputAssemblyState: &vp.ia,
pTessellationState: b.tess_state.as_ref().map(|x| &**x as *const _).unwrap_or(::std::ptr::null()),
pViewportState: b.viewport_state.as_ref().map(|x| &**x as *const _).unwrap_or(::std::ptr::null()),
pRasterizationState: &b.rasterizer_state as *const _, pMultisampleState: b.ms_state_ptr(&ms_empty),
pDepthStencilState: b.ds_state.as_ref().map(|x| &**x as *const _).unwrap_or(::std::ptr::null()),
pColorBlendState: b.color_blending.as_ref().map(|&(ref x, _)| &**x as *const _).unwrap_or(::std::ptr::null()),
pDynamicState: ds.as_ref().map(|x| x as *const _).unwrap_or(::std::ptr::null()),
layout: b._layout.native_ptr(), renderPass: b.rp.native_ptr(), subpass: b.subpass,
basePipelineHandle: base_handle, basePipelineIndex: base_index, flags, .. Default::default()
}
}).collect::<Vec<_>>();
let mut hs = vec![VK_NULL_HANDLE as VkPipeline; builders.len()];
unsafe { Resolver::get().create_graphics_pipelines(self.native_ptr(), cache.map(VkHandle::native_ptr).unwrap_or(VK_NULL_HANDLE as _),
cinfos.len() as _, cinfos.as_ptr(), ::std::ptr::null(), hs.as_mut_ptr()) }.into_result()
.map(|_| hs.into_iter().map(|h| Pipeline(h, self.clone())).collect())
}
}
#[derive(Clone)]
pub struct ComputePipelineBuilder<'d>
{
shader: PipelineShader<'d>,
layout: &'d PipelineLayout
}
impl<'d> ComputePipelineBuilder<'d>
{
pub fn new(layout: &'d PipelineLayout, shader: PipelineShader<'d>) -> Self
{
ComputePipelineBuilder
{
shader, layout
}
}
}
#[cfg(feature = "Implements")]
impl<'d> ComputePipelineBuilder<'d>
{
pub fn create(&self, device: &::Device, cache: Option<&PipelineCache>) -> ::Result<Pipeline>
{
let (stage, _specinfo) = self.shader.createinfo_native(ShaderStage::COMPUTE);
let cinfo = VkComputePipelineCreateInfo
{
stage,
layout: self.layout.native_ptr(),
.. Default::default()
};
let mut pipeline = ::std::mem::MaybeUninit::uninit();
unsafe
{
Resolver::get().create_compute_pipelines(
device.native_ptr(), cache.map(VkHandle::native_ptr).unwrap_or(VK_NULL_HANDLE as _),
1, &cinfo, ::std::ptr::null(), pipeline.as_mut_ptr()
).into_result().map(move |_| Pipeline(pipeline.assume_init(), device.clone()))
}
}
}
#[cfg(feature = "Implements")]
impl ::Device
{
pub fn create_compute_pipelines(&self, builders: &[ComputePipelineBuilder], cache: Option<&PipelineCache>) -> ::Result<Vec<Pipeline>>
{
let (stages, _specinfos): (Vec<_>, Vec<_>) = builders.iter().map(|b| b.shader.createinfo_native(ShaderStage::COMPUTE)).unzip();
let cinfos = builders.iter().zip(stages.into_iter()).map(|(b, stage)| VkComputePipelineCreateInfo
{
stage, layout: b.layout.native_ptr(), .. Default::default()
}).collect::<Vec<_>>();
let mut pipelines = vec![VK_NULL_HANDLE as _; builders.len()];
unsafe
{
Resolver::get().create_compute_pipelines(
self.native_ptr(), cache.map(VkHandle::native_ptr).unwrap_or(VK_NULL_HANDLE as _),
cinfos.len() as _, cinfos.as_ptr(), ::std::ptr::null(), pipelines.as_mut_ptr()
).into_result().map(move |_| pipelines.into_iter().map(|h| Pipeline(h, self.clone())).collect())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PipelineStageFlags(pub VkPipelineStageFlags);
impl PipelineStageFlags
{
pub const TOP_OF_PIPE: Self = PipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
pub const DRAW_INDIRECT: Self = PipelineStageFlags(VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT);
pub const VERTEX_INPUT: Self = PipelineStageFlags(VK_PIPELINE_STAGE_VERTEX_INPUT_BIT);
pub const VERTEX_SHADER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT);
pub const TESSELLATION_CONTROL_SHADER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT);
pub const TESSELLATION_EVALUATION_SHADER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT);
pub const GEOMETRY_SHADER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT);
pub const FRAGMENT_SHADER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
pub const EARLY_FRAGMENT_TESTS: Self = PipelineStageFlags(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT);
pub const LATE_FRAGMENT_TESTS: Self = PipelineStageFlags(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
pub const COLOR_ATTACHMENT_OUTPUT: Self = PipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
pub const TRANSFER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_TRANSFER_BIT);
pub const COMPUTE_SHADER: Self = PipelineStageFlags(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
pub const BOTTOM_OF_PIPE: Self = PipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
pub const HOST: Self = PipelineStageFlags(VK_PIPELINE_STAGE_HOST_BIT);
pub const ALL_GRAPHICS: Self = PipelineStageFlags(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
pub const ALL_COMMANDS: Self = PipelineStageFlags(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
pub fn top_of_pipe(self) -> Self { PipelineStageFlags(self.0 | Self::TOP_OF_PIPE.0) }
pub fn draw_indirect(self) -> Self { PipelineStageFlags(self.0 | Self::DRAW_INDIRECT.0) }
pub fn vertex_input(self) -> Self { PipelineStageFlags(self.0 | Self::VERTEX_INPUT.0) }
pub fn vertex_shader(self) -> Self { PipelineStageFlags(self.0 | Self::VERTEX_SHADER.0) }
pub fn tessellation_control_shader(self) -> Self { PipelineStageFlags(self.0 | Self::TESSELLATION_CONTROL_SHADER.0) }
pub fn tessellation_evaluation_shader(self) -> Self { PipelineStageFlags(self.0 | Self::TESSELLATION_EVALUATION_SHADER.0) }
pub fn geometry_shader(self) -> Self { PipelineStageFlags(self.0 | Self::GEOMETRY_SHADER.0) }
pub fn fragment_shader(self) -> Self { PipelineStageFlags(self.0 | Self::FRAGMENT_SHADER.0) }
pub fn early_fragment_tests(self) -> Self { PipelineStageFlags(self.0 | Self::EARLY_FRAGMENT_TESTS.0) }
pub fn late_fragment_tests(self) -> Self { PipelineStageFlags(self.0 | Self::LATE_FRAGMENT_TESTS.0) }
pub fn color_attachment_output(self) -> Self { PipelineStageFlags(self.0 | Self::COLOR_ATTACHMENT_OUTPUT.0) }
pub fn transfer(self) -> Self { PipelineStageFlags(self.0 | Self::TRANSFER.0) }
pub fn compute_shader(self) -> Self { PipelineStageFlags(self.0 | Self::COMPUTE_SHADER.0) }
pub fn bottom_of_pipe(self) -> Self { PipelineStageFlags(self.0 | Self::BOTTOM_OF_PIPE.0) }
pub fn host(self) -> Self { PipelineStageFlags(self.0 | Self::HOST.0) }
pub fn all_graphics(self) -> Self { PipelineStageFlags(self.0 | Self::ALL_GRAPHICS.0) }
pub fn all_commands(self) -> Self { PipelineStageFlags(self.0 | Self::ALL_COMMANDS.0) }
}