Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 54 additions & 9 deletions naga/src/back/wgsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,6 @@ impl<W: Write> Writer<W> {
}

pub fn write(&mut self, module: &Module, info: &valid::ModuleInfo) -> BackendResult {
if !module.overrides.is_empty() {
return Err(Error::Unimplemented(
"Pipeline constants are not yet supported for this back-end".to_string(),
));
}

self.reset(module);

// Write all `enable` declarations
Expand Down Expand Up @@ -172,6 +166,16 @@ impl<W: Write> Writer<W> {
}
}

// Write all overrides
let mut overrides = module.overrides.iter().peekable();
while let Some((handle, _)) = overrides.next() {
self.write_override(module, handle)?;
// Add extra newline for readability on last iteration
if overrides.peek().is_none() {
writeln!(self.out)?;
}
}

// Write all globals
for (ty, global) in module.global_variables.iter() {
self.write_global(module, global, ty)?;
Expand Down Expand Up @@ -1205,6 +1209,9 @@ impl<W: Write> Writer<W> {
write_expression(self, value)?;
write!(self.out, ")")?;
}
Expression::Override(handle) => {
write!(self.out, "{}", self.names[&NameKey::Override(handle)])?;
}
_ => unreachable!(),
}

Expand Down Expand Up @@ -1255,7 +1262,9 @@ impl<W: Write> Writer<W> {
|writer, expr| writer.write_expr(module, expr, func_ctx),
)?;
}
Expression::Override(_) => unreachable!(),
Expression::Override(handle) => {
write!(self.out, "{}", self.names[&NameKey::Override(handle)])?;
}
Expression::FunctionArgument(pos) => {
let name_key = func_ctx.argument_key(pos);
let name = &self.names[&name_key];
Expand Down Expand Up @@ -1770,6 +1779,38 @@ impl<W: Write> Writer<W> {
Ok(())
}

/// Helper method used to write overrides
///
/// # Notes
/// Ends in a newline
fn write_override(
&mut self,
module: &Module,
handle: Handle<crate::Override>,
) -> BackendResult {
let override_ = &module.overrides[handle];
let name = &self.names[&NameKey::Override(handle)];

// Write @id attribute if present
if let Some(id) = override_.id {
write!(self.out, "@id({id}) ")?;
}

// Write override declaration
write!(self.out, "override {name}: ")?;
self.write_type(module, override_.ty)?;

// Write initializer if present
if let Some(init) = override_.init {
write!(self.out, " = ")?;
self.write_const_expression(module, init, &module.global_expressions)?;
}

writeln!(self.out, ";")?;

Ok(())
}

// See https://github.com/rust-lang/rust-clippy/issues/4979.
#[allow(clippy::missing_const_for_fn)]
pub fn finish(self) -> W {
Expand All @@ -1795,8 +1836,12 @@ impl TypeContext for WriterTypeContext<'_> {
unreachable!("the WGSL back end should always provide type handles");
}

fn write_override<W: Write>(&self, _: Handle<crate::Override>, _: &mut W) -> core::fmt::Result {
unreachable!("overrides should be validated out");
fn write_override<W: Write>(
&self,
handle: Handle<crate::Override>,
out: &mut W,
) -> core::fmt::Result {
write!(out, "{}", self.names[&NameKey::Override(handle)])
}

fn write_non_wgsl_inner<W: Write>(&self, _: &TypeInner, _: &mut W) -> core::fmt::Result {
Expand Down
3 changes: 2 additions & 1 deletion naga/src/front/glsl/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use core::fmt;
use super::{builtins::MacroCall, Span};
use crate::{
AddressSpace, BinaryOperator, Binding, Constant, Expression, Function, GlobalVariable, Handle,
Interpolation, Literal, Sampling, StorageAccess, Type, UnaryOperator,
Interpolation, Literal, Override, Sampling, StorageAccess, Type, UnaryOperator,
};

#[derive(Debug, Clone, Copy)]
pub enum GlobalLookupKind {
Variable(Handle<GlobalVariable>),
Constant(Handle<Constant>, Handle<Type>),
Override(Handle<Override>, Handle<Type>),
BlockSelect(Handle<GlobalVariable>, u32),
}

Expand Down
8 changes: 8 additions & 0 deletions naga/src/front/glsl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ impl<'a> Context<'a> {
Some((v, ty)),
)
}
GlobalLookupKind::Override(v, _ty) => {
let span = self.module.overrides.get_span(v);
(
self.add_expression(Expression::Override(v), span)?,
false,
None,
)
}
};

let var = VariableReference {
Expand Down
1 change: 1 addition & 0 deletions naga/src/front/glsl/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ impl DeclarationContext<'_, '_, '_> {
let expr = match global {
GlobalOrConstant::Global(handle) => Expression::GlobalVariable(handle),
GlobalOrConstant::Constant(handle) => Expression::Constant(handle),
GlobalOrConstant::Override(handle) => Expression::Override(handle),
};
Ok(self.ctx.add_expression(expr, meta)?)
}
Expand Down
1 change: 1 addition & 0 deletions naga/src/front/glsl/parser/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ impl ParsingContext<'_> {
kind: match global {
GlobalOrConstant::Global(handle) => GlobalLookupKind::BlockSelect(handle, i),
GlobalOrConstant::Constant(handle) => GlobalLookupKind::Constant(handle, ty),
GlobalOrConstant::Override(handle) => GlobalLookupKind::Override(handle, ty),
},
entry_arg: None,
mutable: true,
Expand Down
81 changes: 63 additions & 18 deletions naga/src/front/glsl/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use super::{
};
use crate::{
AddressSpace, Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, Interpolation,
LocalVariable, ResourceBinding, Scalar, ScalarKind, ShaderStage, SwizzleComponent, Type,
TypeInner, VectorSize,
LocalVariable, Override, ResourceBinding, Scalar, ScalarKind, ShaderStage, SwizzleComponent,
Type, TypeInner, VectorSize,
};

pub struct VarDeclaration<'a, 'key> {
Expand All @@ -35,6 +35,7 @@ struct BuiltInData {
pub enum GlobalOrConstant {
Global(Handle<GlobalVariable>),
Constant(Handle<Constant>),
Override(Handle<Override>),
}

impl Frontend {
Expand Down Expand Up @@ -481,25 +482,69 @@ impl Frontend {
(GlobalOrConstant::Global(handle), lookup)
}
StorageQualifier::Const => {
let init = init.ok_or_else(|| Error {
kind: ErrorKind::SemanticError("const values must have an initializer".into()),
meta,
})?;
// Check if this is a specialization constant with constant_id
let constant_id = qualifiers.uint_layout_qualifier("constant_id", &mut self.errors);

if let Some(id) = constant_id {
// This is a specialization constant - convert to Override
let id: Option<u16> = match id.try_into() {
Ok(v) => Some(v),
Err(_) => {
self.errors.push(Error {
kind: ErrorKind::SemanticError(
format!(
"constant_id value {id} is too high (maximum is {})",
u16::MAX
)
.into(),
),
meta,
});
None
}
};

let constant = Constant {
name: name.clone(),
ty,
init,
};
let handle = ctx.module.constants.append(constant, meta);
let override_handle = ctx.module.overrides.append(
Override {
name: name.clone(),
id,
ty,
init,
},
meta,
);

let lookup = GlobalLookup {
kind: GlobalLookupKind::Constant(handle, ty),
entry_arg: None,
mutable: false,
};
let lookup = GlobalLookup {
kind: GlobalLookupKind::Override(override_handle, ty),
entry_arg: None,
mutable: false,
};

(GlobalOrConstant::Override(override_handle), lookup)
} else {
// Regular constant
let init = init.ok_or_else(|| Error {
kind: ErrorKind::SemanticError(
"const values must have an initializer".into(),
),
meta,
})?;

(GlobalOrConstant::Constant(handle), lookup)
let constant = Constant {
name: name.clone(),
ty,
init,
};
let handle = ctx.module.constants.append(constant, meta);

let lookup = GlobalLookup {
kind: GlobalLookupKind::Constant(handle, ty),
entry_arg: None,
mutable: false,
};

(GlobalOrConstant::Constant(handle), lookup)
}
}
StorageQualifier::AddressSpace(mut space) => {
match space {
Expand Down
5 changes: 3 additions & 2 deletions naga/src/proc/constant_evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1189,8 +1189,9 @@ impl<'a> ConstantEvaluator<'a> {
Behavior::Wgsl(WgslRestrictions::Const(_)) => {
Err(ConstantEvaluatorError::OverrideExpr)
}
Behavior::Glsl(_) => {
unreachable!()
// GLSL specialization constants (constant_id) become Override expressions
Behavior::Glsl(GlslRestrictions::Const | GlslRestrictions::Runtime(_)) => {
Ok(self.append_expr(expr, span, ExpressionKind::Override))
}
},
ExpressionKind::Runtime => {
Expand Down
16 changes: 16 additions & 0 deletions naga/src/proc/namer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl ExternalTextureNameKey {
#[derive(Debug, Eq, Hash, PartialEq)]
pub enum NameKey {
Constant(Handle<crate::Constant>),
Override(Handle<crate::Override>),
GlobalVariable(Handle<crate::GlobalVariable>),
Type(Handle<crate::Type>),
StructMember(Handle<crate::Type>, u32),
Expand Down Expand Up @@ -374,6 +375,21 @@ impl Namer {
let name = self.call(label);
output.insert(NameKey::Constant(handle), name);
}

for (handle, override_) in module.overrides.iter() {
let label = match override_.name {
Some(ref name) => name,
None => {
use core::fmt::Write;
// Try to be more descriptive about the override values
temp.clear();
write!(temp, "override_{}", output[&NameKey::Type(override_.ty)]).unwrap();
&temp
}
};
let name = self.call(label);
output.insert(NameKey::Override(handle), name);
}
}
}

Expand Down
21 changes: 21 additions & 0 deletions naga/tests/in/glsl/spec-constant.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#version 450

// Specialization constants with constant_id layout qualifier
layout(constant_id = 0) const bool SPEC_CONST_BOOL = true;
layout(constant_id = 1) const int SPEC_CONST_INT = 42;
layout(constant_id = 2) const uint SPEC_CONST_UINT = 10u;
layout(constant_id = 3) const float SPEC_CONST_FLOAT = 3.14;

layout(location = 0) out vec4 o_color;

void main() {
float result = 0.0;

if (SPEC_CONST_BOOL) {
result += float(SPEC_CONST_INT);
}

result += float(SPEC_CONST_UINT) * SPEC_CONST_FLOAT;

o_color = vec4(result, 0.0, 0.0, 1.0);
}
1 change: 1 addition & 0 deletions naga/tests/in/glsl/spec-constant.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
targets = "WGSL"
33 changes: 33 additions & 0 deletions naga/tests/out/wgsl/glsl-spec-constant.frag.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
struct FragmentOutput {
@location(0) o_color: vec4<f32>,
}

@id(0) override SPEC_CONST_BOOL: bool = true;
@id(1) override SPEC_CONST_INT: i32 = 42i;
@id(2) override SPEC_CONST_UINT: u32 = 10u;
@id(3) override SPEC_CONST_FLOAT: f32 = 3.14f;

var<private> o_color: vec4<f32>;

fn main_1() {
var result: f32 = 0f;

if SPEC_CONST_BOOL {
{
let _e7 = result;
result = (_e7 + f32(SPEC_CONST_INT));
}
}
let _e10 = result;
result = (_e10 + (f32(SPEC_CONST_UINT) * SPEC_CONST_FLOAT));
let _e14 = result;
o_color = vec4<f32>(_e14, 0f, 0f, 1f);
return;
}

@fragment
fn main() -> FragmentOutput {
main_1();
let _e1 = o_color;
return FragmentOutput(_e1);
}
Loading