OpenGL ES 2.0 NVIDIA TEGRA 2 развертывание - PullRequest
2 голосов
/ 09 января 2012

У меня проблема с одним из моих новых шейдеров.

Когда я пробую шейдер на разных устройствах, шейдер компилируется и работает без проблем.

Когда я пробую его на NVIDIA TEGRA2 GPU, работает собственный код, я получаю следующую ошибку компиляции:

Шейдер не смог скомпилировать.Вершинный шейдер (0): ошибка C6002: превышен лимит команд 256;532 инструкции, необходимых для компиляции программы 86 строк, 1 ошибка.

Я думаю, что это из-за какого-то вида разворачивания компилятора gcg от NVIDIA, но я не могу понять, как решить эту ситуацию.

Теперь я попытался уменьшить тип операторов if / else, чтобы они не были if / else if, но представляли собой цепочку простых последовательных if (просто чтобы посмотреть, была ли проблема решена), но это не сработало.

Я попытался удалить все условия if, оставив только одно, и шейдер скомпилировался хорошо (хотя он не делает то, что мне действительно нужно).

Это код моего вершинного шейдера, просто фрагментный шейдерсодержит информацию о gl_color и хорошо компилируется.

void main(){

//Converto direttamente in int, cosi le divisioni dopo sono piu veloci
int_character_position = int(character_position);   

uniform_reference =  (int_character_position / 4);

uniform_reference_sub_item = int(mod(character_position,4.0));  

if(uniform_reference == 0) {        
    working_float = charsequence_1[uniform_reference][uniform_reference_sub_item];      
} else if(uniform_reference == 1) {     
    working_float = charsequence_1[uniform_reference][uniform_reference_sub_item];              
} else if(uniform_reference == 2) {
    working_float = charsequence_1[uniform_reference][uniform_reference_sub_item];
} else if(uniform_reference == 3) {
    working_float = charsequence_1[uniform_reference][uniform_reference_sub_item];
} else if(uniform_reference == 4) {
    working_float = charsequence_2[uniform_reference - 4][uniform_reference_sub_item];
} else if(uniform_reference == 5) {
    working_float = charsequence_2[uniform_reference - 4][uniform_reference_sub_item];
} else if(uniform_reference == 6) {
    working_float = charsequence_2[uniform_reference - 4][uniform_reference_sub_item];
} else if(uniform_reference == 7) {
    working_float = charsequence_2[uniform_reference - 4][uniform_reference_sub_item];
} else if(uniform_reference == 8) {
    working_float = charsequence_3[uniform_reference - 8][uniform_reference_sub_item];
} else if(uniform_reference == 9) {
    working_float = charsequence_3[uniform_reference - 8][uniform_reference_sub_item];
} else if(uniform_reference == 10) {
    working_float = charsequence_3[uniform_reference - 8][uniform_reference_sub_item];
} else if(uniform_reference == 11) {
    working_float = charsequence_3[uniform_reference - 8][uniform_reference_sub_item];
} else if(uniform_reference == 12) {
    working_float = charsequence_4[uniform_reference -12][uniform_reference_sub_item];
} else if(uniform_reference == 13) {
    working_float = charsequence_4[uniform_reference -12][uniform_reference_sub_item];
} else if(uniform_reference == 14) {
    working_float = charsequence_4[uniform_reference -12][uniform_reference_sub_item];
} else if(uniform_reference == 15) {
    working_float = charsequence_4[uniform_reference -12][uniform_reference_sub_item];
} else if(uniform_reference == 16) {
    working_float = charsequence_5[uniform_reference -16][uniform_reference_sub_item];
} else if(uniform_reference == 17) {
    working_float = charsequence_5[uniform_reference -16][uniform_reference_sub_item];
} else if(uniform_reference == 18) {
    working_float = charsequence_5[uniform_reference -16][uniform_reference_sub_item];
} else if(uniform_reference == 19) {
    working_float = charsequence_5[uniform_reference -16][uniform_reference_sub_item];
} else if(uniform_reference == 20) {
    working_float = charsequence_6[uniform_reference -20][uniform_reference_sub_item];
} else if(uniform_reference == 21) {
    working_float = charsequence_6[uniform_reference -20][uniform_reference_sub_item];
} else if(uniform_reference == 22) {
    working_float = charsequence_6[uniform_reference -20][uniform_reference_sub_item];
} else if(uniform_reference == 23) {
    working_float = charsequence_6[uniform_reference -20][uniform_reference_sub_item];
}                   
v_texCoord.y = a_texture.y;
v_texCoord.x = a_texture.x + ( 0.0105 * float(working_float));
gl_Position = myMVPMatrix * myVertex;   

1 Ответ

2 голосов
/ 10 января 2012

В реализациях OpenGL ES 2.0 обычно есть максимальное количество поддерживаемых инструкций, но API не требует минимального количества, так как это нецелесообразно.Реализация Nvidia Tegra компилирует источник в 532 инструкции, что превышает его максимальный предел.Единственная возможность (кроме изменения реализации OpenGL ES 2.0) - переписать шейдер, чтобы его можно было скомпилировать с меньшим количеством инструкций.

Не зная подробностей реализации Nvidia, оператор наподобие working_float = charsequence_6[uniform_reference -20][uniform_reference_sub_item];, в сочетании с ветвлением, в конечном итоге приводит к нескольким инструкциям (у вас есть вычитание, загрузка, сохранение и индексация массива).В целом ветвление часто проблематично, так как компилятор может не иметь возможности компилировать несколько инструкций для параллельного выполнения из-за разных потоков кода.

Ваш if - else if - else, если код довольно легко переписать, чтобыон может быть скомпилирован с меньшим количеством инструкций, но при этом имеет то же значение:

if(uniform_reference < 4) {        
    working_float = charsequence_1[uniform_reference][uniform_reference_sub_item];
} else if(uniform_reference < 8) {
    working_float = charsequence_2[uniform_reference - 4][uniform_reference_sub_item];
} else if(uniform_reference < 12) {
    working_float = charsequence_3[uniform_reference - 8][uniform_reference_sub_item];
} else if(uniform_reference < 16) {
    working_float = charsequence_4[uniform_reference -12][uniform_reference_sub_item];
} else if(uniform_reference < 20) {
    working_float = charsequence_5[uniform_reference -16][uniform_reference_sub_item];
} else if(uniform_reference < 24) {
    working_float = charsequence_6[uniform_reference -20][uniform_reference_sub_item];
}

Это может уже соответствовать пределу 256 инструкций.(В коде шейдера простое правило состоит в том, что зачастую размер кода GLSL просто определяет количество инструкций.) Если нет, то кажется, что вы можете заменить uniform_reference - {4,8,etc} на uniform_reference_sub_item, поскольку этов любом случае то же значение;это также сохранит несколько инструкций.В конечном счете, вы можете поместить значения charsequence_ [123456] в массив и проиндексировать его на основе shape_reference, деленного на константу, а также на последовательность символов, чтобы в итоге получилось что-то вроде этого:

working_float = charsequence[uniform_reference / 4][uniform_reference - uniform_reference_sub_item][uniform_reference_sub_item];

Возможно, вы также можете объединить два массива, индексированных uniform_reference и uniform_reference_sub_item, чтобы избавиться и от одного уровня индексации.

...