3
votes

Is is possible to have an array of specialization constants such that the glsl code looks similar to the following:

layout(constant_id = 0) const vec2 arr[2] = vec2[] (
    vec2(2.0f, 2.0f),
    vec2(4.0f, 4.0f)
);

or, alternatively:

layout(constant_id = 0) const float arr[4] = float[] (
    2.0f, 2.0f,
    4.0f, 4.0f
);

As far as I have read there is no limit to the number of specialization constants that can be used so it feels strange that it wouldn't be possible but when I attempt the above the SPIR-V compiler notifies me that 'constant_id' can only be applied to a scalar. Currently I am using a uniform buffer to provide the data but I would like to eliminate the backed buffer and the need to bind the buffer before drawing as well as allow the system to optimize the code during pipeline creation if its possible.

1
If these really are unchanging compile-time constants, then worst-case, you can read the SPIR-V, find the array of interest, and just manipulate the values in-situ before passing them off to Vulkan. - Nicol Bolas
@NicolBolas The data changes infrequently and only when the pipeline needs to be reconstructed anyways. Just to make sure I understand what you are suggesting, you think I should scan the SIR-V in its character array format after it was read in from its file, and replace the array manually. It's a good idea if there is no obvious solution I wasn't even thinking that. - Ryoku
"scan the SIR-V in its character array format" Word array. SPIR-V is defined as an array of 32-bit words. But yes, that's the general idea. - Nicol Bolas

1 Answers

3
votes

While Vulkan-flavored GLSL requires that specialization constants are scalars, SPIR-V itself is not so restrictive. You can declare a specialization constant array, just as you can declare a non-specialized constant array. The latter effectively becomes the former upon specialization constants being provided. The interface for specializing constants in Vulkan acknowledges the possibility that different constants being specialized have different sizes, so an array of them would be valid from an API perspective.

But so long as you are stuck with GLSL, you have to live within its limitations. At least, as far as SPIR-V generation is concerned.

However, if you're willing to do some surgery on the SPIR-V after generating it, you can construct what you need. Given the name of the array in question, you can track down the OpName that matches that array name. Once you find it, you can find the ResultID (every SPIR-V opcode has one) that the OpName opcode specifies. That opcode should be an OpConstantComposite.

All you need to do is turn this OpConstantComposite opcode into OpSpecConstantComposite. The two codes use the same parameters and so forth, so you're just swapping the opcode out for the other one.