2016-12-22 4 views
-1

Ich versuche, eine globale verknüpfte Liste für Vorwärts + Shading zu machen, aber es gibt einigeOpenGL Compute Shader Synchronisation zwischen den Gruppen

Schwierigkeiten bei der Umsetzung.

Für jede Gruppe im Compute-Shader gibt es eine gemeinsame Variable: ein lokales Index-Array, und dieses Array hat eine variable Länge (die Kapazität ist konstant, der Inhalt jedoch nicht). Hier ist das Beispiel:

Shared Int-Array [1024]; // die Deklaration in GLSL

gemeinsame int-Länge; // Es ist auch eine gemeinsame Variable in der Arbeitsgruppe.

Gruppe 0: Länge = 4, array = 3, 5, 7, 1, -1, -1, -1, -1 .... (-1 = nicht gültig)

Gruppe 1: length = 2, array = 1, 6, -1, -1, -1 ....

Gruppe 2: Länge = 1, Array = 8, -1, -1, -1, -1 .. ..

Jetzt möchte ich diese Indizes zu einem globalen Index-Array zusammenführen. ein Shader-Speicherpufferobjekt. Die Reihenfolge basiert auf Gruppenindex:

globaler Index-Array: 3, 5, 7, 1, 1, 6, 8, -1, -1, -1 ......

Die Schwierigkeit Ich weiß nicht, wie ich zwischen verschiedenen Gruppen synchronisieren soll. Seit barrier() in OpenGL garantiert nur die Synchronisation in der gleichen Gruppe.

Und ich fand die in einem anderen Beitrag, dass OpenGL nicht die Synchronisation zwischen verschiedenen Gruppen unterstützt.

OpenGL Compute shader sync different work groups

Also, meine Frage ist. Gibt es überhaupt etwas, um mein Ziel zu erreichen?

Zum Beispiel, kann ich ein Shader Storage Buffer Object deklarieren, wie zum Beispiel die letzte Gruppen-ID, die die Aktualisierung beendet hat, und den Offset des globalen Indexarrays?

Beispiel:

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 

Wird dieser Versuch funktioniert? Oder wird es scheitern und warum?

Wenn es scheitern wird, welche Art von Ansatz wird empfohlen?

+0

Wenn Sie "Gruppe" sagen, meinen Sie "Arbeitsgruppe", oder? Wenn dies der Fall ist, können Arbeitsgruppen keine unterschiedlichen "Längen" haben. Wenn Sie "Länge" angeben, beziehen Sie sich auf die Anzahl der Aufrufe pro Gruppe. –

+0

ja, Gruppe bedeutet Arbeitsgruppe –

+0

Und die verschiedenen Längen? –

Antwort

0

Durch den Blick von ihm, es sieht aus wie Sie Ihre lokale Gruppe in 1D organisiert:

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

Wenn Sie glDispatch(n * X, 1, 1) genannt, haben Sie n Gruppen. Der Prozess zwischen n Gruppen wird auch parallel ausgeführt, so dass Sie nicht wissen, in welcher Reihenfolge die einzelnen groupID aktualisiert werden. Die Verwendung von 'latestGroupIDUpdated' funktioniert nicht.

Hier ist mein Ansatz, sollten Sie die integrierte Variable

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) 

Sie können gl_GlobalInvocationID.x indizieren in Ihrem global 'SSBO Liste verwenden, nutzen ‚length‘ zu speichern.Etwas wie:

GlobalLengthList[gl_GlobalInvocationID.x] = length; 

All dies ist nur den dynamischen Wert zu speichern 'length' in der Gruppe, um in der 'global' SSBO Liste. Alle diese 'length' werden aktualisiert, sobald Sie glMemoryBarrier() in Ihrer C/C++ - Anwendung aufgerufen haben.

Danach müssen Sie dieses Array so ändern, dass es die "Prefix Summe" - einschließlich - des 'Länge' Arrays speichern würde. Dieser Prozess ist stark parallelisiert. Wenn Sie Zeit sparen möchten, können Sie dies in einem separaten Compute-Shader tun. (Ich schlage vor, dies zu prüfen, wenn Ihr Längen-Array lang ist). Sie können dies auch auf der CPU tun.

Nachdem Sie Ihre inklusive Präfixsumme Länge Array (lass es PrefixSumLengthArray nennen), müssen Sie glDispatch() wieder anrufen, so viele Shader-Anrufungen als Gesamt ‚Länge‘ Wert versenden - den letzten Wert in Ihrem PrefixSumLengthArray. Dann werden Sie gl_GlobalInvocationID verwenden, um in Ihre neue SSBO Liste zu indizieren, um Ihre Arrays zu speichern. Etwas wie:

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++; 
} 

Das wird zwischen verschiedenen Gruppen für Sie synchronisieren !!!

+0

Es wird auch alle unnötigen '-1' Werte loswerden. –