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

[wgsl-in] Ensure textureSampleLevel's level argument is an integer for depth textures #6529

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from

Conversation

jamienicol
Copy link
Contributor

Connections
Fixes #4548

Description
The spec specifies that textureSampleLevel() takes an integer type as the level parameter for depth textures (and a float for non-depth textures). We currently accept a float for all texture types. This makes us require the correct type. As a result we now need to convert the value in the SPIR-V backend. For HLSL and MSL, SampleLevel() and metal::level() appear to implicitly convert the integer to floats just fine. And as far as I can tell we do not support non-compare sampling of depth textures on GLSL?

Testing
Manual inspection of output shaders. Shader validation succeeds. Built gecko with change and verified relevant CTS tests (webgpu:shader,validation,expression,call,builtin,textureSampleLevel:level_argument) now pass.

Checklist

  • Run cargo fmt.
  • Run taplo format.
  • Run cargo clippy. If applicable, add:
    • --target wasm32-unknown-unknown
    • --target wasm32-unknown-emscripten
  • Run cargo xtask test to run tests.
  • Add change to CHANGELOG.md. See simple instructions inside file.

@jamienicol jamienicol requested a review from a team as a code owner November 12, 2024 18:05
@teoxoy
Copy link
Member

teoxoy commented Nov 13, 2024

And as far as I can tell we do not support non-compare sampling of depth textures on GLSL?

Looking at the code in the backend I think we do but there are caveats/restrictions.

Comment on lines +525 to +542
crate::ImageClass::Depth { .. } => match resolver[expr] {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
..
}) => {}
_ => {
return Err(ExpressionError::InvalidSampleLevelExactType(expr))
}
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we would modify the GLSL & SPIR-V frontends as well to not regress. I think we need to round the lod then cast it to a u32 so that the behavior is in line with a non-filtering sampler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any GLSL command can be converted to a depth texture textureSampleLevel(). GLSL's textureLod() with a shadow texture takes a vector with an extra component for the coords, and this component is used as the compare value when translated to textureSampleCompareLevel().

textureSampleCompareLevel always has a LOD of zero, so the LOD specified in the GLSL also appears to be lost in translation. I think that occurs here. So as I can tell I don't think there's anything to do for GLSL, but this is all very new to me so could be wrong!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the GLSL frontend, that seems accurate. The SPIR-V frontend can produce a textureSampleLevel() with a depth texture though.

@jamienicol
Copy link
Contributor Author

jamienicol commented Nov 13, 2024

And as far as I can tell we do not support non-compare sampling of depth textures on GLSL?

Looking at the code in the backend I think we do but there are caveats/restrictions.

@teoxoy Could you point me towards this? I'm not very familiar with these things, but my understanding is GLSL's textureLod() or just texture() take a vec with an extra component when using a shadow sampler. This extra component is the compare value. We have code to write this in glsl back here but only when depth_ref is Some, ie using textureSampleCompare.

If I try to translate some wgsl with textureSampleLevel() then we generate GLSL with a vec of the wrong size, as we didn't merge the depth_ref

@teoxoy
Copy link
Member

teoxoy commented Nov 13, 2024

Oh wow that's a "nice" inconsistency between GLSL's sampling functions, some take the depth ref as a separate argument (ex textureGather), so I never expected some to take it as the last element of the vec. It also doesn't seem to be documented in the specs.

On the spec side of things, we are also working on WebGPU Compat (WebGPU on top of OpenGL ES 3.1) and this hasn't been brought up by anyone yet, I will open a new issue.

…r depth textures

Until now we accepted a float, as is the case for non-depth textures.
This makes us compliant with the spec.

The validator is updated to expect an Sint or Uint when the ImageClass
is ImageClass::Depth. The SPIR-V frontend converts the LOD argument
from float to Sint (assuming that it is representable), likewise The
SPIR-V backend now converts the LOD from either Sint or Uint to
Float. HLSL and MSL backends require no changes as they implicitly do
that conversion. GLSL does not support non-compare LOD samples,
therefore no changes are required.
Comment on lines +508 to +516
log::debug!(
"Assuming level {:?} converts losslessly to an integer",
lod_handle
);
let expr = crate::Expression::As {
expr: lod_handle,
kind: crate::ScalarKind::Sint,
convert: Some(4),
};
Copy link
Member

@teoxoy teoxoy Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if we round it first this will behave the same as the sampler doing it. Thoughts?

Copy link
Contributor Author

@jamienicol jamienicol Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My assumption was that a fractional lod interpolated between two mip levels. But I can't see anything in the spec which says that (but nor that it rounds the lod). Do you happen to know what the spec says?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depth textures can only be paired with a non-filtering (or comparison) sampler which means that the mipmapFilter field of the sampler descriptor can't be linear, it must be nearest which sounds like it rounds instead.

A few links:

https://www.w3.org/TR/webgpu/#ref-for-dom-gpusamplerbindingtype-filtering%E2%91%A2
https://www.w3.org/TR/webgpu/#dom-gpusamplerbindingtype-non-filtering
https://www.w3.org/TR/webgpu/#ref-for-dom-gpusampler-isfiltering-slot
https://www.w3.org/TR/webgpu/#enumdef-gpumipmapfiltermode

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

textureSampleLevel(texture_depth_2d_array, ..) expects a float for level when it should be an integer
2 participants