Шейдер GLSL не разворачивает цикл при необходимости

мой 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 кадров в секунду.
Если a=26 программа работает на 20 кадров в секунду.
Если размер aa Размер окна просмотра 1000x1000.
Проблема возникает только при размере aa is > 32.
Значение a поскольку порог изменяется с вызовами массива внутри цикла (aa[i]=aa[i+1]+aa[i-1] дает иной срок).
Я знаю gl_FragColor is не одобрять. Но дело не в этом.

Я предполагаю, что GLSL не разворачивает автоматически цикл, если a>25 и размер (aa)>32. Почему?. Причина, по которой это зависит от размера массива, неизвестна человечеству.

довольно похожее поведение объясняется здесь:
http://www.gamedev.net/topic/519511-glsl-for-loops/

размотка петли вручную решает проблему (3000 кадров в секунду), даже если 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];

1 ответов


Я просто помещаю в обобщающий ответ комментариев здесь, так что это больше не отображается как без ответа.

" #pragma optionNV (развернуть все)"

исправлена непосредственная проблема с nvidia.

в целом, однако, компиляторы GLSL очень зависят от реализации. Причина, по которой есть падение ровно 32, легко объясняется попаданием эвристики компилятора, такой как "не разворачивайте циклы дольше 32". Также огромная скорость разница может исходить из развернутого цикла с использованием констант, в то время как динамический цикл потребует адресуемой памяти массива. Другая причина может заключаться в том, что при развертывании мертвого кода происходит постоянное сворачивание, сводящее весь цикл к нулю.

самый портативный способ исправить это действительно ручное развертывание или даже лучше ручное постоянное складывание. Всегда сомнительно вычислять константы в шейдере фрагментов, которые могут быть вычислены снаружи. Некоторые водители могут поймать его в некоторых случаях, но лучше не полагаться на это.