Вопрос по opengl, concurrency – GLSL, семафоры?

10

У меня уже была проблема с тем, что я хотел смешать значения цвета в единицу изображения, выполнив что-то вроде:

vec4 texelCol = imageLoad(myImage, myTexel);
imageStore(myImage, myTexel, texelCol+newCol);

В сценарии, где несколько фрагментов могут иметь одинаковое значение для «myTexel», это, по-видимому, невозможно, поскольку невозможно создать атомарность между командами imageLoad и imageStore, а другие вызовы шейдеров могут изменить цвет текселя между ними.

Сейчас кто-то сказал мне, что poeple обходит эту проблему, создавая семафоры с использованием атомарных команд на текстурах uint, так что шейдер будет как-то ждать в цикле while, прежде чем получить доступ к texel и, как только он будет свободен, атомарно записать его в целочисленная текстура, чтобы заблокировать другие вызовы фрагментного шейдера, обработать цветную тексель и по окончании атомарно освободить целочисленную тексель.

Но я не могу понять, как это действительно может работать и как будет выглядеть такой код?

Разве можно это сделать? можно ли установить фрагментный шейдер GLSL для ожидания в цикле while? Если это возможно, кто-нибудь может привести пример?

Смотри мой ответ на Stackoverflow.com / а / 16802075/1388799 для работающего в настоящее время решения проблемы семафоров GLSL на картах Nvidia Kepler. Walt Donovan
@ awoodland: барьеры памяти не позволяют другим шейдерам, работающим на том же этапе, читать память. Nicol Bolas
От спецификация расширения Похоже, вам нужно установить подходящие барьеры памяти, либо сMemoryBarrierEXT() илиmemoryBarrier() в самих шейдерах. Flexo♦

Ваш Ответ

1   ответ
8

прика в котором вещи смешаны не имеет значения. В противном случае вам нужно использовать обычные методы.

В основном вы просто реализуете Спинлок. Только вместо одной переменной блокировки у вас будет целая блокировка текстуры.

Сначала вам нужно изображение размером с другое изображение, которое вы будете использовать для атомарных операций. Это должна быть целочисленная текстура сGL_R32UI иuimage форматr32ui чтобы соответствовать. Это должно быть инициализировано с 0. И атомное изображение, и «смешанное» изображение должны быть объявлены «связными».

ВыполнитьimageAtomicCompSwap операция в местоположении на атомном целочисленном изображении. Вы сравниваете его с 0, а значение, которое вы устанавливаете, равно 1.

Если # 1 возвращает 1, это означает, что у кого-то еще есть блокировка. Вернитесь к шагу № 1.

If # 1 возвращает 0, то теперь у вас есть эксклюзивный доступ к текселю (потому что теперь у текселя есть 1, благодаря операции сравнения / замены). Продолжать

Выполните операцию смешивания. ИспускатьmemoryBarrier после операции смешивания.

ВыполнитьimageAtomicExchange, со значением 0. Это разблокирует спин-блокировку.

Причина, по которой это работает, связана с атомарностью. GLSL гарантирует, что атомные атомы.imageAtomicCompareSwap выполняет операцию чтения / условного изменения / записи в виде атомарной последовательности. И потому что это атомное, этоневозможн для других вызовов шейдеров для прерывания или прерывания операции. Это означает, что не имеет значения, сколько потоков шейдера запущено: если 100 из них вызываютimageAtomicCompareSwap(..., 0, 1), точно один из них получит 1 в качестве возвращаемого значения, а остальные получат 0 (для того же текселя, конечно).

Так что только один поток получит блокировку; остальное должно подождать.

ИспользованиеmemoryBarrier()ункция @ гарантирует, что другие ожидающие потоки получат измененные данные, когда они начнут читать их. Опять же, вам нужно использоватьcoherent квалификатор для изображения, с которым вы это делаете.

Я не понимаю, почему целочисленная текстура должна быть размером с экран. Это будет означать одно значение блокировки на фрагмент. но не должно ли быть одно значение блокировки на тексель изображения для записи? Mat
@ Mat: Есть больше текселей изображения, чем пикселей экрана? Это помогло бы узнать эти вещи заранее. Nicol Bolas
иногда больше, обычно меньше. это зависит от случая. Таким образом, фрагментный шейдер останется в цикле while, пока условие не будет выполнено? GLSL не гарантирует, что шейдеры вернутся и, следовательно, прекратят вызов шейдера, если он вращается слишком долго? Mat
@ Mat: GLSL не делает ничего подобного. Тем не менее, водитель может. Это не может вызвать бесконечный цикл (так что Window не убьет ваше приложение), но драйвер или оборудование может автоматически завершить шейдер, который продолжается слишком долго. Или не может. Nicol Bolas
Это старая тема, но разве вы не рискуете заблокировать этот подход? * Antoine Morrier

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