Синхронизировать счетчик атомов по нескольким графическим процессорам

Я использую атомный счетчик в вычислительном шейдере с atomic_uint привязан к динамическому GL_ATOMIC_COUNTER_BUFFER (аналогично этому opengl-atomic-counter учебник маяк3d).

Я использую атомный счетчик в системе частиц, чтобы проверить, достигнуто ли условие для всех частиц; Я ожидаю увидеть counter==numParticles когда все частицы находятся в правильном месте.

Я сопоставляю буфер каждого кадра и проверяю, подсчитал ли атомный счетчик все частицы:

GLuint *ptr = (GLuint *) glMapBuffer( GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY );
GLuint particleCount = ptr[ 0 ];
glUnmapBuffer( GL_ATOMIC_COUNTER_BUFFER );
if( particleCount == numParticles() ){ // do stuff }

На одном хосте GPU код работает нормально и particleCount всегда достигает numParticles() но на мульти хосте GPU particleCount никогда не достигает numParticles(),

Я могу визуально проверить, что условие выполнено, и тест должен быть верным, однако, ParticleCount изменяет каждый кадр, поднимаясь и опускаясь, но никогда не достигая numParticles ().

Я пробовал барьер памяти opengl на GL_ATOMIC_COUNTER_BARRIER_BITПрежде чем я разархивировать particleCount:

glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
GLuint *ptr = (GLuint *) glMapBuffer( GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY );
GLuint particleCount = ptr[ 0 ];
glUnmapBuffer( GL_ATOMIC_COUNTER_BUFFER );
if( particleCount == m_particleSystem->numParticles() )
{ // do stuff }

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

memoryBarrierAtomicCounter();
atomicCounterIncrement( particleCount );

но атомный счетчик не синхронизируется между устройствами.

Как правильно синхронизировать атомный счетчик с несколькими устройствами?

1

Решение

Ваш выбор барьера памяти на самом деле неуместен в этой ситуации.

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

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

  • GL_BUFFER_UPDATE_BARRIER_BIT:

Читает / пишет через glBuffer(Sub)Data, glCopyBufferSubData, glProgramBufferParametersNV, а также glGetBufferSubDataили для буферизации памяти объекта, отображаемой glMapBuffer(Range) после барьера будут отображаться данные, записанные шейдерами до барьера.

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


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

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

(1) шейдерная запись / чтение между командами рендеринга

Один Команда рендеринга пишет бессвязно, а другой читает. Там нет необходимости coherent(Классификатор GLSL)Здесь вообще. Просто используйте glMemoryBarrierПеред выдачей команды рендеринга чтения, используя соответствующий бит доступа.

(2) шейдер пишет, другие операции чтения OpenGL

Снова, coherentНе обязательно Вы должны использовать glMemoryBarrierПеред выполнением чтения, используя битовое поле, которое соответствует интересующей операции чтения.

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

В случае (2), барьер вы хотите GL_BUFFER_UPDATE_BARRIER_BIT, «операция чтения интереса» является glMapBuffer (...) и, как показано выше, это покрыто GL_BUFFER_UPDATE_BARRIER_BIT,

В вашей ситуации вы читаете буфер обратно, используя GL API. Вам нужны команды GL, чтобы дождаться, пока все ожидающие шейдеры завершат запись (это не происходит автоматически при несогласованном доступе к памяти — загрузка / сохранение изображений, атомные счетчики и т. Д.). Это дело учебника (2).

2

Другие решения



Курсы программирования от Skillbox. Черная пятница!
Подробнее >>>
×