Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  ray.rs

  Sprache: Rust
 

Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

use alloc::{
    format,
    string::{String, ToString},
};
use core::fmt::Write;

use crate::{
    back::{
        self,
        msl::{
            writer::{StatementContext, TypeContext, WrappedFunction},
            BackendResult, Error, Writer,
        },
        Baked,
    },
    Handle,
};

pub(super) const RT_NAMESPACE: &str = "metal::raytracing";

/// The ray query type, needs to be a function so it can format the constants.
pub(super) fn metal_intersector_ty() -> String {
    format!("{RT_NAMESPACE}::intersection_query<{RT_NAMESPACE}::instancing, {RT_NAMESPACE}::triangle_data>")
}

pub(super) const INTERSECTION_FUNCTION_NAME: &str = "ray_query_get_intersection";

impl<W: Write> Writer<W> {
    /// Writes a function to get the current intersection from the ray query
    ///
    /// Like other backends, this is needed to have a single branch for constructing
    /// the parts of the intersection that need to be checked whether they do or don't
    /// hit.
    pub(super) fn write_rq_get_intersection_function(
        &mut self,
        module: &crate::Module,
        committed: bool,
    ) -> BackendResult {
        let wrapped = WrappedFunction::RayQueryGetIntersection { committed };
        if !self.wrapped_functions.insert(wrapped) {
            return Ok(());
        }

        let ty = if committed { "committed" } else { "candidate" };
        let intersection = TypeContext {
            handle: module
                .special_types
                .ray_intersection
                .expect("intersection ty should be there for intersection function"),
            gctx: module.to_ctx(),
            names: &self.names,
            access: crate::StorageAccess::empty(),
            first_time: false,
        };
        let level = back::Level(1);
        writeln!(
            self.out,
            "{intersection} {INTERSECTION_FUNCTION_NAME}_{committed}({} intersector) {{",
            metal_intersector_ty()
        )?;
        // Initialize the intersection to its default values (which should be zero).
        writeln!(
            self.out,
            "{level}{intersection} intersection = {intersection} {{}};"
        )?;
        writeln!(self.out, "{level}{RT_NAMESPACE}::intersection_type ty = intersector.get_{ty}_intersection_type();")?;
        // If the ray hit a triangle, call all methods that require that and set the intersection type.
        writeln!(
            self.out,
            "{level}if (ty == {RT_NAMESPACE}::intersection_type::triangle) {{"
        )?;
        writeln!(
            self.out,
            "{level}{level}intersection.kind = {};",
            crate::RayQueryIntersection::Triangle as u32
        )?;
        if !committed {
            writeln!(
                self.out,
                "{level}{level}intersection.t = intersector.get_candidate_triangle_distance();"
            )?;
        }
        writeln!(self.out, "{level}{level}intersection.barycentrics = intersector.get_{ty}_triangle_barycentric_coord();")?;
        writeln!(
            self.out,
            "{level}{level}intersection.front_face = intersector.is_{ty}_triangle_front_facing();"
        )?;
        // Otherwise, if the ray hit an AABB (called a bounding box in metal) set the intersection type
        // (which depends on whether this is a committed or candidate intersection).
        writeln!(
            self.out,
            "{level}}} else if (ty == {RT_NAMESPACE}::intersection_type::bounding_box) {{"
        )?;
        if committed {
            writeln!(
                self.out,
                "{level}{level}intersection.kind = {};",
                crate::RayQueryIntersection::Generated as u32
            )?;
        } else {
            writeln!(
                self.out,
                "{level}{level}intersection.kind = {};",
                crate::RayQueryIntersection::Aabb as u32
            )?;
        }
        writeln!(self.out, "{level}}}")?;

        // If the ray hit anything at all, call all methods that require that.
        writeln!(
            self.out,
            "{level}if (ty != {RT_NAMESPACE}::intersection_type::none) {{"
        )?;
        if committed {
            writeln!(
                self.out,
                "{level}{level}intersection.t = intersector.get_committed_distance();"
            )?;
        }
        writeln!(self.out, "{level}{level}intersection.instance_custom_data = intersector.get_{ty}_user_instance_id();")?;
        writeln!(
            self.out,
            "{level}{level}intersection.instance_index = intersector.get_{ty}_instance_id();"
        )?;
        // Metal does not appear to support obtaining the intersection offset from a ray query.
        //writeln!(self.out, "{level}{level}intersection.sbt_record_offset = intersector.get_{ty}_user_instance_id();")?;
        writeln!(
            self.out,
            "{level}{level}intersection.geometry_index = intersector.get_{ty}_geometry_id();"
        )?;
        writeln!(
            self.out,
            "{level}{level}intersection.primitive_index = intersector.get_{ty}_primitive_id();"
        )?;
        writeln!(self.out, "{level}{level}intersection.object_to_world = intersector.get_{ty}_object_to_world_transform();")?;
        writeln!(self.out, "{level}{level}intersection.world_to_object = intersector.get_{ty}_world_to_object_transform();")?;
        writeln!(self.out, "{level}}}")?;
        writeln!(self.out, "{level}return intersection;")?;
        writeln!(self.out, "}}")?;

        Ok(())
    }

    pub(super) fn write_ray_query_stmt(
        &mut self,
        level: back::Level,
        context: &StatementContext,
        query: Handle<crate::Expression>,
        fun: &crate::RayQueryFunction,
    ) -> BackendResult {
        if context.expression.lang_version < (24) {
            return Err(Error::UnsupportedRayTracing);
        }

        // TODO: check for misuse.
        match *fun {
            crate::RayQueryFunction::Initialize {
                acceleration_structure,
                descriptor,
            } => {
                //TODO: how to deal with winding? Is it by default the same as the other APIs?

                // Put everything in a block so that the variable names
                // do not conflict with user variable names
                writeln!(self.out, "{level}{{")?;

                let inner_level = level.next();

                let naga_ray_desc_ty = TypeContext {
                    handle: context
                        .expression
                        .module
                        .special_types
                        .ray_desc
                        .expect("ray desc is required as an argument so should be there"),
                    gctx: context.expression.module.to_ctx(),
                    names: &self.names,
                    access: crate::StorageAccess::empty(),
                    first_time: false,
                };

                write!(self.out, "{inner_level}{naga_ray_desc_ty} desc = ")?;
                self.put_expression(descriptor, &context.expression, false)?;
                writeln!(self.out, ";")?;

                // Set up intersection parameters
                writeln!(
                    self.out,
                    "{inner_level}{RT_NAMESPACE}::intersection_params params;"
                )?;

                {
                    // Determine whether or not to cull opaque/non-opaques
                    let f_opaque = back::RayFlag::CULL_OPAQUE.bits();
                    let f_no_opaque = back::RayFlag::CULL_NO_OPAQUE.bits();
                    writeln!(
                        self.out,
                        "{inner_level}params.set_opacity_cull_mode(
{inner_level}    (desc.flags & {f_opaque}) != 0 ? {RT_NAMESPACE}::opacity_cull_mode::opaque : (
{inner_level}        (desc.flags & {f_no_opaque}) != 0 ? {RT_NAMESPACE}::opacity_cull_mode::non_opaque : {RT_NAMESPACE}::opacity_cull_mode::none
{inner_level}    )
{inner_level});"
                    )?;
                }
                {
                    // Determine whether to force a particular opacity
                    let f_opaque = back::RayFlag::OPAQUE.bits();
                    let f_no_opaque = back::RayFlag::NO_OPAQUE.bits();
                    writeln!(self.out, "{inner_level}params.force_opacity(
{inner_level}    (desc.flags & {f_opaque}) != 0 ? {RT_NAMESPACE}::forced_opacity::opaque : (
{inner_level}        (desc.flags & {f_no_opaque}) != 0 ? {RT_NAMESPACE}::forced_opacity::non_opaque : {RT_NAMESPACE}::forced_opacity::none
{inner_level}    )
{inner_level});")?;
                }
                {
                    let flag = back::RayFlag::TERMINATE_ON_FIRST_HIT.bits();
                    writeln!(
                        self.out,
                        "{inner_level}params.accept_any_intersection((desc.flags & {flag}) != 0);"
                    )?;
                }

                writeln!(
                    self.out,
                    "{inner_level}{RT_NAMESPACE}::ray ray = {RT_NAMESPACE}::ray(desc.origin, desc.dir, desc.tmin, desc.tmax);"
                )?;

                write!(self.out, "{inner_level}")?;
                // A ray query can by initialized in metal by either using a "non-default constructor"
                // or by calling reset. Ray queries cannot be assigned to in metal, so reset needs to
                // be called.
                self.put_expression(query, &context.expression, true)?;
                write!(self.out, ".reset(ray,")?;
                self.put_expression(acceleration_structure, &context.expression, true)?;
                writeln!(self.out, ", desc.cull_mask, params);")?;
                writeln!(self.out, "{level}}}")?;
            }
            crate::RayQueryFunction::Proceed { result } => {
                write!(self.out, "{level}")?;
                let name = Baked(result).to_string();
                self.start_baking_expression(result, &context.expression, &name)?;
                self.named_expressions.insert(result, name);
                self.put_expression(query, &context.expression, true)?;
                writeln!(self.out, ".next();")?;
            }
            crate::RayQueryFunction::GenerateIntersection { hit_t } => {
                write!(self.out, "{level}")?;
                self.put_expression(query, &context.expression, true)?;
                write!(self.out, ".commit_bounding_box_intersection(")?;
                self.put_expression(hit_t, &context.expression, true)?;
                writeln!(self.out, ");")?;
            }
            crate::RayQueryFunction::ConfirmIntersection => {
                write!(self.out, "{level}")?;
                self.put_expression(query, &context.expression, true)?;
                writeln!(self.out, ".commit_triangle_intersection();")?;
            }
            crate::RayQueryFunction::Terminate => {
                write!(self.out, "{level}")?;
                self.put_expression(query, &context.expression, true)?;
                // Terminate appears to map to abort in spirv-cross, but metal only documents
                // the existence of this method, not what it does.
                writeln!(self.out, ".abort();")?;
            }
        }

        Ok(())
    }
}

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet am  2026-08-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=434850
#Domains=655579