KhronosGroup / KhronosGroup/GLSL
Format layout qualifiers on image function parameters?
- Dominant language
- JavaScript
- Stars
- 458
- Forks
- 114
- Avg merge
- 4m
- Merged PRs (30d)
- 1
Description
Implementations are inconsistent about handling format layout qualifiers on image function parameters, and whether they are included in parameter matching. The GLSL spec seems to have a clear statement about this, but it may not be the "right" answer.
Section 4.10 (Memory Qualifiers) includes this example code, claiming that it is "OK" to pass a qualified image to an unqualified parameter:
```
vec4 funcA(restrict image2D a) { ... }
vec4 funcB(image2D a) { ... }
layout(rgba32f) uniform image2D img1;
layout(rgba32f) coherent uniform image2D img2;
funcA(img1); // OK, adding "restrict" is allowed
funcB(img2); // illegal, stripping "coherent" is not
```
The next sentence says "Layout qualifiers cannot be used on formal function parameters, and layout qualification is not included in parameter matching."
That seems pretty clear, but if a function parameter can't be qualified then it can't be loaded from, because loads require a format qualifier (unless GL_EXT_shader_image_load_formatted is enabled). That also seems to require inlining or cloning functions in order to know the right type, which is something we've tried to avoid in SPIR-V. So this is an unexpected/concerning answer.
Consider the following example:
```
#version 450
layout(local_size_x = 1) in;
layout(binding=0, rgba16f) uniform image2D im;
void f(layout(rgba16f) image2D x)
{
imageStore(x, ivec2(0,0), vec4(0,0,0,0));
imageLoad(x, ivec2(0,0));
}
void g(image2D x)
{
imageStore(x, ivec2(0,0), vec4(0,0,0,0));
}
void main (void)
{
f(im);
g(im);
}
```
glslang generates an error on the definition of f(): "cannot use layout qualifiers on a function parameter". If you remove f(), it successfully compiles the call to g() (passing qualified to nonqualified), but the resulting SPIR-V fails spirv-val "OpFunctionCall Argument '23[%im]'s type does not match Function '8[%_ptr_UniformConstant_7]'s parameter type". If the frontend compiler is supposed to insert a cast, is it supposed to be an OpBitcast? That sounds legal, but is possibly something that has never been tested.
NVIDIA's GLSL compiler generates an error on the call to g() "incompatible type for parameter 1". But it accepts the definition of f and call to f, and generates correct code (AFAICT).
I'm not sure what's the right way to resolve all this. It seems like we should allow format qualifiers on function parameters, so that loads can be supported. And it is fine to allow unqualified function parameters, but I would only expect them to support stores (spec says "it is a compile-time error to pass an image uniform variable or function parameter declared without a format layout qualifier to an image load or atomic function"). If we want to allow passing qualified variables to unqualified parameters, then we either need to relax the type matching rules in SPIR-V or clarify (in GL_KHR_vulkan_glsl?) how to perform the conversion?
Contributor guide
Research direction
Start with GLSL section 4.10 and compare its statements about image layout qualifiers and function-parameter matching with the examples in this issue. Reproduce the glslang and spirv-val results, then compare NVIDIA's compiler behavior. Done means documenting a consistent resolution for parameter qualifiers, image loads and stores, and qualified-to-unqualified argument matching.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100