我在 SSBO 中遇到了变量的奇怪问题。
我有以下结构,其中包含传递给 SSBO 的变量:
struct {
glm::mat4 modelViewMatrix{1};
ViewRenderTypeEnum type{};
glm::vec4 colorStatic{};
} modelSettings;
在哪里,
enum ViewRenderTypeEnum { VIEW_RENDER_TEXT, VIEW_RENDER_CLASSIC, VIEW_RENDER_GRADIENT };
以下是来自 NVIDIA Nsight 的帧事件:
这里是顶点和片段着色器:
//Vertex shader
#version 430
const int TEXT = 0;
const int GUI_SIMPLE_COLOR = 1;
const int GUI_GRADIENT_COLOR = 2;
layout (location = 0) in vec2 vertexIn;
layout (location = 1) in vec2 uvIn;
layout (location = 2) in vec4 colorsIn;
layout(std430, binding = 0) buffer ProgramWideSettings {
mat4 viewProjMatrix;
};
layout(std430, binding = 1) buffer ModelWideSettings {
mat4 modelViewMatrix;
int type;
vec4 colorStatic;
};
out vec2 uvVS;
out vec4 colorVS;
void main() {
gl_Position = viewProjMatrix * modelViewMatrix * vec4(vertexIn, 0.0, 1.0);
switch (type){
case TEXT:{
uvVS = uvIn;
colorVS = colorStatic;
break;
}
case GUI_SIMPLE_COLOR:{
colorVS = colorStatic;
break;
}
case GUI_GRADIENT_COLOR:{
colorVS = colorsIn;
break;
}
}
//colorVS = colorStatic;//Debug output
}
//Fragment shader
#version 430
const int TEXT = 0;
const int GUI_SIMPLE_COLOR = 1;
const int GUI_GRADIENT_COLOR = 2;
layout(std430, binding = 1) buffer ModelWideSettings {
mat4 modelViewMatrix;
int type;
vec4 colorStatic;
};
uniform sampler2D text;
in vec2 uvVS;
in vec4 colorVS;
out vec4 colorOut;
void main() {
switch (type){
case TEXT:{
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, uvVS).r);
colorOut = colorVS * sampled;
break;
}
default :{
colorOut = colorVS;
}
}
//colorOut = colorVS;//Debug output
}
当尝试在着色器和结构中使用此变量顺序进行渲染时,Nsight 显示 SSBO 中没有 colorStatic 变量:
几何图形(两个三角形)在这种情况下不可见,但 Nsight 报告它实际显示。但是如果我在最后一行的顶点着色器中硬编码白色,我可以看到两个白色三角形。
如果我以这种方式重新排序着色器和结构中的变量
struct {
glm::mat4 modelViewMatrix{1};
glm::vec4 colorStatic{};
ViewRenderTypeEnum type{};
} modelSettings;
然后 Nsight 会显示正确的 SSBO 内容
我会看到我的三角形。
所以,我有几个问题: 变量的顺序真的很重要吗?如果是这样,我必须使用哪个顺序以及当我更改它时 OpenGL 中会发生什么?如果没有,你能帮我解决这个奇怪的行为吗?
enum
的大小由 决定
enum
或
enum class name : type
您的
enum
属于第一类,可能比 int
小。使用明确大小的整数,如 int32_t
或 class enum … : int32_t
,以便主机和 GPU 端使用相同的结构布局。
顺序在某种意义上是相关的,因为声明中的顺序也将定义内存中字段的顺序。
Nsight 在第一种情况下不会显示您的
colorStatic
字段,因为它不存在于缓冲区中。使用您的原始布局,根据 std430
对齐规则,您的结构在内存中为 96 字节,但您提供的缓冲区仅为 84 字节,因此最后一个成员甚至没有在内存中提供并且您正在运行进入未定义的行为.
如果你像你一样重新排序元素,std430 对齐规则将不会添加任何进一步的填充(假设你的枚举类型与 32 位整数兼容,正如@datenwolf 指出的那样)并且该结构将在内存中为 84 字节。
这只是忽略
std430
实际含义的典型案例的另一个例子......