Индексация массива с переменной цикла во фрагментном шейдере на устройствах Android

Я пишу коды шейдеров в фреймворке GPUImage в Android. Затем я сталкиваюсь с проблемой индексации массива во фрагментном шейдере.

Согласно Приложению к языку затенения OpenGL ES, в вершинном шейдере юниформ-массивы могут быть проиндексированы. любым целым числом, а переменные массивы могут быть проиндексированы выражением постоянного индекса. Во фрагментном шейдере оба массива (однородный/переменный) могут быть проиндексированы только выражением постоянного индекса. В соответствии с определением выражения постоянного индекса индекс цикла for должен использоваться как индекс массива.

Однако что-то идет не так, когда я использую индекс цикла в качестве индекса массива во фрагментном шейдере. Ошибки компиляции нет, и коды шейдеров можно запускать, но кажется, что программа обрабатывает все значения индекса равными 0 в каждом раунде цикла.

Вот мои коды фрагментных шейдеров:

uniform sampler2D inputImageTexture;
uniform highp float sample_weights[9]; // passed by glUniform1fv
varying highp vec2 texture_coordinate;
varying highp vec2 sample_coordinates[9]; // computed in the vertex shader
...
void main()
{
    lowp vec3 sum = vec3(0.0);
    lowp vec4 fragment_color = texture2D(inputImageTexture, texture_coordinate);
    for (int i = 0; i < 9; i++)
    {
        sum += texture2D(inputImageTexture, sample_coordinates[i]).rgb * sample_weights[i];
    }
    gl_FragColor = vec4(sum, fragment_color.a);
}

Результат будет правильным, если я разверну цикл и получу доступ от [0] до [8] для массивов. Однако при использовании индекса цикла результат неверен и становится таким же, как при запуске

sum += texture2D(inputImageTexture, sample_coordinates[0]).rgb * sample_weights[0];

в 9 раз, и во время процесса не сообщается об ошибке компиляции.

Я протестировал только одно устройство — Nexus 7 с Android версии 4.3. Фреймворк GPUImage использует android.opengl.GLES20, но не GLES30.

Является ли это дополнительным ограничением на коды шейдеров в устройствах Android или в OpenGL ES 2.0, или это проблема, зависящая от устройства?

Обновлено: после тестирования большего количества устройств Android (4.1–4.4) оказалось, что эта проблема возникает только на устройстве Nexus 7. Результаты на других устройствах правильные. Это странно. Является ли это проблемой реализации на отдельных устройствах?


person Mark    schedule 22.07.2014    source источник


Ответы (1)


Это малоизвестный факт, но поиск текстур внутри циклов — неопределенная вещь в GLSL. В частности, крошечное предложение: «Производные не определены в неоднородном потоке управления», см. раздел 8.9 спецификации GLSL ES. И см. раздел 3.9.2, чтобы узнать, что не равномерный поток управления. То, что это работает на других устройствах, случайно.

К сожалению, ваш единственный вариант может заключаться в том, чтобы развернуть цикл.

person ashleysmithgpu    schedule 26.07.2014
comment
Вы также можете изменить texture2D() на texelFetch(), однако это только ES 3.0, и вы не указали, используете ли вы ES 2.0 или ES 3.0, и вам нужно будет использовать фильтрацию GL_NEAREST. Это потому, что этой функции не нужны производные для фильтрации текстуры. - person ashleysmithgpu; 26.07.2014