glslang icon indicating copy to clipboard operation
glslang copied to clipboard

"Constness" of specialization constants doesn't propagate to all types of expressions

Open godlikepanos opened this issue 4 years ago • 13 comments

Hi,

It seems there are some issues with specialization constants where the compiler fails to understand that specific expressions are constexpr. The compiler fails with global const initializers must be constant type of errors.

This is a shader that exhibits the problem:

#version 460

layout(constant_id = 0) const int TILE_SIZE = 0;

const float f = float(TILE_SIZE);   // Fails
const int i[1] = int[](TILE_SIZE);  // Fails
const uint u = TILE_SIZE * 10 + 1;  // Passes

layout (location = 0) out vec4 fragColor;

void main()
{
	fragColor = vec4(0.4, 0.4, 0.8, 1.0);
}

It's practically impossible to initialize the contents of constexpr arrays with specialization constants.

godlikepanos avatar Apr 26 '21 12:04 godlikepanos

Sounds similar to #2025.

DadSchoorse avatar Apr 26 '21 17:04 DadSchoorse

OK. I will try to get to this soon. If someone else wants to contribute a solution, please let me know before you start to avoid duplicate effort.

greg-lunarg avatar Apr 27 '21 19:04 greg-lunarg

I am now looking at this. I will have a fix ASAP.

greg-lunarg avatar May 05 '21 17:05 greg-lunarg

Re the following:

const float f = float(TILE_SIZE);

The current GLSL spec seems to allow this statement, but after some communication with the author and the SPIR-V working group, it appears that the spec intended to disallow int-to-float conversion of a spec constant as a constant expression. Float-to-int is disallowed as well.

Frankly, I am not quite sure why this was decided. To me it seems counter-intuitive to treat spec constants differently than regular constants and a continuing source of confusion and frustration. There is apparently a fairly lengthy philosophical reason which I didn't insist on being given during our meeting today. If you want to know what it is, I can try and ask for it.

I think the other statement is valid and am pressing on to fix that.

greg-lunarg avatar May 12 '21 17:05 greg-lunarg

Thanks for looking into this Greg.

I'm not sure what's the reasoning for disallowing this as well. As you said, and I agree, people intuitively expect for these things to work so having an explanation from the working group would be great.

But I'll also argue that since GLSL allowed that and SPIR-V as well (unless I missed something in the spec) then going back and restricting it now might not be the best idea. There might be software out there that relies in such behaviour.

godlikepanos avatar May 12 '21 19:05 godlikepanos

Well, glslang never allowed it, so folks should not see any regressions here.

There are some other restrictions that make more sense, for example, the trig functions are allowed for constants, but not for spec constants. So constructors like float() are not the only outliers, which softens the blow a bit.

greg-lunarg avatar May 12 '21 19:05 greg-lunarg

Looking at const int i[1] = int[](TILE_SIZE); // Fails now.

greg-lunarg avatar May 31 '21 19:05 greg-lunarg

glslang has commented code and a commented test which holds to the policy that constant arrays containing specialization constants are not allowed, although I can find no such policy in the Vulkan, SPIR-V or GLSL specs. The aforementioned test's file name seems to imply that the policy comes from Vulkan.

I will check with the SPIR-V WG to see if they know more about this policy.

greg-lunarg avatar Jun 01 '21 00:06 greg-lunarg

Once I have a go-ahead from them I should be posting a fix shortly after.

greg-lunarg avatar Jun 01 '21 00:06 greg-lunarg

According to the SPIR-V WG, the construct const int i[1] = int[](TILE_SIZE); is legal in SPIR-V, GLSL and Vulkan. It is only generating an error because support has not yet been implemented in glslang.

I will add support shortly.

greg-lunarg avatar Jun 08 '21 23:06 greg-lunarg