KhronosGroup / glslang

Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator.
Other
2.98k stars 823 forks source link

GLSL array of structs reflection is not accurate #1479

Open cippyboy opened 6 years ago

cippyboy commented 6 years ago

I have a fragment shader like this

struct RELight { vec3 Position; int LightType;

vec3 Direction;
vec3 Attenuation;

vec3 Ambient;
vec3 Diffuse;
vec3 Specular;  
float Intensity;

};

define MAX_LIGHTS 4

layout(std140, binding = 1, set = 0 ) uniform PerFrameBuffer {
uniform mat4 ProjectionMatrix; uniform mat4 ViewMatrix; uniform mat4 WorldMatrix; uniform mat4 InverseWorldMatrix; uniform mat4 ShadowViewMatrix; uniform RELight Light[ MAX_LIGHTS ]; uniform vec4 MaterialColor; };

After which reflection says there's 7 variables

  Name Value Type
[0] {name="Light.Position" offset=320 glDefineType=35665 ...} glslang::TObjectReflection
[1] {name="Light.Ambient" offset=368 glDefineType=35665 ...} glslang::TObjectReflection
[2] {name="Light.Diffuse" offset=384 glDefineType=35665 ...} glslang::TObjectReflection
[3] {name="Light.Intensity" offset=412 glDefineType=5126 ...} glslang::TObjectReflection
[4] {name="Light.Specular" offset=400 glDefineType=35665 ...} glslang::TObjectReflection
[5] {name="Light.Attenuation" offset=352 glDefineType=35665 ...} glslang::TObjectReflection
[6] {name="MaterialColor" offset=704 glDefineType=35666 ...} glslang::TObjectReflection

For each of the RELight fields getUniformArraySize() returns 1 so I assume they're not treated as arrays, but why are there only 7 ? You can see that MaterialColor's offset is 704, so it clearly follows after all 4 RELight structs, but why don't I have 6 (fields) * 4 (array siize) variables and their offsets in the reflection data ? How am I suppose to get the offsets of each field for each instance ?

cippyboy commented 5 years ago

Version 1.1.97, issue still not resolved :\

johnkslang commented 5 years ago

Reflection was refactored recently, including both bug fixes and new functionality (thanks @baldurk), and it was worth seeing what the results would be after that.

Can you say what interface or command-line options you are using, and provide a complete example that generates that output? (Sometimes, it matters what the shader statements accessed.)

Glslang's version is at 7.11.3113. Where is the 1.1.97 coming from?

johnkslang commented 5 years ago

A theory: it might just be that reflection is including only accessed members, and your shader did not access the missing members.

cippyboy commented 4 years ago

Haven't updated from 1.1.97 and I now index these arrays with gl_InstanceIndex and I have the exact same issue.

cippyboy commented 4 years ago

Actually, I just compiled the latest in glslang from Git and the issue is still present :|.

For reference my problem is now that I have this struct :

#define MAX_INSTANCES 2
struct InstanceData
{
     mat4 WorldMatrix;
     mat4 InverseWorldMatrix;
};
layout( std140, binding = 1, set = 0 ) uniform PerObjectBuffer 
{
    InstanceData Instances[ MAX_INSTANCES ];
};

void main()
{
//...
LocalWorldPos = mul( vec4( LocalWorldPos, 1 ), Instances[ uint(gl_InstanceIndex) ].WorldMatrix ).xyz;
//...
}

And all I get is Instances.InverseWorldMatrix Instances.WorldMatrix

For compiling the shader I have this function:

bool CompileVulkanShaderWithReflection( glslang::TProgram & program, const char* pshader, VkShaderStageFlagBits ShaderType )
{
    TBuiltInResource Resources;
    init_resources( Resources );

    // Enable SPIR-V and Vulkan rules when parsing GLSL
    EShMessages messages = (EShMessages)( EShMsgSpvRules | EShMsgVulkanRules );

    EShLanguage stage = FindLanguage( ShaderType );
    glslang::TShader* shader = new glslang::TShader( stage );

    const char* Precat = "#version 310 es\n";
    const char* Macros = "";// #define VULKAN\n";
    if ( !pshader )
        pshader = "";
    const char* Sources[ 3 ] = { Precat, Macros, pshader };
    shader->setStrings( Sources, 3 );

    if ( !shader->parse( &Resources, 100, false, messages ) )
    {
        RELog( shader->getInfoLog() );
        RELog( shader->getInfoDebugLog() );
        return false; // something didn't work
    }

    program.addShader( shader );

    if ( !program.link( messages ) )
    {
        RELog( program.getInfoLog() );
        RELog( program.getInfoDebugLog() );
        return false;
    }

    bool Ret = program.buildReflection();
    return Ret;
}

UPDATE: I took a look at the testing for glslang and I so I made this extremely simple Vertex Shader :


struct deep1 {
    vec2 va[3];
    bool b;
};

struct deep2 {
    int i;
    deep1 d1[4];
};

struct deep3 {    
    deep2 d2;
    vec4 iv4;
};

struct InstanceData
{
     mat4 WorldMatrix;
     mat4 InverseWorldMatrix;
};
layout( std140, binding = 1, set = 0 ) uniform PerObjectBuffer 
{
    deep3 deeps[2];
    InstanceData Instances[ 2 ];    
};

void main()
{
    gl_Position = deeps[0].iv4 + deeps[1].iv4;
}

And reflection still only tells me about a single "deeps.iv4" with Offset 272, so seems like even static indexing is messed up.

UPDATE2: Also ran the standalone glslang with the same file/rules and when outputting reflection I get : Uniform reflection: deeps.iv4: offset 272, type 8b52, size 1, index 0, binding -1, stages 1, topLevelArrayStride 288

Uniform block reflection: PerObjectBuffer: offset -1, type ffffffff, size 832, index -1, binding 1, stages 1, numMembers 24

rpavlik commented 8 months ago

A theory: it might just be that reflection is including only accessed members, and your shader did not access the missing members.

I have also found that members that are not accessed are not shown in reflection, at least in the command line tool with version:

Glslang Version: 7.11.3113
ESSL Version: OpenGL ES GLSL 3.20 glslang Khronos. 11.3113
GLSL Version: 4.60 glslang Khronos. 11.3113
SPIR-V Version 0x00010300, Revision 6
GLSL.std.450 Version 100, Revision 1
Khronos Tool ID 8
SPIR-V Generator Version 7
GL_KHR_vulkan_glsl version 100
ARB_GL_gl_spirv version 100