对齐 SSBO 的内存,它是包含数组的结构数组?

Aligning memory of SSBO that is an array of structs containing an array?

我正在展平一个八叉树并使用 SSBO 将它发送到我的片段着色器,我相信我 运行 遇到了一些内存对齐问题。我正在使用 std430 进行布局并将体素矢量绑定到此 SSBO 这是我着色器中的结构。我正在使用 GLSL 4.3 FYI

struct Voxel
{
    bool data;   // 4
    vec4 pos;    // 16
    vec4 col;    // 16
    float size;  // 4
    int index;   // 4
    int pIndex;  // 4
    int cIdx[8]; // 4, 16 or 32 bytes?
};

layout (std430, binding=2) buffer octreeData
{
    Voxel voxels[];
};

我不是 100% 确定,但我认为我 运行 遇到了使用结构内部的 int cIdx[8] 数组的问题,查看 the spec(第 124 页,第 7.6 节)

  1. If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array element, according to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The array may have padding at the end; the base offset of the member following the array is rounded up to the next multiple of the base alignment.

我不完全确定对齐方式是什么,我知道vec4占用16字节的内存,但我的数组有多少?如果它只是 sizeof(int)*8 那将是 32,但它说它被设置为单个数组元素的大小然后四舍五入到一个 vec4 对吧?那么这是否意味着我的 cIdx 数组具有 16 个字节的基本对齐方式?没有后续成员所以是否有填充添加到我的结构中?

所以总结构内存 = 52 字节(如果我们只为 cIdx 分配 4 个字节),这是否意味着我需要添加 12 个字节的填充,这可能会导致我出现问题?如果它分配 16 个字节,那么该结构总共需要 64 个字节并且没有内存对齐问题吗?

我对应的c++结构

struct Voxel
{
    bool data;
    glm::vec4 pos;
    glm::vec4 col;
    float size;
    int index;
    int pIndex;
    int cIdx[8];
};

然后我将填写我的 std::vector<Voxel> 并像这样将它传递给我的着色器

 glGenBuffers(1, &octreeSSBO);
 glBindBuffer(GL_SHADER_STORAGE_BUFFER, octreeSSBO);
 glBufferData(GL_SHADER_STORAGE_BUFFER, voxelData.size()*sizeof(Voxel), voxelData.data(), GL_DYNAMIC_DRAW);
 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, octreeSSBO);

直接从 voxelData 向量中读取,我可以确认数据已正确填写,我什至偶尔可以看到数据正在传递给着色器,但与我的相比表现不正确期望根据我正在查看的值看到。

这里似乎存在内存对齐问题?

I'm not entirely sure what the alignment is

关于事物的基本对齐方式,规范非常清楚。您的问题不在第 4 项中(std430 不执行第 4 项中指定的舍入)。

您的问题在#2:

If the member is a two- or four-component vector with components consuming N basic machine units, the base alignment is 2N or 4N, respectively.

在 GLSL 中,vec4 的基对齐为 16。这意味着任何 vec4 必须 分配在 16 字节边界上。

pos 必须位于 16 字节边界上。但是,data 只有 4 个字节。因此,datapos之间必须插入12个字节的padding以满足std430的对齐要求。

然而,glm::vec4 的 C++ 对齐为 4。因此 C++ 编译器 不会 data 和 [=14 之间插入一堆填充=].因此,两种语言的类型不一致。

您应该使用 C++11 的 alignas 关键字显式对齐要匹配 GLSL 的 C++ 结构中的所有 GLM 向量:

struct Voxel
{
    bool data;
    alignas(16) glm::vec4 pos;
    alignas(16) glm::vec4 col;
    float size;
    int index;
    int pIndex;
    int cIdx[8];
};

此外,我不会假设 C++ 类型 bool 和 GLSL 类型 bool 具有相同的大小。