8

我的 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不出现 <=32 的大小问题。
视口大小为 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];
4

1 回答 1

7

我只是在此处对评论进行总结性回答,因此不再显示为未回答。

“#pragma optionNV(全部展开)”

修复了 nvidia 上的直接问题。

但总的来说,GLSL 编译器非常依赖于实现。恰好在 32 处下降的原因很容易通过点击编译器启发式来解释,例如“不要展开超过 32 的循环”。此外,巨大的速度差异可能来自使用常量的展开循环,而动态循环将需要可寻址的数组内存。另一个原因可能是,在展开死代码消除时,不断折叠会导致整个循环减少到零。

解决这个问题的最便携的方法是手动展开,甚至更好的手动恒定折叠。在片段着色器中计算可以在外部计算的常量总是有问题的。有些司机可能会在某些情况下抓住它,但最好不要依赖它。

于 2014-02-16T03:50:54.107 回答