我在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
时,我从驱动程序收到以下错误:
生成了GL_INVALID_OPERATION错误。价值无效;预期GL_INT或GL_UNSIGNED_INT64_NV。
但我希望得到这样的错误:
生成了GL_INVALID_OPERATION错误。 'location'无效。
因为如果我没有设置SOME_SPECIAL_CASE
预处理器标志,那么没有这样的索引(0)的位置。然后我决定检查我有什么制服,这需要GL_INT
或GL_UNSIGNED_INT64_NV
,所以我根据它的位置查询统一名称(零):
char buff[20];
GLsizei len = 0;
glGetActiveUniformName(prog.progHandle, 0, 20, &len, buff);
并得到名称'colorTex',这是具有绑定索引DIFFUSE_TEX_UNIT
的sampler2D uniform的名称,也是零。直到现在,我相信统一的位置和绑定点不使用相同的索引,我仍然认为它们没有,因为否则这个着色器,当使用SOME_SPECIAL_CASE
活动编译时会失败,以及我通过我的工作历史编写的许多其他着色器。当我设置不存在的统一位置时,为什么sampler2D统一绑定索引受到影响,看起来完全奇怪,我也使用特定类型(GLSL - uint)
glProgramUniform1ui(prog, location, (GLuint)value);
这也与sampler2D的类型不匹配(因此错误至少与类型不匹配有关)。这是驱动程序错误吗?
还有一件事,我试图检查docs,如果绑定和位置索引真的重叠,并发现此声明:
将相同的统一位置分配给同一着色器或同一程序中的两个制服是非法的。即使这两个制服具有相同的名称和类型,并且在不同的着色器阶段中定义,但明确地为它们分配相同的统一位置是不合法的。将发生链接器错误。
这绝对是错的!多年来我一直这样做。在阅读完这些内容之后又尝试了这一点。具有相同的均匀性,在顶点和片段着色器中具有相同的位置编译并且工作正常。
我的设置:
关于在相同位置使用相同制服的能力,至少在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;
}
这是驱动程序错误吗?
没有.glGetActiveUniformName
采用统一的指数,而不是统一的地点。无法从着色器设置索引;它们只是所有统一变量,从0到活动制服的数量。指数仅用于introspecting properties of uniforms。
没有办法统一位置并要求统一变量的统一索引(或名称)。
但我希望得到这样的错误:...因为如果我没有设置SOME_SPECIAL_CASE预处理器标志,那么没有这样的索引(0)的位置。
当然有。不使用显式位置的统一变量永远不会具有与具有显式位置的统一变量相同的位置。然而,这不是这里发生的事情。
如果没有定义SOME_SPECIAL_CASE
,那么u_blendMode
的声明就不存在了。由于位置0从未被显式统一变量使用,因此现在可用于隐式位置分配。
因此,实现可以将colorTex
的位置指定为零(请注意,这与将binding
指定为零不同)。
如果要始终保留位置0,那么即使您从未使用过u_blendMode
声明也必须始终可见。该规范允许实现仍然优化掉这样的声明,但显式位置本身没有被优化掉。因此,如果您使用location = 0
作为未使用的制服,则位置0可能是也可能不是有效位置。但如果它有效,它将始终引用u_blendMode
。
关于在相同位置使用相同制服的能力,至少在NVIDIA GPU上,以下编译并运行良好:
......好吧,这里似乎有一个很大的规格矛盾。一方面,这似乎是彻头彻尾的禁止:
程序中没有两个默认块统一变量可以具有相同的位置,即使它们未被使用,否则将生成编译时或链接时错误。
另一方面,似乎完全允许:
着色器中的制服在链接到程序或可分离程序时都共享一个全局名称空间。因此,所有静态使用的具有相同名称的统一变量的类型,初始值设定项和任何位置说明符必须匹配链接到单个程序的所有着色器。
强调补充说。
在紧握的手上,强调文本仅在GLSL 4.60中添加;你不会在早期的GLSL版本中找到它,也不会在ARB_explicit_uniform_location本身找到它。
所以说实话......我不知道这是什么意思。因此我提交了一份OpenGL specification bug on it。