Skip to content

[spv-in] Add support for structs that contain pointers #6623

Open
@tombh

Description

@tombh

I'm writing a physics compute shader with rust-gpu. Recently I tried adding Workgroup support, but I ran into this issue with naga validation:

Type [34] '' is invalid:
        Expected data type, found [17]

I'm using Bevy 0.14.1 that depends on naga 0.20.0. But I can reproduce the error with naga-cli on trunk.

I've managed to get a minimal reproducible rust-gpu shader that cross-compiles to a small GLSL shader:

#![cfg_attr(target_arch = "spirv", no_std)]

use spirv_std::{glam::Vec2, spirv};

type Workgroup = [Vec2; 1];

pub struct Cell<'world> {
    pub positions: &'world mut [Vec2],
    pub velocities: &'world [Vec2],
    pub workgroup: &'world mut Workgroup,
}

impl Cell<'_> {
    pub fn physics_for_cell(&mut self) {
        self.workgroup[0] = self.velocities[0];
        self.positions[0] = self.workgroup[0];
    }
}

#[spirv(compute(threads(1)))]
pub fn main(
    #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] positions: &mut [Vec2],
    #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] velocities: &[Vec2],
    #[spirv(workgroup)] workgroup: &mut Workgroup,
) {
    let mut cell = Cell {
        positions,
        velocities,
        workgroup,
    };

    cell.physics_for_cell();
}

And so the validation error now is:

Type [7] '' is invalid:
        Expected data type, found [3]

How do I dump the Naga representation? Would that be an internal WGSL version? Here's the GLSL version from spirv-cross (I don't know if the variable/type numbers match up with Naga's?). Anyway, looking at this version, type 7 could be the workgroup type: shared vec2 _7[1];. But for some reason my hunch is that the problem is the struct in struct in type 6, therefore: struct _6 { _5 _m0 ...

GLSL:

#version 450
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

struct _5
{
    vec2 _m0[];
    uint _m1;
};

struct _6
{
    _5 _m0;
    _5 _m1;
    vec2 _m2[1];
};

layout(binding = 0, std430) buffer _9_3
{
    vec2 _m0[];
} _3;

layout(binding = 1, std430) readonly buffer _9_4
{
    vec2 _m0[];
} _4;

shared vec2 _7[1];

void main()
{
    if (0u < uint(_4._m0.length()))
    {
        _7[0u] = _4._m0[0u];
        if (0u < uint(_3._m0.length()))
        {
            _3._m0[0u] = _7[0u];
        }
        else
        {
        }
    }
    else
    {
    }
}

And here's the SPIR-V:

; SPIR-V
; Version: 1.3
; Generator: Google rspirv; 0
; Bound: 56
; Schema: 0
               OpCapability Shader
               OpMemoryModel Logical Simple
               OpEntryPoint GLCompute %1 "main"
               OpExecutionMode %1 LocalSize 1 1 1
               OpDecorate %_runtimearr_v2float ArrayStride 8
               OpDecorate %_struct_9 Block
               OpMemberDecorate %_struct_9 0 Offset 0
               OpDecorate %3 Binding 0
               OpDecorate %3 DescriptorSet 0
               OpDecorate %4 NonWritable
               OpDecorate %4 Binding 1
               OpDecorate %4 DescriptorSet 0
               OpMemberDecorate %_struct_5 0 Offset 0
               OpMemberDecorate %_struct_5 1 Offset 4
               OpDecorate %_arr_v2float_uint_1 ArrayStride 8
               OpMemberDecorate %_struct_6 0 Offset 0
               OpMemberDecorate %_struct_6 1 Offset 8
               OpMemberDecorate %_struct_6 2 Offset 16
       %void = OpTypeVoid
         %12 = OpTypeFunction %void
      %float = OpTypeFloat 32
    %v2float = OpTypeVector %float 2
%_runtimearr_v2float = OpTypeRuntimeArray %v2float
%_ptr_StorageBuffer__runtimearr_v2float = OpTypePointer StorageBuffer %_runtimearr_v2float
  %_struct_9 = OpTypeStruct %_runtimearr_v2float
%_ptr_StorageBuffer__struct_9 = OpTypePointer StorageBuffer %_struct_9
          %3 = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer
       %uint = OpTypeInt 32 0
     %uint_0 = OpConstant %uint 0
          %4 = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer
  %_struct_5 = OpTypeStruct %_ptr_StorageBuffer__runtimearr_v2float %uint
     %uint_1 = OpConstant %uint 1
%_arr_v2float_uint_1 = OpTypeArray %v2float %uint_1
%_ptr_Workgroup__arr_v2float_uint_1 = OpTypePointer Workgroup %_arr_v2float_uint_1
  %_struct_6 = OpTypeStruct %_struct_5 %_struct_5 %_ptr_Workgroup__arr_v2float_uint_1
          %7 = OpVariable %_ptr_Workgroup__arr_v2float_uint_1 Workgroup
       %bool = OpTypeBool
%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
          %1 = OpFunction %void None %12
         %25 = OpLabel
         %26 = OpAccessChain %_ptr_StorageBuffer__runtimearr_v2float %3 %uint_0
         %27 = OpArrayLength %uint %3 0
         %28 = OpAccessChain %_ptr_StorageBuffer__runtimearr_v2float %4 %uint_0
         %29 = OpArrayLength %uint %4 0
         %53 = OpCompositeConstruct %_struct_5 %26 %27
         %54 = OpCompositeConstruct %_struct_5 %28 %29
         %55 = OpCompositeConstruct %_struct_6 %53 %54 %7
         %36 = OpULessThan %bool %uint_0 %29
               OpSelectionMerge %37 None
               OpBranchConditional %36 %38 %39
         %38 = OpLabel
         %41 = OpInBoundsAccessChain %_ptr_StorageBuffer_v2float %28 %uint_0
         %42 = OpLoad %v2float %41
         %43 = OpInBoundsAccessChain %_ptr_Workgroup_v2float %7 %uint_0
               OpStore %43 %42
         %45 = OpLoad %v2float %43
         %47 = OpULessThan %bool %uint_0 %27
               OpSelectionMerge %48 None
               OpBranchConditional %47 %49 %50
         %49 = OpLabel
         %52 = OpInBoundsAccessChain %_ptr_StorageBuffer_v2float %26 %uint_0
               OpStore %52 %45
               OpBranch %48
         %50 = OpLabel
               OpBranch %48
         %48 = OpLabel
               OpBranch %37
         %39 = OpLabel
               OpBranch %37
         %37 = OpLabel
               OpReturn
               OpFunctionEnd

I originally posted this as a discussion at #6361

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions