Skip to main content

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