Атомные встречные аномалии в геометрии шейдеров

Я пытаюсь контролировать поведение фрагментного шейдера, вычисляя количество вершин в геометрическом шейдере, чтобы, если у меня был поток вершин из 1000 треугольников, когда число достигло 500, я установил некоторые переменные для фрагментного шейдера, который сигнализирует о том, что последний должен переключить свою обработку. Чтобы подсчитать общее количество обработанных вершин (или треугольников), я использую счетчик атомов в геометрическом шейдере. Сначала я планировал сделать это в вершинном шейдере, но потом я где-то читал, что из-за счетчика кэширования вершин не будет увеличиваться при каждом вызове вершины. Но теперь он кажется, что выполнение этого в геометрическом шейдере также не выполняет счет точно.

В моем геометрическом шейдере я делаю это:

layout(triangles) in;

layout (triangle_strip ,max_vertices = 3) out; 

layout(binding=0, offset=0) uniform atomic_uint ac;

out flat float isExterior;

void main()
{
    memoryBarrier();
    uint counter = atomicCounter(ac);
    float switcher = 0.0;
    if (counter >= exteriorSize)
    {
        switcher = 2.0;
    }
    else
    {
        atomicCounterIncrement(ac);
        atomicCounterIncrement(ac);
        atomicCounterIncrement(ac);
    }
    isExterior = switcher;

    // here just emitting primitive....  

экстерьер Size - это форма, содержащая число, равное количеству вершин в массиве. Когда я считываю значение счетчика на процессоре, оно никогда не равно экстерьеру. Но оно почти в 2 раза меньше его. Есть ли кэширование вершин на этапе геометрии а? или я что-то не так делаю?

По сути, мне нужно сказать фрагментному шейдеру: "после того, как номер вершины X начнет выполнять работу Y. Поскольку число вершин меньше, чем число X, работает Z" И я не могу получить этот точный X из атомного счетчика, хотя я увеличиваю его до тех пор, пока не достигнет этого предела.

ОБНОВИТЬ:

Я подозреваю, что проблема с атомарной синхронизацией записи. Если я устанавливаю memoryBarrier в разных местах, значения счетчиков меняются. Но я до сих пор не могу получить, чтобы он возвращал точное значение, равное externalSize.

ОБНОВЛЕНИЕ 2:

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

1 ответ

Геометрический шейдер выполняется для каждого примитива (в данном случае треугольника), тогда как вершинный шейдер выполняет почти для каждой вершины. С помощью glDrawElements позволяет разделить результаты вершин между треугольниками (например, при индексации 0,1,2, затем 0,2,3 использует 0 и 2 дважды: 4 вершины, 2 треугольника и 6 ссылок). Как вы говорите, для совместного использования результатов используется ограниченный кеш, поэтому, если на одну и ту же вершину будет ссылаться долгое время спустя, ее необходимо пересчитать.

Похоже, что существует потенциальная проблема с обновлениями счетчика, возникающая между atomicCounter а также atomicCounterIncrement, Если вы хотите, чтобы целый раздел кода работал, его нужно заблокировать. Это может стать очень медленным в зависимости от того, что вы блокируете.

Вместо этого будет гораздо проще всегда звонить atomicCounterIncrement и потенциально позволяют ac выйти за пределы exteriorSize,

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

Это звучит как exteriorSize должно быть равно количеству треугольников, а не вершин, если это выполняется в геометрическом шейдере. Если вместо этого вы хотите обработку для каждой вершины, то, возможно, измените на GL_POINTS или сохраните результаты вершинного шейдера, используя расширение обратной связи преобразования и затем рисуя из него треугольники (по сути, выполняйте кеширование самостоятельно, но с буфером, который содержит все). Если вы используете glDrawArrays или никогда не используйте повторно вершины, тогда стандартный вершинный шейдер должен подойти.

Наконец, позвонив atomicCounterIncrement три раза это пустая трата времени. Позвоните один раз и используйте counter * 3,

Другие вопросы по тегам