2016-12-22 10 views
-1

Я пытаюсь сделать глобальный связанный список для Форвард + заливка, но есть некоторыеOpenGL Compute Shader синхронизация между группами

трудности в ходе реализации.

Для каждой группы в вычислительном шейдере она имеет общую переменную: локальный индексный массив, и этот массив имеет переменную длину (емкость постоянна, но контент отсутствует). Вот пример:

общий массив int [1024]; // декларация в GLSL

общая длина int; // это также общая переменная в рабочей группе.

Группа 0: длина = 4, массив = 3, 5, 7, 1, -1, -1, -1, -1 .... (-1 = не действует)

Группа 1: длина = 2, массив = 1, 6, -1, -1, -1 ....

Группа 2: длина = 1, массив = 8, -1, -1, -1, -1 .. ..

Теперь я хочу объединить эти индексы в глобальный массив индексов. то есть объект буфера хранилища шейдеров. Порядок основан на индексе группы:

Глобальный массив индекс: 3, 5, 7, 1, 1, 6, 8, -1, -1, -1 ......

сложности Я не знаю, как синхронизировать между различными группами. Поскольку барьер() в OpenGL гарантирует только синхронизацию в той же группе.

И я нашел в другом сообщении, что OpenGL не поддерживает синхронизацию между различными группами.

OpenGL Compute shader sync different work groups

Итак, мой вопрос. В любом случае, для достижения моей цели?

Например, можно объявить некоторый объект буфера хранилища шейдеров, такой как последний идентификатор группы, который завершил обновление, и смещение глобального массива индексов?

пример:

unit latestGroupIDUpdated = -1; // a SSBO 
unit globalIdxOffset = 0; // a SSBO 
in each group: 
while(myGroupId - 1 != latestGroupIDUpdated) 
{ //keep waiting } 

// my previous group has updated the global list 
globalIdxOffset+= myArrayLength; 
latestGroupIDUpdated = myGroupId; 
//now start appending the local index array into global index array 

Будет ли работает эта попытка? Или это не удастся и почему?

Если это не удастся, какой подход рекомендуется?

+0

Когда вы говорите «группа», вы имеете в виду «рабочую группу», верно? Если это так, рабочие группы не могут иметь разную длину. Если по длине вы ссылаетесь на количество запросов на группу. –

+0

да, группа означает рабочая группа –

+0

И разные длины? –

ответ

0

По внешнему виду это, это выглядит, как вы организовали свой МЕСТНЫЙ GROUP в 1D:

layout(local_size_x = X​, local_size_y = 1, local_size_z = 1) in; 

Если вы назвали glDispatch(n * X, 1, 1), вы будете иметь п группы. Процесс между n группами также выполняется параллельно, поэтому вы не будете знать, в каком порядке обновляется каждый groupID. Использование 'latestGroupIDUpdated' не будет работать.

Вот мой подход, вы должны использовать встроенный в переменной

gl_GlobalInvocationID (gl_GlobalInvocationID.x in our case) 
gl_GlobalInvocationID.x = gl_WorkGroupID.x * gl_WorkGroupSize.x + gl_LocalInvocationID.x; 

---//gl_WorkGroupID.x; [0, n) - 'n' : num groups you dispatched 

---//gl_WorkGroupSize.x; X - size (3 in your example) 

---//gl_LocalInvocationID.x; [0, gl_WorkGroupSize.x) - or [0, X) 

Вы можете использовать gl_GlobalInvocationID.x индексировать в свой список «global» SSBO хранить «length».Что-то вроде:

GlobalLengthList[gl_GlobalInvocationID.x] = length; 

Все это просто, чтобы сохранить динамическое значение «length» в групповом порядке в «global» список SSBO. Все эти «length» будут обновляться после вызова glMemoryBarrier() в вашем приложении C/C++.

После этого вам придется изменить этот массив таким образом, чтобы он сохранял «префиксную сумму» - включительно - из массива «длина». Этот процесс сильно распараллелен. Если вы пытаетесь сэкономить время, вы можете сделать это в отдельном вычислительном шейдере. (Я предлагаю посмотреть это, если длина массива длинна). Вы также можете сделать это на CPU.

После того, как у вас есть инклюзивное массив длины префикса суммы (назовем его PrefixSumLengthArray), вам нужно будет позвонить glDispatch() снова послать стольких шейдерных заклинания как общая стоимость «длиной» - последнее значение в вашем PrefixSumLengthArray. Затем вы будете использовать gl_GlobalInvocationID для индексации вашего нового списка SSBO для хранения ваших массивов. Что-то вроде:

int i = 0; // index to PrefixSumLengthArray array get the 'length' upto and including. 

int j = 0; // index [0, length) to get the localArray 

if (gl_GlobalInvocationID.x < PrefixSumLength[i]) { 
     GlobalArrayList[gl_GlobalInvocationID.x] = localArray[j]; 
     j++; 
} else { 
     j = 0; 
     i++; 
} 

Это будет синхронизироваться между различными группами для ya !!!

+0

Он также избавится от всех ненужных значений «-1». –