统一的显式位置和绑定点索引

Mic*_* IV 3 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)
Run Code Online (Sandbox Code Playgroud)

现在,当我将此着色器编译为程序而不声明 SOME_SPECIAL_CASE 并且u_blendMode在运行时仍然设置统一时,我从驱动程序收到以下错误:

生成了 GL_INVALID_OPERATION 错误。值无效;预期的 GL_INT 或 GL_UNSIGNED_INT64_NV。

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

生成了 GL_INVALID_OPERATION 错误。“位置”无效。

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

 char buff[20];
 GLsizei len = 0;
 glGetActiveUniformName(prog.progHandle, 0, 20, &len, buff);
Run Code Online (Sandbox Code Playgroud)

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

glProgramUniform1ui(prog, location, (GLuint)value);
Run Code Online (Sandbox Code Playgroud)

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

还有一件事,如果绑定和位置索引真的重叠,我尝试检查文档并发现以下语句:

在同一个着色器或同一个程序中为两个统一分配相同的统一位置是非法的。即使这两个uniform具有相同的名称和类型,并且在不同的着色器阶段定义,显式地为它们分配相同的uniform位置也是不合法的;将发生链接器错误。

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

我的设置:

  • NVIDIA Quadro P2000,驱动程序 419.17
  • OpenGL 4.5
  • 视窗 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); 
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

#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; 
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 5

是驱动程序错误吗?

glGetActiveUniformName采用统一索引,而不是统一位置。不能从着色器设置索引;它们只是所有的制服变量,从 0 到活动制服的数量。指数仅用于内省制服的属性

没有办法获取统一位置并要求统一变量的统一索引(或名称)。

但我希望得到这样的错误:...因为如果我不设置 SOME_SPECIAL_CASE 预处理器标志,则没有具有此类索引 (0) 的位置。

当然有。不使用显式的地点统一变量将永远不会有相同的位置作为一个统一的变量有明确的位置。然而,这不是这里发生的事情。

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

因此,实现可分配的位置colorTex为零(注意,这是不同的,从分配binding到零)。

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


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

GLSL 规范已经解决了这个问题,现在可以有两个相同的显式统一位置,只要这两个声明本身相同。所以跨着色器阶段的统一位置应该可以工作。