summaryrefslogtreecommitdiffstats
path: root/third_party/rust/naga/src/back/glsl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /third_party/rust/naga/src/back/glsl
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/naga/src/back/glsl')
-rw-r--r--third_party/rust/naga/src/back/glsl/features.rs53
-rw-r--r--third_party/rust/naga/src/back/glsl/mod.rs194
2 files changed, 185 insertions, 62 deletions
diff --git a/third_party/rust/naga/src/back/glsl/features.rs b/third_party/rust/naga/src/back/glsl/features.rs
index e7de05f695..99c128c6d9 100644
--- a/third_party/rust/naga/src/back/glsl/features.rs
+++ b/third_party/rust/naga/src/back/glsl/features.rs
@@ -1,8 +1,8 @@
use super::{BackendResult, Error, Version, Writer};
use crate::{
back::glsl::{Options, WriterFlags},
- AddressSpace, Binding, Expression, Handle, ImageClass, ImageDimension, Interpolation, Sampling,
- Scalar, ScalarKind, ShaderStage, StorageFormat, Type, TypeInner,
+ AddressSpace, Binding, Expression, Handle, ImageClass, ImageDimension, Interpolation,
+ SampleLevel, Sampling, Scalar, ScalarKind, ShaderStage, StorageFormat, Type, TypeInner,
};
use std::fmt::Write;
@@ -48,6 +48,8 @@ bitflags::bitflags! {
///
/// We can always support this, either through the language or a polyfill
const INSTANCE_INDEX = 1 << 22;
+ /// Sample specific LODs of cube / array shadow textures
+ const TEXTURE_SHADOW_LOD = 1 << 23;
}
}
@@ -125,6 +127,7 @@ impl FeaturesManager {
check_feature!(TEXTURE_SAMPLES, 150);
check_feature!(TEXTURE_LEVELS, 130);
check_feature!(IMAGE_SIZE, 430, 310);
+ check_feature!(TEXTURE_SHADOW_LOD, 200, 300);
// Return an error if there are missing features
if missing.is_empty() {
@@ -251,6 +254,11 @@ impl FeaturesManager {
}
}
+ if self.0.contains(Features::TEXTURE_SHADOW_LOD) {
+ // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_shadow_lod.txt
+ writeln!(out, "#extension GL_EXT_texture_shadow_lod : require")?;
+ }
+
Ok(())
}
}
@@ -469,6 +477,47 @@ impl<'a, W> Writer<'a, W> {
}
}
}
+ Expression::ImageSample { image, level, offset, .. } => {
+ if let TypeInner::Image {
+ dim,
+ arrayed,
+ class: ImageClass::Depth { .. },
+ } = *info[image].ty.inner_with(&module.types) {
+ let lod = matches!(level, SampleLevel::Zero | SampleLevel::Exact(_));
+ let bias = matches!(level, SampleLevel::Bias(_));
+ let auto = matches!(level, SampleLevel::Auto);
+ let cube = dim == ImageDimension::Cube;
+ let array2d = dim == ImageDimension::D2 && arrayed;
+ let gles = self.options.version.is_es();
+
+ // We have a workaround of using `textureGrad` instead of `textureLod` if the LOD is zero,
+ // so we don't *need* this extension for those cases.
+ // But if we're explicitly allowed to use the extension (`WriterFlags::TEXTURE_SHADOW_LOD`),
+ // we always use it instead of the workaround.
+ let grad_workaround_applicable = (array2d || (cube && !arrayed)) && level == SampleLevel::Zero;
+ let prefer_grad_workaround = grad_workaround_applicable && !self.options.writer_flags.contains(WriterFlags::TEXTURE_SHADOW_LOD);
+
+ let mut ext_used = false;
+
+ // float texture(sampler2DArrayShadow sampler, vec4 P [, float bias])
+ // float texture(samplerCubeArrayShadow sampler, vec4 P, float compare [, float bias])
+ ext_used |= (array2d || cube && arrayed) && bias;
+
+ // The non `bias` version of this was standardized in GL 4.3, but never in GLES.
+ // float textureOffset(sampler2DArrayShadow sampler, vec4 P, ivec2 offset [, float bias])
+ ext_used |= array2d && (bias || (gles && auto)) && offset.is_some();
+
+ // float textureLod(sampler2DArrayShadow sampler, vec4 P, float lod)
+ // float textureLodOffset(sampler2DArrayShadow sampler, vec4 P, float lod, ivec2 offset)
+ // float textureLod(samplerCubeShadow sampler, vec4 P, float lod)
+ // float textureLod(samplerCubeArrayShadow sampler, vec4 P, float compare, float lod)
+ ext_used |= (cube || array2d) && lod && !prefer_grad_workaround;
+
+ if ext_used {
+ features.request(Features::TEXTURE_SHADOW_LOD);
+ }
+ }
+ }
_ => {}
}
}
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