对齐 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 节)
- 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 个字节。因此,data
和pos
之间必须插入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
具有相同的大小。
我正在展平一个八叉树并使用 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 节)
- 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 个字节。因此,data
和pos
之间必须插入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
具有相同的大小。