diff --git a/src/back/dot/mod.rs b/src/back/dot/mod.rs index eed7c5bd99..dbeb1fa71c 100644 --- a/src/back/dot/mod.rs +++ b/src/back/dot/mod.rs @@ -452,6 +452,7 @@ fn write_function_expressions( offset: _, level, depth_ref, + clamp_to_edge: _, } => { edges.insert("image", image); edges.insert("sampler", sampler); @@ -460,9 +461,7 @@ fn write_function_expressions( edges.insert("array_index", expr); } match level { - crate::SampleLevel::Auto - | crate::SampleLevel::Zero - | crate::SampleLevel::Base => {} + crate::SampleLevel::Auto | crate::SampleLevel::Zero => {} crate::SampleLevel::Exact(expr) => { edges.insert("level", expr); } diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 267d484ea2..bfeef7d88c 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -1862,7 +1862,8 @@ impl<'a, W: Write> Writer<'a, W> { // If we are going to write a `textureSampleBaseClampToEdge` next, // precompute the half-texel before clamping the coordinates. if let crate::Expression::ImageSample { - level: crate::SampleLevel::Base, + level: crate::SampleLevel::Zero, + clamp_to_edge: true, image, .. } = ctx.expressions[handle] @@ -2485,6 +2486,7 @@ impl<'a, W: Write> Writer<'a, W> { offset, level, depth_ref, + clamp_to_edge, } => { let dim = match *ctx.info[image].ty.inner_with(&self.module.types) { TypeInner::Image { dim, .. } => dim, @@ -2506,11 +2508,6 @@ impl<'a, W: Write> Writer<'a, W> { ))) } crate::SampleLevel::Auto => {} - crate::SampleLevel::Base => { - unreachable!( - "textureSampleBaseClampToEdge should not have passed validation" - ) - } } } @@ -2537,7 +2534,6 @@ impl<'a, W: Write> Writer<'a, W> { } } crate::SampleLevel::Gradient { .. } => "textureGrad", - crate::SampleLevel::Base => "textureLod", }; let offset_name = match offset { Some(_) => "Offset", @@ -2570,7 +2566,7 @@ impl<'a, W: Write> Writer<'a, W> { let tex_1d_hack = dim == crate::ImageDimension::D1 && self.options.version.is_es(); let is_vec = tex_1d_hack || coord_dim != 1; - if level == crate::SampleLevel::Base { + if clamp_to_edge { // clamp the coordinates to [ half_texel, 1 - half_texel ] write!(self.out, "clamp(")?; self.write_expr(coordinate, ctx)?; @@ -2653,9 +2649,6 @@ impl<'a, W: Write> Writer<'a, W> { self.write_expr(y, ctx)?; } } - crate::SampleLevel::Base => { - write!(self.out, ", 0.0")?; - } } if let Some(constant) = offset { diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index aed1e4d53f..64980ce3f3 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -1346,7 +1346,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // If we are going to write a `textureSampleBaseClampToEdge` next, // precompute the half-texel before clamping the coordinates. if let crate::Expression::ImageSample { - level: crate::SampleLevel::Base, + level: crate::SampleLevel::Zero, + clamp_to_edge: true, image, .. } = func_ctx.expressions[handle] @@ -2394,6 +2395,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { offset, level, depth_ref, + clamp_to_edge, } => { use crate::SampleLevel as Sl; const COMPONENTS: [&str; 4] = ["", "Green", "Blue", "Alpha"]; @@ -2407,9 +2409,10 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { None => "", }; let level_str = match level { + Sl::Zero if clamp_to_edge => "Level", Sl::Zero if gather.is_none() => "LevelZero", Sl::Auto | Sl::Zero => "", - Sl::Exact(_) | Sl::Base => "Level", + Sl::Exact(_) => "Level", Sl::Bias(_) => "Bias", Sl::Gradient { .. } => "Grad", }; @@ -2418,7 +2421,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, ".{base_str}{cmp_str}{component_str}{level_str}(")?; self.write_expr(module, sampler, func_ctx)?; write!(self.out, ", ")?; - if level == Sl::Base { + if clamp_to_edge { // clamp the coordinates to [ half_texel, 1 - half_texel ] write!(self.out, "clamp(")?; self.write_expr(module, coordinate, func_ctx)?; @@ -2445,6 +2448,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } match level { + Sl::Zero if clamp_to_edge => { + write!(self.out, ", 0.0")?; + } Sl::Auto | Sl::Zero => {} Sl::Exact(expr) => { write!(self.out, ", ")?; @@ -2460,9 +2466,6 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, ", ")?; self.write_expr(module, y, func_ctx)?; } - Sl::Base => { - write!(self.out, ", 0.0")?; - } } if let Some(offset) = offset { diff --git a/src/back/msl/writer.rs b/src/back/msl/writer.rs index d41cc23f25..c5a81bb931 100644 --- a/src/back/msl/writer.rs +++ b/src/back/msl/writer.rs @@ -743,11 +743,15 @@ impl Writer { &mut self, image: Handle, level: crate::SampleLevel, + clamp_to_edge: bool, context: &ExpressionContext, ) -> BackendResult { let has_levels = context.image_needs_lod(image); match level { crate::SampleLevel::Auto => {} + crate::SampleLevel::Zero if clamp_to_edge => { + write!(self.out, ", {NAMESPACE}::level(0.0)")?; + } crate::SampleLevel::Zero => { //TODO: do we support Zero on `Sampled` image classes? } @@ -771,9 +775,6 @@ impl Writer { self.put_expression(y, context, true)?; write!(self.out, ")")?; } - crate::SampleLevel::Base => { - write!(self.out, ", {NAMESPACE}::level(0.0)")?; - } } Ok(()) } @@ -1467,6 +1468,7 @@ impl Writer { offset, level, depth_ref, + clamp_to_edge, } => { let main_op = match gather { Some(_) => "gather", @@ -1481,7 +1483,7 @@ impl Writer { self.put_expression(sampler, context, true)?; write!(self.out, ", ")?; - if level == crate::SampleLevel::Base { + if clamp_to_edge { // clamp the coordinates to [ half_texel, 1 - half_texel ] write!(self.out, "{NAMESPACE}::clamp(")?; self.put_expression(coordinate, context, true)?; @@ -1505,7 +1507,7 @@ impl Writer { self.put_expression(dref, context, true)?; } - self.put_image_sample_level(image, level, context)?; + self.put_image_sample_level(image, level, clamp_to_edge, context)?; if let Some(offset) = offset { write!(self.out, ", ")?; @@ -2671,7 +2673,8 @@ impl Writer { // If we are going to write a `textureSampleBaseClampToEdge` next, // precompute the half-texel before clamping the coordinates. if let crate::Expression::ImageSample { - level: crate::SampleLevel::Base, + level: crate::SampleLevel::Zero, + clamp_to_edge: true, image, .. } = context.expression.function.expressions[handle] diff --git a/src/back/spv/block.rs b/src/back/spv/block.rs index 4dba7ea0ca..5d7ee9d1af 100644 --- a/src/back/spv/block.rs +++ b/src/back/spv/block.rs @@ -1312,6 +1312,7 @@ impl<'w> BlockContext<'w> { offset, level, depth_ref, + clamp_to_edge, } => self.write_image_sample( result_type_id, image, @@ -1322,6 +1323,7 @@ impl<'w> BlockContext<'w> { offset, level, depth_ref, + clamp_to_edge, block, )?, crate::Expression::Select { diff --git a/src/back/spv/image.rs b/src/back/spv/image.rs index 003b821835..9e9df15859 100644 --- a/src/back/spv/image.rs +++ b/src/back/spv/image.rs @@ -915,6 +915,7 @@ impl<'w> BlockContext<'w> { offset: Option>, level: crate::SampleLevel, depth_ref: Option>, + clamp_to_edge: bool, block: &mut Block, ) -> Result { use super::instructions::SampleLod; @@ -947,7 +948,7 @@ impl<'w> BlockContext<'w> { self.get_type_id(LookupType::Local(LocalType::SampledImage { image_type_id })); let sampler_id = self.get_handle_id(sampler); - let coordinates_id = if level == crate::SampleLevel::Base { + let coordinates_id = if clamp_to_edge { self.write_clamped_image_coordinates(image_id, coordinate, block)? } else { self.write_image_coordinates(coordinate, array_index, block)? @@ -983,7 +984,7 @@ impl<'w> BlockContext<'w> { } inst } - (crate::SampleLevel::Zero | crate::SampleLevel::Base, None) => { + (crate::SampleLevel::Zero, None) => { let mut inst = Instruction::image_sample( sample_result_type_id, id, diff --git a/src/back/wgsl/writer.rs b/src/back/wgsl/writer.rs index cb84309fd2..96f954fce1 100644 --- a/src/back/wgsl/writer.rs +++ b/src/back/wgsl/writer.rs @@ -1245,6 +1245,7 @@ impl Writer { offset, level, depth_ref, + clamp_to_edge, } => { use crate::SampleLevel as Sl; @@ -1254,10 +1255,10 @@ impl Writer { }; let suffix_level = match level { Sl::Auto => "", + Sl::Zero if clamp_to_edge => "BaseClampToEdge", Sl::Zero | Sl::Exact(_) => "Level", Sl::Bias(_) => "Bias", Sl::Gradient { .. } => "Grad", - Sl::Base => "BaseClampToEdge", }; write!(self.out, "textureSample{suffix_cmp}{suffix_level}(")?; @@ -1278,7 +1279,8 @@ impl Writer { } match level { - Sl::Auto | Sl::Base => {} + Sl::Auto => {} + Sl::Zero if clamp_to_edge => {} Sl::Zero => { // Level 0 is implied for depth comparison if depth_ref.is_none() { @@ -1318,6 +1320,7 @@ impl Writer { offset, level: _, depth_ref, + clamp_to_edge: _, } => { let suffix_cmp = match depth_ref { Some(_) => "Compare", diff --git a/src/compact/expressions.rs b/src/compact/expressions.rs index b008680a6e..7dc93a8121 100644 --- a/src/compact/expressions.rs +++ b/src/compact/expressions.rs @@ -86,6 +86,7 @@ impl<'tracer> ExpressionTracer<'tracer> { offset, ref level, depth_ref, + clamp_to_edge: _, } => { work_list.push(image); work_list.push(sampler); @@ -96,7 +97,7 @@ impl<'tracer> ExpressionTracer<'tracer> { } use crate::SampleLevel as Sl; match *level { - Sl::Auto | Sl::Zero | Sl::Base => {} + Sl::Auto | Sl::Zero => {} Sl::Exact(expr) | Sl::Bias(expr) => work_list.push(expr), Sl::Gradient { x, y } => work_list.extend([x, y]), } @@ -266,6 +267,7 @@ impl ModuleMap { ref mut offset, ref mut level, ref mut depth_ref, + clamp_to_edge: _, } => { adjust(image); adjust(sampler); @@ -366,7 +368,7 @@ impl ModuleMap { use crate::SampleLevel as Sl; match *level { - Sl::Auto | Sl::Zero | Sl::Base => {} + Sl::Auto | Sl::Zero => {} Sl::Exact(ref mut expr) => adjust(expr), Sl::Bias(ref mut expr) => adjust(expr), Sl::Gradient { diff --git a/src/front/glsl/builtins.rs b/src/front/glsl/builtins.rs index 8d57b66da2..e203860903 100644 --- a/src/front/glsl/builtins.rs +++ b/src/front/glsl/builtins.rs @@ -2167,6 +2167,7 @@ fn texture_call( offset, level, depth_ref: comps.depth_ref, + clamp_to_edge: false, }, meta, )?) diff --git a/src/front/spv/image.rs b/src/front/spv/image.rs index ee58c7ba14..6289f0123b 100644 --- a/src/front/spv/image.rs +++ b/src/front/spv/image.rs @@ -647,6 +647,7 @@ impl> super::Frontend { offset, level, depth_ref, + clamp_to_edge: false, }; self.lookup_expression.insert( result_id, diff --git a/src/front/wgsl/lower/mod.rs b/src/front/wgsl/lower/mod.rs index 0627427ecd..b9d6e3c61e 100644 --- a/src/front/wgsl/lower/mod.rs +++ b/src/front/wgsl/lower/mod.rs @@ -2399,6 +2399,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .then(|| self.expression(args.next()?, ctx.reborrow())) .transpose()?; + let mut clamp_to_edge = false; + let (level, depth_ref) = match fun { Texture::Gather => (crate::SampleLevel::Zero, None), Texture::GatherCompare => { @@ -2428,7 +2430,10 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let level = self.expression(args.next()?, ctx.reborrow())?; (crate::SampleLevel::Exact(level), None) } - Texture::SampleBaseClampToEdge => (crate::SampleLevel::Base, None), + Texture::SampleBaseClampToEdge => { + clamp_to_edge = true; + (crate::SampleLevel::Zero, None) + } }; let offset = args @@ -2448,6 +2453,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { offset, level, depth_ref, + clamp_to_edge, }) } diff --git a/src/lib.rs b/src/lib.rs index 69dfc7d980..3b2b0233fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1221,7 +1221,6 @@ pub enum SampleLevel { x: Handle, y: Handle, }, - Base, } /// Type of an image query. @@ -1415,6 +1414,7 @@ pub enum Expression { offset: Option>, level: SampleLevel, depth_ref: Option>, + clamp_to_edge: bool, }, /// Load a texel from an image. diff --git a/src/proc/mod.rs b/src/proc/mod.rs index 9b84779a92..d50f165a56 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -508,7 +508,7 @@ impl crate::SampleLevel { pub const fn implicit_derivatives(&self) -> bool { match *self { Self::Auto | Self::Bias(_) => true, - Self::Zero | Self::Exact(_) | Self::Gradient { .. } | Self::Base => false, + Self::Zero | Self::Exact(_) | Self::Gradient { .. } => false, } } } diff --git a/src/valid/analyzer.rs b/src/valid/analyzer.rs index 0fa474da5e..fe8cb5e3e9 100644 --- a/src/valid/analyzer.rs +++ b/src/valid/analyzer.rs @@ -600,6 +600,7 @@ impl FunctionInfo { offset: _, level, depth_ref, + clamp_to_edge: _, } => { let image_storage = GlobalOrArgument::from_expression(expression_arena, image)?; let sampler_storage = GlobalOrArgument::from_expression(expression_arena, sampler)?; @@ -619,7 +620,7 @@ impl FunctionInfo { // "nur" == "Non-Uniform Result" let array_nur = array_index.and_then(|h| self.add_ref(h)); let level_nur = match level { - Sl::Auto | Sl::Zero | Sl::Base => None, + Sl::Auto | Sl::Zero => None, Sl::Exact(h) | Sl::Bias(h) => self.add_ref(h), Sl::Gradient { x, y } => self.add_ref(x).or(self.add_ref(y)), }; diff --git a/src/valid/expression.rs b/src/valid/expression.rs index e47a7872d6..3cad033021 100644 --- a/src/valid/expression.rs +++ b/src/valid/expression.rs @@ -390,6 +390,7 @@ impl super::Validator { offset, level, depth_ref, + clamp_to_edge, } => { // check the validity of expressions let image_ty = Self::global_var_ty(module, function, image)?; @@ -515,6 +516,36 @@ impl super::Validator { // check level properties match level { crate::SampleLevel::Auto => ShaderStages::FRAGMENT, + crate::SampleLevel::Zero if clamp_to_edge => { + // TODO: handle external textures + match module.types[image_ty].inner { + Ti::Image { + dim: crate::ImageDimension::D2, + arrayed: false, + class: + crate::ImageClass::Sampled { + kind: Sk::Float, + multi: false, + }, + } => {} + _ => { + return Err(ExpressionError::InvalidSampleBaseClampToEdgeImageType) + } + } + match resolver[coordinate] { + Ti::Vector { + size: crate::VectorSize::Bi, + kind: Sk::Float, + .. + } => {} + _ => { + return Err( + ExpressionError::InvalidSampleBaseClampToEdgeCoordinateType, + ) + } + } + ShaderStages::all() + } crate::SampleLevel::Zero => ShaderStages::all(), crate::SampleLevel::Exact(expr) => { match resolver[expr] { @@ -563,36 +594,6 @@ impl super::Validator { } ShaderStages::all() } - crate::SampleLevel::Base => { - // TODO: handle external textures - match module.types[image_ty].inner { - Ti::Image { - dim: crate::ImageDimension::D2, - arrayed: false, - class: - crate::ImageClass::Sampled { - kind: Sk::Float, - multi: false, - }, - } => {} - _ => { - return Err(ExpressionError::InvalidSampleBaseClampToEdgeImageType) - } - } - match resolver[coordinate] { - Ti::Vector { - size: crate::VectorSize::Bi, - kind: Sk::Float, - .. - } => {} - _ => { - return Err( - ExpressionError::InvalidSampleBaseClampToEdgeCoordinateType, - ) - } - } - ShaderStages::all() - } } } E::ImageLoad { diff --git a/src/valid/handles.rs b/src/valid/handles.rs index 49b32cc8e5..0894061265 100644 --- a/src/valid/handles.rs +++ b/src/valid/handles.rs @@ -290,6 +290,7 @@ impl super::Validator { offset, level, depth_ref, + clamp_to_edge: _, } => { if let Some(offset) = offset { validate_const_expr(offset)?; @@ -302,9 +303,7 @@ impl super::Validator { .check_dep_opt(array_index)?; match level { - crate::SampleLevel::Auto - | crate::SampleLevel::Zero - | crate::SampleLevel::Base => (), + crate::SampleLevel::Auto | crate::SampleLevel::Zero => (), crate::SampleLevel::Exact(expr) => { handle.check_dep(expr)?; } diff --git a/tests/out/ir/shadow.compact.ron b/tests/out/ir/shadow.compact.ron index 9ca6799c21..c379459028 100644 --- a/tests/out/ir/shadow.compact.ron +++ b/tests/out/ir/shadow.compact.ron @@ -522,6 +522,7 @@ offset: None, level: Zero, depth_ref: Some(29), + clamp_to_edge: false, ), ], named_expressions: {}, diff --git a/tests/out/ir/shadow.ron b/tests/out/ir/shadow.ron index 07bf66fcc8..56e91e6f09 100644 --- a/tests/out/ir/shadow.ron +++ b/tests/out/ir/shadow.ron @@ -793,6 +793,7 @@ offset: None, level: Zero, depth_ref: Some(65), + clamp_to_edge: false, ), ], named_expressions: {},