我要写的问题只能通过某些硬件和驱动程序来重现。
我设法在带有399.24驱动程序的GeForce GTX 760和带有416.34的GeForce 950M上重现了它。使用390.87驱动程序的GTX650上不会出现此问题。所有这些GPU的GL_MAX_VERTEX_UNIFORM_VECTORS返回1024,因此我在顶点着色器中将1000硬编码为vec4数组大小。
我尝试编译并链接以下着色器程序。
顶点着色器:
#version 330
uniform vec4 vs[1000];
uniform sampler2D tex;
void main()
{
gl_Position = vs[42];
//gl_Position += texture(tex, vs[0].xy); // (1)
}
片段着色器:
#version 330
out vec4 outFragColor;
void main()
{
outFragColor = vec4(0.0);
}
注释行(1)一切都很好,因此tex
采样器已被优化。但是,如果我们取消注释,则链接失败并显示以下日志:
-----------
Internal error: assembly compile error for vertex shader at offset 427:
-- error message --
line 16, column 9: error: invalid parameter array size
line 20, column 16: error: out of bounds array access
line 22, column 30: error: out of bounds array access
-- internal assembly text --
!!NVvp5.0
OPTION NV_internal;
OPTION NV_gpu_program_fp64;
OPTION NV_bindless_texture;
Error: could not link.
# cgc version 3.4.0001, build date Oct 10 2018
# command line args:
#vendor NVIDIA Corporation
#version 3.4.0.1 COP Build Date Oct 10 2018
#profile gp5vp
#program main
#semantic vs
#semantic tex
#var float4 gl_Position : $vout.POSITION : HPOS : -1 : 1
#var float4 vs[0] : : c[0], 1000 : -1 : 1
#var ulong tex : : c[1000] : -1 : 1
PARAM c[2002] = { program.local[0..2001] };
TEMP R0;
LONG TEMP D0;
TEMP T;
PK64.U D0.x, c[1000];
TEX.F R0, c[0], handle(D0.x), 2D;
ADD.F result.position, R0, c[42];
END
# 3 instructions, 1 R-regs, 1 D-regs
在这里,我们看到数组的寄存器为0..999,采样器的寄存器为1000。除第PARAM c[2002] = { program.local[0..2001] };
行外,任何地方都未引用大于1000的元素。
进一步的数组大小实验表明2002年不是一个常数,而是所需寄存器数量的两倍。
我remember那个
OpenGL的实现被允许拒绝着色器 实施相关的原因。
那么,有没有一种解决方法可以在顶点着色器中使用所有可用的寄存器以及采样器?
如果没有,这种行为背后的原理可能是什么?显然,此着色器不使用任何寄存器来获得临时计算结果。
着色器编译器中的优化不正确吗?
UPD:一个快速复制的示例是here。
UPD2:Webgl repro,具有解决方法说明。