Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add textureSampleBaseClampToEdge #2534

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/back/dot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ fn write_function_expressions(
offset: _,
level,
depth_ref,
clamp_to_edge: _,
} => {
edges.insert("image", image);
edges.insert("sampler", sampler);
Expand All @@ -460,8 +461,7 @@ fn write_function_expressions(
edges.insert("array_index", expr);
}
match level {
crate::SampleLevel::Auto => {}
crate::SampleLevel::Zero => {}
crate::SampleLevel::Auto | crate::SampleLevel::Zero => {}
crate::SampleLevel::Exact(expr) => {
edges.insert("level", expr);
}
Expand Down
90 changes: 72 additions & 18 deletions src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ pub const SUPPORTED_ES_VERSIONS: &[u16] = &[300, 310, 320];
/// of detail for bounds checking in `ImageLoad`
const CLAMPED_LOD_SUFFIX: &str = "_clamped_lod";

/// The suffix of the variable that will hold the calculated half-texel
/// for use with `textureSampleBaseClampToEdge`
const HALF_TEXEL_SUFFIX: &str = "_half_texel";

pub(crate) const MODF_FUNCTION: &str = "naga_modf";
pub(crate) const FREXP_FUNCTION: &str = "naga_frexp";

Expand Down Expand Up @@ -1855,6 +1859,17 @@ 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 {
clamp_to_edge: true,
image,
..
} = ctx.expressions[handle]
{
self.write_half_texel(ctx, handle, image, level)?
}

if let Some(name) = expr_name {
write!(self.out, "{level}")?;
self.write_named_expr(handle, name, handle, ctx)?;
Expand Down Expand Up @@ -2470,6 +2485,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,
Expand Down Expand Up @@ -2548,24 +2564,38 @@ 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;
// Compose a new texture coordinates vector
if is_vec {
write!(self.out, "vec{}(", coord_dim + tex_1d_hack as u8)?;
}
self.write_expr(coordinate, ctx)?;
if tex_1d_hack {
write!(self.out, ", 0.0")?;
}
if let Some(expr) = array_index {
write!(self.out, ", ")?;
self.write_expr(expr, ctx)?;
}
if merge_depth_ref {
write!(self.out, ", ")?;
self.write_expr(depth_ref.unwrap(), ctx)?;
}
if is_vec {
write!(self.out, ")")?;

if clamp_to_edge {
// clamp the coordinates to [ half_texel, 1 - half_texel ]
write!(self.out, "clamp(")?;
self.write_expr(coordinate, ctx)?;
write!(
self.out,
", {}{}{}, vec2(1.0) - {0}{1}{2})",
back::BAKE_PREFIX,
expr.index(),
HALF_TEXEL_SUFFIX
)?
} else {
// Compose a new texture coordinates vector
if is_vec {
write!(self.out, "vec{}(", coord_dim + tex_1d_hack as u8)?;
}
self.write_expr(coordinate, ctx)?;
if tex_1d_hack {
write!(self.out, ", 0.0")?;
}
if let Some(expr) = array_index {
write!(self.out, ", ")?;
self.write_expr(expr, ctx)?;
}
if merge_depth_ref {
write!(self.out, ", ")?;
self.write_expr(depth_ref.unwrap(), ctx)?;
}
if is_vec {
write!(self.out, ")")?;
}
}

if let (Some(expr), false) = (depth_ref, merge_depth_ref) {
Expand Down Expand Up @@ -3480,6 +3510,30 @@ impl<'a, W: Write> Writer<'a, W> {
Ok(())
}

/// Helper function to write the local holding the half-texel
/// for use with `textureSampleBaseClampToEdge`
fn write_half_texel(
&mut self,
ctx: &back::FunctionCtx,
expr: Handle<crate::Expression>,
image: Handle<crate::Expression>,
level: back::Level,
) -> Result<(), Error> {
write!(
self.out,
"{level}vec2 {}{}{} = vec2(0.5) / vec2(textureSize(",
back::BAKE_PREFIX,
expr.index(),
HALF_TEXEL_SUFFIX,
)?;

self.write_expr(image, ctx)?;

writeln!(self.out, ", 0));")?;

Ok(())
}

// Helper method used to retrieve how many elements a coordinate vector
// for the images operations need.
fn get_coordinate_vector_size(&self, dim: crate::ImageDimension, arrayed: bool) -> u8 {
Expand Down
81 changes: 73 additions & 8 deletions src/back/hlsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const SPECIAL_BASE_VERTEX: &str = "base_vertex";
const SPECIAL_BASE_INSTANCE: &str = "base_instance";
const SPECIAL_OTHER: &str = "other";

/// The suffix of the variable that will hold the calculated half-texel
/// for use with `textureSampleBaseClampToEdge`
const HALF_TEXEL_SUFFIX: &str = "_half_texel";

pub(crate) const MODF_FUNCTION: &str = "naga_modf";
pub(crate) const FREXP_FUNCTION: &str = "naga_frexp";

Expand Down Expand Up @@ -1339,6 +1343,17 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
None
};

// If we are going to write a `textureSampleBaseClampToEdge` next,
// precompute the half-texel before clamping the coordinates.
if let crate::Expression::ImageSample {
clamp_to_edge: true,
image,
..
} = func_ctx.expressions[handle]
{
self.write_half_texel(module, handle, image, level, func_ctx)?
}

if let Some(name) = expr_name {
write!(self.out, "{level}")?;
self.write_named_expr(module, handle, name, handle, func_ctx)?;
Expand Down Expand Up @@ -2379,6 +2394,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"];
Expand All @@ -2392,6 +2408,7 @@ 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(_) => "Level",
Expand All @@ -2403,21 +2420,36 @@ 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, ", ")?;
self.write_texture_coordinates(
"float",
coordinate,
array_index,
None,
module,
func_ctx,
)?;
if clamp_to_edge {
// clamp the coordinates to [ half_texel, 1 - half_texel ]
write!(self.out, "clamp(")?;
self.write_expr(module, coordinate, func_ctx)?;
write!(
self.out,
", _expr{}{}, (1.0).xx - _expr{0}{1})",
expr.index(),
HALF_TEXEL_SUFFIX
)?
} else {
self.write_texture_coordinates(
"float",
coordinate,
array_index,
None,
module,
func_ctx,
)?;
}

if let Some(depth_ref) = depth_ref {
write!(self.out, ", ")?;
self.write_expr(module, depth_ref, func_ctx)?;
}

match level {
Sl::Zero if clamp_to_edge => {
write!(self.out, ", 0.0")?;
}
Sl::Auto | Sl::Zero => {}
Sl::Exact(expr) => {
write!(self.out, ", ")?;
Expand Down Expand Up @@ -3259,6 +3291,39 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
}
Ok(())
}

/// Helper function to write the locals holding the half-texel
/// for use with `textureSampleBaseClampToEdge`
fn write_half_texel(
&mut self,
module: &Module,
expr: Handle<crate::Expression>,
image: Handle<crate::Expression>,
level: back::Level,
func_ctx: &back::FunctionCtx,
) -> Result<(), Error> {
let prefix = format!("_expr{}", expr.index());

writeln!(self.out, "{level}float2 {prefix}_dim;")?;

// will not be used, but required for the method call
writeln!(self.out, "{level}float {prefix}_num;")?;

write!(self.out, "{level}")?;
self.write_expr(module, image, func_ctx)?;

writeln!(
self.out,
".GetDimensions(0u, {prefix}_dim.x, {prefix}_dim.y, {prefix}_num);"
)?;

writeln!(
self.out,
"{level}float2 {prefix}{HALF_TEXEL_SUFFIX} = (0.5).xx / {prefix}_dim;"
)?;

Ok(())
}
}

pub(super) struct MatrixType {
Expand Down
69 changes: 67 additions & 2 deletions src/back/msl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const RAY_QUERY_FUN_MAP_INTERSECTION: &str = "_map_intersection_type";
pub(crate) const MODF_FUNCTION: &str = "naga_modf";
pub(crate) const FREXP_FUNCTION: &str = "naga_frexp";

/// The suffix of the variable that will hold the calculated half-texel
/// for use with `textureSampleBaseClampToEdge`
const HALF_TEXEL_SUFFIX: &str = "_half_texel";

/// Write the Metal name for a Naga numeric type: scalar, vector, or matrix.
///
/// The `sizes` slice determines whether this function writes a
Expand Down Expand Up @@ -739,11 +743,15 @@ impl<W: Write> Writer<W> {
&mut self,
image: Handle<crate::Expression>,
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?
}
Expand Down Expand Up @@ -1460,6 +1468,7 @@ impl<W: Write> Writer<W> {
offset,
level,
depth_ref,
clamp_to_edge,
} => {
let main_op = match gather {
Some(_) => "gather",
Expand All @@ -1473,7 +1482,22 @@ impl<W: Write> Writer<W> {
write!(self.out, ".{main_op}{comparison_op}(")?;
self.put_expression(sampler, context, true)?;
write!(self.out, ", ")?;
self.put_expression(coordinate, context, true)?;

if clamp_to_edge {
// clamp the coordinates to [ half_texel, 1 - half_texel ]
write!(self.out, "{NAMESPACE}::clamp(")?;
self.put_expression(coordinate, context, true)?;
write!(
self.out,
", {}{}{}, {NAMESPACE}::float2(1.0) - {0}{1}{2})",
back::BAKE_PREFIX,
expr_handle.index(),
HALF_TEXEL_SUFFIX
)?
} else {
self.put_expression(coordinate, context, true)?;
}

if let Some(expr) = array_index {
write!(self.out, ", ")?;
self.put_expression(expr, context, true)?;
Expand All @@ -1483,7 +1507,7 @@ impl<W: Write> Writer<W> {
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, ", ")?;
Expand Down Expand Up @@ -2646,6 +2670,17 @@ impl<W: Write> Writer<W> {
}
};

// If we are going to write a `textureSampleBaseClampToEdge` next,
// precompute the half-texel before clamping the coordinates.
if let crate::Expression::ImageSample {
clamp_to_edge: true,
image,
..
} = context.expression.function.expressions[handle]
{
self.write_half_texel(handle, image, level, &context.expression)?
}

if let Some(name) = expr_name {
write!(self.out, "{level}")?;
self.start_baking_expression(handle, &context.expression, &name)?;
Expand Down Expand Up @@ -4190,6 +4225,36 @@ impl<W: Write> Writer<W> {
}
Ok(())
}

/// Helper function to write the locals holding the half-texel
/// for use with `textureSampleBaseClampToEdge`
fn write_half_texel(
&mut self,
expr_handle: Handle<crate::Expression>,
image: Handle<crate::Expression>,
level: back::Level,
context: &ExpressionContext,
) -> Result<(), Error> {
let prefix = format!("{}{}", back::BAKE_PREFIX, expr_handle.index());

write!(
self.out,
"{level}{NAMESPACE}::float2 {prefix}_dim = {NAMESPACE}::float2("
)?;

self.put_expression(image, context, true)?;
write!(self.out, ".get_width(), ")?;

self.put_expression(image, context, true)?;
writeln!(self.out, ".get_height());")?;

writeln!(
self.out,
"{level}{NAMESPACE}::float2 {prefix}{HALF_TEXEL_SUFFIX} = {NAMESPACE}::float2(0.5) / {prefix}_dim;"
)?;

Ok(())
}
}

/// Initializing workgroup variables is more tricky for Metal because we have to deal
Expand Down
Loading
Loading