Skip to content

Location assignment for arrayed outputs #500

Description

@Firestar99

PR #482 broke location assignment for tesselation, geometry and mesh shaders.

Specifically, it broke the following rules in 16.1.3. Interface Matching, which all have a quite similar pattern:

  • if the input is declared in a tessellation control or geometry shader as an OpTypeArray with an Element Type equivalent to the OpType* declaration of the output, and neither is a structure member
  • if the output is declared in a mesh shader as an OpTypeArray with an Element Type equivalent to the OpType* declaration of the input, and neither is a structure member
  • if the input is decorated with PerVertexKHR, and is declared in a fragment shader as an OpTypeArray with an Element Type equivalent to the OpType* declaration of the output, and neither the input nor the output is a structure member

TLDR: Their output must be a spirv array (sized or unsized aka. rust slice). This "outer layer" must be ignored in terms of location assignment and only it's element type considered for location size, as all of these shaders expand from one element to many elements, and each element in the array is being sent to their respective output element.

Workaround: manual location assignment with #[spirv(location = 123)]

Activity

  1. self-assigned this
    on Dec 28, 2025
  2. changed the title [-](my bug report)[/-] [+]Location assignment for tesselation, geometry and mesh shaders[/+] on Dec 28, 2025
  3. changed the title [-]Location assignment for tesselation, geometry and mesh shaders[/-] [+]Location assignment for arrayed outputs[/+] on Dec 28, 2025
  4. Firestar99 commented on Dec 28, 2025

    @Firestar99
    MemberAuthor

    Compiletest that has wrong location assignments 0, 9, 18, 21 instead of 0, 1, 2, 3:

    // build-pass
    // compile-flags: -Ctarget-feature=+MeshShadingEXT,+ext:SPV_EXT_mesh_shader
    // compile-flags: -C llvm-args=--disassemble-globals
    // normalize-stderr-test "OpSource .*\n" -> ""
    // normalize-stderr-test "OpLine .*\n" -> ""
    // normalize-stderr-test "%\d+ = OpString .*\n" -> ""
    // normalize-stderr-test "; .*\n" -> ""
    // normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> ""
    // normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple"
    // ignore-spv1.0
    // ignore-spv1.1
    // ignore-spv1.2
    // ignore-spv1.3
    // ignore-vulkan1.0
    // ignore-vulkan1.1
    
    use spirv_std::arch::set_mesh_outputs_ext;
    use spirv_std::glam::{UVec3, Vec4};
    use spirv_std::spirv;
    
    #[spirv(mesh_ext(
        threads(1),
        output_vertices = 9,
        output_primitives_ext = 3,
        output_triangles_ext
    ))]
    pub fn main(
        #[spirv(position)] positions: &mut [Vec4; 9],
        #[spirv(primitive_triangle_indices_ext)] indices: &mut [UVec3; 3],
        // location 0
        out_per_vertex: &mut [u32; 9],
        // location 1
        out_per_vertex2: &mut [f32; 9],
        // location 2
        #[spirv(per_primitive_ext)] out_per_primitive: &mut [u32; 3],
        // location 3
        #[spirv(per_primitive_ext)] out_per_primitive2: &mut [f32; 3],
    ) {
        unsafe {
            set_mesh_outputs_ext(9, 3);
        }
    
        for i in 0..3 {
            positions[i * 3 + 0] = Vec4::new(-0.5, 0.5, 0.0, 1.0);
            positions[i * 3 + 1] = Vec4::new(0.5, 0.5, 0.0, 1.0);
            positions[i * 3 + 2] = Vec4::new(0.0, -0.5, 0.0, 1.0);
        }
    
        for i in 0..9 {
            out_per_vertex[i] = i as u32;
            out_per_vertex2[i] = i as f32;
        }
    
        for i in 0..3 {
            indices[i] = UVec3::new(0, 1, 2) + UVec3::splat(i as u32);
            out_per_primitive[i] = 42;
            out_per_primitive2[i] = 69.;
        }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions