Атомарные счетчики GLSL (и ветвление) во фрагментных шейдерах

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

Представьте себе поток примерно так:

  • в каком-то небольшом неуправляемом цикле, скажем, FOR 0-20 (разрешимая константа во время компиляции) ...
  • получить значения счетчиков для AC1 и AC2
  • проверьте какое-то значение:
  • если x: установить тексель в uimage1D_A по индексу AC1, увеличить AC1
  • else: установить тексель в uimage1D_B по индексу (imgwidth-AC2-1), увеличить AC2

Вопрос: шейдер запрашивает текущее значение счетчика - всегда ли он получает «самое актуальное» значение? Теряю ли я здесь массовый параллелизм фрагментных шейдеров (если говорить только о графических процессорах и драйверах текущего и будущих поколений)?

Что касается ветвления (если x) - я сравниваю тексель в другом (readonly restrict uniform) uimage1D с (uniform) uint. Итак, один операнд определенно является однородным скаляром, а другой - imageLoad().x, хотя изображение однородно - является ли этот вид ветвления все еще «полностью распараллеленным»? Вы можете видеть, что в обеих ветках есть ровно две, почти идентичные инструкции. Предполагая "идеально оптимизирующий" компилятор GLSL, может ли такое ветвление привести к остановке?


person metaleap    schedule 17.03.2012    source источник


Ответы (2)


Атомные счетчики атомные. Но каждая атомарная операция атомарна только для этой операции.

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

Правильный способ сделать то, что вы предлагаете:

  1. проверьте какое-то значение:
  2. if x:
    1. atomicCounterIncrement(AC1), storing the value returned.
    2. Используйте сохраненное значение в качестве текселя, в котором что-то нужно установить в uimage1D_A.
  3. else:
    1. atomicCounterIncrement(AC2), storing the value returned.
    2. Используйте сохраненное значение, чтобы вычислить тексель (imgwidth - val - 1), в котором что-то нужно установить в uimage1D_B.

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

Я настоятельно рекомендую познакомиться с атомными процессорами и потоками на CPU, прежде чем пытаться взяться за работу с GPU. Это частая ошибка новичков при работе с атомиксом. Вы должны быть экспертом по потокам (или, по крайней мере, среднего уровня), если хотите успешно использовать атомику GLSL и загрузку / сохранение изображений.

person Nicol Bolas    schedule 17.03.2012
comment
Спасибо за разъяснения и предупреждения :) - person metaleap; 19.03.2012

Как предложил Никол Болас, если вы хотите гарантировать, что значение, которое вы читаете из атомарного счетчика, никогда не будет прочитано другим ядром, вам необходимо выполнить атомарное приращение и использовать возвращаемое значение, которое не будет иметь ни одно другое ядро, если они не выполнят atomicCounter(AC1), который проверяет значение без увеличения. В тот момент, когда вы атомарно увеличиваете значение и получаете обратно старое значение, вы убедитесь, что все остальные, которые сделают то же самое, получат только увеличенное значение.

Кажется, вы делаете A-буфер, мне любопытно, зачем вам второй счетчик. Я предполагаю, что uimage1D_A - это ваша карта указателей размером с экран на список фрагментов, который хранится в uimage1D_B, я прав? Вы используете AC2 для генерации указателя на новую неиспользуемую часть памяти uimage1D_B, но ваш AC1 предполагает, что вы постепенно получаете доступ к uimage1D_A, поэтому я могу ошибаться :)

person Francisco Inácio    schedule 28.07.2014