LWJGL / lwjgl3

LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications.
https://www.lwjgl.org
BSD 3-Clause "New" or "Revised" License
4.67k stars 628 forks source link

SPIRV-Cross get member name issue #846

Closed tlf30 closed 1 year ago

tlf30 commented 1 year ago

Version

3.3.2 (nightly)

Platform

Windows x64

JDK

Adoptium 19

Module

SPIRV-Cross

Bug description

Hello @Spasi, I don't necessary think this is a LWJGL bug (probably something I am doing wrong...) but I figured I would post here before the SPIRV-Cross repo just in case.

I am trying to get the names of struct members from a uniform binding. Example Shader Code (simplified for example):

struct AmbientLight {
    mat4 viewMatrix;
    vec3 color;
    float intensity;
};

struct PointLight {
    mat4 viewMatrix;
    vec3 color;
    float intensity;
    float range;
};

struct SpotLight {
    mat4 viewMatrix;
    vec3 color;
    float intensity;
    float range;
    float innerConeAngle;
    float outerConeAngle;
};

layout(set = 0, binding = 0) uniform lights_block {
    AmbientLight directionalLights[AMBIENT_LIGHT_COUNT];
    PointLight pointLights[POINT_LIGHT_COUNT];
    SpotLight spotLights[SPOT_LIGHT_COUNT];
} lights;

And I am using the following code to get the member names:

private void processLayoutUniforms(MemoryStack stack, long compiler) {
        //Getting shader uniforms
        PointerBuffer resourcesPointer = stack.mallocPointer(1);
        Spvc.spvc_compiler_create_shader_resources(compiler, resourcesPointer);
        PointerBuffer listPointer = stack.mallocPointer(1);
        PointerBuffer sizePointer = stack.mallocPointer(1);
        Spvc.spvc_resources_get_resource_list_for_type(resourcesPointer.get(0), Spvc.SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, listPointer, sizePointer);

        //Wrapping uniform resources
        int size = (int) sizePointer.get(0);
        SpvcReflectedResource.Buffer resources = SpvcReflectedResource.createSafe(listPointer.get(0), size);

        //Shader uniforms
        for (int i = 0; i < size; i++) {
            //Set Layout
            SpvcReflectedResource resource = resources.get(i);
            int set = Spvc.spvc_compiler_get_decoration(compiler, resource.id(), Spv.SpvDecorationDescriptorSet);
            int binding = Spvc.spvc_compiler_get_decoration(compiler, resource.id(), Spv.SpvDecorationBinding);

            String uniformName = Spvc.spvc_compiler_get_name(compiler, resource.id());
            System.err.println("Base ID Name: " + Spvc.spvc_compiler_get_name(compiler, resource.base_type_id()));
            System.err.println("ID Name: " + uniformName);
            System.err.println("Type ID Name: " + Spvc.spvc_compiler_get_name(compiler, resource.type_id()));

            System.err.println("Uniform Name: " + resource.nameString());
            System.err.println("ID: " + resource.id());
            System.err.println("Set = " + set);
            System.err.println("Binding = " + binding);

            //Get size of uniform
            long typeHandle = Spvc.spvc_compiler_get_type_handle(compiler, resource.base_type_id());
            PointerBuffer structSize = stack.mallocPointer(1);
            Spvc.spvc_compiler_get_declared_struct_size(compiler, typeHandle, structSize);
            System.err.println("Size: " + structSize.get(0));

            getLayoutOfMembers(stack, compiler, typeHandle, resource.base_type_id(), uniformName, 0, uniformName);

            var setLayout = getSetLayout(set);
            setLayout.setDescriptorBinding(binding,
                    new DescriptorBinding(
                            getVkShaderStage(),
                            VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
                            set,
                            binding,
                            structSize.get(0),
                            uniformName
                    )
            );
            setLayout.setDescriptorCount(1); //TODO: Support arrays
        }
    }
private void getLayoutOfMembers(MemoryStack stack, long compiler, long typeHandle, int baseTypeId, String uniform, int currentOffset, String currentPath) {
        //Get uniform members
        int memberTypeCount = Spvc.spvc_type_get_num_member_types(typeHandle);
        System.err.println("Member types: " + memberTypeCount);
        for (int m = 0; m < memberTypeCount; m++) {
            int memberBaseTypeId = Spvc.spvc_type_get_member_type(typeHandle, m);
            long memberTypeHandle = Spvc.spvc_compiler_get_type_handle(compiler, memberBaseTypeId);

            //FIXME: Not getting name for sub-structs
            String memberName = Spvc.spvc_compiler_get_member_name(compiler, baseTypeId, m);
            System.err.println("Member name: " + memberName);
            System.err.println("Base ID Name: " + Spvc.spvc_compiler_get_name(compiler, memberBaseTypeId));

            PointerBuffer memberSize = stack.mallocPointer(1);
            Spvc.spvc_compiler_get_declared_struct_member_size(compiler, typeHandle, m, memberSize);
            System.err.println("Member size: " + memberSize.get(0));

            IntBuffer memberOffset = stack.mallocInt(1);
            Spvc.spvc_compiler_type_struct_member_offset(compiler, typeHandle, m, memberOffset);
            System.err.println("Member offset: " + memberOffset.get(0));

            int arrayDimensions = Spvc.spvc_type_get_num_array_dimensions(memberTypeHandle);
            if (arrayDimensions > 0) {
                System.err.println("Member array dimensions: " + arrayDimensions);
            }

            int memberTypeColumns = Spvc.spvc_type_get_columns(memberTypeHandle);
            if (memberTypeColumns > 1) {
                IntBuffer memberStride = stack.mallocInt(1);
                Spvc.spvc_compiler_type_struct_member_matrix_stride(compiler, typeHandle, m, memberStride);
                System.err.println("Member stride: " + memberStride.get(0));
            }
            System.err.println("Added binding offset: " + currentPath + "." + memberName);
            uniformBindings.add(new ShaderUniformBinding(uniform, currentPath + "." + memberName, memberSize.get(0), memberOffset.get(0), getVkShaderStage()));
            getLayoutOfMembers(stack, compiler, memberTypeHandle, memberBaseTypeId, uniform, memberOffset.get(0), currentPath + "." + memberName);
        }
    }

Take note, I am using getLayoutOfMembers reclusively. It seems that String memberName = Spvc.spvc_compiler_get_member_name(compiler, baseTypeId, m); is returning an empty string for the struct member names. All other getter return expected values.

Output:

Member types: 0
Base ID Name: lights_block
ID Name: lights
Type ID Name: 
Uniform Name: lights_block
ID: 134
Set = 2
Binding = 0
Size: 272
Member types: 3
Member name: directionalLights
Base ID Name: 
Member size: 80
Member offset: 0
Member array dimensions: 1
Added binding offset: lights.directionalLights
Member types: 3
Member name: 
Base ID Name: 
Member size: 64
Member offset: 0
Member stride: 16
Added binding offset: lights.directionalLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 12
Member offset: 64
Added binding offset: lights.directionalLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 76
Added binding offset: lights.directionalLights.
Member types: 0
Member name: pointLights
Base ID Name: 
Member size: 96
Member offset: 80
Member array dimensions: 1
Added binding offset: lights.pointLights
Member types: 4
Member name: 
Base ID Name: 
Member size: 64
Member offset: 0
Member stride: 16
Added binding offset: lights.pointLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 12
Member offset: 64
Added binding offset: lights.pointLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 76
Added binding offset: lights.pointLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 80
Added binding offset: lights.pointLights.
Member types: 0
Member name: spotLights
Base ID Name: 
Member size: 96
Member offset: 176
Member array dimensions: 1
Added binding offset: lights.spotLights
Member types: 6
Member name: 
Base ID Name: 
Member size: 64
Member offset: 0
Member stride: 16
Added binding offset: lights.spotLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 12
Member offset: 64
Added binding offset: lights.spotLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 76
Added binding offset: lights.spotLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 80
Added binding offset: lights.spotLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 84
Added binding offset: lights.spotLights.
Member types: 0
Member name: 
Base ID Name: 
Member size: 4
Member offset: 88
Added binding offset: lights.spotLights.

As stated, I think this is either something I am doing wrong, or an issue in SPIRV-Cross, but I wanted to check here first.

Thank you, Trevor

Stacktrace or crash log output

No response

Spasi commented 1 year ago

Hey @tlf30,

https://github.com/KhronosGroup/SPIRV-Cross/issues/1190 should help. Looks like you need to use spvc_type_get_base_type_id.

tlf30 commented 1 year ago

Thank you for the help @Spasi and sorry for the long delay. I have been diving deep into this, and finally have an understanding of what is going on in the decompiler.

Here is a working function:

private void getLayoutOfMembers(MemoryStack stack, long compiler, long baseTypeHandle, int baseTypeId, String uniform, int currentOffset, String currentPath) {
        //Get uniform members
        int memberTypeCount = Spvc.spvc_type_get_num_member_types(baseTypeHandle);
        System.err.println("Member types: " + memberTypeCount);
        for (int m = 0; m < memberTypeCount; m++) {
            int memberTypeId = Spvc.spvc_type_get_member_type(baseTypeHandle, m);
            long memberTypeHandle = Spvc.spvc_compiler_get_type_handle(compiler, memberTypeId);
            int memberBaseTypeId = Spvc.spvc_type_get_base_type_id(memberTypeHandle);
            long memberBaseTypeHandle = Spvc.spvc_compiler_get_type_handle(compiler, memberBaseTypeId);

            System.err.println("ParentBaseTypeId = " + baseTypeId + "; ParentBaseTypeHande = " + baseTypeHandle + "; TypeId = " + memberTypeId + "; TypeHandle = " + memberTypeHandle + " BaseTypeId = " + memberBaseTypeId + "; BaseTypeHandle = " + memberBaseTypeHandle);

            String memberName = Spvc.spvc_compiler_get_member_name(compiler, baseTypeId, m);
            System.err.println("Member Base Type ID name: " + memberName);
            if (memberName.isEmpty()) {
                memberName = String.valueOf(m);
            }

            PointerBuffer memberSize = stack.mallocPointer(1);
            Spvc.spvc_compiler_get_declared_struct_member_size(compiler, baseTypeHandle, m, memberSize);
            System.err.println("Member size: " + memberSize.get(0));

            IntBuffer memberOffset = stack.mallocInt(1);
            Spvc.spvc_compiler_type_struct_member_offset(compiler, baseTypeHandle, m, memberOffset);
            //System.err.println("Member offset: " + memberOffset.get(0));

            int arrayDimensions = Spvc.spvc_type_get_num_array_dimensions(memberBaseTypeHandle);
            if (arrayDimensions > 0) {
                System.err.println("Member array dimensions: " + arrayDimensions);
            }

            int memberTypeColumns = Spvc.spvc_type_get_columns(memberBaseTypeHandle);
            if (memberTypeColumns > 1) {
                IntBuffer memberStride = stack.mallocInt(1);
                Spvc.spvc_compiler_type_struct_member_matrix_stride(compiler, baseTypeHandle, m, memberStride);
                System.err.println("Member stride: " + memberStride.get(0));
            }
            String fullMemberPath = currentPath + "." + memberName;
            System.err.println("Added binding offset: " + fullMemberPath);
            uniformBindings.add(new ShaderUniformBinding(uniform, fullMemberPath, memberSize.get(0), memberOffset.get(0), getVkShaderStage()));
            getLayoutOfMembers(stack, compiler, memberTypeHandle, memberBaseTypeId, uniform, memberOffset.get(0), currentPath + "." + memberName);
        }
    }

Thank you so much for the help, it made all the difference in getting me in the correct direction.