spirv-std 0.4.0

Standard functions and types for SPIR-V
Documentation
//! Ray-tracing data types
use crate::vector::Vector;
#[cfg(target_arch = "spirv")]
use core::arch::asm;

/// An acceleration structure type which is an opaque reference to an
/// acceleration structure handle as defined in the client API specification.
#[spirv(acceleration_structure)]
#[derive(Copy, Clone)]
pub struct AccelerationStructure {
    pub(crate) _private: u32,
}

impl AccelerationStructure {
    /// Converts a 64-bit integer into an [`AccelerationStructure`].
    /// # Safety
    /// The 64-bit integer must point to a valid acceleration structure.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpConvertUToAccelerationStructureKHR")]
    #[inline]
    pub unsafe fn from_u64(id: u64) -> AccelerationStructure {
        // Since we can't represent an uninitalized opaque type in Rust at the
        // moment, we need to create and return the acceleration structure entirely
        // in assembly.
        asm! {
            "%ret = OpTypeAccelerationStructureKHR",
            "%result = OpConvertUToAccelerationStructureKHR %ret {id}",
            "OpReturnValue %result",
            id = in(reg) id,
            options(noreturn)
        }
    }

    /// Converts a vector of two 32 bit integers into an [`AccelerationStructure`].
    /// # Safety
    /// The combination must point to a valid acceleration structure.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpConvertUToAccelerationStructureKHR")]
    #[inline]
    pub unsafe fn from_vec(id: impl Vector<u32, 2>) -> AccelerationStructure {
        // Since we can't represent an uninitalized opaque type in Rust at the
        // moment, we need to create and return the acceleration structure entirely
        // in assembly.
        asm! {
            "%ret = OpTypeAccelerationStructureKHR",
            "%id = OpLoad _ {id}",
            "%result = OpConvertUToAccelerationStructureKHR %ret %id",
            "OpReturnValue %result",
            id = in(reg) &id,
            options(noreturn),
        }
    }

    #[spirv_std_macros::gpu_only]
    /// Trace a ray into the acceleration structure.
    ///
    /// - `structure` is the descriptor for the acceleration structure to trace into.
    /// - `ray_flags` contains one or more of the Ray Flag values.
    /// - `cull_mask` is the mask to test against the instance mask. Only the 8
    ///   least-significant bits of are used by this instruction - other bits
    ///   are ignored.
    /// - `sbt_offset` and `sbt_stride` control indexing into the SBT (Shader
    ///   Binding Table) for hit shaders called from this trace. Only the 4
    ///   least-significant bits of `sbt_offset` and `sbt_stride` are used by this
    ///   instruction - other bits are ignored.
    /// - `miss_index` is the index of the miss shader to be called from this
    ///   trace call. Only the 16 least-significant bits are used by this
    ///   instruction - other bits are ignored.
    /// - `ray_origin`, `ray_tmin`, `ray_direction`, and `ray_tmax` control the
    ///   basic parameters of the ray to be traced.
    ///
    /// - `payload` is a pointer to the ray payload structure to use for this trace.
    ///   `payload` must have a storage class of `ray_payload`
    ///   or `incoming_ray_payload`.
    ///
    /// This instruction is allowed only in `ray_generation`, `closest_hit` and
    /// `miss` execution models.
    ///
    /// This instruction is a shader call instruction which may invoke shaders with
    /// the `intersection`, `any_hit`, `closest_hit`, and `miss`
    /// execution models.
    #[doc(alias = "OpTraceRayKHR")]
    #[inline]
    #[allow(clippy::too_many_arguments)]
    pub unsafe fn trace_ray<T>(
        &self,
        ray_flags: RayFlags,
        cull_mask: i32,
        sbt_offset: i32,
        sbt_stride: i32,
        miss_index: i32,
        ray_origin: impl Vector<f32, 3>,
        ray_tmin: f32,
        ray_direction: impl Vector<f32, 3>,
        ray_tmax: f32,
        payload: &mut T,
    ) {
        asm! {
            "%acceleration_structure = OpLoad _ {acceleration_structure}",
            "%ray_origin = OpLoad _ {ray_origin}",
            "%ray_direction = OpLoad _ {ray_direction}",
            "OpTraceRayKHR \
            %acceleration_structure \
            {ray_flags} \
            {cull_mask} \
            {sbt_offset} \
            {sbt_stride} \
            {miss_index} \
            %ray_origin \
            {ray_tmin} \
            %ray_direction \
            {ray_tmax} \
            {payload}",
            acceleration_structure = in(reg) self,
            ray_flags = in(reg) ray_flags.bits(),
            cull_mask = in(reg) cull_mask,
            sbt_offset = in(reg) sbt_offset,
            sbt_stride = in(reg) sbt_stride,
            miss_index = in(reg) miss_index,
            ray_origin = in(reg) &ray_origin,
            ray_tmin = in(reg) ray_tmin,
            ray_direction = in(reg) &ray_direction,
            ray_tmax = in(reg) ray_tmax,
            payload = in(reg) payload,
        }
    }
}

bitflags::bitflags! {
    /// Flags controlling the properties of an OpTraceRayKHR instruction.
    /// Despite being a mask and allowing multiple bits to be combined, it is
    /// invalid for more than one of these four bits to be set: `OPAQUE`,
    /// `NO_OPAQUE`, `CULL_OPAQUE`, `CULL_NO_OPAQUE`, only one of
    /// `CULL_BACK_FACING_TRIANGLES` and `CULL_FRONT_FACING_TRIANGLES` may
    /// be set.
    pub struct RayFlags: u32 {
        /// No flags specified.
        const NONE = 0;
        /// Force all intersections with the trace to be opaque.
        const OPAQUE = 1;
        /// Force all intersections with the trace to be non-opaque.
        const NO_OPAQUE = 2;
        /// Accept the first hit discovered.
        const TERMINATE_ON_FIRST_HIT = 4;
        /// Do not execute a closest hit shader.
        const SKIP_CLOSEST_HIT_SHADER = 8;
        /// Do not intersect with the back face of triangles.
        const CULL_BACK_FACING_TRIANGLES = 16;
        /// Do not intersect with the front face of triangles.
        const CULL_FRONT_FACING_TRIANGLES = 32;
        /// Do not intersect with opaque geometry.
        const CULL_OPAQUE = 64;
        /// Do not intersect with non-opaque geometry.
        const CULL_NO_OPAQUE = 128;
        /// Do not intersect with any triangle geometries.
        const SKIP_TRIANGLES = 256;
        /// Do not intersect with any AABB (Axis Aligned Bounding Box) geometries.
        const SKIP_AABBS = 512;
    }
}

/// Describes the type of the intersection which is currently the candidate in a ray query,
/// returned by [`RayQuery::get_candidate_intersection_type`].
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::upper_case_acronyms)]
pub enum CandidateIntersection {
    /// A potential intersection with a triangle is being considered.
    Triangle = 0,
    /// A potential intersection with an axis-aligned bounding box is being considered.
    AABB = 1,
}

/// Describes the type of the intersection currently committed in a ray query, returned by
/// [`RayQuery::get_committed_intersection_type`].
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CommittedIntersection {
    /// No intersection is committed.
    None = 0,
    /// An intersection with a triangle has been committed.
    Triangle = 1,
    /// A user-generated intersection has been committed.
    Generated = 2,
}

/// A ray query type which is an opaque object representing a ray traversal.
#[spirv(ray_query)]
pub struct RayQuery {
    _private: u32,
}

/// Constructs an uninitialized ray query variable. Using the syntax
/// `let (mut)? <name>`. Where `name` is the name of the ray query variable.
#[macro_export]
macro_rules! ray_query {
    (let $name:ident) => {
        $crate::ray_query!(@inner $name)
    };
    (let mut $name:ident) => {
        $crate::ray_query!(@inner $name, mut)
    };
    (@inner $name:ident $(, $mut:tt)?) => {
        let $name: &$($mut)? RayQuery = unsafe {
            let $name : *mut RayQuery;
            ::core::arch::asm! {
                "%ray_query = OpTypeRayQueryKHR",
                "%ray_query_ptr = OpTypePointer Generic %ray_query",
                "{name} = OpVariable %ray_query_ptr Function",
                name = out(reg) $name,
            }

            &$($mut)? *$name
        };
    }
}

impl RayQuery {
    /// Initialize a ray query object, defining parameters of traversal. After this
    /// call, a new ray trace can be performed with [`Self::proceed`]. Any
    /// previous traversal state stored in the object is lost.
    ///
    /// - `ray_query` is a pointer to the ray query to initialize.
    /// - `acceleration_structure` is the descriptor for the acceleration structure
    ///   to trace into.
    /// - `ray_flags` contains one or more of the Ray Flag values.
    /// - `cull_mask` is the mask to test against the instance mask.  Only the 8
    ///   least-significant bits of `cull_mask` are used by this instruction - other
    ///   bits are ignored.
    /// - `ray_origin`, `ray_tmin`, `ray_direction`, and `ray_tmax` control the
    ///   basic parameters of the ray to be traced.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryInitializeKHR")]
    #[inline]
    #[allow(clippy::too_many_arguments)]
    pub unsafe fn initialize(
        &mut self,
        acceleration_structure: &AccelerationStructure,
        ray_flags: RayFlags,
        cull_mask: u32,
        ray_origin: impl Vector<f32, 3>,
        ray_tmin: f32,
        ray_direction: impl Vector<f32, 3>,
        ray_tmax: f32,
    ) {
        asm! {
            "%acceleration_structure = OpLoad _ {acceleration_structure}",
            "%origin = OpLoad _ {ray_origin}",
            "%direction = OpLoad _ {ray_direction}",
            "OpRayQueryInitializeKHR \
                {ray_query} \
                %acceleration_structure \
                {ray_flags} \
                {cull_mask} \
                %origin \
                {ray_tmin} \
                %direction \
                {ray_tmax}",
            ray_query = in(reg) self,
            acceleration_structure = in(reg) acceleration_structure,
            ray_flags = in(reg) ray_flags.bits(),
            cull_mask = in(reg) cull_mask,
            ray_origin = in(reg) &ray_origin,
            ray_tmin = in(reg) ray_tmin,
            ray_direction = in(reg) &ray_direction,
            ray_tmax = in(reg) ray_tmax,
        }
    }

    /// Allow traversal to proceed. Returns `true` if traversal is incomplete,
    /// and `false` when it has completed. A previous call to [`Self::proceed`]
    /// with the same ray query object must not have already returned `false`.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryProceedKHR")]
    #[inline]
    pub unsafe fn proceed(&self) -> bool {
        let mut result = false;

        asm! {
            "%bool = OpTypeBool",
            "%result = OpRayQueryProceedKHR %bool {ray_query}",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Terminates further execution of a ray query; further calls to
    /// [`Self::proceed`] will return `false`. The value returned by any prior
    /// execution of [`Self::proceed`] with the same ray query object must have
    /// been true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryTerminateKHR")]
    #[inline]
    pub unsafe fn terminate(&self) {
        asm!("OpRayQueryTerminateKHR {}", in(reg) self)
    }

    /// Confirms a triangle intersection to be included in the determination
    /// of the closest hit for a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must
    /// have returned true. The current intersection candidate must have a
    /// [`Self::get_candidate_intersection_type()`] of
    /// [`CandidateIntersection::Triangle`].
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryConfirmIntersectionKHR")]
    #[inline]
    pub unsafe fn confirm_intersection(&self) {
        asm!("OpRayQueryConfirmIntersectionKHR {}", in(reg) self)
    }

    /// Returns the type of the current candidate intersection.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionTypeKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_type(&self) -> CandidateIntersection {
        let result: u32;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionTypeKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        match result {
            0 => CandidateIntersection::Triangle,
            1 => CandidateIntersection::AABB,
            _ => CandidateIntersection::Triangle,
        }
    }

    /// Returns the type of the current candidate intersection.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionTypeKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_type(&self) -> CommittedIntersection {
        let result: u32;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionTypeKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        match result {
            0 => CommittedIntersection::None,
            1 => CommittedIntersection::Triangle,
            2 => CommittedIntersection::Generated,
            _ => CommittedIntersection::None,
        }
    }

    /// Returns the "Ray Tmin" value used by the ray query.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetRayTMinKHR")]
    #[inline]
    pub unsafe fn get_ray_t_min(&self) -> f32 {
        let result;

        asm! {
            "%f32 = OpTypeFloat 32",
            "{result} = OpRayQueryGetRayTMinKHR %f32 {ray_query}",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Returns the "Ray Flags" value used by the ray query.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetRayFlagsKHR")]
    #[inline]
    pub unsafe fn get_ray_flags(&self) -> RayFlags {
        let result;

        asm! {
            "{result} = OpRayQueryGetRayFlagsKHR typeof{result} {ray_query}",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        RayFlags::from_bits_truncate(result)
    }

    /// Gets the "T" value for the current or previous intersection considered
    /// in a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    /// The current intersection candidate must have a [`Self::get_candidate_intersection_type()`]
    /// of [`CandidateIntersection::Triangle`].
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionTKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_t(&self) -> f32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionTKHR typeof{result} {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the "T" value for the current or previous intersection considered
    /// in a ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionTKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_t(&self) -> f32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionTKHR typeof{result} {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the custom index of the instance for the current intersection
    /// considered in a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionInstanceCustomIndexKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_instance_custom_index(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionInstanceCustomIndexKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the custom index of the instance for the current intersection
    /// considered in a ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionInstanceCustomIndexKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_instance_custom_index(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionInstanceCustomIndexKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the id of the instance for the current intersection considered in a
    /// ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionInstanceIdKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_instance_id(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionInstanceIdKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the id of the instance for the current intersection considered in a
    /// ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionInstanceIdKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_instance_id(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionInstanceIdKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the shader binding table record offset for the current intersection
    /// considered in a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_shader_binding_table_record_offset(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the shader binding table record offset for the current intersection
    /// considered in a ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_shader_binding_table_record_offset(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the geometry index for the current intersection considered in a
    /// ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionGeometryIndexKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_geometry_index(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionGeometryIndexKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the geometry index for the current intersection considered in a
    /// ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionGeometryIndexKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_geometry_index(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionGeometryIndexKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the primitive index for the current intersection considered in a
    /// ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionPrimitiveIndexKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_primitive_index(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "{result} = OpRayQueryGetIntersectionPrimitiveIndexKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the primitive index for the current intersection considered in a
    /// ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionPrimitiveIndexKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_primitive_index(&self) -> u32 {
        let result;

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "{result} = OpRayQueryGetIntersectionPrimitiveIndexKHR %u32 {ray_query} %intersection",
            ray_query = in(reg) self,
            result = out(reg) result,
        }

        result
    }

    /// Gets the second and third barycentric coordinates of the current
    /// intersection considered in a ray query against the primitive it hit.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    /// The current intersection candidate must have a [`Self::get_candidate_intersection_type()`]
    /// of [`CandidateIntersection::Triangle`].
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionBarycentricsKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_barycentrics<V: Vector<f32, 2>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "%result = OpRayQueryGetIntersectionBarycentricsKHR typeof*{result} {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the second and third barycentric coordinates of the current
    /// intersection considered in a ray query against the primitive it hit.
    ///
    /// There must be a current committed intersection. Its
    /// [`Self::get_committed_intersection_type()`] must be [`CommittedIntersection::Triangle`].
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionBarycentricsKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_barycentrics<V: Vector<f32, 2>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "%result = OpRayQueryGetIntersectionBarycentricsKHR typeof*{result} {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Returns whether the current intersection considered in a ray query was with
    /// the front face (`true`) or back face (`false`) of a primitive.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    /// The current intersection candidate must have a [`Self::get_candidate_intersection_type()`]
    /// of [`CandidateIntersection::Triangle`].
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionFrontFaceKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_front_face(&self) -> bool {
        let mut result = false;

        asm! {
            "%bool = OpTypeBool",
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "%result = OpRayQueryGetIntersectionFrontFaceKHR %bool {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Returns whether the current intersection considered in a ray query was with
    /// the front face (`true`) or back face (`false`) of a primitive.
    ///
    /// There must be a current committed intersection. Its
    /// [`Self::get_committed_intersection_type()`] must be [`CommittedIntersection::Triangle`].
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionFrontFaceKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_front_face(&self) -> bool {
        let mut result = false;

        asm! {
            "%bool = OpTypeBool",
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "%result = OpRayQueryGetIntersectionFrontFaceKHR %bool {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Returns whether a candidate intersection considered in a ray query was with
    /// an opaque AABB (Axis Aligned Bounding Box) or not.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR")]
    #[inline]
    pub unsafe fn get_intersection_candidate_aabb_opaque(&self) -> bool {
        let mut result = false;

        asm! {
            "%bool = OpTypeBool",
            "%result = OpRayQueryGetIntersectionCandidateAABBOpaqueKHR %bool {ray_query}",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the object-space ray direction for the current intersection considered
    /// in a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionObjectRayDirectionKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_object_ray_direction<V: Vector<f32, 3>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "%result = OpRayQueryGetIntersectionObjectRayDirectionKHR typeof*{result} {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the object-space ray direction for the current intersection considered
    /// in a ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionObjectRayDirectionKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_object_ray_direction<V: Vector<f32, 3>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "%result = OpRayQueryGetIntersectionObjectRayDirectionKHR typeof*{result} {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the object-space ray origin for the current intersection considered in
    /// a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionObjectRayOriginKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_object_ray_origin<V: Vector<f32, 3>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 0",
            "%result = OpRayQueryGetIntersectionObjectRayOriginKHR typeof*{result} {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the object-space ray origin for the current intersection considered in
    /// a ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionObjectRayOriginKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_object_ray_origin<V: Vector<f32, 3>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%intersection = OpConstant %u32 1",
            "%result = OpRayQueryGetIntersectionObjectRayOriginKHR typeof*{result} {ray_query} %intersection",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the world-space direction for the ray traced in a ray query.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetWorldRayDirectionKHR")]
    #[inline]
    pub unsafe fn get_world_ray_direction<V: Vector<f32, 3>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%result = OpRayQueryGetWorldRayDirectionKHR typeof*{result} {ray_query}",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets the world-space origin for the ray traced in a ray query.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetWorldRayOriginKHR")]
    #[inline]
    pub unsafe fn get_world_ray_origin<V: Vector<f32, 3>>(&self) -> V {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%result = OpRayQueryGetWorldRayOriginKHR typeof*{result} {ray_query}",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets a matrix that transforms values to world-space from the object-space of
    /// the current intersection considered in a ray query.
    ///
    /// [`Self::proceed()`] must have been called on this object, and it must have returned true.
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionObjectToWorldKHR")]
    #[inline]
    pub unsafe fn get_candidate_intersection_object_to_world<V: Vector<f32, 3>>(&self) -> [V; 4] {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%f32 = OpTypeFloat 32",
            "%f32x3 = OpTypeVector %f32 3",
            "%f32x3x4 = OpTypeMatrix %f32x3 4",
            "%intersection = OpConstant %u32 0",
            "%matrix = OpRayQueryGetIntersectionObjectToWorldKHR %f32x3x4 {ray_query} %intersection",
            "%col0 = OpCompositeExtract %f32x3 %matrix 0",
            "%col1 = OpCompositeExtract %f32x3 %matrix 1",
            "%col2 = OpCompositeExtract %f32x3 %matrix 2",
            "%col3 = OpCompositeExtract %f32x3 %matrix 3",
            "%result = OpCompositeConstruct typeof*{result} %col0 %col1 %col2 %col3",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }

    /// Gets a matrix that transforms values to world-space from the object-space of
    /// the current intersection considered in a ray query.
    ///
    /// There must be a current committed intersection.
    ///
    /// TODO: Improve docs. Can't right now due to
    /// <https://github.com/KhronosGroup/SPIRV-Registry/issues/128>
    #[spirv_std_macros::gpu_only]
    #[doc(alias = "OpRayQueryGetIntersectionObjectToWorldKHR")]
    #[inline]
    pub unsafe fn get_committed_intersection_object_to_world<V: Vector<f32, 3>>(&self) -> [V; 4] {
        let mut result = Default::default();

        asm! {
            "%u32 = OpTypeInt 32 0",
            "%f32 = OpTypeFloat 32",
            "%f32x3 = OpTypeVector %f32 3",
            "%f32x3x4 = OpTypeMatrix %f32x3 4",
            "%intersection = OpConstant %u32 1",
            "%matrix = OpRayQueryGetIntersectionObjectToWorldKHR %f32x3x4 {ray_query} %intersection",
            "%col0 = OpCompositeExtract %f32x3 %matrix 0",
            "%col1 = OpCompositeExtract %f32x3 %matrix 1",
            "%col2 = OpCompositeExtract %f32x3 %matrix 2",
            "%col3 = OpCompositeExtract %f32x3 %matrix 3",
            "%result = OpCompositeConstruct typeof*{result} %col0 %col1 %col2 %col3",
            "OpStore {result} %result",
            ray_query = in(reg) self,
            result = in(reg) &mut result,
        }

        result
    }
}