opengl - 统一显式位置和绑定(bind)点索引

标签 opengl glsl

我在 GLSL 中遇到以下错误。这是片段着色器:

#version 450 core
#define DIFFUSE_TEX_UNIT   0
#define INDEX_UNIFORM_LOC  0

layout(binding  = DIFFUSE_TEX_UNIT)   uniform  sampler2D colorTex;

#ifdef SOME_SPECIAL_CASE

 layout (location = INDEX_UNIFORM_LOC) uniform uint u_blendMode;

 //...more code here related to the case

 #endif
 //... rest of the code(not important)

现在,当我在没有声明 SOME_SPECIAL_CASE 的情况下将此着色器编译到程序中,并且在运行时仍然设置 u_blendMode uniform 时,我从驱动程序中收到以下错误:

GL_INVALID_OPERATION error generated. value is invalid; expected GL_INT or GL_UNSIGNED_INT64_NV.

但我希望得到这样的错误:

GL_INVALID_OPERATION error generated. ' location ' is invalid.

因为如果我不设置 SOME_SPECIAL_CASE 预处理器标志,就没有这样一个索引 (0) 的位置。然后我决定检查我有什么制服,这需要 GL_INTGL_UNSIGNED_INT64_NV,所以我根据它的位置(零)查询制服名称:

 char buff[20];
 GLsizei len = 0;
 glGetActiveUniformName(prog.progHandle, 0, 20, &len, buff);

并得到名称“colorTex”,这是具有绑定(bind)索引 DIFFUSE_TEX_UNIT 的 sampler2D uniform 的名称,它也是零。 直到现在,我相信统一的位置和绑定(bind)点不使用相同的索引,我仍然相信它们不会,因为否则这个着色器,当使用 SOME_SPECIAL_CASE active 编译时会失败,以及许多其他着色器我已经写了我的工作历史。因此,当我设置不存在的统一位置时,为什么 sampler2D 统一绑定(bind)索引会受到影响,而且我还使用特定类型(GLSL - uint),这看起来非常奇怪

glProgramUniform1ui(prog, location, (GLuint)value);

这也不匹配 sampler2D 的类型(因此错误至少在类型不匹配方面是正确的)。 是驱动程序错误吗?

还有一件事,我试着 checkin docs如果绑定(bind)和位置索引确实重叠并发现此语句:

It is illegal to assign the same uniform location to two uniforms in the same shader or the same program. Even if those two uniforms have the same name and type, and are defined in different shader stages, it is not legal to explicitly assign them the same uniform location; a linker error will occur.

这是绝对错误的!多年来我一直这样做。并在阅读这些行后再次尝试。具有相同的制服,在顶点和片段着色器中具有相同的位置可以编译并正常工作。

我的设置:

  • NVIDIA Quadro P2000,驱动程序 419.17
  • OpenGL 4.5
  • Windows 10 64 位

关于在同一位置使用相同制服的能力,至少在 NVIDIA GPU 上,以下编译和运行良好:

顶点着色器

#version 450 core
#define MVP_UNIFORM_LOC 2

layout(location = 0)      in vec2 v_Position;
layout(location = MVP_UNIFORM_LOC) uniform mat4 u_MVP;
smooth out vec2 texCoord;
void main()
{
    texCoord = v_Position;
    gl_Position = u_MVP * vec4(v_Position,0.0,1.0); 
}

片段着色器:

#version 450 core
#define MVP_UNIFORM_LOC 2
#define TEX_MAP_UNIT 5

layout(binding  = TEX_MAP_UNIT ) uniform  sampler2D texMap;
layout(location = MVP_UNIFORM_LOC) uniform mat4 u_MVP;
smooth in  vec2 texCoord;
out vec4 OUTPUT;

 void main()
{
    vec4 tex = texture(texMap, texCoord);    
    OUTPUT =  u_MVP * tex; 
}

最佳答案

Is it a driver bug?

没有。 glGetActiveUniformName 采用统一的索引,而不是统一的位置。不能从着色器设置索引;它们只是所有制服变量,从 0 到事件制服的数量。索引仅用于 introspecting properties of uniforms .

无法获取统一位置并请求统一变量的统一索引(或名称)。

But I would expect to get an error like this: ... Because there is no location with such an index (0) if I don't set SOME_SPECIAL_CASE preprocessor flag.

当然有。不使用显式位置的统一变量永远不会与确实具有显式位置的统一变量具有相同的位置。 但是,这不是这里发生的事情。

如果未定义SOME_SPECIAL_CASE,则u_blendMode 的声明不存在。由于位置 0 从未被显式统一变量使用,它现在可用于隐式位置分配。

因此实现可以将 colorTex 的位置分配给零(请注意,这与将 binding 分配给零不同)。

如果您想始终保留位置 0,则 u_blendMode 的声明必须始终可见,即使您从未使用它。规范允许实现仍然优化掉这样的声明,但是显式位置本身 没有被优化掉。因此,如果您对未使用的制服使用 location = 0,则位置 0 可能是也可能不是有效位置。但如果有效,它将始终引用u_blendMode


Regarding the ability to use same uniform on same location,at least on NVIDIA GPU the following compiles and runs fine:

GLSL 规范已经解决了这个问题,它是 now OK to have two explicit uniform locations that are the same ,只要这两个声明本身是相同的。因此,跨着色器阶段的统一位置应该可以工作。

关于opengl - 统一显式位置和绑定(bind)点索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55750408/

相关文章:

c++ - 使用 glDrawElements 不绘制我的 .obj 文件

c++ - 在 cpack 输出中包含外部库

c++ - SDL2 OpengGL 抗锯齿无效

python - 如何将 C++ 或 GLM 结构表示为 numpy 数组?

opengl - imageAtomicCompSwap 文档和使用

c++ - 围绕相机旋转 opengl c++/设置旋转中心

c++ - 在哪里下载 opengl sdk(v.3 或 v.4)?

OpenGL/GLSL - 纹理过滤的实现

c++ - OpenGL 3.0 窗口碰撞检测

java - LibGDX:如何使用 OpenGL 2.0 实现平面着色外观?