Может ли вычислительный шейдер записывать одно и то же значение из многих потоков в одну и ту же общую память?

#glsl #compute-shader

#glsl #вычислительный шейдер

Вопрос:

Я хотел бы имитировать логическое сокращение в вычислительном шейдере с помощью одной bool переменной (не массива), просто инициализируя переменную false значением, которое могут видеть все потоки, а затем заставляя каждый поток либо вносить true значение в сокращение, записывая его в переменную, либо вносить false значение, ничего не делая.

Пример:

 shared bool someNumberIsBig;

// ...

void main()
{
    uint id = gl_LocalInvocationID.x;
    uint gid = gl_GlobalInvocationID.x;

    if (id == 0) someNumberIsBig = false;
    memoryBarrierShared();
    barrier();

    uint oneNumber = someBuffer[gid];

    if (oneNumber > 5) someNumberIsBig = true; // WOW that's big
    memoryBarrierShared();
    barrier();

    if (someNumberIsBig)
    {
        // do some work, with dynamic uniformity even, and with an
        // assurance that at least one number was indeed big...  or not??
    }
}
  

Мне это кажется простым, но, возможно, конкурирующие записи в одно и то же местоположение могут каким-то образом вызвать проблему. Полагаюсь ли я здесь на какое-либо неопределенное или зависящее от реализации поведение?

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

Ответ №1:

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

Но если вы все еще хотите использовать общую память, это поддерживается. Единственная проблема с ними — это некогерентная память и порядок выполнения. Но ваш пример решает проблему как с барьером памяти, так и с барьером выполнения. Если вы хотите выполнять более сложные операции с общей памятью, вам придется использовать атомарные встроенные функции. Более подробную информацию можно найти в OGL wiki.