Оптимизация шейдеров: является ли троичный оператор эквивалентным ветвлению? - PullRequest
25 голосов
/ 06 февраля 2011

Я работаю над вершинным шейдером, в котором я хочу условно отбросить некоторые вершины:

float visible = texture(VisibleTexture, index).x;
if (visible > threshold)
    gl_Vertex.z = 9999; // send out of frustum

Я знаю, что ветви убивают производительность, когда между соседними данными мало общего.В этом случае каждая другая вершина может получить различное «видимое» значение, что негативно скажется на производительности кластера ядра локального шейдера (насколько я понимаю).

На мой вопрос: лучше ли троичный оператор(независимо от проблем с читабельностью)?

float visible = texture(VisibleTexture, index).x;
gl_Vertex.z = (visible > threshold) ? 9999 : gl_Vertex.z;

Если нет, стоит ли преобразовывать его в вычисление?

float visible = texture(VisibleTexture, index).x;
visible = sign(visible - threshold) * .5 + .5; // 1=visible, 0=invisible
gl_Vertex.z += 9999 * visible; // original value only for visible

Есть ли еще лучший способ отбрасывать вершины, не полагаясь на геометрию?шейдер?

Заранее спасибо за любую помощь!

Ответы [ 5 ]

9 голосов
/ 13 сентября 2011

Это математическое решение может быть использовано для замены условных операторов. Это также реализовано в OpenCL как bitselect(condition, falsereturnvalue, truereturnvalue);

int a = in0[i], b = in1[i];
int cmp = a < b; //if TRUE, cmp has all bits 1, if FALSE all bits 0
// & bitwise AND
// | bitwise OR
// ~ flips all bits
out[i] = (a&cmp) | (b&~cmp); //a when TRUE and b when FALSE

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

8 голосов
/ 06 февраля 2011

Тернарный оператор является просто синтаксическим сахаром для оператора if.Они одинаковы.

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

Часто по умолчанию ветвление не используется.

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

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

Ваш пробег может варьироваться от одного компилятора и GPU к другому.

7 голосов
/ 26 января 2017

На самом деле это зависит от используемого вами шейдерного языка.

  • В HLSL и Cg троичный оператор никогда не приведет к ветвлению.Вместо этого оба возможных результата всегда оцениваются, а неиспользованный результат отбрасывается.Цитируя документацию HLSL :

    В отличие от оценки короткого замыкания &&, || и?: В C, выражения HLSL никогда не закорачивают оценку, потому что они являются векторнымиоперации.Все стороны выражения всегда вычисляются.

    Для Cg ситуация аналогична, и здесь тройной условный оператор является векторным оператором.( документация ):

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

  • В ESSL и GLSL троичный оператор всегда приводит к ветвлению.Это не векторный оператор, поэтому условие должно быть вычислено как логическое.См. GLSL-спецификацию :

    . Он работает с тремя выражениями (exp1? Exp2: exp3).Этот оператор вычисляет первое выражение, которое должно привести к скалярному логическому значению.Если результат равен true, он выбирает для оценки второго выражения, в противном случае он выбирает для оценки третьего выражения.Оценивается только одно из второго и третьего выражений.

    ( Источник для ESSL )

Иллюстрация различия приведена дляэкземпляр доступен на тестовом сайте Khronos WebGL для троичных операторов .

1 голос
/ 02 декабря 2013

Ответ зависит от трех вещей:

  1. компилятор и какие виды оптимизации он выполняет
  2. архитектура и язык
  3. точная ситуация, в которой вы находитесьиспользуя тернарный оператор.

Рассмотрим этот пример:

int a = condition ? 100 : 0;

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

int a = condition * 100

Такой же тип оптимизации может быть возможен с эквивалентным условием if:

int a = 0;

if (condition) {
    a = 100;
}

Все зависит от конкретных оптимизаций, выполняемых компилятором..

В общем, мой совет: если вы можете использовать троичный оператор, предпочтительнее использовать его.Скорее всего, он будет оптимизирован компилятором.Это также приводит к более декларативному стилю кода.

0 голосов
/ 06 февраля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...