我从 AMD 下载了GPU ShaderAnalyzer并将以下 GLSL 程序输入其中:
uniform mat4 ModelViewMatrix;
attribute vec4 VertexPosition;
void doSomething1(void) {
gl_Position = ModelViewMatrix * VertexPosition;
}
void doSomething2(void) {
gl_Position = ModelViewMatrix * VertexPosition;
}
void main(void) {
doSomething1();
doSomething2();
}
这在从 Radeon HD 2400 到 Radeon HD 6970 的每张卡上产生了以下反汇编(或等效):
; -------- Disassembly --------------------
00 CALL_FS NO_BARRIER
01 ALU: ADDR(32) CNT(16) KCACHE0(CB0:0-15)
0 x: MUL ____, R1.w, KC0[3].w
y: MUL ____, R1.w, KC0[3].z
z: MUL ____, R1.w, KC0[3].y
w: MUL ____, R1.w, KC0[3].x
1 x: MULADD R127.x, R1.z, KC0[2].w, PV0.x
y: MULADD R127.y, R1.z, KC0[2].z, PV0.y
z: MULADD R127.z, R1.z, KC0[2].y, PV0.z
w: MULADD R127.w, R1.z, KC0[2].x, PV0.w
2 x: MULADD R127.x, R1.y, KC0[1].w, PV1.x
y: MULADD R127.y, R1.y, KC0[1].z, PV1.y
z: MULADD R127.z, R1.y, KC0[1].y, PV1.z
w: MULADD R127.w, R1.y, KC0[1].x, PV1.w
3 x: MULADD R1.x, R1.x, KC0[0].x, PV2.w
y: MULADD R1.y, R1.x, KC0[0].y, PV2.z
z: MULADD R1.z, R1.x, KC0[0].z, PV2.y
w: MULADD R1.w, R1.x, KC0[0].w, PV2.x
02 EXP_DONE: POS0, R1
03 EXP_DONE: PARAM0, R0.____
04 ALU: ADDR(48) CNT(1)
4 x: NOP ____
05 NOP NO_BARRIER
END_OF_PROGRAM
然后我在方法中注释掉了doSomething2()
函数及其调用main
。结果完全相同:AMD 工具中的每个着色器都优化了冗余数学。所以这个问题的答案是肯定的:在一般情况下,GLSL 编译器将足够聪明地执行这种优化,@nicol-bolas 在他的评论中指出的警告:编译器优化特定于每个编译器,并且有没有 100% 保证这对所有编译器都是正确的。当然,最安全的选择是尽可能自己执行此类优化——但很高兴知道,无论出于何种原因,您都无法做到这一点。
更新:我在 Cg(NVIDIA 的编译器之一)下编译了相同的程序,有和没有注释掉第二个函数调用,在这两种情况下它都产生了以下结果:
mul r0, v0.y, c1
mad r0, v0.x, c0, r0
mad r0, v0.z, c2, r0
mad oPos, v0.w, c3, r0
所以是的,NVIDIA 也对其进行了优化——或者至少,Cg 编译器做了。我发现Cg 编译的代码可以在 Intel GPU 上运行的说法,但这超出了我的专业范围,所以就这样吧。
如果有人想为此添加测试用例,请随意,但在这一点上,我觉得这个问题已经得到了适当的回答。