Использование двух шейдеров вместо одного с операторами IF

Я работаю над портированием относительно большого источника ES 1.1 для ES 2.0.

В OpenGL ES 2.0 (что означает, что все использует шейдеры), я хочу рисовать чайник три раза.

  1. Первый, с однородным цветом (ala old glColor4f).

  2. Второй, с цветным вершин (у чайника есть свой массив вершинный цвет)

  3. Третий, с текстурой на вершине

  4. И, возможно, четвертый, с текстурой и цветом на вершине. А также то, возможно, пятый, с нормалями.

Есть два варианта, которые я имею в реализации, насколько я знаю. Первый заключается в создании шейдера, который поддерживает все вышеперечисленное, с униформой, которая настроена на изменение поведения (например, использовать единую цветовую униформу или единообразную цветовую единицу).

Второй выбор - создать другой шейдер для каждой ситуации. С некоторой предварительной предварительной обработкой шейдеров это не так сложно сделать, но проблема связана с производительностью при переключении шейдеров между объектами чертежа. Я читал, что это не тривиально мало.

Я имею в виду, что лучший способ сделать это - построить и то и другое, но было бы хорошо слышать любые входы.

9 голосов | спросил kamziro 20 J000000Saturday13 2013, 11:43:23

2 ответа


10

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

Худший случай с ветвлением будет выглядеть примерно так:

  • оцениваются обе стороны ветки.
  • команда «mix» или «step» будет сгенерирована компилятором шейдеров и вставлена ​​в ваш код, чтобы решить, какую сторону использовать.

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

Apple " Руководство по программированию OpenGL ES для iOS " (которое может быть принято как репрезентативное для вашего целевого оборудования), это говорит о ветвлении:

  

Избегать ветвления

     

Филиалы обескуражены в шейдерах, так как они могут уменьшить возможность параллельного выполнения операций на 3D-графических процессорах. Если ваши шейдеры должны использовать ветви, выполните следующие рекомендации:

     
  • Наилучшая производительность: ветвь на константе, известная при компиляции шейдера.
  •   
  • Допустимо: ветвь на равномерной переменной.
  •   
  • Потенциально медленный: Ветвление по значению, вычисленному внутри шейдера.
  •   

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

Даже если вы уверены, что находитесь в «приемлемом» слоте здесь, вам все равно нужно учитывать, что с 4 или 5 случаями для выбора между ними вы будете поднимать количество команд в ваших шейдерах. Вы должны знать ограничения количества инструкций на своем целевом оборудовании и убедиться, что вы не переходите их выше, ссылаясь снова на ссылку Apple выше:

  

Реализации OpenGL ES не требуется для реализации резервной копии программного обеспечения при превышении этих пределов; вместо этого шейдер просто не компилирует или не связывает.

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

ответил Maximus Minimus 20 J000000Saturday13 2013, 13:01:10
3

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

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

Кроме того, есть еще несколько способов сделать это: «Uber-shaders» и немного обманывают с помощью программ шейдера OpenGL.

«Убер-шейдеры» по сути являются первым выбором, минус ветвление, но у вас будет несколько шейдеров. Вместо использования операторов if вы используете препроцессор - #define, #ifdef, #else , #endif и скомпилировать разные версии, включая правильный #define для того, что вам нужно.

vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif

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

//ins, outs, uniforms

float getShadowCoefficient();

void main()
{
    //shading stuff goes here

    gl_FragColor = color * getShadowCoefficient();
}

Тогда у меня могло бы быть несколько других шейдерных файлов, которые определяют getShadowCoefficient(), необходимую униформу и ничего больше. Например, shadow_none.glsl содержит:

float getShadowCoefficient()
{
    return 1;
}

И shadow_simple.glsl содержит (упрощенное из моего шейдера, реализующего CSM):

in vec4 eye_position;

uniform sampler2DShadow shad_tex;
uniform mat4 shad_mat;

float getShadowCoefficient()
{
    vec4 shad_coord = shad_mat * eye_position;
    return texture(shad_tex, shad_coord).x;
}

И вы можете просто выбрать, хотите ли вы затенения или нет, связав другой шейдер shadow_*. У этого решения может быть больше накладных расходов, но я бы хотел подумать, что компилятор GLSL достаточно хорош, чтобы оптимизировать лишние накладные расходы по сравнению с другими способами. Я не проводил никаких тестов на этом, но именно так мне это нравится.

ответил Robert Rouhani 20 J000000Saturday13 2013, 12:57:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132