use crate::device::Device;
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, PartialStateMode, StateMode};
use crate::{DeviceSize, Version};
use std::collections::HashMap;
#[derive(Clone, Copy, Debug)]
pub struct InputAssemblyState {
pub topology: PartialStateMode<PrimitiveTopology, PrimitiveTopologyClass>,
pub primitive_restart_enable: StateMode<bool>,
}
impl InputAssemblyState {
#[inline]
pub fn new() -> Self {
Self {
topology: PartialStateMode::Fixed(PrimitiveTopology::TriangleList),
primitive_restart_enable: StateMode::Fixed(false),
}
}
#[inline]
pub fn topology(mut self, topology: PrimitiveTopology) -> Self {
self.topology = PartialStateMode::Fixed(topology);
self
}
#[inline]
pub fn topology_dynamic(mut self, topology_class: PrimitiveTopologyClass) -> Self {
self.topology = PartialStateMode::Dynamic(topology_class);
self
}
#[inline]
pub fn primitive_restart_enable(mut self) -> Self {
self.primitive_restart_enable = StateMode::Fixed(true);
self
}
#[inline]
pub fn primitive_restart_enable_dynamic(mut self) -> Self {
self.primitive_restart_enable = StateMode::Dynamic;
self
}
pub(crate) fn to_vulkan(
&self,
device: &Device,
dynamic_state_modes: &mut HashMap<DynamicState, bool>,
) -> Result<ash::vk::PipelineInputAssemblyStateCreateInfo, GraphicsPipelineCreationError> {
let topology = match self.topology {
PartialStateMode::Fixed(topology) => {
match topology {
PrimitiveTopology::LineListWithAdjacency
| PrimitiveTopology::LineStripWithAdjacency
| PrimitiveTopology::TriangleListWithAdjacency
| PrimitiveTopology::TriangleStripWithAdjacency => {
if !device.enabled_features().geometry_shader {
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "geometry_shader",
reason: "InputAssemblyState::topology was set to a WithAdjacency PrimitiveTopology",
});
}
}
PrimitiveTopology::PatchList => {
if !device.enabled_features().tessellation_shader {
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "tessellation_shader",
reason: "InputAssemblyState::topology was set to PrimitiveTopology::PatchList",
});
}
}
_ => (),
}
dynamic_state_modes.insert(DynamicState::PrimitiveTopology, false);
topology.into()
}
PartialStateMode::Dynamic(topology_class) => {
if !(device.api_version() >= Version::V1_3
|| device.enabled_features().extended_dynamic_state)
{
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "InputAssemblyState::topology was set to Dynamic",
});
}
dynamic_state_modes.insert(DynamicState::PrimitiveTopology, true);
topology_class.example().into()
}
};
let primitive_restart_enable = match self.primitive_restart_enable {
StateMode::Fixed(primitive_restart_enable) => {
if primitive_restart_enable {
match self.topology {
PartialStateMode::Fixed(
PrimitiveTopology::PointList
| PrimitiveTopology::LineList
| PrimitiveTopology::TriangleList
| PrimitiveTopology::LineListWithAdjacency
| PrimitiveTopology::TriangleListWithAdjacency,
) => {
if !device.enabled_features().primitive_topology_list_restart {
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "primitive_topology_list_restart",
reason: "InputAssemblyState::primitive_restart_enable was set to true in combination with a List PrimitiveTopology",
});
}
}
PartialStateMode::Fixed(PrimitiveTopology::PatchList) => {
if !device
.enabled_features()
.primitive_topology_patch_list_restart
{
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "primitive_topology_patch_list_restart",
reason: "InputAssemblyState::primitive_restart_enable was set to true in combination with PrimitiveTopology::PatchList",
});
}
}
_ => (),
}
}
dynamic_state_modes.insert(DynamicState::PrimitiveRestartEnable, false);
primitive_restart_enable as ash::vk::Bool32
}
StateMode::Dynamic => {
if !(device.api_version() >= Version::V1_3
|| device.enabled_features().extended_dynamic_state2)
{
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "extended_dynamic_state2",
reason: "InputAssemblyState::primitive_restart_enable was set to Dynamic",
});
}
dynamic_state_modes.insert(DynamicState::PrimitiveRestartEnable, true);
Default::default()
}
};
Ok(ash::vk::PipelineInputAssemblyStateCreateInfo {
flags: ash::vk::PipelineInputAssemblyStateCreateFlags::empty(),
topology,
primitive_restart_enable,
..Default::default()
})
}
}
impl Default for InputAssemblyState {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum PrimitiveTopology {
PointList = ash::vk::PrimitiveTopology::POINT_LIST.as_raw(),
LineList = ash::vk::PrimitiveTopology::LINE_LIST.as_raw(),
LineStrip = ash::vk::PrimitiveTopology::LINE_STRIP.as_raw(),
TriangleList = ash::vk::PrimitiveTopology::TRIANGLE_LIST.as_raw(),
TriangleStrip = ash::vk::PrimitiveTopology::TRIANGLE_STRIP.as_raw(),
TriangleFan = ash::vk::PrimitiveTopology::TRIANGLE_FAN.as_raw(),
LineListWithAdjacency = ash::vk::PrimitiveTopology::LINE_LIST_WITH_ADJACENCY.as_raw(),
LineStripWithAdjacency = ash::vk::PrimitiveTopology::LINE_STRIP_WITH_ADJACENCY.as_raw(),
TriangleListWithAdjacency = ash::vk::PrimitiveTopology::TRIANGLE_LIST_WITH_ADJACENCY.as_raw(),
TriangleStripWithAdjacency = ash::vk::PrimitiveTopology::TRIANGLE_STRIP_WITH_ADJACENCY.as_raw(),
PatchList = ash::vk::PrimitiveTopology::PATCH_LIST.as_raw(),
}
impl Default for PrimitiveTopology {
#[inline]
fn default() -> Self {
PrimitiveTopology::TriangleList
}
}
impl From<PrimitiveTopology> for ash::vk::PrimitiveTopology {
#[inline]
fn from(val: PrimitiveTopology) -> ash::vk::PrimitiveTopology {
Self::from_raw(val as i32)
}
}
impl PrimitiveTopology {
#[inline]
pub fn class(&self) -> PrimitiveTopologyClass {
match self {
Self::PointList => PrimitiveTopologyClass::Point,
Self::LineList
| Self::LineStrip
| Self::LineListWithAdjacency
| Self::LineStripWithAdjacency => PrimitiveTopologyClass::Line,
Self::TriangleList
| Self::TriangleStrip
| Self::TriangleFan
| Self::TriangleListWithAdjacency
| Self::TriangleStripWithAdjacency => PrimitiveTopologyClass::Triangle,
Self::PatchList => PrimitiveTopologyClass::Patch,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PrimitiveTopologyClass {
Point,
Line,
Triangle,
Patch,
}
impl PrimitiveTopologyClass {
#[inline]
pub(crate) fn example(&self) -> PrimitiveTopology {
match self {
Self::Point => PrimitiveTopology::PointList,
Self::Line => PrimitiveTopology::LineList,
Self::Triangle => PrimitiveTopology::TriangleList,
Self::Patch => PrimitiveTopology::PatchList,
}
}
}
pub unsafe trait Index {
fn ty() -> IndexType;
}
unsafe impl Index for u8 {
#[inline(always)]
fn ty() -> IndexType {
IndexType::U8
}
}
unsafe impl Index for u16 {
#[inline(always)]
fn ty() -> IndexType {
IndexType::U16
}
}
unsafe impl Index for u32 {
#[inline(always)]
fn ty() -> IndexType {
IndexType::U32
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
#[repr(i32)]
pub enum IndexType {
U8 = ash::vk::IndexType::UINT8_EXT.as_raw(),
U16 = ash::vk::IndexType::UINT16.as_raw(),
U32 = ash::vk::IndexType::UINT32.as_raw(),
}
impl IndexType {
#[inline]
pub fn size(&self) -> DeviceSize {
match self {
IndexType::U8 => 1,
IndexType::U16 => 2,
IndexType::U32 => 4,
}
}
}
impl From<IndexType> for ash::vk::IndexType {
#[inline]
fn from(val: IndexType) -> Self {
Self::from_raw(val as i32)
}
}