bort_vk/
pipeline_graphics.rs

1use crate::{
2    Device, DeviceOwned, PipelineAccess, PipelineCache, PipelineLayout, RenderPass, ShaderStage,
3    ALLOCATION_CALLBACK_NONE,
4};
5use ash::{
6    prelude::VkResult,
7    vk::{self, Handle},
8};
9use std::sync::Arc;
10
11pub struct GraphicsPipeline {
12    handle: vk::Pipeline,
13    properties: GraphicsPipelineProperties,
14
15    // dependencies
16    pipeline_layout: Arc<PipelineLayout>,
17    // note: we don't need to store references to `ShaderModule`, `RenderPass` or `PipelineCache` as per https://registry.khronos.org/vulkan/specs/1.0/html/vkspec.html#fundamentals-objectmodel-lifetime
18}
19
20impl GraphicsPipeline {
21    pub fn new(
22        pipeline_layout: Arc<PipelineLayout>,
23        properties: GraphicsPipelineProperties,
24        shader_stages: &[ShaderStage],
25        render_pass: &RenderPass,
26        pipeline_cache: Option<&PipelineCache>,
27    ) -> VkResult<Self> {
28        // populate vkPipelineShaderStageCreateInfo
29        let shader_stages_vk = shader_stages
30            .iter()
31            .map(|stage| stage.create_info_builder().build())
32            .collect::<Vec<vk::PipelineShaderStageCreateInfo>>();
33
34        // populate the sub-structs of vkGraphicsPipelineCreateInfo defined by GraphicsPipelineProperties
35        let properties_vk = properties.vk_create_infos();
36
37        // use these and other args to populate the fields of vkGraphicsPipelineCreateInfo
38        let create_info_builder = properties
39            .write_create_info_builder(vk::GraphicsPipelineCreateInfo::builder(), &properties_vk);
40        let create_info_builder = create_info_builder
41            .stages(&shader_stages_vk)
42            .render_pass(render_pass.handle())
43            .layout(pipeline_layout.handle());
44
45        let cache_handle = if let Some(pipeline_cache) = pipeline_cache {
46            pipeline_cache.handle()
47        } else {
48            vk::PipelineCache::null()
49        };
50
51        let handle_res = unsafe {
52            pipeline_layout.device().inner().create_graphics_pipelines(
53                cache_handle,
54                &[create_info_builder.build()],
55                ALLOCATION_CALLBACK_NONE,
56            )
57        };
58        // note: cbf taking VK_PIPELINE_COMPILE_REQUIRED into account rn...
59        let handle = handle_res.map_err(|(_pipelines, err_code)| err_code)?[0];
60
61        Ok(Self {
62            handle,
63            properties,
64            pipeline_layout,
65        })
66    }
67
68    /// Safety requirements found in docs for the following:
69    ///   - [`VertexInputState::from_create_info`]
70    ///   - [`ViewportState::from_create_info`]
71    ///   - [`MultisampleState::from_create_info`]
72    ///   - [`ColorBlendState::from_create_info`]
73    ///   - [`DynamicState::from_create_info`]
74    pub unsafe fn new_from_create_info(
75        pipeline_layout: Arc<PipelineLayout>,
76        create_info_builder: vk::GraphicsPipelineCreateInfoBuilder,
77        pipeline_cache: Option<&PipelineCache>,
78    ) -> VkResult<Self> {
79        let properties =
80            unsafe { GraphicsPipelineProperties::from_create_info_builder(&create_info_builder) };
81
82        let cache_handle = if let Some(pipeline_cache) = pipeline_cache {
83            pipeline_cache.handle()
84        } else {
85            vk::PipelineCache::null()
86        };
87
88        let handle_res = unsafe {
89            pipeline_layout.device().inner().create_graphics_pipelines(
90                cache_handle,
91                &[create_info_builder.build()],
92                ALLOCATION_CALLBACK_NONE,
93            )
94        };
95        // note: cbf taking VK_PIPELINE_COMPILE_REQUIRED into account rn...
96        let handle = handle_res.map_err(|(_pipelines, err_code)| err_code)?[0];
97
98        Ok(Self {
99            handle,
100            properties,
101            pipeline_layout,
102        })
103    }
104
105    pub fn new_batch_create<'a>(
106        device: &Device,
107        per_pipeline_params: Vec<PerPipelineCreationParams<'a>>,
108        pipeline_cache: Option<&PipelineCache>,
109    ) -> VkResult<Vec<Self>> {
110        let pipeline_count = per_pipeline_params.len();
111
112        // populate the sub-structs of vkGraphicsPipelineCreateInfo defined by GraphicsPipelineProperties
113        let mut pipeline_properties_vk = Vec::<GraphicsPipelinePropertiesCreateInfosVk>::new();
114        for pipeline_index in 0..pipeline_count {
115            let properties_vk = per_pipeline_params[pipeline_index]
116                .properties
117                .vk_create_infos();
118            pipeline_properties_vk.push(properties_vk);
119        }
120
121        // populate the vkPipelineShaderStageCreateInfo structs
122        let mut shader_stage_handles = Vec::<Vec<vk::PipelineShaderStageCreateInfo>>::new();
123        for pipeline_index in 0..pipeline_count {
124            let shader_stages_vk: Vec<vk::PipelineShaderStageCreateInfo> = per_pipeline_params
125                [pipeline_index]
126                .shader_stages
127                .iter()
128                .map(|stage| stage.create_info_builder().build())
129                .collect();
130            shader_stage_handles.push(shader_stages_vk);
131        }
132
133        // use these and other args to populate the fields of vkGraphicsPipelineCreateInfo
134        let mut create_info_builders = Vec::<vk::GraphicsPipelineCreateInfoBuilder>::new();
135        for pipeline_index in 0..pipeline_count {
136            let create_info_builder = per_pipeline_params[pipeline_index]
137                .properties
138                .write_create_info_builder(
139                    vk::GraphicsPipelineCreateInfo::builder(),
140                    &pipeline_properties_vk[pipeline_index],
141                );
142
143            let create_info_builder = create_info_builder
144                .stages(&shader_stage_handles[pipeline_index])
145                .render_pass(per_pipeline_params[pipeline_index].render_pass.handle())
146                .layout(per_pipeline_params[pipeline_index].pipeline_layout.handle());
147
148            create_info_builders.push(create_info_builder);
149        }
150
151        let create_infos: Vec<vk::GraphicsPipelineCreateInfo> = create_info_builders
152            .into_iter()
153            .map(|builder| builder.build())
154            .collect();
155
156        let cache_handle = if let Some(pipeline_cache) = pipeline_cache {
157            pipeline_cache.handle()
158        } else {
159            vk::PipelineCache::null()
160        };
161
162        let pipeline_handles = unsafe {
163            device.inner().create_graphics_pipelines(
164                cache_handle,
165                &create_infos,
166                ALLOCATION_CALLBACK_NONE,
167            )
168        }
169        .map_err(|(_pipelines, err_code)| err_code)?; // note: cbf taking VK_PIPELINE_COMPILE_REQUIRED into account...
170
171        let pipelines: Vec<GraphicsPipeline> = per_pipeline_params
172            .into_iter()
173            .enumerate()
174            .map(|(index, params)| Self {
175                handle: pipeline_handles[index],
176                properties: params.properties,
177                pipeline_layout: params.pipeline_layout.clone(),
178            })
179            .collect();
180
181        Ok(pipelines)
182    }
183
184    // Getters
185
186    #[inline]
187    pub fn properties(&self) -> &GraphicsPipelineProperties {
188        &self.properties
189    }
190}
191
192impl PipelineAccess for GraphicsPipeline {
193    #[inline]
194    fn handle(&self) -> vk::Pipeline {
195        self.handle
196    }
197
198    #[inline]
199    fn pipeline_layout(&self) -> &Arc<PipelineLayout> {
200        &self.pipeline_layout
201    }
202
203    #[inline]
204    fn bind_point(&self) -> vk::PipelineBindPoint {
205        vk::PipelineBindPoint::GRAPHICS
206    }
207}
208
209impl DeviceOwned for GraphicsPipeline {
210    #[inline]
211    fn device(&self) -> &Arc<Device> {
212        &self.pipeline_layout.device()
213    }
214
215    #[inline]
216    fn handle_raw(&self) -> u64 {
217        self.handle.as_raw()
218    }
219}
220
221impl Drop for GraphicsPipeline {
222    fn drop(&mut self) {
223        unsafe {
224            self.device()
225                .inner()
226                .destroy_pipeline(self.handle, ALLOCATION_CALLBACK_NONE)
227        }
228    }
229}
230
231// Properties
232
233/// Allows usage of `from_create_info_ptr`
234trait FromCreateInfo<VkCreateInfo> {
235    fn from_create_info(value: &VkCreateInfo) -> Self;
236}
237
238/// If `vk_create_info_ptr` isn't null, this function dereferences it then returns the result of
239/// `from_create_info`. Otherwise returns `Default::default()`.
240///
241/// Safety:
242/// - if `vk_create_info_ptr` is not null, it must point to something
243unsafe fn from_create_info_ptr<Properties, VkCreateInfo>(
244    vk_create_info_ptr: *const VkCreateInfo,
245) -> Properties
246where
247    Properties: FromCreateInfo<VkCreateInfo> + Default,
248    VkCreateInfo: Copy + Clone,
249{
250    if vk_create_info_ptr != std::ptr::null() {
251        let vk_create_info = unsafe { *vk_create_info_ptr };
252        Properties::from_create_info(&vk_create_info)
253    } else {
254        Default::default()
255    }
256}
257
258/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html>
259///
260/// Note: doesn't include shader stages, render pass, pipeline layout or pipeline cache
261#[derive(Debug, Clone, Default)]
262pub struct GraphicsPipelineProperties {
263    pub flags: vk::PipelineCreateFlags,
264    pub subpass_index: u32,
265    pub vertex_input_state: VertexInputState,
266    pub input_assembly_state: InputAssemblyState,
267    pub tessellation_state: TessellationState,
268    pub viewport_state: ViewportState,
269    pub rasterization_state: RasterizationState,
270    pub multisample_state: MultisampleState,
271    pub depth_stencil_state: DepthStencilState,
272    pub color_blend_state: ColorBlendState,
273    pub dynamic_state: DynamicState,
274}
275impl GraphicsPipelineProperties {
276    /// Returns the `builder` arg containing references to the structs in `properties_vk`.
277    ///
278    /// Note: this doesn't populate:
279    /// - `layout`
280    /// - `render_pass`
281    /// - `subpass`
282    /// - `stages`
283    /// - `base_pipeline_handle`
284    /// - `base_pipeline_index`
285    pub fn write_create_info_builder<'a>(
286        &'a self,
287        builder: vk::GraphicsPipelineCreateInfoBuilder<'a>,
288        properties_vk: &'a GraphicsPipelinePropertiesCreateInfosVk<'a>,
289    ) -> vk::GraphicsPipelineCreateInfoBuilder<'a> {
290        // pass references to `properties_vk` to `builder` to populate relevant members
291        builder
292            .flags(self.flags)
293            .subpass(self.subpass_index)
294            .vertex_input_state(&properties_vk.vertex_input_state_vk)
295            .input_assembly_state(&properties_vk.input_assembly_state_vk)
296            .tessellation_state(&properties_vk.tessellation_state_vk)
297            .viewport_state(&properties_vk.viewport_state_vk)
298            .rasterization_state(&properties_vk.rasterization_state_vk)
299            .multisample_state(&properties_vk.multisample_state_vk)
300            .depth_stencil_state(&properties_vk.depth_stencil_state_vk)
301            .color_blend_state(&properties_vk.color_blend_state_vk)
302            .dynamic_state(&properties_vk.dynamic_state_vk)
303    }
304
305    /// Returns a set of vk::*CreateInfoBuilder structs populated by the members of `self`.
306    /// Use this with `Self::write_create_info_builder` to populate a `GraphicsPipelineCreateInfoBuilder`.
307    pub fn vk_create_infos<'a>(&'a self) -> GraphicsPipelinePropertiesCreateInfosVk<'a> {
308        let mut properties_vk = GraphicsPipelinePropertiesCreateInfosVk::default();
309        // write vk create-info builders for each member to `properties_vk`
310        properties_vk.vertex_input_state_vk = self.vertex_input_state.create_info_builder();
311        properties_vk.input_assembly_state_vk = self.input_assembly_state.create_info_builder();
312        properties_vk.tessellation_state_vk = self.tessellation_state.create_info_builder();
313        properties_vk.viewport_state_vk = self.viewport_state.create_info_builder();
314        properties_vk.rasterization_state_vk = self.rasterization_state.create_info_builder();
315        properties_vk.multisample_state_vk = self.multisample_state.create_info_builder();
316        properties_vk.depth_stencil_state_vk = self.depth_stencil_state.create_info_builder();
317        properties_vk.color_blend_state_vk = self.color_blend_state.create_info_builder();
318        properties_vk.dynamic_state_vk = self.dynamic_state.create_info_builder();
319        properties_vk
320    }
321
322    /// Safety:
323    /// - if any of the following members aren't null they must point to something!
324    ///     - `p_vertex_input_state`
325    ///     - `p_input_assembly_state`
326    ///     - `p_tessellation_state`
327    ///     - `p_viewport_state`
328    ///     - `p_rasterization_state`
329    ///     - `p_multisample_state`
330    ///     - `p_depth_stencil_state`
331    ///     - `p_color_blend_state`
332    ///     - `p_dynamic_state`
333    /// - see docs for the following functions for additional safety requirements:
334    ///     - [`VertexInputState::from_create_info_ptr`]
335    ///     - [`ViewportState::from_create_info_ptr`]
336    ///     - [`MultisampleState::from_create_info_ptr`]
337    ///     - [`ColorBlendState::from_create_info_ptr`]
338    ///     - [`DynamicState::from_create_info_ptr`]
339    pub unsafe fn from_create_info(value: &vk::GraphicsPipelineCreateInfo) -> Self {
340        let vertex_input_state = if value.p_vertex_input_state != std::ptr::null() {
341            let vk_create_info = unsafe { *value.p_vertex_input_state };
342            VertexInputState::from_create_info(&vk_create_info)
343        } else {
344            Default::default()
345        };
346        let input_assembly_state = from_create_info_ptr(value.p_input_assembly_state);
347        let tessellation_state = from_create_info_ptr(value.p_tessellation_state);
348        let viewport_state = if value.p_viewport_state != std::ptr::null() {
349            let vk_create_info = unsafe { *value.p_viewport_state };
350            ViewportState::from_create_info(&vk_create_info)
351        } else {
352            Default::default()
353        };
354        let rasterization_state = from_create_info_ptr(value.p_rasterization_state);
355        let multisample_state = if value.p_multisample_state != std::ptr::null() {
356            let vk_create_info = unsafe { *value.p_multisample_state };
357            MultisampleState::from_create_info(&vk_create_info)
358        } else {
359            Default::default()
360        };
361        let depth_stencil_state = from_create_info_ptr(value.p_depth_stencil_state);
362        let color_blend_state = if value.p_color_blend_state != std::ptr::null() {
363            let vk_create_info = unsafe { *value.p_color_blend_state };
364            ColorBlendState::from_create_info(&vk_create_info)
365        } else {
366            Default::default()
367        };
368        let dynamic_state = if value.p_dynamic_state != std::ptr::null() {
369            let vk_create_info = unsafe { *value.p_dynamic_state };
370            DynamicState::from_create_info(&vk_create_info)
371        } else {
372            Default::default()
373        };
374
375        Self {
376            flags: value.flags,
377            subpass_index: value.subpass,
378            vertex_input_state,
379            input_assembly_state,
380            tessellation_state,
381            viewport_state,
382            rasterization_state,
383            multisample_state,
384            depth_stencil_state,
385            color_blend_state,
386            dynamic_state,
387        }
388    }
389
390    /// Safety requirements found in docs for the following:
391    ///   - [`VertexInputState::from_create_info`]
392    ///   - [`ViewportState::from_create_info`]
393    ///   - [`MultisampleState::from_create_info`]
394    ///   - [`ColorBlendState::from_create_info`]
395    ///   - [`DynamicState::from_create_info`]
396    pub unsafe fn from_create_info_builder(value: &vk::GraphicsPipelineCreateInfoBuilder) -> Self {
397        Self::from_create_info(value)
398    }
399}
400
401// Sub-Properties
402
403#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineColorBlendAttachmentState.html>"]
404#[derive(Debug, Clone)]
405pub struct ColorBlendState {
406    pub flags: vk::PipelineColorBlendStateCreateFlags,
407    pub logic_op: Option<vk::LogicOp>,
408    pub attachments: Vec<vk::PipelineColorBlendAttachmentState>,
409    pub blend_constants: [f32; 4],
410}
411impl Default for ColorBlendState {
412    fn default() -> Self {
413        Self {
414            flags: vk::PipelineColorBlendStateCreateFlags::empty(),
415            logic_op: None,
416            attachments: Vec::new(),
417            blend_constants: [0.; 4],
418        }
419    }
420}
421impl ColorBlendState {
422    pub fn new_default(attachments: Vec<vk::PipelineColorBlendAttachmentState>) -> Self {
423        Self {
424            attachments,
425            ..Default::default()
426        }
427    }
428
429    pub fn write_create_info_builder<'a>(
430        &'a self,
431        builder: vk::PipelineColorBlendStateCreateInfoBuilder<'a>,
432    ) -> vk::PipelineColorBlendStateCreateInfoBuilder<'a> {
433        builder
434            .flags(self.flags)
435            .logic_op_enable(self.logic_op.is_some())
436            .logic_op(self.logic_op.unwrap_or(vk::LogicOp::CLEAR))
437            .attachments(&self.attachments)
438            .blend_constants(self.blend_constants)
439    }
440
441    pub fn create_info_builder(&self) -> vk::PipelineColorBlendStateCreateInfoBuilder {
442        self.write_create_info_builder(vk::PipelineColorBlendStateCreateInfo::builder())
443    }
444
445    // Presets
446
447    pub fn blend_state_disabled() -> vk::PipelineColorBlendAttachmentState {
448        vk::PipelineColorBlendAttachmentState {
449            color_write_mask: vk::ColorComponentFlags::RGBA,
450            ..Default::default()
451        }
452    }
453
454    /// Returns `vk::PipelineColorBlendAttachmentState` where the output of the fragment shader is ignored and the
455    /// destination is untouched.
456    pub fn blend_state_ignore_source() -> vk::PipelineColorBlendAttachmentState {
457        vk::PipelineColorBlendAttachmentState {
458            blend_enable: 1,
459            color_blend_op: vk::BlendOp::ADD,
460            src_color_blend_factor: vk::BlendFactor::ZERO,
461            src_alpha_blend_factor: vk::BlendFactor::DST_COLOR,
462            alpha_blend_op: vk::BlendOp::ADD,
463            dst_color_blend_factor: vk::BlendFactor::ZERO,
464            dst_alpha_blend_factor: vk::BlendFactor::DST_COLOR,
465            color_write_mask: vk::ColorComponentFlags::RGBA,
466            ..Default::default()
467        }
468    }
469
470    /// Returns `vk::PipelineColorBlendAttachmentState` where the colors are added, and alpha is set to the maximum of
471    /// the two.
472    pub fn blend_state_additive() -> vk::PipelineColorBlendAttachmentState {
473        vk::PipelineColorBlendAttachmentState {
474            blend_enable: 1,
475            color_blend_op: vk::BlendOp::ADD,
476            src_color_blend_factor: vk::BlendFactor::ONE,
477            src_alpha_blend_factor: vk::BlendFactor::ONE,
478            alpha_blend_op: vk::BlendOp::MAX,
479            dst_color_blend_factor: vk::BlendFactor::ONE,
480            dst_alpha_blend_factor: vk::BlendFactor::ONE,
481            color_write_mask: vk::ColorComponentFlags::RGBA,
482            ..Default::default()
483        }
484    }
485
486    /// Safety:
487    /// - if `p_attachments` is not null, it must point to an array of `attachment_count` values
488    pub unsafe fn from_create_info(value: &vk::PipelineColorBlendStateCreateInfo) -> Self {
489        let mut attachments = Vec::<vk::PipelineColorBlendAttachmentState>::new();
490        for i in 0..value.attachment_count {
491            let attachment_state = unsafe { *value.p_attachments.offset(i as isize) };
492            attachments.push(attachment_state);
493        }
494
495        let logic_op = if value.logic_op_enable == 0 {
496            None
497        } else {
498            Some(value.logic_op)
499        };
500
501        Self {
502            flags: value.flags,
503            logic_op,
504            attachments,
505            blend_constants: value.blend_constants,
506        }
507    }
508
509    pub fn from_create_info_builder(value: &vk::PipelineColorBlendStateCreateInfoBuilder) -> Self {
510        unsafe { Self::from_create_info(value) }
511    }
512}
513
514#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineDepthStencilStateCreateInfo.html>"]
515#[derive(Debug, Clone)]
516pub struct DepthStencilState {
517    pub flags: vk::PipelineDepthStencilStateCreateFlags,
518    pub depth_test_enable: bool,
519    pub depth_write_enable: bool,
520    pub depth_compare_op: vk::CompareOp,
521    pub depth_bounds_test_enable: bool,
522    pub stencil_test_enable: bool,
523    pub front: vk::StencilOpState,
524    pub back: vk::StencilOpState,
525    pub min_depth_bounds: f32,
526    pub max_depth_bounds: f32,
527}
528impl Default for DepthStencilState {
529    fn default() -> Self {
530        Self {
531            flags: vk::PipelineDepthStencilStateCreateFlags::empty(),
532            depth_test_enable: false,
533            depth_write_enable: false,
534            depth_compare_op: vk::CompareOp::ALWAYS,
535            depth_bounds_test_enable: false,
536            stencil_test_enable: false,
537            front: vk::StencilOpState::default(),
538            back: vk::StencilOpState::default(),
539            min_depth_bounds: 0.,
540            max_depth_bounds: 0.,
541        }
542    }
543}
544impl DepthStencilState {
545    pub fn write_create_info_builder<'a>(
546        &self,
547        builder: vk::PipelineDepthStencilStateCreateInfoBuilder<'a>,
548    ) -> vk::PipelineDepthStencilStateCreateInfoBuilder<'a> {
549        builder
550            .flags(self.flags)
551            .depth_test_enable(self.depth_test_enable)
552            .depth_write_enable(self.depth_write_enable)
553            .depth_compare_op(self.depth_compare_op)
554            .depth_bounds_test_enable(self.depth_bounds_test_enable)
555            .stencil_test_enable(self.depth_bounds_test_enable)
556            .front(self.front)
557            .back(self.back)
558            .min_depth_bounds(self.min_depth_bounds)
559            .max_depth_bounds(self.max_depth_bounds)
560    }
561
562    pub fn create_info_builder(&self) -> vk::PipelineDepthStencilStateCreateInfoBuilder {
563        self.write_create_info_builder(vk::PipelineDepthStencilStateCreateInfo::builder())
564    }
565
566    pub fn from_create_info_builder(
567        value: &vk::PipelineDepthStencilStateCreateInfoBuilder,
568    ) -> Self {
569        Self::from_create_info(value)
570    }
571}
572impl FromCreateInfo<vk::PipelineDepthStencilStateCreateInfo> for DepthStencilState {
573    fn from_create_info(value: &vk::PipelineDepthStencilStateCreateInfo) -> Self {
574        Self {
575            flags: value.flags,
576            depth_test_enable: value.depth_test_enable != 0,
577            depth_write_enable: value.depth_write_enable != 0,
578            depth_compare_op: value.depth_compare_op,
579            depth_bounds_test_enable: value.depth_bounds_test_enable != 0,
580            stencil_test_enable: value.stencil_test_enable != 0,
581            front: value.front,
582            back: value.back,
583            min_depth_bounds: value.min_depth_bounds,
584            max_depth_bounds: value.max_depth_bounds,
585        }
586    }
587}
588
589#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineDynamicStateCreateInfo.html>"]
590#[derive(Debug, Clone)]
591pub struct DynamicState {
592    pub flags: vk::PipelineDynamicStateCreateFlags,
593    pub dynamic_states: Vec<vk::DynamicState>,
594}
595impl Default for DynamicState {
596    fn default() -> Self {
597        Self {
598            flags: vk::PipelineDynamicStateCreateFlags::empty(),
599            dynamic_states: Vec::new(),
600        }
601    }
602}
603impl DynamicState {
604    pub fn new_default(dynamic_states: Vec<vk::DynamicState>) -> Self {
605        Self {
606            dynamic_states,
607            ..Default::default()
608        }
609    }
610
611    pub fn write_create_info_builder<'a>(
612        &'a self,
613        builder: vk::PipelineDynamicStateCreateInfoBuilder<'a>,
614    ) -> vk::PipelineDynamicStateCreateInfoBuilder<'a> {
615        builder
616            .flags(self.flags)
617            .dynamic_states(&self.dynamic_states)
618    }
619
620    pub fn create_info_builder(&self) -> vk::PipelineDynamicStateCreateInfoBuilder {
621        self.write_create_info_builder(vk::PipelineDynamicStateCreateInfo::builder())
622    }
623
624    /// Safety:
625    /// - if `p_dynamic_states` is not null, it must point to an array of `dynamic_state_count` values
626    pub unsafe fn from_create_info(value: &vk::PipelineDynamicStateCreateInfo) -> Self {
627        let mut dynamic_states = Vec::<vk::DynamicState>::new();
628        for i in 0..value.dynamic_state_count {
629            let dynamic_state = unsafe { *value.p_dynamic_states.offset(i as isize) };
630            dynamic_states.push(dynamic_state);
631        }
632
633        Self {
634            flags: value.flags,
635            dynamic_states,
636        }
637    }
638
639    pub fn from_create_info_builder(value: &vk::PipelineDynamicStateCreateInfoBuilder) -> Self {
640        unsafe { Self::from_create_info(value) }
641    }
642}
643
644#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineInputAssemblyStateCreateInfo.html>"]
645#[derive(Debug, Clone)]
646pub struct InputAssemblyState {
647    pub flags: vk::PipelineInputAssemblyStateCreateFlags,
648    pub topology: vk::PrimitiveTopology,
649    pub primitive_restart_enable: bool,
650}
651impl Default for InputAssemblyState {
652    fn default() -> Self {
653        Self {
654            flags: vk::PipelineInputAssemblyStateCreateFlags::empty(),
655            topology: vk::PrimitiveTopology::TRIANGLE_LIST,
656            primitive_restart_enable: false,
657        }
658    }
659}
660impl InputAssemblyState {
661    pub fn write_create_info_builder<'a>(
662        &self,
663        builder: vk::PipelineInputAssemblyStateCreateInfoBuilder<'a>,
664    ) -> vk::PipelineInputAssemblyStateCreateInfoBuilder<'a> {
665        builder
666            .flags(self.flags)
667            .topology(self.topology)
668            .primitive_restart_enable(self.primitive_restart_enable)
669    }
670
671    pub fn create_info_builder(&self) -> vk::PipelineInputAssemblyStateCreateInfoBuilder {
672        self.write_create_info_builder(vk::PipelineInputAssemblyStateCreateInfo::builder())
673    }
674
675    pub fn from_create_info_builder(
676        value: &vk::PipelineInputAssemblyStateCreateInfoBuilder,
677    ) -> Self {
678        Self::from_create_info(value)
679    }
680}
681impl FromCreateInfo<vk::PipelineInputAssemblyStateCreateInfo> for InputAssemblyState {
682    fn from_create_info(value: &vk::PipelineInputAssemblyStateCreateInfo) -> Self {
683        Self {
684            flags: value.flags,
685            topology: value.topology,
686            primitive_restart_enable: value.primitive_restart_enable != 0,
687        }
688    }
689}
690
691#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineMultisampleStateCreateInfo.html>"]
692#[derive(Debug, Clone)]
693pub struct MultisampleState {
694    pub flags: vk::PipelineMultisampleStateCreateFlags,
695    pub rasterization_samples: vk::SampleCountFlags,
696    pub sample_shading_enable: bool,
697    pub min_sample_shading: f32,
698    pub sample_mask: Vec<vk::SampleMask>,
699    pub alpha_to_coverage_enable: bool,
700    pub alpha_to_one_enable: bool,
701}
702impl Default for MultisampleState {
703    fn default() -> Self {
704        Self {
705            flags: vk::PipelineMultisampleStateCreateFlags::empty(),
706            rasterization_samples: vk::SampleCountFlags::TYPE_1,
707            sample_shading_enable: false,
708            min_sample_shading: 1.,
709            sample_mask: Vec::new(),
710            alpha_to_coverage_enable: false,
711            alpha_to_one_enable: false,
712        }
713    }
714}
715impl MultisampleState {
716    pub fn write_create_info_builder<'a>(
717        &'a self,
718        builder: vk::PipelineMultisampleStateCreateInfoBuilder<'a>,
719    ) -> vk::PipelineMultisampleStateCreateInfoBuilder<'a> {
720        builder
721            .flags(self.flags)
722            .rasterization_samples(self.rasterization_samples)
723            .sample_shading_enable(self.sample_shading_enable)
724            .min_sample_shading(self.min_sample_shading)
725            .sample_mask(&self.sample_mask)
726            .alpha_to_coverage_enable(self.alpha_to_coverage_enable)
727            .alpha_to_one_enable(self.alpha_to_one_enable)
728    }
729
730    pub fn create_info_builder(&self) -> vk::PipelineMultisampleStateCreateInfoBuilder {
731        self.write_create_info_builder(vk::PipelineMultisampleStateCreateInfo::builder())
732    }
733
734    /// Safety:
735    /// - If `p_sample_mask` is not null and `rasterization_samples` is equal to `VK_SAMPLE_COUNT_64_BIT`
736    ///   the `p_sample_mask` must point to an array of 2 values as per
737    ///   [VUID-VkPipelineMultisampleStateCreateInfo-pSampleMask-parameter](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineMultisampleStateCreateInfo.html)
738    pub unsafe fn from_create_info(value: &vk::PipelineMultisampleStateCreateInfo) -> Self {
739        let mut sample_mask = Vec::<vk::SampleMask>::new();
740        if value.p_sample_mask != std::ptr::null() {
741            let lower_32_bit_sample_mask = unsafe { *value.p_sample_mask };
742            sample_mask.push(lower_32_bit_sample_mask);
743
744            if value.rasterization_samples == vk::SampleCountFlags::TYPE_64 {
745                let upper_32_bit_sample_mask = unsafe { *value.p_sample_mask.offset(1) };
746                sample_mask.push(upper_32_bit_sample_mask);
747            }
748        }
749
750        Self {
751            flags: value.flags,
752            rasterization_samples: value.rasterization_samples,
753            sample_shading_enable: value.sample_shading_enable != 0,
754            min_sample_shading: value.min_sample_shading,
755            sample_mask,
756            alpha_to_coverage_enable: value.alpha_to_coverage_enable != 0,
757            alpha_to_one_enable: value.alpha_to_one_enable != 0,
758        }
759    }
760
761    /// NOTE: the builder makes no guarentee of the length of the `p_sample_mask` array (even
762    /// if rasterization_samples > VK_SAMPLE_COUNT_32_BIT) so to keep this fn safe, only the
763    /// first value is `p_sample_mask` is stored (assuming the ptr isn't null).
764    pub fn from_create_info_builder(value: &vk::PipelineMultisampleStateCreateInfoBuilder) -> Self {
765        let mut sample_mask = Vec::<vk::SampleMask>::new();
766        if value.p_sample_mask != std::ptr::null() {
767            // NOTE: the builder makes no guarentee that there's anything else in p_sample_mask (even
768            // if rasterization_samples > VK_SAMPLE_COUNT_32_BIT) so here we play it safe and ignore
769            // any higher bits that may be stored here.
770            let lower_32_bit_sample_mask = unsafe { *value.p_sample_mask };
771            sample_mask.push(lower_32_bit_sample_mask);
772        }
773
774        Self {
775            flags: value.flags,
776            rasterization_samples: value.rasterization_samples,
777            sample_shading_enable: value.sample_shading_enable != 0,
778            min_sample_shading: value.min_sample_shading,
779            sample_mask,
780            alpha_to_coverage_enable: value.alpha_to_coverage_enable != 0,
781            alpha_to_one_enable: value.alpha_to_one_enable != 0,
782        }
783    }
784}
785
786#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineRasterizationStateCreateInfo.html>"]
787#[derive(Debug, Clone)]
788pub struct RasterizationState {
789    pub flags: vk::PipelineRasterizationStateCreateFlags,
790    pub depth_clamp_enable: bool,
791    pub rasterizer_discard_enable: bool,
792    pub polygon_mode: vk::PolygonMode,
793    pub cull_mode: vk::CullModeFlags,
794    pub front_face: vk::FrontFace,
795    pub depth_bias_enable: bool,
796    pub depth_bias_constant_factor: f32,
797    pub depth_bias_clamp: f32,
798    pub depth_bias_slope_factor: f32,
799    pub line_width: f32,
800}
801impl Default for RasterizationState {
802    fn default() -> Self {
803        Self {
804            flags: vk::PipelineRasterizationStateCreateFlags::empty(),
805            depth_clamp_enable: false,
806            rasterizer_discard_enable: false,
807            polygon_mode: vk::PolygonMode::FILL,
808            cull_mode: vk::CullModeFlags::NONE,
809            front_face: vk::FrontFace::COUNTER_CLOCKWISE,
810            depth_bias_enable: false,
811            depth_bias_constant_factor: 1.,
812            depth_bias_clamp: 0.,
813            depth_bias_slope_factor: 1.,
814            line_width: 1.,
815        }
816    }
817}
818impl RasterizationState {
819    pub fn write_create_info_builder<'a>(
820        &self,
821        builder: vk::PipelineRasterizationStateCreateInfoBuilder<'a>,
822    ) -> vk::PipelineRasterizationStateCreateInfoBuilder<'a> {
823        builder
824            .flags(self.flags)
825            .depth_clamp_enable(self.depth_clamp_enable)
826            .rasterizer_discard_enable(self.rasterizer_discard_enable)
827            .polygon_mode(self.polygon_mode)
828            .cull_mode(self.cull_mode)
829            .front_face(self.front_face)
830            .depth_bias_enable(self.depth_bias_enable)
831            .depth_bias_constant_factor(self.depth_bias_constant_factor)
832            .depth_bias_clamp(self.depth_bias_clamp)
833            .depth_bias_slope_factor(self.depth_bias_slope_factor)
834            .line_width(self.line_width)
835    }
836
837    pub fn create_info_builder(&self) -> vk::PipelineRasterizationStateCreateInfoBuilder {
838        self.write_create_info_builder(vk::PipelineRasterizationStateCreateInfo::builder())
839    }
840
841    pub fn from_create_info_builder(
842        value: &vk::PipelineRasterizationStateCreateInfoBuilder,
843    ) -> Self {
844        Self::from_create_info(value)
845    }
846}
847impl FromCreateInfo<vk::PipelineRasterizationStateCreateInfo> for RasterizationState {
848    fn from_create_info(value: &vk::PipelineRasterizationStateCreateInfo) -> Self {
849        Self {
850            flags: value.flags,
851            depth_clamp_enable: value.depth_clamp_enable != 0,
852            rasterizer_discard_enable: value.rasterizer_discard_enable != 0,
853            polygon_mode: value.polygon_mode,
854            cull_mode: value.cull_mode,
855            front_face: value.front_face,
856            depth_bias_enable: value.depth_bias_enable != 0,
857            depth_bias_constant_factor: value.depth_bias_constant_factor,
858            depth_bias_clamp: value.depth_bias_clamp,
859            depth_bias_slope_factor: value.depth_bias_slope_factor,
860            line_width: value.line_width,
861        }
862    }
863}
864
865#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineTessellationStateCreateInfo.html>"]
866#[derive(Debug, Clone)]
867pub struct TessellationState {
868    pub flags: vk::PipelineTessellationStateCreateFlags,
869    pub patch_control_points: u32,
870}
871impl Default for TessellationState {
872    fn default() -> Self {
873        Self {
874            flags: vk::PipelineTessellationStateCreateFlags::empty(),
875            patch_control_points: 0,
876        }
877    }
878}
879impl TessellationState {
880    pub fn write_create_info_builder<'a>(
881        &self,
882        builder: vk::PipelineTessellationStateCreateInfoBuilder<'a>,
883    ) -> vk::PipelineTessellationStateCreateInfoBuilder<'a> {
884        builder
885            .flags(self.flags)
886            .patch_control_points(self.patch_control_points)
887    }
888
889    pub fn create_info_builder(&self) -> vk::PipelineTessellationStateCreateInfoBuilder {
890        self.write_create_info_builder(vk::PipelineTessellationStateCreateInfo::builder())
891    }
892
893    pub fn from_create_info_builder(
894        value: &vk::PipelineTessellationStateCreateInfoBuilder,
895    ) -> Self {
896        Self::from_create_info(value)
897    }
898}
899impl FromCreateInfo<vk::PipelineTessellationStateCreateInfo> for TessellationState {
900    fn from_create_info(value: &vk::PipelineTessellationStateCreateInfo) -> Self {
901        Self {
902            flags: value.flags,
903            patch_control_points: value.patch_control_points,
904        }
905    }
906}
907
908#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineVertexInputStateCreateInfo.html>"]
909#[derive(Debug, Clone)]
910pub struct VertexInputState {
911    pub flags: vk::PipelineVertexInputStateCreateFlags,
912    pub vertex_binding_descriptions: Vec<vk::VertexInputBindingDescription>,
913    pub vertex_attribute_descriptions: Vec<vk::VertexInputAttributeDescription>,
914}
915impl Default for VertexInputState {
916    fn default() -> Self {
917        Self {
918            flags: vk::PipelineVertexInputStateCreateFlags::empty(),
919            vertex_binding_descriptions: Vec::new(),
920            vertex_attribute_descriptions: Vec::new(),
921        }
922    }
923}
924impl VertexInputState {
925    pub fn write_create_info_builder<'a>(
926        &'a self,
927        builder: vk::PipelineVertexInputStateCreateInfoBuilder<'a>,
928    ) -> vk::PipelineVertexInputStateCreateInfoBuilder<'a> {
929        builder
930            .flags(self.flags)
931            .vertex_binding_descriptions(&self.vertex_binding_descriptions)
932            .vertex_attribute_descriptions(&self.vertex_attribute_descriptions)
933    }
934
935    pub fn create_info_builder(&self) -> vk::PipelineVertexInputStateCreateInfoBuilder {
936        self.write_create_info_builder(vk::PipelineVertexInputStateCreateInfo::builder())
937    }
938
939    /// Safety:
940    /// - if `p_vertex_binding_descriptions` is not null, it must point to an array of `vertex_binding_description_count` values
941    /// - if `p_vertex_attribute_descriptions` is not null, it must point to an array of `vertex_attribute_description_count` values
942    pub unsafe fn from_create_info(value: &vk::PipelineVertexInputStateCreateInfo) -> Self {
943        let mut vertex_binding_descriptions = Vec::<vk::VertexInputBindingDescription>::new();
944        for i in 0..value.vertex_binding_description_count {
945            let binding_description =
946                unsafe { *value.p_vertex_binding_descriptions.offset(i as isize) };
947            vertex_binding_descriptions.push(binding_description);
948        }
949
950        let mut vertex_attribute_descriptions = Vec::<vk::VertexInputAttributeDescription>::new();
951        for i in 0..value.vertex_attribute_description_count {
952            let attribute_description =
953                unsafe { *value.p_vertex_attribute_descriptions.offset(i as isize) };
954            vertex_attribute_descriptions.push(attribute_description);
955        }
956
957        Self {
958            flags: value.flags,
959            vertex_binding_descriptions,
960            vertex_attribute_descriptions,
961        }
962    }
963
964    pub fn from_create_info_builder(value: &vk::PipelineVertexInputStateCreateInfoBuilder) -> Self {
965        unsafe { Self::from_create_info(value) }
966    }
967}
968
969#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineViewportStateCreateInfo.html>"]
970#[derive(Debug, Clone)]
971pub struct ViewportState {
972    pub flags: vk::PipelineViewportStateCreateFlags,
973    pub viewports: Vec<vk::Viewport>,
974    pub scissors: Vec<vk::Rect2D>,
975}
976impl Default for ViewportState {
977    fn default() -> Self {
978        Self {
979            flags: vk::PipelineViewportStateCreateFlags::empty(),
980            viewports: Vec::new(),
981            scissors: Vec::new(),
982        }
983    }
984}
985impl ViewportState {
986    pub fn new_dynamic(viewport_count: usize, scissor_count: usize) -> Self {
987        Self {
988            viewports: vec![Default::default(); viewport_count],
989            scissors: vec![Default::default(); scissor_count],
990            ..Default::default()
991        }
992    }
993
994    pub fn write_create_info_builder<'a>(
995        &'a self,
996        builder: vk::PipelineViewportStateCreateInfoBuilder<'a>,
997    ) -> vk::PipelineViewportStateCreateInfoBuilder<'a> {
998        builder
999            .flags(self.flags)
1000            .viewports(&self.viewports)
1001            .scissors(&self.scissors)
1002    }
1003
1004    pub fn create_info_builder(&self) -> vk::PipelineViewportStateCreateInfoBuilder {
1005        self.write_create_info_builder(vk::PipelineViewportStateCreateInfo::builder())
1006    }
1007
1008    /// Safety:
1009    /// - if `p_viewports` is not null, it must point to an array of `viewport_count` values
1010    /// - if `p_scissors` is not null, it must point to an array of `scissor_count` values
1011    pub unsafe fn from_create_info(value: &vk::PipelineViewportStateCreateInfo) -> Self {
1012        let mut viewports = Vec::<vk::Viewport>::new();
1013        for i in 0..value.viewport_count {
1014            let viewport = unsafe { *value.p_viewports.offset(i as isize) };
1015            viewports.push(viewport);
1016        }
1017
1018        let mut scissors = Vec::<vk::Rect2D>::new();
1019        for i in 0..value.scissor_count {
1020            let scissor = unsafe { *value.p_scissors.offset(i as isize) };
1021            scissors.push(scissor);
1022        }
1023
1024        Self {
1025            flags: value.flags,
1026            viewports,
1027            scissors,
1028        }
1029    }
1030
1031    pub fn from_create_info_builder(value: &vk::PipelineViewportStateCreateInfoBuilder) -> Self {
1032        unsafe { Self::from_create_info(value) }
1033    }
1034}
1035
1036// Helper stuff (ft. borrow checker wrestling <3 rust)
1037
1038/// Per-pipeline creation arguments
1039#[derive(Clone)]
1040pub struct PerPipelineCreationParams<'a> {
1041    pipeline_layout: Arc<PipelineLayout>,
1042    properties: GraphicsPipelineProperties,
1043    shader_stages: Vec<ShaderStage>,
1044    render_pass: &'a RenderPass,
1045}
1046
1047/// The equivilent vk*CreateInfo structs for the members of `GraphicsPipelineProperties`.
1048///
1049/// These are populated in `GraphicsPipelineProperties::vk_create_infos` in order for the
1050/// `GraphicsPipelineCreateInfo` to have references to create info structs whose lifetimes
1051/// can be ensured to live for the duration of the builder.
1052pub struct GraphicsPipelinePropertiesCreateInfosVk<'a> {
1053    pub vertex_input_state_vk: vk::PipelineVertexInputStateCreateInfoBuilder<'a>,
1054    pub input_assembly_state_vk: vk::PipelineInputAssemblyStateCreateInfoBuilder<'a>,
1055    pub tessellation_state_vk: vk::PipelineTessellationStateCreateInfoBuilder<'a>,
1056    pub viewport_state_vk: vk::PipelineViewportStateCreateInfoBuilder<'a>,
1057    pub rasterization_state_vk: vk::PipelineRasterizationStateCreateInfoBuilder<'a>,
1058    pub multisample_state_vk: vk::PipelineMultisampleStateCreateInfoBuilder<'a>,
1059    pub depth_stencil_state_vk: vk::PipelineDepthStencilStateCreateInfoBuilder<'a>,
1060    pub color_blend_state_vk: vk::PipelineColorBlendStateCreateInfoBuilder<'a>,
1061    pub dynamic_state_vk: vk::PipelineDynamicStateCreateInfoBuilder<'a>,
1062}
1063impl<'a> Default for GraphicsPipelinePropertiesCreateInfosVk<'a> {
1064    fn default() -> Self {
1065        Self {
1066            vertex_input_state_vk: vk::PipelineVertexInputStateCreateInfo::builder(),
1067            input_assembly_state_vk: vk::PipelineInputAssemblyStateCreateInfo::builder(),
1068            tessellation_state_vk: vk::PipelineTessellationStateCreateInfo::builder(),
1069            viewport_state_vk: vk::PipelineViewportStateCreateInfo::builder(),
1070            rasterization_state_vk: vk::PipelineRasterizationStateCreateInfo::builder(),
1071            multisample_state_vk: vk::PipelineMultisampleStateCreateInfo::builder(),
1072            depth_stencil_state_vk: vk::PipelineDepthStencilStateCreateInfo::builder(),
1073            color_blend_state_vk: vk::PipelineColorBlendStateCreateInfo::builder(),
1074            dynamic_state_vk: vk::PipelineDynamicStateCreateInfo::builder(),
1075        }
1076    }
1077}