SSBO CPU 映射返回正确数据,但数据 'different' 到 GPU 上的 SSBO
SSBO CPU mapping returning correct data, but data is 'different' to the SSBO on GPU
我 运行 在尝试按如下方式使用 SSBO 时遇到问题:
GLuint lightSSBO;
glGenBuffers(1, &lightSSBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, lightSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int) + sizeof(LightData) * 10, NULL, GL_DYNAMIC_DRAW);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &lightCount);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(int), sizeof(LightData) * lights.size(), &lights[0]);
void* ptr = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
std::cout << "lightCount value = " << *(int*)ptr << "\n";
std::cout << "First Light: \n";
ptr = (int*)ptr + 1;
std::cout << "\tType: " << *(unsigned int*)ptr << "\n";
ptr = (int*)ptr + 1;
std::cout << "\tPosition: " << vec4ToString((glm::vec4*)ptr) << "\n";
ptr = (float*)ptr + 4;
std::cout << "\tDirection: " << vec4ToString((glm::vec4*)ptr) << "\n";
ptr = (float*)ptr + 4;
std::cout << "\tColour: " << vec4ToString((glm::vec4*)ptr) << "\n";
ptr = (float*)ptr + 4;
std::cout << "\tSize: " << *(float*)ptr << "\n";
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
在上面的代码摘录中,ptr 输出我分配给 lightCount 和 lights[0] 的正确值,这意味着缓冲区表面上具有正确的数据。但是,当我尝试在 GPU (Lights[0]) 上访问超过 lightCount 时,我得到了不正确的值。例如,Lights[0].Colour 只是 returns (0,0,0,?),尽管通过上面的 ptr 正确显示为 (1,0.2,0.2,1)。
struct LightData
{
uint Type;
vec4 Position;
vec4 Direction;
vec4 Colour;
float Size;
};
layout (std430, binding = 0) buffer LightBuffer
{
int LightCount;
LightData[] Lights;
};
void main()
{
FragColor = Lights[0].Colour;
}
以及控制台的完整性输出:(正确的值)
lightCount value = 1
First Light:
Type: 1
Position: 0.000000, 0.000000, 0.000000, 1.000000
Direction: -0.707107, 0.000000, -0.707107, 1.000000
Colour: 1.000000, 0.200000, 0.200000, 1.000000
Size: 0
注意:将着色器颜色更改为 Position 仍然 不正确并且如果我更改基础数据也不会更改,这表明 Light 阵列要么没有做到GPU 或我以某种方式错误地访问它。
有谁知道为什么会这样?此外,我对 glBufferData 的最终 GLenum 参数的 meaning/options 感到困惑,甚至 https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_shader_storage_buffer_object.txt 似乎也没有提到它。
GLSL 结构和 C++ 结构有不同的对齐规则。对于结构,规范规定:
If the member is a structure, the base alignment of the structure is N, where
N is the largest base alignment value of any of its members, and rounded
up to the base alignment of a vec4. The individual members of this substructure are then assigned offsets by applying this set of rules recursively,
where the base offset of the first member of the sub-structure is equal to the
aligned offset of the structure. The structure may have padding at the end;
the base offset of the member following the sub-structure is rounded up to
the next multiple of the base alignment of the structure.
我们来分析结构:
struct LightData
{
uint Type;
vec4 Position;
vec4 Direction;
vec4 Colour;
float Size;
};
最大的成员是一个vec4(=16字节对齐)。这意味着整个结构也需要对齐到 16 个字节。该结构的成员大小为 4 + 3 * 16 + 4 = 56 字节。 16 的下一个更大的倍数是 64,这意味着所有结构都需要在末尾额外填充 8 个字节。
由于在第一个结构之前有一个额外的成员int LightCount;
,您还需要在它们之间添加填充以确保第一个结构从 16 字节偏移量开始。
与您的 glsl 缓冲区定义相匹配的 C++ 结构应如下所示:
struct LightData
{
unsigned int Type;
vec4 Position;
vec4 Direction;
vec4 Colour;
float Size;
int padding[2];
}
struct Buffer
{
int LightCount;
int padding[3];
Light Lights[NUM_LIGHTS];
}
我 运行 在尝试按如下方式使用 SSBO 时遇到问题:
GLuint lightSSBO;
glGenBuffers(1, &lightSSBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, lightSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int) + sizeof(LightData) * 10, NULL, GL_DYNAMIC_DRAW);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &lightCount);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(int), sizeof(LightData) * lights.size(), &lights[0]);
void* ptr = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
std::cout << "lightCount value = " << *(int*)ptr << "\n";
std::cout << "First Light: \n";
ptr = (int*)ptr + 1;
std::cout << "\tType: " << *(unsigned int*)ptr << "\n";
ptr = (int*)ptr + 1;
std::cout << "\tPosition: " << vec4ToString((glm::vec4*)ptr) << "\n";
ptr = (float*)ptr + 4;
std::cout << "\tDirection: " << vec4ToString((glm::vec4*)ptr) << "\n";
ptr = (float*)ptr + 4;
std::cout << "\tColour: " << vec4ToString((glm::vec4*)ptr) << "\n";
ptr = (float*)ptr + 4;
std::cout << "\tSize: " << *(float*)ptr << "\n";
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
在上面的代码摘录中,ptr 输出我分配给 lightCount 和 lights[0] 的正确值,这意味着缓冲区表面上具有正确的数据。但是,当我尝试在 GPU (Lights[0]) 上访问超过 lightCount 时,我得到了不正确的值。例如,Lights[0].Colour 只是 returns (0,0,0,?),尽管通过上面的 ptr 正确显示为 (1,0.2,0.2,1)。
struct LightData
{
uint Type;
vec4 Position;
vec4 Direction;
vec4 Colour;
float Size;
};
layout (std430, binding = 0) buffer LightBuffer
{
int LightCount;
LightData[] Lights;
};
void main()
{
FragColor = Lights[0].Colour;
}
以及控制台的完整性输出:(正确的值)
lightCount value = 1
First Light:
Type: 1
Position: 0.000000, 0.000000, 0.000000, 1.000000
Direction: -0.707107, 0.000000, -0.707107, 1.000000
Colour: 1.000000, 0.200000, 0.200000, 1.000000
Size: 0
注意:将着色器颜色更改为 Position 仍然 不正确并且如果我更改基础数据也不会更改,这表明 Light 阵列要么没有做到GPU 或我以某种方式错误地访问它。
有谁知道为什么会这样?此外,我对 glBufferData 的最终 GLenum 参数的 meaning/options 感到困惑,甚至 https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_shader_storage_buffer_object.txt 似乎也没有提到它。
GLSL 结构和 C++ 结构有不同的对齐规则。对于结构,规范规定:
If the member is a structure, the base alignment of the structure is N, where N is the largest base alignment value of any of its members, and rounded up to the base alignment of a vec4. The individual members of this substructure are then assigned offsets by applying this set of rules recursively, where the base offset of the first member of the sub-structure is equal to the aligned offset of the structure. The structure may have padding at the end; the base offset of the member following the sub-structure is rounded up to the next multiple of the base alignment of the structure.
我们来分析结构:
struct LightData
{
uint Type;
vec4 Position;
vec4 Direction;
vec4 Colour;
float Size;
};
最大的成员是一个vec4(=16字节对齐)。这意味着整个结构也需要对齐到 16 个字节。该结构的成员大小为 4 + 3 * 16 + 4 = 56 字节。 16 的下一个更大的倍数是 64,这意味着所有结构都需要在末尾额外填充 8 个字节。
由于在第一个结构之前有一个额外的成员int LightCount;
,您还需要在它们之间添加填充以确保第一个结构从 16 字节偏移量开始。
与您的 glsl 缓冲区定义相匹配的 C++ 结构应如下所示:
struct LightData
{
unsigned int Type;
vec4 Position;
vec4 Direction;
vec4 Colour;
float Size;
int padding[2];
}
struct Buffer
{
int LightCount;
int padding[3];
Light Lights[NUM_LIGHTS];
}