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


Quelle  mod.rs   Sprache: unbekannt

 
/*!
[`Module`](super::Module) processing functionality.
*/

mod constant_evaluator;
mod emitter;
pub mod index;
mod layouter;
mod namer;
mod terminator;
mod typifier;

pub use constant_evaluator::{
    ConstantEvaluator, ConstantEvaluatorError, ExpressionKind, ExpressionKindTracker,
};
pub use emitter::Emitter;
pub use index::{BoundsCheckPolicies, BoundsCheckPolicy, IndexableLength, IndexableLengthError};
pub use layouter::{Alignment, LayoutError, LayoutErrorInner, Layouter, TypeLayout};
pub use namer::{EntryPointIndex, NameKey, Namer};
pub use terminator::ensure_block_returns;
pub use typifier::{ResolveContext, ResolveError, TypeResolution};

impl From<super::StorageFormat> for super::Scalar {
    fn from(format: super::StorageFormat) -> Self {
        use super::{ScalarKind as Sk, StorageFormat as Sf};
        let kind = match format {
            Sf::R8Unorm => Sk::Float,
            Sf::R8Snorm => Sk::Float,
            Sf::R8Uint => Sk::Uint,
            Sf::R8Sint => Sk::Sint,
            Sf::R16Uint => Sk::Uint,
            Sf::R16Sint => Sk::Sint,
            Sf::R16Float => Sk::Float,
            Sf::Rg8Unorm => Sk::Float,
            Sf::Rg8Snorm => Sk::Float,
            Sf::Rg8Uint => Sk::Uint,
            Sf::Rg8Sint => Sk::Sint,
            Sf::R32Uint => Sk::Uint,
            Sf::R32Sint => Sk::Sint,
            Sf::R32Float => Sk::Float,
            Sf::Rg16Uint => Sk::Uint,
            Sf::Rg16Sint => Sk::Sint,
            Sf::Rg16Float => Sk::Float,
            Sf::Rgba8Unorm => Sk::Float,
            Sf::Rgba8Snorm => Sk::Float,
            Sf::Rgba8Uint => Sk::Uint,
            Sf::Rgba8Sint => Sk::Sint,
            Sf::Bgra8Unorm => Sk::Float,
            Sf::Rgb10a2Uint => Sk::Uint,
            Sf::Rgb10a2Unorm => Sk::Float,
            Sf::Rg11b10Ufloat => Sk::Float,
            Sf::Rg32Uint => Sk::Uint,
            Sf::Rg32Sint => Sk::Sint,
            Sf::Rg32Float => Sk::Float,
            Sf::Rgba16Uint => Sk::Uint,
            Sf::Rgba16Sint => Sk::Sint,
            Sf::Rgba16Float => Sk::Float,
            Sf::Rgba32Uint => Sk::Uint,
            Sf::Rgba32Sint => Sk::Sint,
            Sf::Rgba32Float => Sk::Float,
            Sf::R16Unorm => Sk::Float,
            Sf::R16Snorm => Sk::Float,
            Sf::Rg16Unorm => Sk::Float,
            Sf::Rg16Snorm => Sk::Float,
            Sf::Rgba16Unorm => Sk::Float,
            Sf::Rgba16Snorm => Sk::Float,
        };
        super::Scalar { kind, width: 4 }
    }
}

impl super::ScalarKind {
    pub const fn is_numeric(self) -> bool {
        match self {
            crate::ScalarKind::Sint
            | crate::ScalarKind::Uint
            | crate::ScalarKind::Float
            | crate::ScalarKind::AbstractInt
            | crate::ScalarKind::AbstractFloat => true,
            crate::ScalarKind::Bool => false,
        }
    }
}

impl super::Scalar {
    pub const I32: Self = Self {
        kind: crate::ScalarKind::Sint,
        width: 4,
    };
    pub const U32: Self = Self {
        kind: crate::ScalarKind::Uint,
        width: 4,
    };
    pub const F32: Self = Self {
        kind: crate::ScalarKind::Float,
        width: 4,
    };
    pub const F64: Self = Self {
        kind: crate::ScalarKind::Float,
        width: 8,
    };
    pub const I64: Self = Self {
        kind: crate::ScalarKind::Sint,
        width: 8,
    };
    pub const U64: Self = Self {
        kind: crate::ScalarKind::Uint,
        width: 8,
    };
    pub const BOOL: Self = Self {
        kind: crate::ScalarKind::Bool,
        width: crate::BOOL_WIDTH,
    };
    pub const ABSTRACT_INT: Self = Self {
        kind: crate::ScalarKind::AbstractInt,
        width: crate::ABSTRACT_WIDTH,
    };
    pub const ABSTRACT_FLOAT: Self = Self {
        kind: crate::ScalarKind::AbstractFloat,
        width: crate::ABSTRACT_WIDTH,
    };

    pub const fn is_abstract(self) -> bool {
        match self.kind {
            crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => true,
            crate::ScalarKind::Sint
            | crate::ScalarKind::Uint
            | crate::ScalarKind::Float
            | crate::ScalarKind::Bool => false,
        }
    }

    /// Construct a float `Scalar` with the given width.
    ///
    /// This is especially common when dealing with
    /// `TypeInner::Matrix`, where the scalar kind is implicit.
    pub const fn float(width: crate::Bytes) -> Self {
        Self {
            kind: crate::ScalarKind::Float,
            width,
        }
    }

    pub const fn to_inner_scalar(self) -> crate::TypeInner {
        crate::TypeInner::Scalar(self)
    }

    pub const fn to_inner_vector(self, size: crate::VectorSize) -> crate::TypeInner {
        crate::TypeInner::Vector { size, scalar: self }
    }

    pub const fn to_inner_atomic(self) -> crate::TypeInner {
        crate::TypeInner::Atomic(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HashableLiteral {
    F64(u64),
    F32(u32),
    U32(u32),
    I32(i32),
    U64(u64),
    I64(i64),
    Bool(bool),
    AbstractInt(i64),
    AbstractFloat(u64),
}

impl From<crate::Literal> for HashableLiteral {
    fn from(l: crate::Literal) -> Self {
        match l {
            crate::Literal::F64(v) => Self::F64(v.to_bits()),
            crate::Literal::F32(v) => Self::F32(v.to_bits()),
            crate::Literal::U32(v) => Self::U32(v),
            crate::Literal::I32(v) => Self::I32(v),
            crate::Literal::U64(v) => Self::U64(v),
            crate::Literal::I64(v) => Self::I64(v),
            crate::Literal::Bool(v) => Self::Bool(v),
            crate::Literal::AbstractInt(v) => Self::AbstractInt(v),
            crate::Literal::AbstractFloat(v) => Self::AbstractFloat(v.to_bits()),
        }
    }
}

impl crate::Literal {
    pub const fn new(value: u8, scalar: crate::Scalar) -> Option<Self> {
        match (value, scalar.kind, scalar.width) {
            (value, crate::ScalarKind::Float, 8) => Some(Self::F64(value as _)),
            (value, crate::ScalarKind::Float, 4) => Some(Self::F32(value as _)),
            (value, crate::ScalarKind::Uint, 4) => Some(Self::U32(value as _)),
            (value, crate::ScalarKind::Sint, 4) => Some(Self::I32(value as _)),
            (value, crate::ScalarKind::Uint, 8) => Some(Self::U64(value as _)),
            (value, crate::ScalarKind::Sint, 8) => Some(Self::I64(value as _)),
            (1, crate::ScalarKind::Bool, crate::BOOL_WIDTH) => Some(Self::Bool(true)),
            (0, crate::ScalarKind::Bool, crate::BOOL_WIDTH) => Some(Self::Bool(false)),
            _ => None,
        }
    }

    pub const fn zero(scalar: crate::Scalar) -> Option<Self> {
        Self::new(0, scalar)
    }

    pub const fn one(scalar: crate::Scalar) -> Option<Self> {
        Self::new(1, scalar)
    }

    pub const fn width(&self) -> crate::Bytes {
        match *self {
            Self::F64(_) | Self::I64(_) | Self::U64(_) => 8,
            Self::F32(_) | Self::U32(_) | Self::I32(_) => 4,
            Self::Bool(_) => crate::BOOL_WIDTH,
            Self::AbstractInt(_) | Self::AbstractFloat(_) => crate::ABSTRACT_WIDTH,
        }
    }
    pub const fn scalar(&self) -> crate::Scalar {
        match *self {
            Self::F64(_) => crate::Scalar::F64,
            Self::F32(_) => crate::Scalar::F32,
            Self::U32(_) => crate::Scalar::U32,
            Self::I32(_) => crate::Scalar::I32,
            Self::U64(_) => crate::Scalar::U64,
            Self::I64(_) => crate::Scalar::I64,
            Self::Bool(_) => crate::Scalar::BOOL,
            Self::AbstractInt(_) => crate::Scalar::ABSTRACT_INT,
            Self::AbstractFloat(_) => crate::Scalar::ABSTRACT_FLOAT,
        }
    }
    pub const fn scalar_kind(&self) -> crate::ScalarKind {
        self.scalar().kind
    }
    pub const fn ty_inner(&self) -> crate::TypeInner {
        crate::TypeInner::Scalar(self.scalar())
    }
}

pub const POINTER_SPAN: u32 = 4;

impl super::TypeInner {
    /// Return the scalar type of `self`.
    ///
    /// If `inner` is a scalar, vector, or matrix type, return
    /// its scalar type. Otherwise, return `None`.
    pub const fn scalar(&self) -> Option<super::Scalar> {
        use crate::TypeInner as Ti;
        match *self {
            Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => Some(scalar),
            Ti::Matrix { scalar, .. } => Some(scalar),
            _ => None,
        }
    }

    pub fn scalar_kind(&self) -> Option<super::ScalarKind> {
        self.scalar().map(|scalar| scalar.kind)
    }

    /// Returns the scalar width in bytes
    pub fn scalar_width(&self) -> Option<u8> {
        self.scalar().map(|scalar| scalar.width)
    }

    pub const fn pointer_space(&self) -> Option<crate::AddressSpace> {
        match *self {
            Self::Pointer { space, .. } => Some(space),
            Self::ValuePointer { space, .. } => Some(space),
            _ => None,
        }
    }

    pub fn is_atomic_pointer(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
        match *self {
            crate::TypeInner::Pointer { base, .. } => match types[base].inner {
                crate::TypeInner::Atomic { .. } => true,
                _ => false,
            },
            _ => false,
        }
    }

    /// Get the size of this type.
    pub fn size(&self, _gctx: GlobalCtx) -> u32 {
        match *self {
            Self::Scalar(scalar) | Self::Atomic(scalar) => scalar.width as u32,
            Self::Vector { size, scalar } => size as u32 * scalar.width as u32,
            // matrices are treated as arrays of aligned columns
            Self::Matrix {
                columns,
                rows,
                scalar,
            } => Alignment::from(rows) * scalar.width as u32 * columns as u32,
            Self::Pointer { .. } | Self::ValuePointer { .. } => POINTER_SPAN,
            Self::Array {
                base: _,
                size,
                stride,
            } => {
                let count = match size {
                    super::ArraySize::Constant(count) => count.get(),
                    // any struct member or array element needing a size at pipeline-creation time
                    // must have a creation-fixed footprint
                    super::ArraySize::Pending(_) => 0,
                    // A dynamically-sized array has to have at least one element
                    super::ArraySize::Dynamic => 1,
                };
                count * stride
            }
            Self::Struct { span, .. } => span,
            Self::Image { .. }
            | Self::Sampler { .. }
            | Self::AccelerationStructure
            | Self::RayQuery
            | Self::BindingArray { .. } => 0,
        }
    }

    /// Return the canonical form of `self`, or `None` if it's already in
    /// canonical form.
    ///
    /// Certain types have multiple representations in `TypeInner`. This
    /// function converts all forms of equivalent types to a single
    /// representative of their class, so that simply applying `Eq` to the
    /// result indicates whether the types are equivalent, as far as Naga IR is
    /// concerned.
    pub fn canonical_form(
        &self,
        types: &crate::UniqueArena<crate::Type>,
    ) -> Option<crate::TypeInner> {
        use crate::TypeInner as Ti;
        match *self {
            Ti::Pointer { base, space } => match types[base].inner {
                Ti::Scalar(scalar) => Some(Ti::ValuePointer {
                    size: None,
                    scalar,
                    space,
                }),
                Ti::Vector { size, scalar } => Some(Ti::ValuePointer {
                    size: Some(size),
                    scalar,
                    space,
                }),
                _ => None,
            },
            _ => None,
        }
    }

    /// Compare `self` and `rhs` as types.
    ///
    /// This is mostly the same as `<TypeInner as Eq>::eq`, but it treats
    /// `ValuePointer` and `Pointer` types as equivalent.
    ///
    /// When you know that one side of the comparison is never a pointer, it's
    /// fine to not bother with canonicalization, and just compare `TypeInner`
    /// values with `==`.
    pub fn equivalent(
        &self,
        rhs: &crate::TypeInner,
        types: &crate::UniqueArena<crate::Type>,
    ) -> bool {
        let left = self.canonical_form(types);
        let right = rhs.canonical_form(types);
        left.as_ref().unwrap_or(self) == right.as_ref().unwrap_or(rhs)
    }

    pub fn is_dynamically_sized(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
        use crate::TypeInner as Ti;
        match *self {
            Ti::Array { size, .. } => size == crate::ArraySize::Dynamic,
            Ti::Struct { ref members, .. } => members
                .last()
                .map(|last| types[last.ty].inner.is_dynamically_sized(types))
                .unwrap_or(false),
            _ => false,
        }
    }

    pub fn components(&self) -> Option<u32> {
        Some(match *self {
            Self::Vector { size, .. } => size as u32,
            Self::Matrix { columns, .. } => columns as u32,
            Self::Array {
                size: crate::ArraySize::Constant(len),
                ..
            } => len.get(),
            Self::Struct { ref members, .. } => members.len() as u32,
            _ => return None,
        })
    }

    pub fn component_type(&self, index: usize) -> Option<TypeResolution> {
        Some(match *self {
            Self::Vector { scalar, .. } => TypeResolution::Value(crate::TypeInner::Scalar(scalar)),
            Self::Matrix { rows, scalar, .. } => {
                TypeResolution::Value(crate::TypeInner::Vector { size: rows, scalar })
            }
            Self::Array {
                base,
                size: crate::ArraySize::Constant(_),
                ..
            } => TypeResolution::Handle(base),
            Self::Struct { ref members, .. } => TypeResolution::Handle(members[index].ty),
            _ => return None,
        })
    }
}

impl super::AddressSpace {
    pub fn access(self) -> crate::StorageAccess {
        use crate::StorageAccess as Sa;
        match self {
            crate::AddressSpace::Function
            | crate::AddressSpace::Private
            | crate::AddressSpace::WorkGroup => Sa::LOAD | Sa::STORE,
            crate::AddressSpace::Uniform => Sa::LOAD,
            crate::AddressSpace::Storage { access } => access,
            crate::AddressSpace::Handle => Sa::LOAD,
            crate::AddressSpace::PushConstant => Sa::LOAD,
        }
    }
}

impl super::MathFunction {
    pub const fn argument_count(&self) -> usize {
        match *self {
            // comparison
            Self::Abs => 1,
            Self::Min => 2,
            Self::Max => 2,
            Self::Clamp => 3,
            Self::Saturate => 1,
            // trigonometry
            Self::Cos => 1,
            Self::Cosh => 1,
            Self::Sin => 1,
            Self::Sinh => 1,
            Self::Tan => 1,
            Self::Tanh => 1,
            Self::Acos => 1,
            Self::Asin => 1,
            Self::Atan => 1,
            Self::Atan2 => 2,
            Self::Asinh => 1,
            Self::Acosh => 1,
            Self::Atanh => 1,
            Self::Radians => 1,
            Self::Degrees => 1,
            // decomposition
            Self::Ceil => 1,
            Self::Floor => 1,
            Self::Round => 1,
            Self::Fract => 1,
            Self::Trunc => 1,
            Self::Modf => 1,
            Self::Frexp => 1,
            Self::Ldexp => 2,
            // exponent
            Self::Exp => 1,
            Self::Exp2 => 1,
            Self::Log => 1,
            Self::Log2 => 1,
            Self::Pow => 2,
            // geometry
            Self::Dot => 2,
            Self::Outer => 2,
            Self::Cross => 2,
            Self::Distance => 2,
            Self::Length => 1,
            Self::Normalize => 1,
            Self::FaceForward => 3,
            Self::Reflect => 2,
            Self::Refract => 3,
            // computational
            Self::Sign => 1,
            Self::Fma => 3,
            Self::Mix => 3,
            Self::Step => 2,
            Self::SmoothStep => 3,
            Self::Sqrt => 1,
            Self::InverseSqrt => 1,
            Self::Inverse => 1,
            Self::Transpose => 1,
            Self::Determinant => 1,
            Self::QuantizeToF16 => 1,
            // bits
            Self::CountTrailingZeros => 1,
            Self::CountLeadingZeros => 1,
            Self::CountOneBits => 1,
            Self::ReverseBits => 1,
            Self::ExtractBits => 3,
            Self::InsertBits => 4,
            Self::FirstTrailingBit => 1,
            Self::FirstLeadingBit => 1,
            // data packing
            Self::Pack4x8snorm => 1,
            Self::Pack4x8unorm => 1,
            Self::Pack2x16snorm => 1,
            Self::Pack2x16unorm => 1,
            Self::Pack2x16float => 1,
            Self::Pack4xI8 => 1,
            Self::Pack4xU8 => 1,
            // data unpacking
            Self::Unpack4x8snorm => 1,
            Self::Unpack4x8unorm => 1,
            Self::Unpack2x16snorm => 1,
            Self::Unpack2x16unorm => 1,
            Self::Unpack2x16float => 1,
            Self::Unpack4xI8 => 1,
            Self::Unpack4xU8 => 1,
        }
    }
}

impl crate::Expression {
    /// Returns true if the expression is considered emitted at the start of a function.
    pub const fn needs_pre_emit(&self) -> bool {
        match *self {
            Self::Literal(_)
            | Self::Constant(_)
            | Self::Override(_)
            | Self::ZeroValue(_)
            | Self::FunctionArgument(_)
            | Self::GlobalVariable(_)
            | Self::LocalVariable(_) => true,
            _ => false,
        }
    }

    /// Return true if this expression is a dynamic array/vector/matrix index,
    /// for [`Access`].
    ///
    /// This method returns true if this expression is a dynamically computed
    /// index, and as such can only be used to index matrices when they appear
    /// behind a pointer. See the documentation for [`Access`] for details.
    ///
    /// Note, this does not check the _type_ of the given expression. It's up to
    /// the caller to establish that the `Access` expression is well-typed
    /// through other means, like [`ResolveContext`].
    ///
    /// [`Access`]: crate::Expression::Access
    /// [`ResolveContext`]: crate::proc::ResolveContext
    pub const fn is_dynamic_index(&self) -> bool {
        match *self {
            Self::Literal(_) | Self::ZeroValue(_) | Self::Constant(_) => false,
            _ => true,
        }
    }
}

impl crate::Function {
    /// Return the global variable being accessed by the expression `pointer`.
    ///
    /// Assuming that `pointer` is a series of `Access` and `AccessIndex`
    /// expressions that ultimately access some part of a `GlobalVariable`,
    /// return a handle for that global.
    ///
    /// If the expression does not ultimately access a global variable, return
    /// `None`.
    pub fn originating_global(
        &self,
        mut pointer: crate::Handle<crate::Expression>,
    ) -> Option<crate::Handle<crate::GlobalVariable>> {
        loop {
            pointer = match self.expressions[pointer] {
                crate::Expression::Access { base, .. } => base,
                crate::Expression::AccessIndex { base, .. } => base,
                crate::Expression::GlobalVariable(handle) => return Some(handle),
                crate::Expression::LocalVariable(_) => return None,
                crate::Expression::FunctionArgument(_) => return None,
                // There are no other expressions that produce pointer values.
                _ => unreachable!(),
            }
        }
    }
}

impl crate::SampleLevel {
    pub const fn implicit_derivatives(&self) -> bool {
        match *self {
            Self::Auto | Self::Bias(_) => true,
            Self::Zero | Self::Exact(_) | Self::Gradient { .. } => false,
        }
    }
}

impl crate::Binding {
    pub const fn to_built_in(&self) -> Option<crate::BuiltIn> {
        match *self {
            crate::Binding::BuiltIn(built_in) => Some(built_in),
            Self::Location { .. } => None,
        }
    }
}

impl super::SwizzleComponent {
    pub const XYZW: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];

    pub const fn index(&self) -> u32 {
        match *self {
            Self::X => 0,
            Self::Y => 1,
            Self::Z => 2,
            Self::W => 3,
        }
    }
    pub const fn from_index(idx: u32) -> Self {
        match idx {
            0 => Self::X,
            1 => Self::Y,
            2 => Self::Z,
            _ => Self::W,
        }
    }
}

impl super::ImageClass {
    pub const fn is_multisampled(self) -> bool {
        match self {
            crate::ImageClass::Sampled { multi, .. } | crate::ImageClass::Depth { multi } => multi,
            crate::ImageClass::Storage { .. } => false,
        }
    }

    pub const fn is_mipmapped(self) -> bool {
        match self {
            crate::ImageClass::Sampled { multi, .. } | crate::ImageClass::Depth { multi } => !multi,
            crate::ImageClass::Storage { .. } => false,
        }
    }

    pub const fn is_depth(self) -> bool {
        matches!(self, crate::ImageClass::Depth { .. })
    }
}

impl crate::Module {
    pub const fn to_ctx(&self) -> GlobalCtx<'_> {
        GlobalCtx {
            types: &self.types,
            constants: &self.constants,
            overrides: &self.overrides,
            global_expressions: &self.global_expressions,
        }
    }
}

#[derive(Debug)]
pub(super) enum U32EvalError {
    NonConst,
    Negative,
}

#[derive(Clone, Copy)]
pub struct GlobalCtx<'a> {
    pub types: &'a crate::UniqueArena<crate::Type>,
    pub constants: &'a crate::Arena<crate::Constant>,
    pub overrides: &'a crate::Arena<crate::Override>,
    pub global_expressions: &'a crate::Arena<crate::Expression>,
}

impl GlobalCtx<'_> {
    /// Try to evaluate the expression in `self.global_expressions` using its `handle` and return it as a `u32`.
    #[allow(dead_code)]
    pub(super) fn eval_expr_to_u32(
        &self,
        handle: crate::Handle<crate::Expression>,
    ) -> Result<u32, U32EvalError> {
        self.eval_expr_to_u32_from(handle, self.global_expressions)
    }

    /// Try to evaluate the expression in the `arena` using its `handle` and return it as a `u32`.
    pub(super) fn eval_expr_to_u32_from(
        &self,
        handle: crate::Handle<crate::Expression>,
        arena: &crate::Arena<crate::Expression>,
    ) -> Result<u32, U32EvalError> {
        match self.eval_expr_to_literal_from(handle, arena) {
            Some(crate::Literal::U32(value)) => Ok(value),
            Some(crate::Literal::I32(value)) => {
                value.try_into().map_err(|_| U32EvalError::Negative)
            }
            _ => Err(U32EvalError::NonConst),
        }
    }

    /// Try to evaluate the expression in the `arena` using its `handle` and return it as a `bool`.
    #[allow(dead_code)]
    pub(super) fn eval_expr_to_bool_from(
        &self,
        handle: crate::Handle<crate::Expression>,
        arena: &crate::Arena<crate::Expression>,
    ) -> Option<bool> {
        match self.eval_expr_to_literal_from(handle, arena) {
            Some(crate::Literal::Bool(value)) => Some(value),
            _ => None,
        }
    }

    #[allow(dead_code)]
    pub(crate) fn eval_expr_to_literal(
        &self,
        handle: crate::Handle<crate::Expression>,
    ) -> Option<crate::Literal> {
        self.eval_expr_to_literal_from(handle, self.global_expressions)
    }

    fn eval_expr_to_literal_from(
        &self,
        handle: crate::Handle<crate::Expression>,
        arena: &crate::Arena<crate::Expression>,
    ) -> Option<crate::Literal> {
        fn get(
            gctx: GlobalCtx,
            handle: crate::Handle<crate::Expression>,
            arena: &crate::Arena<crate::Expression>,
        ) -> Option<crate::Literal> {
            match arena[handle] {
                crate::Expression::Literal(literal) => Some(literal),
                crate::Expression::ZeroValue(ty) => match gctx.types[ty].inner {
                    crate::TypeInner::Scalar(scalar) => crate::Literal::zero(scalar),
                    _ => None,
                },
                _ => None,
            }
        }
        match arena[handle] {
            crate::Expression::Constant(c) => {
                get(*self, self.constants[c].init, self.global_expressions)
            }
            _ => get(*self, handle, arena),
        }
    }
}

/// Return an iterator over the individual components assembled by a
/// `Compose` expression.
///
/// Given `ty` and `components` from an `Expression::Compose`, return an
/// iterator over the components of the resulting value.
///
/// Normally, this would just be an iterator over `components`. However,
/// `Compose` expressions can concatenate vectors, in which case the i'th
/// value being composed is not generally the i'th element of `components`.
/// This function consults `ty` to decide if this concatenation is occurring,
/// and returns an iterator that produces the components of the result of
/// the `Compose` expression in either case.
pub fn flatten_compose<'arenas>(
    ty: crate::Handle<crate::Type>,
    components: &'arenas [crate::Handle<crate::Expression>],
    expressions: &'arenas crate::Arena<crate::Expression>,
    types: &'arenas crate::UniqueArena<crate::Type>,
) -> impl Iterator<Item = crate::Handle<crate::Expression>> + 'arenas {
    // Returning `impl Iterator` is a bit tricky. We may or may not
    // want to flatten the components, but we have to settle on a
    // single concrete type to return. This function returns a single
    // iterator chain that handles both the flattening and
    // non-flattening cases.
    let (size, is_vector) = if let crate::TypeInner::Vector { size, .. } = types[ty].inner {
        (size as usize, true)
    } else {
        (components.len(), false)
    };

    /// Flatten `Compose` expressions if `is_vector` is true.
    fn flatten_compose<'c>(
        component: &'c crate::Handle<crate::Expression>,
        is_vector: bool,
        expressions: &'c crate::Arena<crate::Expression>,
    ) -> &'c [crate::Handle<crate::Expression>] {
        if is_vector {
            if let crate::Expression::Compose {
                ty: _,
                components: ref subcomponents,
            } = expressions[*component]
            {
                return subcomponents;
            }
        }
        std::slice::from_ref(component)
    }

    /// Flatten `Splat` expressions if `is_vector` is true.
    fn flatten_splat<'c>(
        component: &'c crate::Handle<crate::Expression>,
        is_vector: bool,
        expressions: &'c crate::Arena<crate::Expression>,
    ) -> impl Iterator<Item = crate::Handle<crate::Expression>> {
        let mut expr = *component;
        let mut count = 1;
        if is_vector {
            if let crate::Expression::Splat { size, value } = expressions[expr] {
                expr = value;
                count = size as usize;
            }
        }
        std::iter::repeat(expr).take(count)
    }

    // Expressions like `vec4(vec3(vec2(6, 7), 8), 9)` require us to
    // flatten up to two levels of `Compose` expressions.
    //
    // Expressions like `vec4(vec3(1.0), 1.0)` require us to flatten
    // `Splat` expressions. Fortunately, the operand of a `Splat` must
    // be a scalar, so we can stop there.
    components
        .iter()
        .flat_map(move |component| flatten_compose(component, is_vector, expressions))
        .flat_map(move |component| flatten_compose(component, is_vector, expressions))
        .flat_map(move |component| flatten_splat(component, is_vector, expressions))
        .take(size)
}

#[test]
fn test_matrix_size() {
    let module = crate::Module::default();
    assert_eq!(
        crate::TypeInner::Matrix {
            columns: crate::VectorSize::Tri,
            rows: crate::VectorSize::Tri,
            scalar: crate::Scalar::F32,
        }
        .size(module.to_ctx()),
        48,
    );
}

[ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge