/// Information about a builtin used in [`add_builtin`](Frontend::add_builtin). struct BuiltInData { /// The type of the builtin.
inner: TypeInner, /// The associated builtin class.
builtin: BuiltIn, /// Whether the builtin can be written to or not.
mutable: bool, /// The storage used for the builtin.
storage: StorageQualifier,
}
let components = check_swizzle_components("xyzw")
.or_else(|| check_swizzle_components("rgba"))
.or_else(|| check_swizzle_components("stpq"));
iflet Some(components) = components { iflet ExprPos::Lhs = pos { let not_unique = (1..components.len())
.any(|i| components[i..].contains(&components[i - 1])); if not_unique { self.errors.push(Error {
kind: ErrorKind::SemanticError(
format!(
concat!( "swizzle cannot have duplicate components in ", "left-hand-side expression for \"{:?}\""
),
name
)
.into(),
),
meta,
})
}
}
letmut pattern = [SwizzleComponent::X; 4]; for (pat, component) in pattern.iter_mut().zip(&components) {
*pat = *component;
}
// flatten nested swizzles (vec.zyx.xy.x => vec.z) letmut expression = expression; iflet Expression::Swizzle {
size: _,
vector,
pattern: ref src_pattern,
} = ctx[expression]
{
expression = vector; for pat in &mut pattern {
*pat = src_pattern[pat.index() as usize];
}
}
let size = match components.len() { // Swizzles with just one component are accesses and not swizzles 1 => { match pos { // If the position is in the right hand side and the base // vector is a pointer, load it, otherwise the swizzle would // produce a pointer
ExprPos::Rhs if is_pointer => {
expression = ctx.add_expression(
Expression::Load {
pointer: expression,
},
meta,
)?;
}
_ => {}
}; return ctx.add_expression(
Expression::AccessIndex {
base: expression,
index: pattern[0].index(),
},
meta,
);
} 2 => VectorSize::Bi, 3 => VectorSize::Tri, 4 => VectorSize::Quad,
_ => { self.errors.push(Error {
kind: ErrorKind::SemanticError(
format!("Bad swizzle size for \"{name:?}\"").into(),
),
meta,
});
VectorSize::Quad
}
};
if is_pointer { // NOTE: for lhs expression, this extra load ends up as an unused expr, because the // assignment will extract the pointer and use it directly anyway. Unfortunately we // need it for validation to pass, as swizzles cannot operate on pointer values.
expression = ctx.add_expression(
Expression::Load {
pointer: expression,
},
meta,
)?;
}
Ok(ctx.add_expression(
Expression::Swizzle {
size,
vector: expression,
pattern,
},
meta,
)?)
} else {
Err(Error {
kind: ErrorKind::SemanticError(
format!("Invalid swizzle for vector \"{name}\"").into(),
),
meta,
})
}
}
_ => Err(Error {
kind: ErrorKind::SemanticError(
format!("Can't lookup field on this type \"{name}\"").into(),
),
meta,
}),
}
}
pub(crate) fn add_global_var(
&mutself,
ctx: &mut Context,
VarDeclaration {
qualifiers, mut ty,
name,
init,
meta,
}: VarDeclaration,
) -> Result<GlobalOrConstant> { let storage = qualifiers.storage.0; let (ret, lookup) = match storage {
StorageQualifier::Input | StorageQualifier::Output => { let input = storage == StorageQualifier::Input; // TODO: glslang seems to use a counter for variables without // explicit location (even if that causes collisions) let location = qualifiers
.uint_layout_qualifier("location", &mutself.errors)
.unwrap_or(0); let interpolation = qualifiers.interpolation.take().map(|(i, _)| i).or_else(|| { let kind = ctx.module.types[ty].inner.scalar_kind()?;
Some(match kind {
ScalarKind::Float => Interpolation::Perspective,
_ => Interpolation::Flat,
})
}); let sampling = qualifiers.sampling.take().map(|(s, _)| s);
match qualifiers.layout_qualifiers.remove(&QualifierKey::Format) {
Some((QualifierValue::Format(f), _)) => format = f, // TODO: glsl supports images without format qualifier // if they are `writeonly`
None => self.errors.push(Error {
kind: ErrorKind::SemanticError( "image types require a format layout qualifier".into(),
),
meta,
}),
_ => unreachable!(),
}
ty = ctx.module.types.insert( Type {
name: None,
inner: TypeInner::Image {
dim,
arrayed,
class: crate::ImageClass::Storage { format, access },
},
},
meta,
);
}
space = AddressSpace::Handle
}
TypeInner::Sampler { .. } => space = AddressSpace::Handle,
_ => { if qualifiers.none_layout_qualifier("push_constant", &mutself.errors) {
space = AddressSpace::PushConstant
}
}
},
AddressSpace::Function => space = AddressSpace::Private,
_ => {}
};
let binding = match space {
AddressSpace::Uniform | AddressSpace::Storage { .. } | AddressSpace::Handle => { let binding = qualifiers.uint_layout_qualifier("binding", &mutself.errors); if binding.is_none() { self.errors.push(Error {
kind: ErrorKind::SemanticError( "uniform/buffer blocks require layout(binding=X)".into(),
),
meta,
});
} let set = qualifiers.uint_layout_qualifier("set", &mutself.errors);
binding.map(|binding| ResourceBinding {
group: set.unwrap_or(0),
binding,
})
}
_ => None,
};
¤ 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.0.21Bemerkung:
(vorverarbeitet am 2026-06-23)
¤
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.