Skip to main content

vk_graph/driver/
ray_tracing.rs

1//! Ray tracing pipeline types
2
3use {
4    super::{
5        DriverError,
6        device::Device,
7        merge_push_constant_ranges,
8        physical_device::khr::RayTracingPipelineProperties,
9        shader::{DescriptorBindingMap, PipelineDescriptorInfo, Shader},
10    },
11    crate::lazy_str,
12    ash::vk::{self, Handle},
13    derive_builder::Builder,
14    log::warn,
15    std::{
16        ffi::CString,
17        fmt::{Debug, Formatter},
18        hash::{Hash, Hasher},
19        sync::Arc,
20        thread::panicking,
21    },
22};
23
24/// Smart pointer handle of a ray tracing pipeline object.
25///
26/// Also contains information about the object.
27///
28/// See [`VkPipeline`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkPipeline.html).
29#[derive(Clone)]
30#[read_only::cast]
31pub struct RayTracingPipeline {
32    pub(crate) inner: Arc<RayTracingPipelineInner>,
33}
34
35impl RayTracingPipeline {
36    /// Creates a new ray tracing pipeline on the given device.
37    ///
38    /// The correct pipeline stages will be enabled based on the provided shaders. See [`Shader`]
39    /// for details on all available stages.
40    ///
41    /// See [`VkRayTracingPipelineCreateInfoKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRayTracingPipelineCreateInfoKHR.html).
42    ///
43    /// The number and composition of the `shader_groups` parameter must match the actual shaders
44    /// provided.
45    ///
46    /// `shaders` may contain pre-built [`Shader`] values or any inputs that can be converted into
47    /// them. Invalid shader data is returned as [`DriverError::InvalidData`] through the `Result`
48    /// instead of panicking.
49    ///
50    /// # Examples
51    ///
52    /// Basic usage:
53    ///
54    /// ```no_run
55    /// # use std::sync::Arc;
56    /// # use ash::vk;
57    /// # use vk_graph::driver::DriverError;
58    /// # use vk_graph::driver::device::{Device, DeviceInfo};
59    /// # use vk_graph::driver::ray_tracing::{
60    /// #     RayTracingPipeline,
61    /// #     RayTracingPipelineInfo,
62    /// #     RayTracingShaderGroup,
63    /// # };
64    /// # use vk_graph::driver::shader::Shader;
65    /// # fn main() -> Result<(), DriverError> {
66    /// # let device = Device::create(DeviceInfo::default())?;
67    /// # let my_rgen_code = [0u8; 1];
68    /// # let my_chit_code = [0u8; 1];
69    /// # let my_miss_code = [0u8; 1];
70    /// # let my_shadow_code = [0u8; 1];
71    /// // shader code is raw SPIR-V code as bytes
72    /// let info = RayTracingPipelineInfo::default().into_builder().max_ray_recursion_depth(1);
73    /// let pipeline = RayTracingPipeline::create(
74    ///     &device,
75    ///     info,
76    ///     [
77    ///         Shader::new_ray_gen(my_rgen_code.as_slice()),
78    ///         Shader::new_closest_hit(my_chit_code.as_slice()),
79    ///         Shader::new_miss(my_miss_code.as_slice()),
80    ///         Shader::new_miss(my_shadow_code.as_slice()),
81    ///     ],
82    ///     [
83    ///         RayTracingShaderGroup::new_general(0),
84    ///         RayTracingShaderGroup::new_triangles(1, None),
85    ///         RayTracingShaderGroup::new_general(2),
86    ///         RayTracingShaderGroup::new_general(3),
87    ///     ],
88    /// )?;
89    ///
90    /// assert_ne!(pipeline.handle(), vk::Pipeline::null());
91    /// assert_eq!(pipeline.info().max_ray_recursion_depth, 1);
92    /// # Ok(()) }
93    /// ```
94    #[profiling::function]
95    pub fn create<S>(
96        device: &Device,
97        info: impl Into<RayTracingPipelineInfo>,
98        shaders: impl IntoIterator<Item = S>,
99        shader_groups: impl IntoIterator<Item = RayTracingShaderGroup>,
100    ) -> Result<Self, DriverError>
101    where
102        S: TryInto<Shader>,
103        S::Error: Into<DriverError>,
104    {
105        if device.physical.vk_khr_ray_tracing_pipeline.is_none() {
106            warn!("unsupported ray tracing pipeline creation: missing ray tracing properties");
107
108            return Err(DriverError::Unsupported);
109        }
110
111        let info = info.into();
112        let shader_groups = shader_groups
113            .into_iter()
114            .map(|shader_group| shader_group.into())
115            .collect::<Vec<_>>();
116        let group_count = shader_groups.len();
117
118        let shaders = shaders
119            .into_iter()
120            .map(|shader| shader.try_into().map_err(Into::into))
121            .collect::<Result<Vec<_>, _>>()?;
122        let push_constants = shaders
123            .iter()
124            .map(|shader| shader.push_constant_range())
125            .filter_map(|mut push_const| push_const.take())
126            .collect::<Vec<_>>();
127
128        // Use SPIR-V reflection to get the types and counts of all descriptors
129        let mut descriptor_bindings = Shader::merge_descriptor_bindings(
130            shaders.iter().map(|shader| shader.descriptor_bindings()),
131        )?;
132        for (descriptor_info, _) in descriptor_bindings.values_mut() {
133            if descriptor_info.binding_count() == 0 {
134                descriptor_info.set_binding_count(info.bindless_descriptor_count);
135            }
136        }
137
138        let descriptor_info = PipelineDescriptorInfo::create(device, &descriptor_bindings)?;
139        let layouts = descriptor_info
140            .layouts
141            .values()
142            .map(|layout| layout.handle)
143            .collect::<Box<_>>();
144
145        unsafe {
146            let layout = device
147                .create_pipeline_layout(
148                    &vk::PipelineLayoutCreateInfo::default()
149                        .set_layouts(&layouts)
150                        .push_constant_ranges(&push_constants),
151                    None,
152                )
153                .map_err(|err| {
154                    warn!("unable to create ray tracing pipeline layout: {err}");
155
156                    DriverError::Unsupported
157                })?;
158            let entry_points: Box<[CString]> = shaders
159                .iter()
160                .map(|shader| CString::new(shader.entry_name.as_str()))
161                .collect::<Result<_, _>>()
162                .map_err(|err| {
163                    warn!("invalid ray tracing shader entry name: {err}");
164
165                    DriverError::InvalidData
166                })?;
167            let specialization_infos: Box<[Option<vk::SpecializationInfo>]> = shaders
168                .iter()
169                .map(|shader| shader.specialization.as_ref().map(Into::into))
170                .collect();
171            let mut shader_stages: Vec<vk::PipelineShaderStageCreateInfo> =
172                Vec::with_capacity(shaders.len());
173            let mut shader_modules = Vec::with_capacity(shaders.len());
174            for (idx, shader) in shaders.iter().enumerate() {
175                let module = device
176                    .create_shader_module(
177                        &vk::ShaderModuleCreateInfo::default().code(shader.spirv.words()),
178                        None,
179                    )
180                    .map_err(|err| {
181                        warn!("unable to create ray tracing shader module: {err}");
182
183                        device.destroy_pipeline_layout(layout, None);
184
185                        for module in shader_modules.drain(..) {
186                            device.destroy_shader_module(module, None);
187                        }
188
189                        DriverError::Unsupported
190                    })?;
191
192                shader_modules.push(module);
193
194                let mut stage = vk::PipelineShaderStageCreateInfo::default()
195                    .module(module)
196                    .name(entry_points[idx].as_ref())
197                    .stage(shader.stage);
198
199                if let Some(specialization_info) = &specialization_infos[idx] {
200                    stage = stage.specialization_info(specialization_info);
201                }
202
203                shader_stages.push(stage);
204            }
205
206            let mut dynamic_states = Vec::with_capacity(1);
207
208            if info.dynamic_stack_size {
209                dynamic_states.push(vk::DynamicState::RAY_TRACING_PIPELINE_STACK_SIZE_KHR);
210            }
211
212            let khr_ray_tracing_pipeline = Device::expect_vk_khr_ray_tracing_pipeline(device);
213
214            let handle = khr_ray_tracing_pipeline.create_ray_tracing_pipelines(
215                vk::DeferredOperationKHR::null(),
216                Device::pipeline_cache(device),
217                &[vk::RayTracingPipelineCreateInfoKHR::default()
218                    .stages(&shader_stages)
219                    .groups(&shader_groups)
220                    .max_pipeline_ray_recursion_depth(
221                        info.max_ray_recursion_depth.min(
222                            device
223                                .physical
224                                .expect_ray_tracing_pipeline_properties()
225                                .max_ray_recursion_depth,
226                        ),
227                    )
228                    .layout(layout)
229                    .dynamic_state(
230                        &vk::PipelineDynamicStateCreateInfo::default()
231                            .dynamic_states(&dynamic_states),
232                    )],
233                None,
234            );
235
236            for shader_module in shader_modules.iter().copied() {
237                device.destroy_shader_module(shader_module, None);
238            }
239
240            let handle = handle
241                .map_err(|(pipelines, err)| {
242                    warn!("unable to create ray tracing pipeline: {err}");
243
244                    for pipeline in pipelines {
245                        device.destroy_pipeline(pipeline, None);
246                    }
247
248                    device.destroy_pipeline_layout(layout, None);
249
250                    DriverError::Unsupported
251                })?
252                .into_iter()
253                .find(|handle| !handle.is_null())
254                .ok_or_else(|| {
255                    warn!("missing pipeline handle");
256
257                    DriverError::Unsupported
258                })?;
259            let &RayTracingPipelineProperties {
260                shader_group_handle_size,
261                ..
262            } = device.physical.expect_ray_tracing_pipeline_properties();
263
264            let push_constants = merge_push_constant_ranges(&push_constants).into_boxed_slice();
265
266            /*
267            SAFETY:
268            See [`vkGetRayTracingShaderGroupHandlesKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkGetRayTracingShaderGroupHandlesKHR.html)
269            Valid usage of this function requires:
270            1. pipeline must be a ray tracing pipeline
271            2. first_group must be less than the number of shader groups in the pipeline
272            3. the sum of first_group and group_count must be less than or equal to the number of
273               shader groups in the pipeline
274            4. data_size must be at least shader_group_handle_size * group_count
275            5. pipeline must not have been created with VK_PIPELINE_CREATE_LIBRARY_BIT_KHR
276            */
277            let shader_group_handles = {
278                khr_ray_tracing_pipeline.get_ray_tracing_shader_group_handles(
279                    handle,
280                    0,
281                    group_count as u32,
282                    group_count * shader_group_handle_size as usize,
283                )
284            }
285            .map_err(|_| DriverError::InvalidData)?
286            .into_boxed_slice();
287
288            Ok(Self {
289                inner: Arc::new(RayTracingPipelineInner {
290                    descriptor_bindings,
291                    descriptor_info,
292                    device: device.clone(),
293                    handle,
294                    info,
295                    layout,
296                    push_constants,
297                    shader_group_handles,
298                }),
299            })
300        }
301    }
302
303    /// The device which owns this ray tracing pipeline.
304    pub fn device(&self) -> &Device {
305        &self.inner.device
306    }
307
308    /// Returns a handle to a shader group of this pipeline.
309    ///
310    /// This can be used to construct a shader binding table.
311    ///
312    /// # Examples
313    ///
314    /// See
315    /// [`ray_tracing.rs`](https://github.com/attackgoat/vk-graph/blob/master/examples/ray_tracing.rs)
316    /// for a detailed example that constructs a shader binding table buffer using this function.
317    ///
318    /// See [`vkGetRayTracingShaderGroupHandlesKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkGetRayTracingShaderGroupHandlesKHR.html).
319    pub fn group_handle(&self, idx: usize) -> &[u8] {
320        let &RayTracingPipelineProperties {
321            shader_group_handle_size,
322            ..
323        } = self
324            .inner
325            .device
326            .physical
327            .expect_ray_tracing_pipeline_properties();
328        let start = idx * shader_group_handle_size as usize;
329        let end = start + shader_group_handle_size as usize;
330
331        &self.inner.shader_group_handles[start..end]
332    }
333
334    /// Queries ray tracing pipeline shader group shader stack size.
335    ///
336    /// The return value is the ray tracing pipeline stack size in bytes for the specified shader as
337    /// called from the specified shader group.
338    ///
339    /// See [`vkGetRayTracingShaderGroupStackSizeKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkGetRayTracingShaderGroupStackSizeKHR.html).
340    #[profiling::function]
341    pub fn group_stack_size(
342        &self,
343        group: u32,
344        group_shader: vk::ShaderGroupShaderKHR,
345    ) -> vk::DeviceSize {
346        /*
347        Safely use unchecked because the ray tracing extension is checked during pipeline creation
348        */
349        let khr_ray_tracing_pipeline =
350            Device::expect_vk_khr_ray_tracing_pipeline(&self.inner.device);
351
352        unsafe {
353            khr_ray_tracing_pipeline.get_ray_tracing_shader_group_stack_size(
354                self.handle(),
355                group,
356                group_shader,
357            )
358        }
359    }
360
361    /// The native Vulkan pipeline handle of this ray tracing pipeline.
362    pub fn handle(&self) -> vk::Pipeline {
363        self.inner.handle
364    }
365
366    /// Gets the information used to create this object.
367    pub fn info(&self) -> RayTracingPipelineInfo {
368        self.inner.info
369    }
370
371    /// Sets the debugging name assigned to this pipeline.
372    pub fn set_debug_name(&self, name: impl AsRef<str>) {
373        Device::try_set_debug_utils_object_name(&self.inner.device, self.inner.handle, &name);
374        Device::try_set_private_data_object_name(
375            &self.inner.device,
376            vk::ObjectType::PIPELINE,
377            self.inner.handle,
378            &name,
379        );
380        Device::try_set_debug_utils_object_name(
381            &self.inner.device,
382            self.inner.layout,
383            lazy_str!("{} (layout)", name.as_ref()),
384        );
385
386        for (set_idx, layout) in &self.inner.descriptor_info.layouts {
387            layout.set_debug_name(lazy_str!("{} (DS{set_idx})", name.as_ref()));
388        }
389    }
390
391    /// Sets the debugging name assigned to this pipeline.
392    pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
393        self.set_debug_name(name);
394
395        self
396    }
397}
398
399impl Debug for RayTracingPipeline {
400    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
401        let mut res = f.debug_struct(stringify!(RayTracingPipeline));
402
403        if let Some(debug_name) = &Device::private_data_object_name(
404            &self.inner.device,
405            vk::ObjectType::PIPELINE,
406            self.inner.handle,
407        ) {
408            res.field("debug_name", debug_name);
409        }
410
411        res.field("handle", &self.inner.handle)
412            .finish_non_exhaustive()
413    }
414}
415
416impl Eq for RayTracingPipeline {}
417
418impl Hash for RayTracingPipeline {
419    fn hash<H: Hasher>(&self, state: &mut H) {
420        Arc::as_ptr(&self.inner).hash(state);
421    }
422}
423
424impl PartialEq for RayTracingPipeline {
425    fn eq(&self, other: &Self) -> bool {
426        Arc::ptr_eq(&self.inner, &other.inner)
427    }
428}
429
430/// Information used to create a [`RayTracingPipeline`] instance.
431#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
432#[builder(
433    build_fn(private, name = "fallible_build"),
434    derive(Clone, Copy, Debug),
435    pattern = "owned"
436)]
437pub struct RayTracingPipelineInfo {
438    /// The number of descriptors to allocate for a given binding when using bindless (unbounded)
439    /// syntax.
440    ///
441    /// The default is `8192`.
442    ///
443    /// # Examples
444    ///
445    /// Basic usage (GLSL):
446    ///
447    /// ```
448    /// # vk_shader_macros::glsl!(target: vulkan1_2, r#"
449    /// #version 460 core
450    /// #extension GL_EXT_nonuniform_qualifier : require
451    /// #pragma shader_stage(closest)
452    ///
453    /// layout(set = 0, binding = 0, rgba8) readonly uniform image2D my_binding[];
454    ///
455    /// void main() {
456    ///     // my_binding will have space for 8,192 images by default
457    /// }
458    /// # "#);
459    /// ```
460    #[builder(default = "8192")]
461    pub bindless_descriptor_count: u32,
462
463    /// Allow [setting the stack size dynamically] for a ray tracing pipeline.
464    ///
465    /// When set, you must manually set the stack size during ray tracing commands using
466    /// [`RayTracingCommandRef::set_stack_size`](crate::cmd::RayTracingCommandRef::set_stack_size).
467    ///
468    /// See [`vkCmdSetRayTracingPipelineStackSizeKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdSetRayTracingPipelineStackSizeKHR.html).
469    #[builder(default)]
470    pub dynamic_stack_size: bool,
471
472    /// The [maximum recursion depth] of shaders executed by this pipeline.
473    ///
474    /// The default is `16`.
475    ///
476    /// See [`VkRayTracingPipelineCreateInfoKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRayTracingPipelineCreateInfoKHR.html).
477    #[builder(default = "16")]
478    pub max_ray_recursion_depth: u32,
479}
480
481impl RayTracingPipelineInfo {
482    /// Creates a default `RayTracingPipelineInfoBuilder`.
483    pub fn builder() -> RayTracingPipelineInfoBuilder {
484        Default::default()
485    }
486
487    /// Converts a `RayTracingPipelineInfo` into a `RayTracingPipelineInfoBuilder`.
488    pub fn into_builder(self) -> RayTracingPipelineInfoBuilder {
489        RayTracingPipelineInfoBuilder {
490            bindless_descriptor_count: Some(self.bindless_descriptor_count),
491            dynamic_stack_size: Some(self.dynamic_stack_size),
492            max_ray_recursion_depth: Some(self.max_ray_recursion_depth),
493        }
494    }
495}
496
497impl Default for RayTracingPipelineInfo {
498    fn default() -> Self {
499        Self {
500            bindless_descriptor_count: 8192,
501            dynamic_stack_size: false,
502            max_ray_recursion_depth: 16,
503        }
504    }
505}
506
507impl From<RayTracingPipelineInfoBuilder> for RayTracingPipelineInfo {
508    fn from(info: RayTracingPipelineInfoBuilder) -> Self {
509        info.build()
510    }
511}
512
513impl RayTracingPipelineInfoBuilder {
514    /// Builds a new `RayTracingPipelineInfo`.
515    #[inline(always)]
516    pub fn build(self) -> RayTracingPipelineInfo {
517        self.fallible_build()
518            .expect("invalid ray tracing pipeline info")
519    }
520}
521
522#[derive(Debug)]
523pub(crate) struct RayTracingPipelineInner {
524    pub descriptor_bindings: DescriptorBindingMap,
525    pub descriptor_info: PipelineDescriptorInfo,
526    pub device: Device,
527    pub handle: vk::Pipeline,
528    pub info: RayTracingPipelineInfo,
529    pub layout: vk::PipelineLayout,
530    pub push_constants: Box<[vk::PushConstantRange]>,
531    pub shader_group_handles: Box<[u8]>,
532}
533
534impl Drop for RayTracingPipelineInner {
535    #[profiling::function]
536    fn drop(&mut self) {
537        if panicking() {
538            return;
539        }
540
541        Device::clear_private_data_object_name(&self.device, vk::ObjectType::PIPELINE, self.handle)
542            .unwrap_or_else(|err| warn!("unable to clear private data object name: {err}"));
543
544        unsafe {
545            self.device.destroy_pipeline(self.handle, None);
546            self.device.destroy_pipeline_layout(self.layout, None);
547        }
548    }
549}
550
551/// Describes the set of shader stages to be included in each shader group in the ray tracing
552/// pipeline.
553///
554/// See [`VkRayTracingShaderGroupCreateInfoKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRayTracingShaderGroupCreateInfoKHR.html).
555#[derive(Clone, Copy, Debug)]
556pub struct RayTracingShaderGroup {
557    /// The optional index of the any-hit shader in the group if the shader group has type of
558    /// [RayTracingShaderGroupType::TrianglesHitGroup] or
559    /// [RayTracingShaderGroupType::ProceduralHitGroup].
560    pub any_hit_shader: Option<u32>,
561
562    /// The optional index of the closest hit shader in the group if the shader group has type of
563    /// [RayTracingShaderGroupType::TrianglesHitGroup] or
564    /// [RayTracingShaderGroupType::ProceduralHitGroup].
565    pub closest_hit_shader: Option<u32>,
566
567    /// The index of the ray generation, miss, or callable shader in the group if the shader group
568    /// has type of [RayTracingShaderGroupType::General].
569    pub general_shader: Option<u32>,
570
571    /// The index of the intersection shader in the group if the shader group has type of
572    /// [RayTracingShaderGroupType::ProceduralHitGroup].
573    pub intersection_shader: Option<u32>,
574
575    /// The type of hit group specified in this structure.
576    pub shader_group_type: RayTracingShaderGroupType,
577}
578
579impl RayTracingShaderGroup {
580    fn new(
581        shader_group_type: RayTracingShaderGroupType,
582        general_shader: impl Into<Option<u32>>,
583        intersection_shader: impl Into<Option<u32>>,
584        closest_hit_shader: impl Into<Option<u32>>,
585        any_hit_shader: impl Into<Option<u32>>,
586    ) -> Self {
587        let any_hit_shader = any_hit_shader.into();
588        let closest_hit_shader = closest_hit_shader.into();
589        let general_shader = general_shader.into();
590        let intersection_shader = intersection_shader.into();
591
592        Self {
593            any_hit_shader,
594            closest_hit_shader,
595            general_shader,
596            intersection_shader,
597            shader_group_type,
598        }
599    }
600
601    /// Creates a new general-type shader group with the given general shader.
602    pub fn new_general(general_shader: impl Into<Option<u32>>) -> Self {
603        Self::new(
604            RayTracingShaderGroupType::General,
605            general_shader,
606            None,
607            None,
608            None,
609        )
610    }
611
612    /// Creates a new procedural-type shader group with the given intersection shader, and optional
613    /// closest-hit and any-hit shaders.
614    pub fn new_procedural(
615        intersection_shader: u32,
616        closest_hit_shader: impl Into<Option<u32>>,
617        any_hit_shader: impl Into<Option<u32>>,
618    ) -> Self {
619        Self::new(
620            RayTracingShaderGroupType::ProceduralHitGroup,
621            None,
622            intersection_shader,
623            closest_hit_shader,
624            any_hit_shader,
625        )
626    }
627
628    /// Creates a new triangles-type shader group with the given closest-hit shader and optional
629    /// any-hit shader.
630    pub fn new_triangles(closest_hit_shader: u32, any_hit_shader: impl Into<Option<u32>>) -> Self {
631        Self::new(
632            RayTracingShaderGroupType::TrianglesHitGroup,
633            None,
634            None,
635            closest_hit_shader,
636            any_hit_shader,
637        )
638    }
639}
640
641impl From<RayTracingShaderGroup> for vk::RayTracingShaderGroupCreateInfoKHR<'static> {
642    fn from(shader_group: RayTracingShaderGroup) -> Self {
643        vk::RayTracingShaderGroupCreateInfoKHR::default()
644            .ty(shader_group.shader_group_type.into())
645            .any_hit_shader(shader_group.any_hit_shader.unwrap_or(vk::SHADER_UNUSED_KHR))
646            .closest_hit_shader(
647                shader_group
648                    .closest_hit_shader
649                    .unwrap_or(vk::SHADER_UNUSED_KHR),
650            )
651            .general_shader(shader_group.general_shader.unwrap_or(vk::SHADER_UNUSED_KHR))
652            .intersection_shader(
653                shader_group
654                    .intersection_shader
655                    .unwrap_or(vk::SHADER_UNUSED_KHR),
656            )
657    }
658}
659
660/// Describes a type of ray tracing shader group, which is a collection of shaders which run in the
661/// specified mode.
662#[derive(Clone, Copy, Debug)]
663pub enum RayTracingShaderGroupType {
664    /// A shader group with a general shader.
665    General,
666
667    /// A shader group with an intersection shader, and optional closest-hit and any-hit shaders.
668    ProceduralHitGroup,
669
670    /// A shader group with a closest-hit shader and optional any-hit shader.
671    TrianglesHitGroup,
672}
673
674impl From<RayTracingShaderGroupType> for vk::RayTracingShaderGroupTypeKHR {
675    fn from(shader_group_type: RayTracingShaderGroupType) -> Self {
676        match shader_group_type {
677            RayTracingShaderGroupType::General => vk::RayTracingShaderGroupTypeKHR::GENERAL,
678            RayTracingShaderGroupType::ProceduralHitGroup => {
679                vk::RayTracingShaderGroupTypeKHR::PROCEDURAL_HIT_GROUP
680            }
681            RayTracingShaderGroupType::TrianglesHitGroup => {
682                vk::RayTracingShaderGroupTypeKHR::TRIANGLES_HIT_GROUP
683            }
684        }
685    }
686}
687
688#[cfg(test)]
689mod test {
690    use super::*;
691
692    type Info = RayTracingPipelineInfo;
693    type Builder = RayTracingPipelineInfoBuilder;
694
695    #[test]
696    pub fn ray_tracing_pipeline_info() {
697        let info = Info::default();
698        let builder = info.into_builder().build();
699
700        assert_eq!(info, builder);
701    }
702
703    #[test]
704    pub fn ray_tracing_pipeline_info_builder() {
705        let info = Info::default();
706        let builder = Builder::default().build();
707
708        assert_eq!(info, builder);
709    }
710}