Shader packs: a texel offset given as a parameter moves the coordinate

GLSL asks a texel offset to be a constant expression; GL drivers also take one a
function receives as a `const in ivec2` parameter (Arc's FXAA samples its neighbours
that way, so its final pass was skipped in every dimension). Such an offset now moves
the coordinate by that many texels of the base level; a constant one stays an offset.
This commit is contained in:
PzmuV1517 committed 2026-11-06 01:52:10 +02:00
1 parent 1da773a501
commit 623aa1d3ea
2 files changed
+79 -1

No files matched your search

@@ -162,6 +162,36 @@ fn a_matrix_built_from_one_vector_takes_its_components_column_by_column() {
); );
} }
#[test]
fn a_texel_offset_a_function_gets_as_a_parameter_moves_the_coordinate() {
// Arc's FXAA: `textureLodOffset(tex, uv, 0.0, offset)` with `const in ivec2 offset`.
let module = assert_terrain_translates(
"#version 330\nuniform sampler2D colortex4;\n\
float lumaAt(const in vec2 uv, const in ivec2 offset) {\n\
return textureLodOffset(colortex4, uv, 0.0, offset).r + textureOffset(colortex4, uv, offset).g;\n}\n\
layout(location = 0) out vec4 color;\n\
void main() { color = vec4(lumaAt(vec2(0.5), ivec2(0, -1)), textureOffset(colortex4, vec2(0.5), ivec2(1, 0)).r, 0.0, 1.0); }\n",
);
// The constant offset in `main` stays an offset.
let offsets = module
.functions
.iter()
.map(|(_, f)| &f.expressions)
.chain(module.entry_points.iter().map(|e| &e.function.expressions))
.flat_map(|e| e.iter())
.filter(|(_, e)| {
matches!(
e,
naga::Expression::ImageSample {
offset: Some(_),
..
}
)
})
.count();
assert_eq!(offsets, 1);
}
#[test] #[test]
fn integer_samplers_read_through_the_float_sampling_functions() { fn integer_samplers_read_through_the_float_sampling_functions() {
// Mello, Voyager, Exposa, Reverie: `uint mask = texture(colortex3, uv).r` on a usampler2D. // Mello, Voyager, Exposa, Reverie: `uint mask = texture(colortex3, uv).r` on a usampler2D.
+49 -1
View File
@@ -2582,12 +2582,60 @@ fn texture_call(
ctx.conversion(array_index_expr, meta, Scalar::I32)?; ctx.conversion(array_index_expr, meta, Scalar::I32)?;
} }
// A texel offset must be a constant expression, but GL drivers also take one a
// function gets as a parameter (`const in ivec2 offset`, Arc's FXAA). Such an offset
// moves the coordinate by that many texels of the base level instead.
let mut coordinate = comps.coordinate;
let mut offset = offset;
if let Some(by) = offset.filter(|&o| !ctx.local_expression_kind_tracker.is_const(o)) {
let size = ctx.add_expression(
Expression::ImageQuery {
image,
query: ImageQuery::Size { level: None },
},
meta,
)?;
let size = ctx.add_expression(
Expression::As {
expr: size,
kind: Sk::Float,
convert: Some(4),
},
meta,
)?;
let by = ctx.add_expression(
Expression::As {
expr: by,
kind: Sk::Float,
convert: Some(4),
},
meta,
)?;
let shift = ctx.add_expression(
Expression::Binary {
op: BinaryOperator::Divide,
left: by,
right: size,
},
meta,
)?;
coordinate = ctx.add_expression(
Expression::Binary {
op: BinaryOperator::Add,
left: coordinate,
right: shift,
},
meta,
)?;
offset = None;
}
Ok(ctx.add_expression( Ok(ctx.add_expression(
Expression::ImageSample { Expression::ImageSample {
image, image,
sampler, sampler,
gather: None, //TODO gather: None, //TODO
coordinate: comps.coordinate, coordinate,
array_index, array_index,
offset, offset,
level, level,