summaryrefslogtreecommitdiffstats
path: root/third_party/rust/naga/src/back/glsl/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/naga/src/back/glsl/mod.rs')
-rw-r--r--third_party/rust/naga/src/back/glsl/mod.rs194
1 files changed, 134 insertions, 60 deletions
diff --git a/third_party/rust/naga/src/back/glsl/mod.rs b/third_party/rust/naga/src/back/glsl/mod.rs
index e346d43257..9bda594610 100644
--- a/third_party/rust/naga/src/back/glsl/mod.rs
+++ b/third_party/rust/naga/src/back/glsl/mod.rs
@@ -178,7 +178,7 @@ impl Version {
/// Note: `location=` for vertex inputs and fragment outputs is supported
/// unconditionally for GLES 300.
fn supports_explicit_locations(&self) -> bool {
- *self >= Version::Desktop(410) || *self >= Version::new_gles(310)
+ *self >= Version::Desktop(420) || *self >= Version::new_gles(310)
}
fn supports_early_depth_test(&self) -> bool {
@@ -646,16 +646,6 @@ impl<'a, W: Write> Writer<'a, W> {
// preprocessor not the processor ¯\_(ツ)_/¯
self.features.write(self.options, &mut self.out)?;
- // Write the additional extensions
- if self
- .options
- .writer_flags
- .contains(WriterFlags::TEXTURE_SHADOW_LOD)
- {
- // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shadow_lod.txt
- writeln!(self.out, "#extension GL_EXT_texture_shadow_lod : require")?;
- }
-
// glsl es requires a precision to be specified for floats and ints
// TODO: Should this be user configurable?
if es {
@@ -1300,7 +1290,14 @@ impl<'a, W: Write> Writer<'a, W> {
let inner = expr_info.ty.inner_with(&self.module.types);
- if let Expression::Math { fun, arg, arg1, .. } = *expr {
+ if let Expression::Math {
+ fun,
+ arg,
+ arg1,
+ arg2,
+ ..
+ } = *expr
+ {
match fun {
crate::MathFunction::Dot => {
// if the expression is a Dot product with integer arguments,
@@ -1315,6 +1312,14 @@ impl<'a, W: Write> Writer<'a, W> {
}
}
}
+ crate::MathFunction::ExtractBits => {
+ // Only argument 1 is re-used.
+ self.need_bake_expressions.insert(arg1.unwrap());
+ }
+ crate::MathFunction::InsertBits => {
+ // Only argument 2 is re-used.
+ self.need_bake_expressions.insert(arg2.unwrap());
+ }
crate::MathFunction::CountLeadingZeros => {
if let Some(crate::ScalarKind::Sint) = inner.scalar_kind() {
self.need_bake_expressions.insert(arg);
@@ -2451,6 +2456,9 @@ impl<'a, W: Write> Writer<'a, W> {
crate::Literal::I64(_) => {
return Err(Error::Custom("GLSL has no 64-bit integer type".into()));
}
+ crate::Literal::U64(_) => {
+ return Err(Error::Custom("GLSL has no 64-bit integer type".into()));
+ }
crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
return Err(Error::Custom(
"Abstract types should not appear in IR presented to backends".into(),
@@ -2620,51 +2628,49 @@ impl<'a, W: Write> Writer<'a, W> {
level,
depth_ref,
} => {
- let dim = match *ctx.resolve_type(image, &self.module.types) {
- TypeInner::Image { dim, .. } => dim,
+ let (dim, class, arrayed) = match *ctx.resolve_type(image, &self.module.types) {
+ TypeInner::Image {
+ dim,
+ class,
+ arrayed,
+ ..
+ } => (dim, class, arrayed),
_ => unreachable!(),
};
-
- if dim == crate::ImageDimension::Cube
- && array_index.is_some()
- && depth_ref.is_some()
- {
- match level {
- crate::SampleLevel::Zero
- | crate::SampleLevel::Exact(_)
- | crate::SampleLevel::Gradient { .. }
- | crate::SampleLevel::Bias(_) => {
- return Err(Error::Custom(String::from(
- "gsamplerCubeArrayShadow isn't supported in textureGrad, \
- textureLod or texture with bias",
- )))
- }
- crate::SampleLevel::Auto => {}
+ let mut err = None;
+ if dim == crate::ImageDimension::Cube {
+ if offset.is_some() {
+ err = Some("gsamplerCube[Array][Shadow] doesn't support texture sampling with offsets");
+ }
+ if arrayed
+ && matches!(class, crate::ImageClass::Depth { .. })
+ && matches!(level, crate::SampleLevel::Gradient { .. })
+ {
+ err = Some("samplerCubeArrayShadow don't support textureGrad");
}
}
+ if gather.is_some() && level != crate::SampleLevel::Zero {
+ err = Some("textureGather doesn't support LOD parameters");
+ }
+ if let Some(err) = err {
+ return Err(Error::Custom(String::from(err)));
+ }
- // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL.
- // To emulate this, we will have to use textureGrad with a constant gradient of 0.
- let workaround_lod_array_shadow_as_grad = (array_index.is_some()
- || dim == crate::ImageDimension::Cube)
- && depth_ref.is_some()
- && gather.is_none()
- && !self
- .options
- .writer_flags
- .contains(WriterFlags::TEXTURE_SHADOW_LOD);
-
- //Write the function to be used depending on the sample level
+ // `textureLod[Offset]` on `sampler2DArrayShadow` and `samplerCubeShadow` does not exist in GLSL,
+ // unless `GL_EXT_texture_shadow_lod` is present.
+ // But if the target LOD is zero, we can emulate that by using `textureGrad[Offset]` with a constant gradient of 0.
+ let workaround_lod_with_grad = ((dim == crate::ImageDimension::Cube && !arrayed)
+ || (dim == crate::ImageDimension::D2 && arrayed))
+ && level == crate::SampleLevel::Zero
+ && matches!(class, crate::ImageClass::Depth { .. })
+ && !self.features.contains(Features::TEXTURE_SHADOW_LOD);
+
+ // Write the function to be used depending on the sample level
let fun_name = match level {
crate::SampleLevel::Zero if gather.is_some() => "textureGather",
+ crate::SampleLevel::Zero if workaround_lod_with_grad => "textureGrad",
crate::SampleLevel::Auto | crate::SampleLevel::Bias(_) => "texture",
- crate::SampleLevel::Zero | crate::SampleLevel::Exact(_) => {
- if workaround_lod_array_shadow_as_grad {
- "textureGrad"
- } else {
- "textureLod"
- }
- }
+ crate::SampleLevel::Zero | crate::SampleLevel::Exact(_) => "textureLod",
crate::SampleLevel::Gradient { .. } => "textureGrad",
};
let offset_name = match offset {
@@ -2727,7 +2733,7 @@ impl<'a, W: Write> Writer<'a, W> {
crate::SampleLevel::Auto => (),
// Zero needs level set to 0
crate::SampleLevel::Zero => {
- if workaround_lod_array_shadow_as_grad {
+ if workaround_lod_with_grad {
let vec_dim = match dim {
crate::ImageDimension::Cube => 3,
_ => 2,
@@ -2739,13 +2745,8 @@ impl<'a, W: Write> Writer<'a, W> {
}
// Exact and bias require another argument
crate::SampleLevel::Exact(expr) => {
- if workaround_lod_array_shadow_as_grad {
- log::warn!("Unable to `textureLod` a shadow array, ignoring the LOD");
- write!(self.out, ", vec2(0,0), vec2(0,0)")?;
- } else {
- write!(self.out, ", ")?;
- self.write_expr(expr, ctx)?;
- }
+ write!(self.out, ", ")?;
+ self.write_expr(expr, ctx)?;
}
crate::SampleLevel::Bias(_) => {
// This needs to be done after the offset writing
@@ -3155,7 +3156,29 @@ impl<'a, W: Write> Writer<'a, W> {
Mf::Abs => "abs",
Mf::Min => "min",
Mf::Max => "max",
- Mf::Clamp => "clamp",
+ Mf::Clamp => {
+ let scalar_kind = ctx
+ .resolve_type(arg, &self.module.types)
+ .scalar_kind()
+ .unwrap();
+ match scalar_kind {
+ crate::ScalarKind::Float => "clamp",
+ // Clamp is undefined if min > max. In practice this means it can use a median-of-three
+ // instruction to determine the value. This is fine according to the WGSL spec for float
+ // clamp, but integer clamp _must_ use min-max. As such we write out min/max.
+ _ => {
+ write!(self.out, "min(max(")?;
+ self.write_expr(arg, ctx)?;
+ write!(self.out, ", ")?;
+ self.write_expr(arg1.unwrap(), ctx)?;
+ write!(self.out, "), ")?;
+ self.write_expr(arg2.unwrap(), ctx)?;
+ write!(self.out, ")")?;
+
+ return Ok(());
+ }
+ }
+ }
Mf::Saturate => {
write!(self.out, "clamp(")?;
@@ -3370,8 +3393,59 @@ impl<'a, W: Write> Writer<'a, W> {
}
Mf::CountOneBits => "bitCount",
Mf::ReverseBits => "bitfieldReverse",
- Mf::ExtractBits => "bitfieldExtract",
- Mf::InsertBits => "bitfieldInsert",
+ Mf::ExtractBits => {
+ // The behavior of ExtractBits is undefined when offset + count > bit_width. We need
+ // to first sanitize the offset and count first. If we don't do this, AMD and Intel chips
+ // will return out-of-spec values if the extracted range is not within the bit width.
+ //
+ // This encodes the exact formula specified by the wgsl spec, without temporary values:
+ // https://gpuweb.github.io/gpuweb/wgsl/#extractBits-unsigned-builtin
+ //
+ // w = sizeof(x) * 8
+ // o = min(offset, w)
+ // c = min(count, w - o)
+ //
+ // bitfieldExtract(x, o, c)
+ //
+ // extract_bits(e, min(offset, w), min(count, w - min(offset, w))))
+ let scalar_bits = ctx
+ .resolve_type(arg, &self.module.types)
+ .scalar_width()
+ .unwrap();
+
+ write!(self.out, "bitfieldExtract(")?;
+ self.write_expr(arg, ctx)?;
+ write!(self.out, ", int(min(")?;
+ self.write_expr(arg1.unwrap(), ctx)?;
+ write!(self.out, ", {scalar_bits}u)), int(min(",)?;
+ self.write_expr(arg2.unwrap(), ctx)?;
+ write!(self.out, ", {scalar_bits}u - min(")?;
+ self.write_expr(arg1.unwrap(), ctx)?;
+ write!(self.out, ", {scalar_bits}u))))")?;
+
+ return Ok(());
+ }
+ Mf::InsertBits => {
+ // InsertBits has the same considerations as ExtractBits above
+ let scalar_bits = ctx
+ .resolve_type(arg, &self.module.types)
+ .scalar_width()
+ .unwrap();
+
+ write!(self.out, "bitfieldInsert(")?;
+ self.write_expr(arg, ctx)?;
+ write!(self.out, ", ")?;
+ self.write_expr(arg1.unwrap(), ctx)?;
+ write!(self.out, ", int(min(")?;
+ self.write_expr(arg2.unwrap(), ctx)?;
+ write!(self.out, ", {scalar_bits}u)), int(min(",)?;
+ self.write_expr(arg3.unwrap(), ctx)?;
+ write!(self.out, ", {scalar_bits}u - min(")?;
+ self.write_expr(arg2.unwrap(), ctx)?;
+ write!(self.out, ", {scalar_bits}u))))")?;
+
+ return Ok(());
+ }
Mf::FindLsb => "findLSB",
Mf::FindMsb => "findMSB",
// data packing