spirv_std/
ray_tracing.rs

1//! Ray-tracing data types
2
3// NOTE(eddyb) "&-masking with zero", likely due to `NONE = 0` in `bitflags!`.
4#![allow(clippy::bad_bit_mask)]
5
6use crate::matrix::Matrix4x3;
7#[cfg(target_arch = "spirv")]
8use core::arch::asm;
9use glam::{UVec2, Vec2, Vec3};
10
11/// An acceleration structure type which is an opaque reference to an
12/// acceleration structure handle as defined in the client API specification.
13#[spirv(acceleration_structure)]
14#[derive(Copy, Clone)]
15// HACK(eddyb) avoids "transparent newtype of `_anti_zst_padding`" misinterpretation.
16#[repr(C)]
17pub struct AccelerationStructure {
18    // HACK(eddyb) avoids the layout becoming ZST (and being elided in one way
19    // or another, before `#[spirv(acceleration_structure)]` can special-case it).
20    _anti_zst_padding: core::mem::MaybeUninit<u32>,
21}
22
23impl AccelerationStructure {
24    /// Converts a 64-bit integer into an [`AccelerationStructure`].
25    /// # Safety
26    /// The 64-bit integer must point to a valid acceleration structure.
27    #[spirv_std_macros::gpu_only]
28    #[doc(alias = "OpConvertUToAccelerationStructureKHR")]
29    #[inline]
30    pub unsafe fn from_u64(id: u64) -> AccelerationStructure {
31        unsafe {
32            // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
33            let mut result_slot = core::mem::MaybeUninit::uninit();
34            asm! {
35                "%ret = OpTypeAccelerationStructureKHR",
36                "%result = OpConvertUToAccelerationStructureKHR %ret {id}",
37                "OpStore {result_slot} %result",
38                id = in(reg) id,
39                result_slot = in(reg) result_slot.as_mut_ptr(),
40            }
41            result_slot.assume_init()
42        }
43    }
44
45    /// Converts a vector of two 32 bit integers into an [`AccelerationStructure`].
46    /// # Safety
47    /// The combination must point to a valid acceleration structure.
48    #[spirv_std_macros::gpu_only]
49    #[doc(alias = "OpConvertUToAccelerationStructureKHR")]
50    #[inline]
51    pub unsafe fn from_vec(id: UVec2) -> AccelerationStructure {
52        unsafe {
53            // FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
54            let mut result_slot = core::mem::MaybeUninit::uninit();
55            asm! {
56                "%ret = OpTypeAccelerationStructureKHR",
57                "%id = OpLoad _ {id}",
58                "%result = OpConvertUToAccelerationStructureKHR %ret %id",
59                "OpStore {result_slot} %result",
60                id = in(reg) &id,
61                result_slot = in(reg) result_slot.as_mut_ptr(),
62            }
63            result_slot.assume_init()
64        }
65    }
66
67    #[spirv_std_macros::gpu_only]
68    /// Trace a ray into the acceleration structure.
69    ///
70    /// - `structure` is the descriptor for the acceleration structure to trace into.
71    /// - `ray_flags` contains one or more of the Ray Flag values.
72    /// - `cull_mask` is the mask to test against the instance mask. Only the 8
73    ///   least-significant bits of are used by this instruction - other bits
74    ///   are ignored.
75    /// - `sbt_offset` and `sbt_stride` control indexing into the SBT (Shader
76    ///   Binding Table) for hit shaders called from this trace. Only the 4
77    ///   least-significant bits of `sbt_offset` and `sbt_stride` are used by this
78    ///   instruction - other bits are ignored.
79    /// - `miss_index` is the index of the miss shader to be called from this
80    ///   trace call. Only the 16 least-significant bits are used by this
81    ///   instruction - other bits are ignored.
82    /// - `ray_origin`, `ray_tmin`, `ray_direction`, and `ray_tmax` control the
83    ///   basic parameters of the ray to be traced.
84    ///
85    /// - `payload` is a pointer to the ray payload structure to use for this trace.
86    ///   `payload` must have a storage class of `ray_payload`
87    ///   or `incoming_ray_payload`.
88    ///
89    /// This instruction is allowed only in `ray_generation`, `closest_hit` and
90    /// `miss` execution models.
91    ///
92    /// This instruction is a shader call instruction which may invoke shaders with
93    /// the `intersection`, `any_hit`, `closest_hit`, and `miss`
94    /// execution models.
95    #[doc(alias = "OpTraceRayKHR")]
96    #[inline]
97    #[allow(clippy::too_many_arguments)]
98    pub unsafe fn trace_ray<T>(
99        &self,
100        ray_flags: RayFlags,
101        cull_mask: i32,
102        sbt_offset: i32,
103        sbt_stride: i32,
104        miss_index: i32,
105        ray_origin: Vec3,
106        ray_tmin: f32,
107        ray_direction: Vec3,
108        ray_tmax: f32,
109        payload: &mut T,
110    ) {
111        unsafe {
112            asm! {
113                "%acceleration_structure = OpLoad _ {acceleration_structure}",
114                "%ray_origin = OpLoad _ {ray_origin}",
115                "%ray_direction = OpLoad _ {ray_direction}",
116                "OpTraceRayKHR \
117                %acceleration_structure \
118                {ray_flags} \
119                {cull_mask} \
120                {sbt_offset} \
121                {sbt_stride} \
122                {miss_index} \
123                %ray_origin \
124                {ray_tmin} \
125                %ray_direction \
126                {ray_tmax} \
127                {payload}",
128                acceleration_structure = in(reg) self,
129                ray_flags = in(reg) ray_flags.bits(),
130                cull_mask = in(reg) cull_mask,
131                sbt_offset = in(reg) sbt_offset,
132                sbt_stride = in(reg) sbt_stride,
133                miss_index = in(reg) miss_index,
134                ray_origin = in(reg) &ray_origin,
135                ray_tmin = in(reg) ray_tmin,
136                ray_direction = in(reg) &ray_direction,
137                ray_tmax = in(reg) ray_tmax,
138                payload = in(reg) payload,
139            }
140        }
141    }
142}
143
144bitflags::bitflags! {
145    /// Flags controlling the properties of an OpTraceRayKHR instruction.
146    /// Despite being a mask and allowing multiple bits to be combined, it is
147    /// invalid for more than one of these four bits to be set: `OPAQUE`,
148    /// `NO_OPAQUE`, `CULL_OPAQUE`, `CULL_NO_OPAQUE`, only one of
149    /// `CULL_BACK_FACING_TRIANGLES` and `CULL_FRONT_FACING_TRIANGLES` may
150    /// be set.
151    #[repr(transparent)]
152    #[cfg_attr(feature = "bytemuck", derive(bytemuck::Zeroable, bytemuck::Pod))]
153    pub struct RayFlags: u32 {
154        /// No flags specified.
155        const NONE = 0;
156        /// Force all intersections with the trace to be opaque.
157        const OPAQUE = 1;
158        /// Force all intersections with the trace to be non-opaque.
159        const NO_OPAQUE = 2;
160        /// Accept the first hit discovered.
161        const TERMINATE_ON_FIRST_HIT = 4;
162        /// Do not execute a closest hit shader.
163        const SKIP_CLOSEST_HIT_SHADER = 8;
164        /// Do not intersect with the back face of triangles.
165        const CULL_BACK_FACING_TRIANGLES = 16;
166        /// Do not intersect with the front face of triangles.
167        const CULL_FRONT_FACING_TRIANGLES = 32;
168        /// Do not intersect with opaque geometry.
169        const CULL_OPAQUE = 64;
170        /// Do not intersect with non-opaque geometry.
171        const CULL_NO_OPAQUE = 128;
172        /// Do not intersect with any triangle geometries.
173        const SKIP_TRIANGLES = 256;
174        /// Do not intersect with any AABB (Axis Aligned Bounding Box) geometries.
175        const SKIP_AABBS = 512;
176    }
177}
178
179/// Describes the type of the intersection which is currently the candidate in a ray query,
180/// returned by [`RayQuery::get_candidate_intersection_type`].
181#[repr(u32)]
182#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
183#[allow(clippy::upper_case_acronyms)]
184pub enum CandidateIntersection {
185    /// A potential intersection with a triangle is being considered.
186    Triangle = 0,
187    /// A potential intersection with an axis-aligned bounding box is being considered.
188    AABB = 1,
189}
190
191/// Describes the type of the intersection currently committed in a ray query, returned by
192/// [`RayQuery::get_committed_intersection_type`].
193#[repr(u32)]
194#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
195pub enum CommittedIntersection {
196    /// No intersection is committed.
197    None = 0,
198    /// An intersection with a triangle has been committed.
199    Triangle = 1,
200    /// A user-generated intersection has been committed.
201    Generated = 2,
202}
203
204/// A ray query type which is an opaque object representing a ray traversal.
205#[spirv(ray_query)]
206// HACK(eddyb) avoids "transparent newtype of `_anti_zst_padding`" misinterpretation.
207#[repr(C)]
208// HACK(eddyb) false positive due to `rustc` not understanding e.g. `ray_query!`.
209#[allow(dead_code)]
210pub struct RayQuery {
211    // HACK(eddyb) avoids the layout becoming ZST (and being elided in one way
212    // or another, before `#[spirv(ray_query)]` can special-case it).
213    _anti_zst_padding: core::mem::MaybeUninit<u32>,
214}
215
216/// Constructs an uninitialized ray query variable. Using the syntax
217/// `let (mut)? <name>`. Where `name` is the name of the ray query variable.
218#[macro_export]
219macro_rules! ray_query {
220    (let $name:ident) => {
221        $crate::ray_query!(@inner $name)
222    };
223    (let mut $name:ident) => {
224        $crate::ray_query!(@inner $name, mut)
225    };
226    (@inner $name:ident $(, $mut:tt)?) => {
227        let $name: &$($mut)? RayQuery = unsafe {
228            let $name : *mut RayQuery;
229            ::core::arch::asm! {
230                "%ray_query = OpTypeRayQueryKHR",
231                "%ray_query_ptr = OpTypePointer Generic %ray_query",
232                "{name} = OpVariable %ray_query_ptr Function",
233                name = out(reg) $name,
234            }
235
236            &$($mut)? *$name
237        };
238    }
239}
240
241impl RayQuery {
242    /// Initialize a ray query object, defining parameters of traversal. After this
243    /// call, a new ray trace can be performed with [`Self::proceed`]. Any
244    /// previous traversal state stored in the object is lost.
245    ///
246    /// - `ray_query` is a pointer to the ray query to initialize.
247    /// - `acceleration_structure` is the descriptor for the acceleration structure
248    ///   to trace into.
249    /// - `ray_flags` contains one or more of the Ray Flag values.
250    /// - `cull_mask` is the mask to test against the instance mask.  Only the 8
251    ///   least-significant bits of `cull_mask` are used by this instruction - other
252    ///   bits are ignored.
253    /// - `ray_origin`, `ray_tmin`, `ray_direction`, and `ray_tmax` control the
254    ///   basic parameters of the ray to be traced.
255    #[spirv_std_macros::gpu_only]
256    #[doc(alias = "OpRayQueryInitializeKHR")]
257    #[inline]
258    #[allow(clippy::too_many_arguments)]
259    pub unsafe fn initialize(
260        &mut self,
261        acceleration_structure: &AccelerationStructure,
262        ray_flags: RayFlags,
263        cull_mask: u32,
264        ray_origin: Vec3,
265        ray_tmin: f32,
266        ray_direction: Vec3,
267        ray_tmax: f32,
268    ) {
269        unsafe {
270            asm! {
271                "%acceleration_structure = OpLoad _ {acceleration_structure}",
272                "%origin = OpLoad _ {ray_origin}",
273                "%direction = OpLoad _ {ray_direction}",
274                "OpRayQueryInitializeKHR \
275                    {ray_query} \
276                    %acceleration_structure \
277                    {ray_flags} \
278                    {cull_mask} \
279                    %origin \
280                    {ray_tmin} \
281                    %direction \
282                    {ray_tmax}",
283                ray_query = in(reg) self,
284                acceleration_structure = in(reg) acceleration_structure,
285                ray_flags = in(reg) ray_flags.bits(),
286                cull_mask = in(reg) cull_mask,
287                ray_origin = in(reg) &ray_origin,
288                ray_tmin = in(reg) ray_tmin,
289                ray_direction = in(reg) &ray_direction,
290                ray_tmax = in(reg) ray_tmax,
291            }
292        }
293    }
294
295    /// Allow traversal to proceed. Returns `true` if traversal is incomplete,
296    /// and `false` when it has completed. A previous call to [`Self::proceed`]
297    /// with the same ray query object must not have already returned `false`.
298    #[spirv_std_macros::gpu_only]
299    #[doc(alias = "OpRayQueryProceedKHR")]
300    #[inline]
301    pub unsafe fn proceed(&self) -> bool {
302        unsafe {
303            let mut result = false;
304
305            asm! {
306                "%bool = OpTypeBool",
307                "%result = OpRayQueryProceedKHR %bool {ray_query}",
308                "OpStore {result} %result",
309                ray_query = in(reg) self,
310                result = in(reg) &mut result,
311            }
312
313            result
314        }
315    }
316
317    /// Terminates further execution of a ray query; further calls to
318    /// [`Self::proceed`] will return `false`. The value returned by any prior
319    /// execution of [`Self::proceed`] with the same ray query object must have
320    /// been true.
321    #[spirv_std_macros::gpu_only]
322    #[doc(alias = "OpRayQueryTerminateKHR")]
323    #[inline]
324    pub unsafe fn terminate(&self) {
325        unsafe { asm!("OpRayQueryTerminateKHR {}", in(reg) self) }
326    }
327
328    /// Confirms a triangle intersection to be included in the determination
329    /// of the closest hit for a ray query.
330    ///
331    /// [`Self::proceed()`] must have been called on this object, and it must
332    /// have returned true. The current intersection candidate must have a
333    /// [`Self::get_candidate_intersection_type()`] of
334    /// [`CandidateIntersection::Triangle`].
335    #[spirv_std_macros::gpu_only]
336    #[doc(alias = "OpRayQueryConfirmIntersectionKHR")]
337    #[inline]
338    pub unsafe fn confirm_intersection(&self) {
339        unsafe { asm!("OpRayQueryConfirmIntersectionKHR {}", in(reg) self) }
340    }
341
342    /// Returns the type of the current candidate intersection.
343    ///
344    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
345    #[spirv_std_macros::gpu_only]
346    #[doc(alias = "OpRayQueryGetIntersectionTypeKHR")]
347    #[inline]
348    pub unsafe fn get_candidate_intersection_type(&self) -> CandidateIntersection {
349        unsafe {
350            let result: u32;
351
352            asm! {
353                "%u32 = OpTypeInt 32 0",
354                "%intersection = OpConstant %u32 0",
355                "{result} = OpRayQueryGetIntersectionTypeKHR %u32 {ray_query} %intersection",
356                ray_query = in(reg) self,
357                result = out(reg) result,
358            }
359
360            match result {
361                0 => CandidateIntersection::Triangle,
362                1 => CandidateIntersection::AABB,
363                _ => CandidateIntersection::Triangle,
364            }
365        }
366    }
367
368    /// Returns the type of the current candidate intersection.
369    #[spirv_std_macros::gpu_only]
370    #[doc(alias = "OpRayQueryGetIntersectionTypeKHR")]
371    #[inline]
372    pub unsafe fn get_committed_intersection_type(&self) -> CommittedIntersection {
373        unsafe {
374            let result: u32;
375
376            asm! {
377                "%u32 = OpTypeInt 32 0",
378                "%intersection = OpConstant %u32 1",
379                "{result} = OpRayQueryGetIntersectionTypeKHR %u32 {ray_query} %intersection",
380                ray_query = in(reg) self,
381                result = out(reg) result,
382            }
383
384            match result {
385                0 => CommittedIntersection::None,
386                1 => CommittedIntersection::Triangle,
387                2 => CommittedIntersection::Generated,
388                _ => CommittedIntersection::None,
389            }
390        }
391    }
392
393    /// Returns the "Ray Tmin" value used by the ray query.
394    #[spirv_std_macros::gpu_only]
395    #[doc(alias = "OpRayQueryGetRayTMinKHR")]
396    #[inline]
397    pub unsafe fn get_ray_t_min(&self) -> f32 {
398        unsafe {
399            let result;
400
401            asm! {
402                "%f32 = OpTypeFloat 32",
403                "{result} = OpRayQueryGetRayTMinKHR %f32 {ray_query}",
404                ray_query = in(reg) self,
405                result = out(reg) result,
406            }
407
408            result
409        }
410    }
411
412    /// Returns the "Ray Flags" value used by the ray query.
413    #[spirv_std_macros::gpu_only]
414    #[doc(alias = "OpRayQueryGetRayFlagsKHR")]
415    #[inline]
416    pub unsafe fn get_ray_flags(&self) -> RayFlags {
417        unsafe {
418            let result;
419
420            asm! {
421                "{result} = OpRayQueryGetRayFlagsKHR typeof{result} {ray_query}",
422                ray_query = in(reg) self,
423                result = out(reg) result,
424            }
425
426            RayFlags::from_bits_truncate(result)
427        }
428    }
429
430    /// Gets the "T" value for the current or previous intersection considered
431    /// in a ray query.
432    ///
433    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
434    /// The current intersection candidate must have a [`Self::get_candidate_intersection_type()`]
435    /// of [`CandidateIntersection::Triangle`].
436    #[spirv_std_macros::gpu_only]
437    #[doc(alias = "OpRayQueryGetIntersectionTKHR")]
438    #[inline]
439    pub unsafe fn get_candidate_intersection_t(&self) -> f32 {
440        unsafe {
441            let result;
442
443            asm! {
444                "%u32 = OpTypeInt 32 0",
445                "%intersection = OpConstant %u32 0",
446                "{result} = OpRayQueryGetIntersectionTKHR typeof{result} {ray_query} %intersection",
447                ray_query = in(reg) self,
448                result = out(reg) result,
449            }
450
451            result
452        }
453    }
454
455    /// Gets the "T" value for the current or previous intersection considered
456    /// in a ray query.
457    ///
458    /// There must be a current committed intersection.
459    ///
460    /// TODO: Improve docs. Can't right now due to
461    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
462    #[spirv_std_macros::gpu_only]
463    #[doc(alias = "OpRayQueryGetIntersectionTKHR")]
464    #[inline]
465    pub unsafe fn get_committed_intersection_t(&self) -> f32 {
466        unsafe {
467            let result;
468
469            asm! {
470                "%u32 = OpTypeInt 32 0",
471                "%intersection = OpConstant %u32 1",
472                "{result} = OpRayQueryGetIntersectionTKHR typeof{result} {ray_query} %intersection",
473                ray_query = in(reg) self,
474                result = out(reg) result,
475            }
476
477            result
478        }
479    }
480
481    /// Gets the custom index of the instance for the current intersection
482    /// considered in a ray query.
483    ///
484    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
485    #[spirv_std_macros::gpu_only]
486    #[doc(alias = "OpRayQueryGetIntersectionInstanceCustomIndexKHR")]
487    #[inline]
488    pub unsafe fn get_candidate_intersection_instance_custom_index(&self) -> u32 {
489        unsafe {
490            let result;
491
492            asm! {
493                "%u32 = OpTypeInt 32 0",
494                "%intersection = OpConstant %u32 0",
495                "{result} = OpRayQueryGetIntersectionInstanceCustomIndexKHR %u32 {ray_query} %intersection",
496                ray_query = in(reg) self,
497                result = out(reg) result,
498            }
499
500            result
501        }
502    }
503
504    /// Gets the custom index of the instance for the current intersection
505    /// considered in a ray query.
506    ///
507    /// There must be a current committed intersection.
508    ///
509    /// TODO: Improve docs. Can't right now due to
510    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
511    #[spirv_std_macros::gpu_only]
512    #[doc(alias = "OpRayQueryGetIntersectionInstanceCustomIndexKHR")]
513    #[inline]
514    pub unsafe fn get_committed_intersection_instance_custom_index(&self) -> u32 {
515        unsafe {
516            let result;
517
518            asm! {
519                "%u32 = OpTypeInt 32 0",
520                "%intersection = OpConstant %u32 1",
521                "{result} = OpRayQueryGetIntersectionInstanceCustomIndexKHR %u32 {ray_query} %intersection",
522                ray_query = in(reg) self,
523                result = out(reg) result,
524            }
525
526            result
527        }
528    }
529
530    /// Gets the id of the instance for the current intersection considered in a
531    /// ray query.
532    ///
533    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
534    #[spirv_std_macros::gpu_only]
535    #[doc(alias = "OpRayQueryGetIntersectionInstanceIdKHR")]
536    #[inline]
537    pub unsafe fn get_candidate_intersection_instance_id(&self) -> u32 {
538        unsafe {
539            let result;
540
541            asm! {
542                "%u32 = OpTypeInt 32 0",
543                "%intersection = OpConstant %u32 0",
544                "{result} = OpRayQueryGetIntersectionInstanceIdKHR %u32 {ray_query} %intersection",
545                ray_query = in(reg) self,
546                result = out(reg) result,
547            }
548
549            result
550        }
551    }
552
553    /// Gets the id of the instance for the current intersection considered in a
554    /// ray query.
555    ///
556    /// There must be a current committed intersection.
557    ///
558    /// TODO: Improve docs. Can't right now due to
559    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
560    #[spirv_std_macros::gpu_only]
561    #[doc(alias = "OpRayQueryGetIntersectionInstanceIdKHR")]
562    #[inline]
563    pub unsafe fn get_committed_intersection_instance_id(&self) -> u32 {
564        unsafe {
565            let result;
566
567            asm! {
568                "%u32 = OpTypeInt 32 0",
569                "%intersection = OpConstant %u32 1",
570                "{result} = OpRayQueryGetIntersectionInstanceIdKHR %u32 {ray_query} %intersection",
571                ray_query = in(reg) self,
572                result = out(reg) result,
573            }
574
575            result
576        }
577    }
578
579    /// Gets the shader binding table record offset for the current intersection
580    /// considered in a ray query.
581    ///
582    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
583    #[spirv_std_macros::gpu_only]
584    #[doc(alias = "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR")]
585    #[inline]
586    pub unsafe fn get_candidate_intersection_shader_binding_table_record_offset(&self) -> u32 {
587        unsafe {
588            let result;
589
590            asm! {
591                "%u32 = OpTypeInt 32 0",
592                "%intersection = OpConstant %u32 0",
593                "{result} = OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR %u32 {ray_query} %intersection",
594                ray_query = in(reg) self,
595                result = out(reg) result,
596            }
597
598            result
599        }
600    }
601
602    /// Gets the shader binding table record offset for the current intersection
603    /// considered in a ray query.
604    ///
605    /// There must be a current committed intersection.
606    ///
607    /// TODO: Improve docs. Can't right now due to
608    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
609    #[spirv_std_macros::gpu_only]
610    #[doc(alias = "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR")]
611    #[inline]
612    pub unsafe fn get_committed_intersection_shader_binding_table_record_offset(&self) -> u32 {
613        unsafe {
614            let result;
615
616            asm! {
617                "%u32 = OpTypeInt 32 0",
618                "%intersection = OpConstant %u32 1",
619                "{result} = OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR %u32 {ray_query} %intersection",
620                ray_query = in(reg) self,
621                result = out(reg) result,
622            }
623
624            result
625        }
626    }
627
628    /// Gets the geometry index for the current intersection considered in a
629    /// ray query.
630    ///
631    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
632    #[spirv_std_macros::gpu_only]
633    #[doc(alias = "OpRayQueryGetIntersectionGeometryIndexKHR")]
634    #[inline]
635    pub unsafe fn get_candidate_intersection_geometry_index(&self) -> u32 {
636        unsafe {
637            let result;
638
639            asm! {
640                "%u32 = OpTypeInt 32 0",
641                "%intersection = OpConstant %u32 0",
642                "{result} = OpRayQueryGetIntersectionGeometryIndexKHR %u32 {ray_query} %intersection",
643                ray_query = in(reg) self,
644                result = out(reg) result,
645            }
646
647            result
648        }
649    }
650
651    /// Gets the geometry index for the current intersection considered in a
652    /// ray query.
653    ///
654    /// There must be a current committed intersection.
655    ///
656    /// TODO: Improve docs. Can't right now due to
657    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
658    #[spirv_std_macros::gpu_only]
659    #[doc(alias = "OpRayQueryGetIntersectionGeometryIndexKHR")]
660    #[inline]
661    pub unsafe fn get_committed_intersection_geometry_index(&self) -> u32 {
662        unsafe {
663            let result;
664
665            asm! {
666                "%u32 = OpTypeInt 32 0",
667                "%intersection = OpConstant %u32 1",
668                "{result} = OpRayQueryGetIntersectionGeometryIndexKHR %u32 {ray_query} %intersection",
669                ray_query = in(reg) self,
670                result = out(reg) result,
671            }
672
673            result
674        }
675    }
676
677    /// Gets the primitive index for the current intersection considered in a
678    /// ray query.
679    ///
680    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
681    #[spirv_std_macros::gpu_only]
682    #[doc(alias = "OpRayQueryGetIntersectionPrimitiveIndexKHR")]
683    #[inline]
684    pub unsafe fn get_candidate_intersection_primitive_index(&self) -> u32 {
685        unsafe {
686            let result;
687
688            asm! {
689                "%u32 = OpTypeInt 32 0",
690                "%intersection = OpConstant %u32 0",
691                "{result} = OpRayQueryGetIntersectionPrimitiveIndexKHR %u32 {ray_query} %intersection",
692                ray_query = in(reg) self,
693                result = out(reg) result,
694            }
695
696            result
697        }
698    }
699
700    /// Gets the primitive index for the current intersection considered in a
701    /// ray query.
702    ///
703    /// There must be a current committed intersection.
704    ///
705    /// TODO: Improve docs. Can't right now due to
706    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
707    #[spirv_std_macros::gpu_only]
708    #[doc(alias = "OpRayQueryGetIntersectionPrimitiveIndexKHR")]
709    #[inline]
710    pub unsafe fn get_committed_intersection_primitive_index(&self) -> u32 {
711        unsafe {
712            let result;
713
714            asm! {
715                "%u32 = OpTypeInt 32 0",
716                "%intersection = OpConstant %u32 1",
717                "{result} = OpRayQueryGetIntersectionPrimitiveIndexKHR %u32 {ray_query} %intersection",
718                ray_query = in(reg) self,
719                result = out(reg) result,
720            }
721
722            result
723        }
724    }
725
726    /// Gets the second and third barycentric coordinates of the current
727    /// intersection considered in a ray query against the primitive it hit.
728    ///
729    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
730    /// The current intersection candidate must have a [`Self::get_candidate_intersection_type()`]
731    /// of [`CandidateIntersection::Triangle`].
732    #[spirv_std_macros::gpu_only]
733    #[doc(alias = "OpRayQueryGetIntersectionBarycentricsKHR")]
734    #[inline]
735    pub unsafe fn get_candidate_intersection_barycentrics(&self) -> Vec2 {
736        unsafe {
737            let mut result = Default::default();
738
739            asm! {
740                "%u32 = OpTypeInt 32 0",
741                "%intersection = OpConstant %u32 0",
742                "%result = OpRayQueryGetIntersectionBarycentricsKHR typeof*{result} {ray_query} %intersection",
743                "OpStore {result} %result",
744                ray_query = in(reg) self,
745                result = in(reg) &mut result,
746            }
747
748            result
749        }
750    }
751
752    /// Gets the second and third barycentric coordinates of the current
753    /// intersection considered in a ray query against the primitive it hit.
754    ///
755    /// There must be a current committed intersection. Its
756    /// [`Self::get_committed_intersection_type()`] must be [`CommittedIntersection::Triangle`].
757    ///
758    /// TODO: Improve docs. Can't right now due to
759    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
760    #[spirv_std_macros::gpu_only]
761    #[doc(alias = "OpRayQueryGetIntersectionBarycentricsKHR")]
762    #[inline]
763    pub unsafe fn get_committed_intersection_barycentrics(&self) -> Vec2 {
764        unsafe {
765            let mut result = Default::default();
766
767            asm! {
768                "%u32 = OpTypeInt 32 0",
769                "%intersection = OpConstant %u32 1",
770                "%result = OpRayQueryGetIntersectionBarycentricsKHR typeof*{result} {ray_query} %intersection",
771                "OpStore {result} %result",
772                ray_query = in(reg) self,
773                result = in(reg) &mut result,
774            }
775
776            result
777        }
778    }
779
780    /// Returns whether the current intersection considered in a ray query was with
781    /// the front face (`true`) or back face (`false`) of a primitive.
782    ///
783    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
784    /// The current intersection candidate must have a [`Self::get_candidate_intersection_type()`]
785    /// of [`CandidateIntersection::Triangle`].
786    #[spirv_std_macros::gpu_only]
787    #[doc(alias = "OpRayQueryGetIntersectionFrontFaceKHR")]
788    #[inline]
789    pub unsafe fn get_candidate_intersection_front_face(&self) -> bool {
790        unsafe {
791            let mut result = false;
792
793            asm! {
794                "%bool = OpTypeBool",
795                "%u32 = OpTypeInt 32 0",
796                "%intersection = OpConstant %u32 0",
797                "%result = OpRayQueryGetIntersectionFrontFaceKHR %bool {ray_query} %intersection",
798                "OpStore {result} %result",
799                ray_query = in(reg) self,
800                result = in(reg) &mut result,
801            }
802
803            result
804        }
805    }
806
807    /// Returns whether the current intersection considered in a ray query was with
808    /// the front face (`true`) or back face (`false`) of a primitive.
809    ///
810    /// There must be a current committed intersection. Its
811    /// [`Self::get_committed_intersection_type()`] must be [`CommittedIntersection::Triangle`].
812    ///
813    /// TODO: Improve docs. Can't right now due to
814    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
815    #[spirv_std_macros::gpu_only]
816    #[doc(alias = "OpRayQueryGetIntersectionFrontFaceKHR")]
817    #[inline]
818    pub unsafe fn get_committed_intersection_front_face(&self) -> bool {
819        unsafe {
820            let mut result = false;
821
822            asm! {
823                "%bool = OpTypeBool",
824                "%u32 = OpTypeInt 32 0",
825                "%intersection = OpConstant %u32 1",
826                "%result = OpRayQueryGetIntersectionFrontFaceKHR %bool {ray_query} %intersection",
827                "OpStore {result} %result",
828                ray_query = in(reg) self,
829                result = in(reg) &mut result,
830            }
831
832            result
833        }
834    }
835
836    /// Returns whether a candidate intersection considered in a ray query was with
837    /// an opaque AABB (Axis Aligned Bounding Box) or not.
838    #[spirv_std_macros::gpu_only]
839    #[doc(alias = "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR")]
840    #[inline]
841    pub unsafe fn get_intersection_candidate_aabb_opaque(&self) -> bool {
842        unsafe {
843            let mut result = false;
844
845            asm! {
846                "%bool = OpTypeBool",
847                "%result = OpRayQueryGetIntersectionCandidateAABBOpaqueKHR %bool {ray_query}",
848                "OpStore {result} %result",
849                ray_query = in(reg) self,
850                result = in(reg) &mut result,
851            }
852
853            result
854        }
855    }
856
857    /// Gets the object-space ray direction for the current intersection considered
858    /// in a ray query.
859    ///
860    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
861    #[spirv_std_macros::gpu_only]
862    #[doc(alias = "OpRayQueryGetIntersectionObjectRayDirectionKHR")]
863    #[inline]
864    pub unsafe fn get_candidate_intersection_object_ray_direction(&self) -> Vec3 {
865        unsafe {
866            let mut result = Default::default();
867
868            asm! {
869                "%u32 = OpTypeInt 32 0",
870                "%intersection = OpConstant %u32 0",
871                "%result = OpRayQueryGetIntersectionObjectRayDirectionKHR typeof*{result} {ray_query} %intersection",
872                "OpStore {result} %result",
873                ray_query = in(reg) self,
874                result = in(reg) &mut result,
875            }
876
877            result
878        }
879    }
880
881    /// Gets the object-space ray direction for the current intersection considered
882    /// in a ray query.
883    ///
884    /// There must be a current committed intersection.
885    ///
886    /// TODO: Improve docs. Can't right now due to
887    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
888    #[spirv_std_macros::gpu_only]
889    #[doc(alias = "OpRayQueryGetIntersectionObjectRayDirectionKHR")]
890    #[inline]
891    pub unsafe fn get_committed_intersection_object_ray_direction(&self) -> Vec3 {
892        unsafe {
893            let mut result = Default::default();
894
895            asm! {
896                "%u32 = OpTypeInt 32 0",
897                "%intersection = OpConstant %u32 1",
898                "%result = OpRayQueryGetIntersectionObjectRayDirectionKHR typeof*{result} {ray_query} %intersection",
899                "OpStore {result} %result",
900                ray_query = in(reg) self,
901                result = in(reg) &mut result,
902            }
903
904            result
905        }
906    }
907
908    /// Gets the object-space ray origin for the current intersection considered in
909    /// a ray query.
910    ///
911    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
912    #[spirv_std_macros::gpu_only]
913    #[doc(alias = "OpRayQueryGetIntersectionObjectRayOriginKHR")]
914    #[inline]
915    pub unsafe fn get_candidate_intersection_object_ray_origin(&self) -> Vec3 {
916        unsafe {
917            let mut result = Default::default();
918
919            asm! {
920                "%u32 = OpTypeInt 32 0",
921                "%intersection = OpConstant %u32 0",
922                "%result = OpRayQueryGetIntersectionObjectRayOriginKHR typeof*{result} {ray_query} %intersection",
923                "OpStore {result} %result",
924                ray_query = in(reg) self,
925                result = in(reg) &mut result,
926            }
927
928            result
929        }
930    }
931
932    /// Gets the object-space ray origin for the current intersection considered in
933    /// a ray query.
934    ///
935    /// There must be a current committed intersection.
936    ///
937    /// TODO: Improve docs. Can't right now due to
938    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
939    #[spirv_std_macros::gpu_only]
940    #[doc(alias = "OpRayQueryGetIntersectionObjectRayOriginKHR")]
941    #[inline]
942    pub unsafe fn get_committed_intersection_object_ray_origin(&self) -> Vec3 {
943        unsafe {
944            let mut result = Default::default();
945
946            asm! {
947                "%u32 = OpTypeInt 32 0",
948                "%intersection = OpConstant %u32 1",
949                "%result = OpRayQueryGetIntersectionObjectRayOriginKHR typeof*{result} {ray_query} %intersection",
950                "OpStore {result} %result",
951                ray_query = in(reg) self,
952                result = in(reg) &mut result,
953            }
954
955            result
956        }
957    }
958
959    /// Gets the world-space direction for the ray traced in a ray query.
960    #[spirv_std_macros::gpu_only]
961    #[doc(alias = "OpRayQueryGetWorldRayDirectionKHR")]
962    #[inline]
963    pub unsafe fn get_world_ray_direction(&self) -> Vec3 {
964        unsafe {
965            let mut result = Default::default();
966
967            asm! {
968                "%u32 = OpTypeInt 32 0",
969                "%result = OpRayQueryGetWorldRayDirectionKHR typeof*{result} {ray_query}",
970                "OpStore {result} %result",
971                ray_query = in(reg) self,
972                result = in(reg) &mut result,
973            }
974
975            result
976        }
977    }
978
979    /// Gets the world-space origin for the ray traced in a ray query.
980    #[spirv_std_macros::gpu_only]
981    #[doc(alias = "OpRayQueryGetWorldRayOriginKHR")]
982    #[inline]
983    pub unsafe fn get_world_ray_origin(&self) -> Vec3 {
984        unsafe {
985            let mut result = Default::default();
986
987            asm! {
988                "%u32 = OpTypeInt 32 0",
989                "%result = OpRayQueryGetWorldRayOriginKHR typeof*{result} {ray_query}",
990                "OpStore {result} %result",
991                ray_query = in(reg) self,
992                result = in(reg) &mut result,
993            }
994
995            result
996        }
997    }
998
999    /// Gets a matrix that transforms values to world-space from the object-space of
1000    /// the current intersection considered in a ray query.
1001    ///
1002    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
1003    #[spirv_std_macros::gpu_only]
1004    #[doc(alias = "OpRayQueryGetIntersectionObjectToWorldKHR")]
1005    #[inline]
1006    pub unsafe fn get_candidate_intersection_object_to_world(&self) -> Matrix4x3 {
1007        unsafe {
1008            let mut result = Default::default();
1009
1010            asm! {
1011                "%u32 = OpTypeInt 32 0",
1012                "%intersection = OpConstant %u32 0",
1013                "%result = OpRayQueryGetIntersectionObjectToWorldKHR typeof*{result} {ray_query} %intersection",
1014                "OpStore {result} %result",
1015                ray_query = in(reg) self,
1016                result = in(reg) &mut result,
1017            }
1018
1019            result
1020        }
1021    }
1022
1023    /// Gets a matrix that transforms values to world-space from the object-space of
1024    /// the current intersection considered in a ray query.
1025    ///
1026    /// There must be a current committed intersection.
1027    ///
1028    /// TODO: Improve docs. Can't right now due to
1029    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
1030    #[spirv_std_macros::gpu_only]
1031    #[doc(alias = "OpRayQueryGetIntersectionObjectToWorldKHR")]
1032    #[inline]
1033    pub unsafe fn get_committed_intersection_object_to_world(&self) -> Matrix4x3 {
1034        unsafe {
1035            let mut result = Default::default();
1036
1037            asm! {
1038                "%u32 = OpTypeInt 32 0",
1039                "%intersection = OpConstant %u32 1",
1040                "%result = OpRayQueryGetIntersectionObjectToWorldKHR typeof*{result} {ray_query} %intersection",
1041                "OpStore {result} %result",
1042                ray_query = in(reg) self,
1043                result = in(reg) &mut result,
1044            }
1045
1046            result
1047        }
1048    }
1049
1050    /// Gets the vertex positions for the triangle at the current intersection.
1051    ///
1052    /// Requires Capability `RayQueryPositionFetchKHR` and extension `SPV_KHR_ray_tracing_position_fetch`
1053    #[spirv_std_macros::gpu_only]
1054    #[doc(alias = "OpRayQueryGetIntersectionTriangleVertexPositionsKHR")]
1055    #[inline]
1056    pub unsafe fn get_intersection_triangle_vertex_positions(&self) -> [Vec3; 3] {
1057        unsafe {
1058            let mut result = Default::default();
1059
1060            asm! {
1061                "%u32 = OpTypeInt 32 0",
1062                "%intersection = OpConstant %u32 0",
1063                "%result = OpRayQueryGetIntersectionTriangleVertexPositionsKHR typeof*{result} {ray_query} %intersection",
1064                "OpStore {result} %result",
1065                ray_query = in(reg) self,
1066                result = in(reg) &mut result,
1067            }
1068
1069            result
1070        }
1071    }
1072}