-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[naga] Support textureSampleBaseClampToEdge()
for texture2d
#7709
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
base: trunk
Are you sure you want to change the base?
[naga] Support textureSampleBaseClampToEdge()
for texture2d
#7709
Conversation
b25453c
to
466e9b8
Compare
133ad63
to
b27265b
Compare
6df8c7c
to
9103208
Compare
9103208
to
05da8d1
Compare
textureSampleBaseClampToEdge()
for texture2d
Adds a new flag to the IR indicating when image sample coordinates are to be clamped. Adds wgsl-in support for parsing and lowering to IR. Validation ensures this flag is only used when sampling a 2D non-arrayed sampled texture, without offset, gather, or depth comparison. This matches the WGSL requirements, with the exception of supporting `texture_external` textures, which will follow in a later patch. SPIRV, HLSL, and Metal backends are supported so far, with GLSL left for a follow up. (In GLSL the texture will simply be sampled without the coordinates being clamped.) It may seem unfortunate to have to handle this separately for each backend, and indeed it would have been possible to implement this simply in the WGSL frontend. However, future patches will add support for using textureSampleBaseClampToEdge() with external textures, which will actually have to be handled by each backend. This patch is laying the groundwork for that.
This doesn't do anything yet, but unblocks running some CTS tests.
… execution tests to CTS test list
05da8d1
to
b71a0e2
Compare
@jamienicol This is a bit dumb, but does b71a0e2 look okay to you? The MSL backend has no obligations here, since it's a validation error, but I just felt it would be nicer for the MSL backend to die instead of quietly misbehaving. |
@jimblandy I don't mind it at all. I wouldn't want to go hugely out of the way to repeat validation in the backends, but that is simple enough. Personally I'd prefer an assertion to returning an error: if we hit that case there's a bug somewhere and I'd rather we know about it via crash reports than users just suffering in silence. But I might be in the minority of preferring crashes to errors. |
Any reason to limit that to MSL rather than doing it for all backends? or was that just as an example? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like @jimblandy is ramping up on review now, so I won't drive a full review myself, but I'll comment on some things I noticed before I left on vacation and now.
naga/src/back/hlsl/writer.rs
Outdated
Expression::ImageSample { | ||
coordinate: | ||
crate::SampleCoordinate { | ||
expr: coordinate, | ||
clamp_to_edge: true, | ||
}, | ||
image, | ||
sampler, | ||
.. | ||
} => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: It's very unfortunate that we simply don't use the other fields in the case where clamp_to_edge
is true. This feels like an appropriate place to use an enum
, but I can only imagine this will rewrite quite a bit of code for a questionable benefit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this is the same thing I was bringing up here: #7709 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ErichDonGubler Jim and I had previously discussed how to enforce valid combinations of ImageSample flags using the type system. (eg using enums). It's a problem that goes beyond just clamp_to_edge
. We didn't think it was worth it in the end. I think Jim's suggestion above is a happy middle ground.
naga/src/back/glsl/mod.rs
Outdated
@@ -3042,9 +3042,11 @@ impl<'a, W: Write> Writer<'a, W> { | |||
// The space here isn't required but it helps with readability | |||
write!(self.out, ", ")?; | |||
|
|||
// TODO: handle coordinate.clamp_to_edge |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: This shouldn't remain as a TODO
item; this should graduate to an issue before getting merged, if it's intended to outlast this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #7791. Linked to it in a comment.
deno_webgpu/texture.rs
Outdated
impl Drop for GPUExternalTexture { | ||
fn drop(&mut self) {} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick(non-blocking): This Drop
implementation shouldn't be necessary at all, AFAIK, with the current behavior you have. I might be wrong in the case of Deno's expected trait implementations, but I don't think so?
If you're going to fill it out later, though, then 🤷🏻♂️.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I swear I thought I saw other empty drop impls and just copied that. But looking now I can't find them.
I think long term we would expect GPUExternalTexture
to impl Drop
. And to call into wgpu's (yet to be added) Global::external_texture_drop()
. But actually implementing external texture in deno is something I wasn't planning to do so in the short term.
I will remove the impl for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed in cd4d2d9
WrappedImageSample { | ||
clamp_to_edge: true, | ||
} => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: Is there a reason not to destructure and then do if clamp_to_edge
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A subsequent patch will take ImageClass
in to account to. So it'll look like:
match sample {
WrappedImageSample {
clamp_to_edge: true,
class: ImageClass::External,
} => {
...
}
WrappedImageSample {
clamp_to_edge: true,
class: ImageClass::Sampled { kind: ScalarKind::Float, multi: false},
} => {
...
}
_ => {}
}
would you instead propose something like this?
let WrappedImageSample { clamp_to_edge, class } = sample;
match (clamp_to_edge, class) {
(true, ImageClass::External) => {
...
}
(true, ImageClass::Sampled { kind: ScalarKind::Float, multi: false}) => {
...
}
_ => {}
}
If so, no complaints from me if you think that's more conventional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, if you're going to add another match
arm, I don't think this is a worthy nitpick. I was going to suggest that simply use clamp_to_edge
, but if you're adding class
to the mix, I think it's more a question of taste than what's more idiomatic.
I think it's easier to read what you've speculated as my proposal, but if the match
gets particularly big, it might be nice to have the redundant member names. Up to you!
It'd make sense for all backends. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts so far:
naga/src/back/msl/writer.rs
Outdated
writeln!(self.out, "{l1}{NAMESPACE}::float2 half_texel = 0.5 / {NAMESPACE}::float2(tex.get_width(0u), tex.get_height(0u));")?; | ||
writeln!( | ||
self.out, | ||
"{l1}return tex.sample(samp, {NAMESPACE}::clamp(coords, half_texel, 1.0 - half_texel), 0.0);" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to me this will not always sample the base mip level, as textureSampleBaseClampToEdge
requires. Should we also pass {NAMESPACE}::level(0)
before the 0.0
offset?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need an offset so the 0.0
is supposed to be the level. But indeed I forgot to wrap it in {NAMESPACE}::level()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 2fb382c
naga/src/back/hlsl/writer.rs
Outdated
Expression::ImageSample { | ||
coordinate: | ||
crate::SampleCoordinate { | ||
expr: coordinate, | ||
clamp_to_edge: true, | ||
}, | ||
image, | ||
sampler, | ||
.. | ||
} => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this is the same thing I was bringing up here: #7709 (comment)
Did the same thing for HLSL in 2fb382c. Slightly different approach for SPIRV as the implementation is different. In theory it should be able to handle other sample flags, except for the level which must be zero. So I've added a check for that alone - I don't think the backends should be in the business of repeating validation in its entirety - rather they should make a reasonable effort to ensure their own constraints are satisfied. |
Yes, 100%. Backends are allowed to panic and misbehave when validation is buggy. My wanting to tighten up these matches was just opportunistic: it seemed like a small change might save someone some debugging time in he future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deno part LGTM
Adds a new flag to the IR indicating when image sample coordinates are to be clamped. Adds wgsl-in support for parsing and lowering to IR. Validation ensures this flag is only used when sampling a 2D non-arrayed sampled texture, without offset, gather, or depth comparison. This matches the WGSL requirements, with the exception of supporting
texture_external
textures, which will follow in a later patch.SPIRV, HLSL, and Metal backends are supported so far, with GLSL left for a follow up. (In GLSL the texture will simply be sampled without the coordinates being clamped.)
It may seem unfortunate to have to handle this separately for each backend, and indeed it would have been possible to implement this simply in the WGSL frontend. However, future patches will add support for using textureSampleBaseClampToEdge() with external textures, which will actually have to be handled by each backend. This patch is laying the groundwork for that.
Connections
Part of #4386
Fixes #7539
Testing
Added snapshot test
Makes these CTS tests pass
Squash or Rebase?
Rebase
Checklist
cargo fmt
.taplo format
.cargo clippy --tests
. If applicable, add:--target wasm32-unknown-unknown
cargo xtask test
to run tests.CHANGELOG.md
entry.