Как «распределить» память атомарно в GLSL SSBO? - PullRequest
0 голосов
/ 10 ноября 2018

Я строю древовидную структуру внутри буфера в glsl.

Каждый узел в дереве имеет 8 целых чисел, которые определяют местоположение 8 дочерних узлов в массиве.

Так, например:

tree[0].children = [1,5,3,9,100000,7,100,10]
tree[1].children = [2,3,4,900,8,11,20,13]

Возможные возможные результаты.

Способ, которым один поток «выделяет» память. Буфер имеет глобальный индекс, инициализированный до 0.

Текущий поток проверяет, равен ли один из дочерних элементов текущего узла 0, если это так, он увеличивает индекс на 1 и устанавливает значение дочернего элемента в предыдущее значение индекса.

Другими словами:

if(tree[node].children[current_child] == 0) {
     tree[node].children[current_child] = tree_index++;
}

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

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

int mrun = 100;
while ((tree[0].children[child] <= 0) && (mrun > 0))
{
    mrun--;
    //If the node wasn't allocated, allocate its memory (which also releases the lock)
    if( (atomicCompSwap( tree[0].children[child] , 0 , -1) == 0 ))
    {
        tree[0].children[child] = int(atomicAdd(t_index, 1));
    }
}

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

Я попытался решить проблему, выполнив:

  atomicCompSwap(tree[0].children[child], 0, atomicAdd(t_index, 1));

Однако это не дает желаемого эффекта, эти операции не выполняются атомарно одновременно, поэтому я в итоге выполняю неправильные распределения.

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

...