[naga] Introduce Baked newtype for writing baked expression names.

Introduce a newtype `naga:🔙:Baked` that wraps a
`Handle<Expression>` and formats with `std::fmt::Display` as a baked
expression identifier. Use this in all backends for generating baked
identifiers.

Delete `BAKE_PREFIX`, as it's no longer used outside of `Baked`'s
`Display` implementation.

This is a step towards making `Handle::index` less prominent in the
code base.
This commit is contained in:
Jim Blandy 2024-06-19 12:38:50 -07:00 committed by Teodor Tanasoaia
parent 1e784c9c0a
commit 2a3c35383a
6 changed files with 57 additions and 46 deletions

View File

@ -112,6 +112,16 @@ impl<T> Handle<T> {
const unsafe fn from_usize_unchecked(index: usize) -> Self {
Handle::new(Index::new_unchecked((index + 1) as u32))
}
/// Write this handle's index to `formatter`, preceded by `prefix`.
pub fn write_prefixed(
&self,
formatter: &mut std::fmt::Formatter,
prefix: &'static str,
) -> std::fmt::Result {
formatter.write_str(prefix)?;
<usize as std::fmt::Display>::fmt(&self.index(), formatter)
}
}
/// A strongly typed range of handles.

View File

@ -46,7 +46,7 @@ to output a [`Module`](crate::Module) into glsl
pub use features::Features;
use crate::{
back,
back::{self, Baked},
proc::{self, NameKey},
valid, Handle, ShaderStage, TypeInner,
};
@ -1982,7 +1982,7 @@ impl<'a, W: Write> Writer<'a, W> {
// Also, we use sanitized names! It defense backend from generating variable with name from reserved keywords.
Some(self.namer.call(name))
} else if self.need_bake_expressions.contains(&handle) {
Some(format!("{}{}", back::BAKE_PREFIX, handle.index()))
Some(Baked(handle).to_string())
} else {
None
};
@ -2310,7 +2310,7 @@ impl<'a, W: Write> Writer<'a, W> {
// This is done in `Emit` by never emitting a variable name for pointer variables
self.write_barrier(crate::Barrier::WORK_GROUP, level)?;
let result_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let result_name = Baked(result).to_string();
write!(self.out, "{level}")?;
// Expressions cannot have side effects, so just writing the expression here is fine.
self.write_named_expr(pointer, result_name, result, ctx)?;
@ -2335,7 +2335,7 @@ impl<'a, W: Write> Writer<'a, W> {
} => {
write!(self.out, "{level}")?;
if let Some(expr) = result {
let name = format!("{}{}", back::BAKE_PREFIX, expr.index());
let name = Baked(expr).to_string();
let result = self.module.functions[function].result.as_ref().unwrap();
self.write_type(result.ty)?;
write!(self.out, " {name}")?;
@ -2369,7 +2369,7 @@ impl<'a, W: Write> Writer<'a, W> {
} => {
write!(self.out, "{level}")?;
if let Some(result) = result {
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
let res_ty = ctx.resolve_type(result, &self.module.types);
self.write_value_type(res_ty)?;
write!(self.out, " {res_name} = ")?;
@ -2399,7 +2399,7 @@ impl<'a, W: Write> Writer<'a, W> {
Statement::RayQuery { .. } => unreachable!(),
Statement::SubgroupBallot { result, predicate } => {
write!(self.out, "{level}")?;
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
let res_ty = ctx.info[result].ty.inner_with(&self.module.types);
self.write_value_type(res_ty)?;
write!(self.out, " {res_name} = ")?;
@ -2419,7 +2419,7 @@ impl<'a, W: Write> Writer<'a, W> {
result,
} => {
write!(self.out, "{level}")?;
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
let res_ty = ctx.info[result].ty.inner_with(&self.module.types);
self.write_value_type(res_ty)?;
write!(self.out, " {res_name} = ")?;
@ -2476,7 +2476,7 @@ impl<'a, W: Write> Writer<'a, W> {
result,
} => {
write!(self.out, "{level}")?;
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
let res_ty = ctx.info[result].ty.inner_with(&self.module.types);
self.write_value_type(res_ty)?;
write!(self.out, " {res_name} = ")?;
@ -3865,9 +3865,8 @@ impl<'a, W: Write> Writer<'a, W> {
// Define our local and start a call to `clamp`
write!(
self.out,
"int {}{}{} = clamp(",
back::BAKE_PREFIX,
expr.index(),
"int {}{} = clamp(",
Baked(expr),
CLAMPED_LOD_SUFFIX
)?;
// Write the lod that will be clamped
@ -4205,13 +4204,7 @@ impl<'a, W: Write> Writer<'a, W> {
// `textureSize` call, but this needs to be the clamped lod, this should
// have been generated earlier and put in a local.
if class.is_mipmapped() {
write!(
self.out,
", {}{}{}",
back::BAKE_PREFIX,
handle.index(),
CLAMPED_LOD_SUFFIX
)?;
write!(self.out, ", {}{}", Baked(handle), CLAMPED_LOD_SUFFIX)?;
}
// Close the `textureSize` call
write!(self.out, ")")?;
@ -4229,13 +4222,7 @@ impl<'a, W: Write> Writer<'a, W> {
// Add the clamped lod (if present) as the second argument to the
// image load function.
if level.is_some() {
write!(
self.out,
", {}{}{}",
back::BAKE_PREFIX,
handle.index(),
CLAMPED_LOD_SUFFIX
)?;
write!(self.out, ", {}{}", Baked(handle), CLAMPED_LOD_SUFFIX)?;
}
// If a sample argument is needed we need to clamp it between 0 and

View File

@ -7,7 +7,7 @@ use super::{
BackendResult, Error, Options,
};
use crate::{
back,
back::{self, Baked},
proc::{self, NameKey},
valid, Handle, Module, ScalarKind, ShaderStage, TypeInner,
};
@ -1891,7 +1891,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, "{level}")?;
if let Some(expr) = result {
write!(self.out, "const ")?;
let name = format!("{}{}", back::BAKE_PREFIX, expr.index());
let name = Baked(expr).to_string();
let expr_ty = &func_ctx.info[expr].ty;
match *expr_ty {
proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
@ -1922,7 +1922,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
let res_name = match result {
None => None,
Some(result) => {
let name = format!("{}{}", back::BAKE_PREFIX, result.index());
let name = Baked(result).to_string();
match func_ctx.info[result].ty {
proc::TypeResolution::Handle(handle) => {
self.write_type(module, handle)?
@ -2099,7 +2099,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
Statement::RayQuery { .. } => unreachable!(),
Statement::SubgroupBallot { result, predicate } => {
write!(self.out, "{level}")?;
let name = format!("{}{}", back::BAKE_PREFIX, result.index());
let name = Baked(result).to_string();
write!(self.out, "const uint4 {name} = ")?;
self.named_expressions.insert(result, name);
@ -2118,7 +2118,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
} => {
write!(self.out, "{level}")?;
write!(self.out, "const ")?;
let name = format!("{}{}", back::BAKE_PREFIX, result.index());
let name = Baked(result).to_string();
match func_ctx.info[result].ty {
proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
proc::TypeResolution::Value(ref value) => {
@ -2182,7 +2182,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
} => {
write!(self.out, "{level}")?;
write!(self.out, "const ")?;
let name = format!("{}{}", back::BAKE_PREFIX, result.index());
let name = Baked(result).to_string();
match func_ctx.info[result].ty {
proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
proc::TypeResolution::Value(ref value) => {

View File

@ -28,12 +28,26 @@ pub mod pipeline_constants;
pub const COMPONENTS: &[char] = &['x', 'y', 'z', 'w'];
/// Indent for backends.
pub const INDENT: &str = " ";
/// Prefix used for baking.
pub const BAKE_PREFIX: &str = "_e";
/// Expressions that need baking.
pub type NeedBakeExpressions = crate::FastHashSet<crate::Handle<crate::Expression>>;
/// A type for displaying expression handles as baking identifiers.
///
/// Given an [`Expression`] [`Handle`] `h`, `Baked(h)` implements
/// [`std::fmt::Display`], showing the handle's index prefixed by
/// [`BAKE_PREFIX`].
///
/// [`Expression`]: crate::Expression
/// [`Handle`]: crate::Handle
struct Baked(crate::Handle<crate::Expression>);
impl std::fmt::Display for Baked {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.write_prefixed(f, "_e")
}
}
/// Specifies the values of pipeline-overridable constants in the shader module.
///
/// If an `@id` attribute was specified on the declaration,

View File

@ -1,7 +1,7 @@
use super::{sampler as sm, Error, LocationMode, Options, PipelineOptions, TranslationInfo};
use crate::{
arena::Handle,
back,
back::{self, Baked},
proc::index,
proc::{self, NameKey, TypeResolution},
valid, FastHashMap, FastHashSet,
@ -2854,7 +2854,7 @@ impl<W: Write> Writer<W> {
};
if bake {
Some(format!("{}{}", back::BAKE_PREFIX, handle.index()))
Some(Baked(handle).to_string())
} else {
None
}
@ -3009,7 +3009,7 @@ impl<W: Write> Writer<W> {
} => {
write!(self.out, "{level}")?;
if let Some(expr) = result {
let name = format!("{}{}", back::BAKE_PREFIX, expr.index());
let name = Baked(expr).to_string();
self.start_baking_expression(expr, &context.expression, &name)?;
self.named_expressions.insert(expr, name);
}
@ -3064,7 +3064,7 @@ impl<W: Write> Writer<W> {
// operating on a 64-bit value, `result` is `None`.
write!(self.out, "{level}")?;
let fun_str = if let Some(result) = result {
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
self.start_baking_expression(result, &context.expression, &res_name)?;
self.named_expressions.insert(result, res_name);
fun.to_msl()?
@ -3170,7 +3170,7 @@ impl<W: Write> Writer<W> {
}
crate::RayQueryFunction::Proceed { result } => {
write!(self.out, "{level}")?;
let name = format!("{}{}", back::BAKE_PREFIX, result.index());
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)?;

View File

@ -1,6 +1,6 @@
use super::Error;
use crate::{
back,
back::{self, Baked},
proc::{self, NameKey},
valid, Handle, Module, ShaderStage, TypeInner,
};
@ -641,7 +641,7 @@ impl<W: Write> Writer<W> {
_ => false,
};
if min_ref_count <= info.ref_count || required_baking_expr {
Some(format!("{}{}", back::BAKE_PREFIX, handle.index()))
Some(Baked(handle).to_string())
} else {
None
}
@ -733,7 +733,7 @@ impl<W: Write> Writer<W> {
} => {
write!(self.out, "{level}")?;
if let Some(expr) = result {
let name = format!("{}{}", back::BAKE_PREFIX, expr.index());
let name = Baked(expr).to_string();
self.start_named_expr(module, expr, func_ctx, &name)?;
self.named_expressions.insert(expr, name);
}
@ -755,7 +755,7 @@ impl<W: Write> Writer<W> {
} => {
write!(self.out, "{level}")?;
if let Some(result) = result {
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
self.start_named_expr(module, result, func_ctx, &res_name)?;
self.named_expressions.insert(result, res_name);
}
@ -774,7 +774,7 @@ impl<W: Write> Writer<W> {
Statement::WorkGroupUniformLoad { pointer, result } => {
write!(self.out, "{level}")?;
// TODO: Obey named expressions here.
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
self.start_named_expr(module, result, func_ctx, &res_name)?;
self.named_expressions.insert(result, res_name);
write!(self.out, "workgroupUniformLoad(")?;
@ -934,7 +934,7 @@ impl<W: Write> Writer<W> {
Statement::RayQuery { .. } => unreachable!(),
Statement::SubgroupBallot { result, predicate } => {
write!(self.out, "{level}")?;
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
self.start_named_expr(module, result, func_ctx, &res_name)?;
self.named_expressions.insert(result, res_name);
@ -951,7 +951,7 @@ impl<W: Write> Writer<W> {
result,
} => {
write!(self.out, "{level}")?;
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
self.start_named_expr(module, result, func_ctx, &res_name)?;
self.named_expressions.insert(result, res_name);
@ -1006,7 +1006,7 @@ impl<W: Write> Writer<W> {
result,
} => {
write!(self.out, "{level}")?;
let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
let res_name = Baked(result).to_string();
self.start_named_expr(module, result, func_ctx, &res_name)?;
self.named_expressions.insert(result, res_name);