【发布时间】:2013-09-01 10:54:45
【问题描述】:
我的 9600GT 讨厌我。
片段着色器:
#version 130
uint aa[33] = uint[33](
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0
);
void main() {
int i=0;
int a=26;
for (i=0; i<a; i++) aa[i]=aa[i+1];
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}
如果a=25 程序以 3000 fps 运行。
如果a=26 程序以 20 fps 运行。
如果aa
视口大小为 1000x1000。
仅当aa 的大小>32 时才会出现问题。a 的值作为阈值随循环内对数组的调用而变化(aa[i]=aa[i+1]+aa[i-1] 给出不同的截止日期)。
我知道gl_FragColor 已被弃用。但这不是问题。
我的猜测是,如果 a>25 和 size(aa)>32,GLSL 不会自动展开循环。为什么。之所以依赖于数组的大小,是人类不知道的。
此处解释了一个非常相似的行为:
http://www.gamedev.net/topic/519511-glsl-for-loops/
手动展开循环确实可以解决问题 (3000 fps),即使 aa 大小>32:
aa[0]=aa[1];
aa[1]=aa[2];
aa[2]=aa[3];
aa[3]=aa[4];
aa[4]=aa[5];
aa[5]=aa[6];
aa[6]=aa[7];
aa[7]=aa[8];
aa[8]=aa[9];
aa[9]=aa[10];
aa[10]=aa[11];
aa[11]=aa[12];
aa[12]=aa[13];
aa[13]=aa[14];
aa[14]=aa[15];
aa[15]=aa[16];
aa[16]=aa[17];
aa[17]=aa[18];
aa[18]=aa[19];
aa[19]=aa[20];
aa[20]=aa[21];
aa[21]=aa[22];
aa[22]=aa[23];
aa[23]=aa[24];
aa[24]=aa[25];
aa[25]=aa[26];
aa[26]=aa[27];
aa[27]=aa[28];
aa[28]=aa[29];
aa[29]=aa[30];
aa[30]=aa[31];
aa[31]=aa[32];
aa[32]=aa[33];
【问题讨论】:
-
@NicolBolas 为什么当 a=26 帧率急剧下降?
-
唯一知道这一点的人是实现了您的 OpenGL 编译器的人。
-
是否有类似 #pragma optionNV(unroll none) 之类的命令强制 opengl 始终执行展开?
-
@user2464424:是的,NV 确实有很多专有的 GLSL
#pragma指令。展开循环是这些指令之一。您想要的特定非便携式编译指示是#pragma optionNV (unroll all)。通常最好自己展开这些东西,因为 AMD/Intel/... 不知道#pragma是什么。每个供应商实现自己的编译器的乐趣 - 我有点喜欢 HLSL 的一件事,微软实现了唯一的编译器,所以那里的一切都非常一致。 -
我预计速度差异主要是由于循环代码在展开后全部被消除(如果未展开则不会被消除),而不是由于循环开销。如果您将循环替换为无法消除死代码或恒定折叠到几乎没有的东西,我希望您不会看到展开代码和非展开代码之间的速度差异很大......
标签: opengl glsl fragment-shader loop-unrolling