Skip to content

Commit ef924a2

Browse files
committed
Add GLSL constant_id layout qualifier support and WGSL backend override output
1 parent 75188a7 commit ef924a2

File tree

11 files changed

+199
-30
lines changed

11 files changed

+199
-30
lines changed

naga/src/back/wgsl/writer.rs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,6 @@ impl<W: Write> Writer<W> {
135135
}
136136

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

146140
// Write all `enable` declarations
@@ -172,6 +166,16 @@ impl<W: Write> Writer<W> {
172166
}
173167
}
174168

169+
// Write all overrides
170+
let mut overrides = module.overrides.iter().peekable();
171+
while let Some((handle, _)) = overrides.next() {
172+
self.write_override(module, handle)?;
173+
// Add extra newline for readability on last iteration
174+
if overrides.peek().is_none() {
175+
writeln!(self.out)?;
176+
}
177+
}
178+
175179
// Write all globals
176180
for (ty, global) in module.global_variables.iter() {
177181
self.write_global(module, global, ty)?;
@@ -1205,6 +1209,9 @@ impl<W: Write> Writer<W> {
12051209
write_expression(self, value)?;
12061210
write!(self.out, ")")?;
12071211
}
1212+
Expression::Override(handle) => {
1213+
write!(self.out, "{}", self.names[&NameKey::Override(handle)])?;
1214+
}
12081215
_ => unreachable!(),
12091216
}
12101217

@@ -1255,7 +1262,9 @@ impl<W: Write> Writer<W> {
12551262
|writer, expr| writer.write_expr(module, expr, func_ctx),
12561263
)?;
12571264
}
1258-
Expression::Override(_) => unreachable!(),
1265+
Expression::Override(handle) => {
1266+
write!(self.out, "{}", self.names[&NameKey::Override(handle)])?;
1267+
}
12591268
Expression::FunctionArgument(pos) => {
12601269
let name_key = func_ctx.argument_key(pos);
12611270
let name = &self.names[&name_key];
@@ -1770,6 +1779,38 @@ impl<W: Write> Writer<W> {
17701779
Ok(())
17711780
}
17721781

1782+
/// Helper method used to write overrides
1783+
///
1784+
/// # Notes
1785+
/// Ends in a newline
1786+
fn write_override(
1787+
&mut self,
1788+
module: &Module,
1789+
handle: Handle<crate::Override>,
1790+
) -> BackendResult {
1791+
let override_ = &module.overrides[handle];
1792+
let name = &self.names[&NameKey::Override(handle)];
1793+
1794+
// Write @id attribute if present
1795+
if let Some(id) = override_.id {
1796+
write!(self.out, "@id({id}) ")?;
1797+
}
1798+
1799+
// Write override declaration
1800+
write!(self.out, "override {name}: ")?;
1801+
self.write_type(module, override_.ty)?;
1802+
1803+
// Write initializer if present
1804+
if let Some(init) = override_.init {
1805+
write!(self.out, " = ")?;
1806+
self.write_const_expression(module, init, &module.global_expressions)?;
1807+
}
1808+
1809+
writeln!(self.out, ";")?;
1810+
1811+
Ok(())
1812+
}
1813+
17731814
// See https://github.com/rust-lang/rust-clippy/issues/4979.
17741815
#[allow(clippy::missing_const_for_fn)]
17751816
pub fn finish(self) -> W {
@@ -1795,8 +1836,12 @@ impl TypeContext for WriterTypeContext<'_> {
17951836
unreachable!("the WGSL back end should always provide type handles");
17961837
}
17971838

1798-
fn write_override<W: Write>(&self, _: Handle<crate::Override>, _: &mut W) -> core::fmt::Result {
1799-
unreachable!("overrides should be validated out");
1839+
fn write_override<W: Write>(
1840+
&self,
1841+
handle: Handle<crate::Override>,
1842+
out: &mut W,
1843+
) -> core::fmt::Result {
1844+
write!(out, "{}", self.names[&NameKey::Override(handle)])
18001845
}
18011846

18021847
fn write_non_wgsl_inner<W: Write>(&self, _: &TypeInner, _: &mut W) -> core::fmt::Result {

naga/src/front/glsl/ast.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use core::fmt;
44
use super::{builtins::MacroCall, Span};
55
use crate::{
66
AddressSpace, BinaryOperator, Binding, Constant, Expression, Function, GlobalVariable, Handle,
7-
Interpolation, Literal, Sampling, StorageAccess, Type, UnaryOperator,
7+
Interpolation, Literal, Override, Sampling, StorageAccess, Type, UnaryOperator,
88
};
99

1010
#[derive(Debug, Clone, Copy)]
1111
pub enum GlobalLookupKind {
1212
Variable(Handle<GlobalVariable>),
1313
Constant(Handle<Constant>, Handle<Type>),
14+
Override(Handle<Override>, Handle<Type>),
1415
BlockSelect(Handle<GlobalVariable>, u32),
1516
}
1617

naga/src/front/glsl/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ impl<'a> Context<'a> {
211211
Some((v, ty)),
212212
)
213213
}
214+
GlobalLookupKind::Override(v, _ty) => {
215+
let span = self.module.overrides.get_span(v);
216+
(
217+
self.add_expression(Expression::Override(v), span)?,
218+
false,
219+
None,
220+
)
221+
}
214222
};
215223

216224
let var = VariableReference {

naga/src/front/glsl/parser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ impl DeclarationContext<'_, '_, '_> {
436436
let expr = match global {
437437
GlobalOrConstant::Global(handle) => Expression::GlobalVariable(handle),
438438
GlobalOrConstant::Constant(handle) => Expression::Constant(handle),
439+
GlobalOrConstant::Override(handle) => Expression::Override(handle),
439440
};
440441
Ok(self.ctx.add_expression(expr, meta)?)
441442
}

naga/src/front/glsl/parser/declarations.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ impl ParsingContext<'_> {
608608
kind: match global {
609609
GlobalOrConstant::Global(handle) => GlobalLookupKind::BlockSelect(handle, i),
610610
GlobalOrConstant::Constant(handle) => GlobalLookupKind::Constant(handle, ty),
611+
GlobalOrConstant::Override(handle) => GlobalLookupKind::Override(handle, ty),
611612
},
612613
entry_arg: None,
613614
mutable: true,

naga/src/front/glsl/variables.rs

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use super::{
88
};
99
use crate::{
1010
AddressSpace, Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, Interpolation,
11-
LocalVariable, ResourceBinding, Scalar, ScalarKind, ShaderStage, SwizzleComponent, Type,
12-
TypeInner, VectorSize,
11+
LocalVariable, Override, ResourceBinding, Scalar, ScalarKind, ShaderStage, SwizzleComponent,
12+
Type, TypeInner, VectorSize,
1313
};
1414

1515
pub struct VarDeclaration<'a, 'key> {
@@ -35,6 +35,7 @@ struct BuiltInData {
3535
pub enum GlobalOrConstant {
3636
Global(Handle<GlobalVariable>),
3737
Constant(Handle<Constant>),
38+
Override(Handle<Override>),
3839
}
3940

4041
impl Frontend {
@@ -481,25 +482,65 @@ impl Frontend {
481482
(GlobalOrConstant::Global(handle), lookup)
482483
}
483484
StorageQualifier::Const => {
484-
let init = init.ok_or_else(|| Error {
485-
kind: ErrorKind::SemanticError("const values must have an initializer".into()),
486-
meta,
487-
})?;
485+
// Check if this is a specialization constant with constant_id
486+
let constant_id = qualifiers.uint_layout_qualifier("constant_id", &mut self.errors);
487+
488+
if let Some(id) = constant_id {
489+
// This is a specialization constant - convert to Override
490+
let id: Option<u16> = match id.try_into() {
491+
Ok(v) => Some(v),
492+
Err(_) => {
493+
self.errors.push(Error {
494+
kind: ErrorKind::SemanticError(
495+
format!("constant_id value {id} is too high (maximum is {})", u16::MAX).into(),
496+
),
497+
meta,
498+
});
499+
None
500+
}
501+
};
488502

489-
let constant = Constant {
490-
name: name.clone(),
491-
ty,
492-
init,
493-
};
494-
let handle = ctx.module.constants.append(constant, meta);
503+
let override_handle = ctx.module.overrides.append(
504+
Override {
505+
name: name.clone(),
506+
id,
507+
ty,
508+
init,
509+
},
510+
meta,
511+
);
495512

496-
let lookup = GlobalLookup {
497-
kind: GlobalLookupKind::Constant(handle, ty),
498-
entry_arg: None,
499-
mutable: false,
500-
};
513+
let lookup = GlobalLookup {
514+
kind: GlobalLookupKind::Override(override_handle, ty),
515+
entry_arg: None,
516+
mutable: false,
517+
};
518+
519+
(GlobalOrConstant::Override(override_handle), lookup)
520+
} else {
521+
// Regular constant
522+
let init = init.ok_or_else(|| Error {
523+
kind: ErrorKind::SemanticError(
524+
"const values must have an initializer".into(),
525+
),
526+
meta,
527+
})?;
501528

502-
(GlobalOrConstant::Constant(handle), lookup)
529+
let constant = Constant {
530+
name: name.clone(),
531+
ty,
532+
init,
533+
};
534+
let handle = ctx.module.constants.append(constant, meta);
535+
536+
let lookup = GlobalLookup {
537+
kind: GlobalLookupKind::Constant(handle, ty),
538+
entry_arg: None,
539+
mutable: false,
540+
};
541+
542+
(GlobalOrConstant::Constant(handle), lookup)
543+
}
503544
}
504545
StorageQualifier::AddressSpace(mut space) => {
505546
match space {

naga/src/proc/constant_evaluator.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,8 +1189,9 @@ impl<'a> ConstantEvaluator<'a> {
11891189
Behavior::Wgsl(WgslRestrictions::Const(_)) => {
11901190
Err(ConstantEvaluatorError::OverrideExpr)
11911191
}
1192-
Behavior::Glsl(_) => {
1193-
unreachable!()
1192+
// GLSL specialization constants (constant_id) become Override expressions
1193+
Behavior::Glsl(GlslRestrictions::Const | GlslRestrictions::Runtime(_)) => {
1194+
Ok(self.append_expr(expr, span, ExpressionKind::Override))
11941195
}
11951196
},
11961197
ExpressionKind::Runtime => {

naga/src/proc/namer.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ impl ExternalTextureNameKey {
5151
#[derive(Debug, Eq, Hash, PartialEq)]
5252
pub enum NameKey {
5353
Constant(Handle<crate::Constant>),
54+
Override(Handle<crate::Override>),
5455
GlobalVariable(Handle<crate::GlobalVariable>),
5556
Type(Handle<crate::Type>),
5657
StructMember(Handle<crate::Type>, u32),
@@ -374,6 +375,21 @@ impl Namer {
374375
let name = self.call(label);
375376
output.insert(NameKey::Constant(handle), name);
376377
}
378+
379+
for (handle, override_) in module.overrides.iter() {
380+
let label = match override_.name {
381+
Some(ref name) => name,
382+
None => {
383+
use core::fmt::Write;
384+
// Try to be more descriptive about the override values
385+
temp.clear();
386+
write!(temp, "override_{}", output[&NameKey::Type(override_.ty)]).unwrap();
387+
&temp
388+
}
389+
};
390+
let name = self.call(label);
391+
output.insert(NameKey::Override(handle), name);
392+
}
377393
}
378394
}
379395

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#version 450
2+
3+
// Specialization constants with constant_id layout qualifier
4+
layout(constant_id = 0) const bool SPEC_CONST_BOOL = true;
5+
layout(constant_id = 1) const int SPEC_CONST_INT = 42;
6+
layout(constant_id = 2) const uint SPEC_CONST_UINT = 10u;
7+
layout(constant_id = 3) const float SPEC_CONST_FLOAT = 3.14;
8+
9+
layout(location = 0) out vec4 o_color;
10+
11+
void main() {
12+
float result = 0.0;
13+
14+
if (SPEC_CONST_BOOL) {
15+
result += float(SPEC_CONST_INT);
16+
}
17+
18+
result += float(SPEC_CONST_UINT) * SPEC_CONST_FLOAT;
19+
20+
o_color = vec4(result, 0.0, 0.0, 1.0);
21+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
targets = "WGSL"

0 commit comments

Comments
 (0)