I am using glslang in my C++ based Vulkan project to deduce information about shaders that I am using to help automatically build my descriptor sets and descriptor set layouts. I have come to a point that I need to support unsized/runtime-defined arrays (See https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Arrays_of_arrays).
The glslang library appropriately compiles the shader and when looking at the SPIRV does show that I am generating a TypeRuntimeArray.
However, when digging through the reflection all but the most simple of cases are not reflected.
I have taken steps to make sure that the reflection isnt optimized out or hidden. I have tried manually enabling the array of arrays extension, and have tried in vertex, compute and fragment shader stages. The shaders are compiled with #version 450. I've tried seeing if std430 vs 140 provides different results to no avail.
I've also made sure that when indexing into the unsized array I'm not indexing with a constant. I've tried providing index's from built in types such as gl_VertexIndex, and from the push_constant block or seperate uniform-blocks
Take the following example that does appropriately reflect:
layout(std430) buffer Buffer1
{
float[] unsizedArray;
} myBuffer1;
The reflection for the unsizedArray is available from both TProgram.dumpReflection() and getting the reflection and playing with it.
However, it will only work for that simple case. If we try either
layout(std430) buffer Buffer1
{
float[][10] unsizedArray;
} myBuffer1;
or
struct MyType{
vec4 thingy;
int otherThingy;
}
layout(std430) buffer Buffer1
{
MyType[] unsizedArray;
} myBuffer1;
No reflection of the inner unsized array is provided is provided. We can get reflection on the outer array from the first failed example, or on the variable from MyType, but there doesn't seem to be any way to get the inner array information. As far as I can tell there is no way to 'walk-up' the tree tree from the reflected variable.
Aside from parsing the spirv myself is there anyway to convince glslang to reflect the unsized array?
Edit: Examples to give a little more info
#version 450
struct MyStruct{
float z;
};
layout(binding = 5,std430) buffer StorageBlock{
float[] myArray;
} storage;
layout(push_constant, std430) uniform Constant{
int index;
} ps;
void main() {
float test = storage.myArray[ps.index];
}
// A simple function I I built just to show this. There are quite a few other functions provided
// by both the reflection and glsl::TProgram object, but I haven't found anyway to get the inner array.
function parseUniform(glslang::TObjectReflection& reflection){
reflection->dump(); // This just outputs a string to stdout
auto type = reflection.getType();
if( type->isArray() ) {
bool isUnsizedArray = type->isUnsizedArray();
bool containsUnsizedArray = type->containsUnsizedArray();
bool isArrayOfArrays = type->isArrayOfArrays();
bool isSizedArray = type->isSizedArray();
auto arraySizes = (glslang::TArraySizes*)type->getArraySizes();
bool isInnerUnsized = arraySizes->isInnerUnsized();
bool hasUnsized = arraySizes->hasUnsized();
int numDims = arraySizes->getNumDims();
bool isVariablyIndexed = arraySizes->isVariablyIndexed();
std::cout << "isUnsizedArray(): " << isUnsizedArray << "\n";
std::cout << "containsUnsizedArray(): " << containsUnsizedArray << "\n";
std::cout << "isArrayOfArrays(): " << isArrayOfArrays << "\n";
std::cout << "isSizedArray(): " << isSizedArray << "\n";
std::cout << "isInnerUnsized(): " << isInnerUnsized << "\n";
std::cout << "numDims: " << numDims << "\n";
std::cout << "isVariablyIndexed(): " << isVariablyIndexed << "\n";
std::cout << "hasUnsized(): " << hasUnsized << "\n";
}
}
If we query reflection data using the function above on a storage block defined like
layout(binding = 5,std430) buffer StorageBlock{
float[] myArray;
} storage;
The output is
StorageBlock.myArray: offset 0, type 1406, size 0, index 0, binding -1, stages 32, arrayStride 4, topLevelArrayStride 4
isUnsizedArray(): 1
containsUnsizedArray(): 1
isArrayOfArrays(): 0
isSizedArray(): 0
isInnerUnsized(): 0
numDims: 1
isVariablyIndexed(): 1
hasUnsized(): 1
If we call on a simple multi-dimensional array:
layout(binding = 5,std430) buffer StorageBlock{
float[][5] myArray;
} storage;
The singular reflected uniform that is provided outputs
StorageBlock.myArray: offset 0, type 1406, size 1, index 0, binding -1, stages 32, arrayStride 4, topLevelArrayStride 40
isUnsizedArray(): 0
containsUnsizedArray(): 0
isArrayOfArrays(): 0
isSizedArray(): 1
isInnerUnsized(): 0
numDims: 1
isVariablyIndexed(): 0
hasUnsized(): 0
And if we call using a struct we only get:
layout(binding = 5,std430) buffer StorageBlock{
MyStruct[] myArray;
} storage;
We get:
StorageBlock.myArray.z: offset 0, type 1406, size 1, index 0, binding -1, stages 32, topLevelArrayStride 4
Because .z is of course a single float and not an array we don't get any of the array information. In all of these tests only one uniform is 'reflected'