logo
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright (c) 2021 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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.

//! Subdivides primitives into smaller primitives.

use crate::device::Device;
use crate::pipeline::graphics::input_assembly::{
    InputAssemblyState, PrimitiveTopology, PrimitiveTopologyClass,
};
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, PartialStateMode, StateMode};
use fnv::FnvHashMap;

/// The state in a graphics pipeline describing the tessellation shader execution of a graphics
/// pipeline.
#[derive(Clone, Copy, Debug)]
pub struct TessellationState {
    /// The number of patch control points to use.
    ///
    /// If set to `Dynamic`, the
    /// [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points)
    /// feature must be enabled on the device.
    pub patch_control_points: StateMode<u32>,
}

impl TessellationState {
    /// Creates a new `TessellationState` with 3 patch control points.
    #[inline]
    pub fn new() -> Self {
        Self {
            patch_control_points: StateMode::Fixed(3),
        }
    }

    /// Sets the number of patch control points.
    #[inline]
    pub fn patch_control_points(mut self, num: u32) -> Self {
        self.patch_control_points = StateMode::Fixed(num);
        self
    }

    /// Sets the number of patch control points to dynamic.
    pub fn patch_control_points_dynamic(mut self) -> Self {
        self.patch_control_points = StateMode::Dynamic;
        self
    }

    pub(crate) fn to_vulkan(
        &self,
        device: &Device,
        dynamic_state_modes: &mut FnvHashMap<DynamicState, bool>,
        input_assembly_state: &InputAssemblyState,
    ) -> Result<ash::vk::PipelineTessellationStateCreateInfo, GraphicsPipelineCreationError> {
        if !matches!(
            input_assembly_state.topology,
            PartialStateMode::Dynamic(PrimitiveTopologyClass::Patch)
                | PartialStateMode::Fixed(PrimitiveTopology::PatchList)
        ) {
            return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
        }

        let patch_control_points = match self.patch_control_points {
            StateMode::Fixed(patch_control_points) => {
                if patch_control_points <= 0
                    || patch_control_points
                        > device
                            .physical_device()
                            .properties()
                            .max_tessellation_patch_size
                {
                    return Err(GraphicsPipelineCreationError::InvalidNumPatchControlPoints);
                }
                dynamic_state_modes.insert(DynamicState::PatchControlPoints, false);
                patch_control_points
            }
            StateMode::Dynamic => {
                if !device
                    .enabled_features()
                    .extended_dynamic_state2_patch_control_points
                {
                    return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
                        feature: "extended_dynamic_state2_patch_control_points",
                        reason: "TessellationState::patch_control_points was set to Dynamic",
                    });
                }
                dynamic_state_modes.insert(DynamicState::PatchControlPoints, true);
                Default::default()
            }
        };

        Ok(ash::vk::PipelineTessellationStateCreateInfo {
            flags: ash::vk::PipelineTessellationStateCreateFlags::empty(),
            patch_control_points,
            ..Default::default()
        })
    }
}

impl Default for TessellationState {
    /// Returns [`TessellationState::new()`].
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}