GLSL, Semaphoren?

8

Ich hatte vorher schon das Problem, dass ich Farbwerte in einer Bildeinheit mischen wollte, indem ich so etwas mache:

%Vor%

In einem Szenario, in dem mehrere Fragmente den gleichen Wert für 'myTexel' haben können, ist dies nicht möglich, da zwischen den Befehlen imageLoad und imageStore keine Atomizität erzeugt werden kann und andere Shader-Aufrufe die Texelfarbe dazwischen ändern können.

Nun hat mir jemand gesagt, dass Leute um dieses Problem herum arbeiten, indem sie Semaphore mit den atomaren Kommandos auf Uint-Texturen erstellen, so dass der Shader irgendwie in einer while-Schleife auf das Texel wartet und sobald es frei ist, atomar schreibt itno die Integer-Textur, um andere Fragment-Shader-Aufrufe zu blockieren, die Farbe texel zu verarbeiten und nach Beendigung atomar das Integer-Texel wieder freizugeben.

Aber ich kann mir nicht vorstellen, wie das wirklich funktionieren könnte und wie ein solcher Code aussehen würde?

Ist das wirklich möglich? Kann ein GLSL-Fragment-Shader so eingestellt werden, dass er in einer while-Schleife wartet? Wenn es möglich ist, kann jemand ein Beispiel geben?

    
Mat 18.05.2012, 12:42
quelle

1 Antwort

6

Ja, Sie können das tun, aber nur so lange, wie die Reihenfolge , in der die Dinge vermischt sind, irrelevant ist. Andernfalls müssen Sie die üblichen Techniken verwenden.

Im Grunde implementieren Sie nur einen Spinlock . Nur statt einer Sperrvariable haben Sie die Sperren einer ganzen Textur.

Sie benötigen zuerst ein Bild in der Größe Ihres anderen Bildes, das Sie für atomare Operationen verwenden. Es muss eine Integer-Textur mit GL_R32UI und ein uimage Format von r32ui sein, damit sie übereinstimmen. Es sollte mit Nullen initialisiert werden. Sowohl das Atombild als auch das "Blending" -Bild müssen als "kohärent" deklariert werden.

  1. Führen Sie eine imageAtomicCompSwap -Operation an der Stelle des atomaren Integer-Bildes durch. Sie vergleichen es mit 0, und der Wert, auf den Sie es setzen, ist 1.

  2. Wenn # 1 1 zurückgibt, bedeutet dies, dass jemand anderes die Sperre hat. Gehen Sie zurück zu Schritt 1.

  3. Wenn # 1 0 zurückgibt, haben Sie exklusiven Zugriff auf das Texel (weil das Texel jetzt 1 enthält, dank der Operation compare / swap). Weiter.

  4. Führen Sie Ihren Mischvorgang aus. Senden Sie eine memoryBarrier nach Ihrer Mischoperation.

  5. Führen Sie imageAtomicExchange mit dem Wert 0 aus. Dadurch wird der Spinlock entsperrt.

Der Grund, warum das funktioniert, liegt an den Atomics. GLSL stellt sicher, dass Atome atomar sind. imageAtomicCompareSwap führt eine Lese- / Bedingungsmodifizierungs- / Schreiboperation als atomare Sequenz aus. Und weil es atomar ist, ist es unmöglich , dass andere Shaderaufrufe die Operation unterbrechen oder unterbrechen. Das bedeutet, dass es egal ist, wie viele Threads eines Shaders laufen: Wenn 100 imageAtomicCompareSwap(..., 0, 1) aufrufen, erhält genau einer von ihnen 1 als Rückgabewert, und der Rest erhält 0 (für dasselbe Texel, natürlich).

Also wird nur ein Thread die Sperre bekommen; der Rest muss warten.

Die Verwendung der Funktion memoryBarrier() stellt sicher, dass andere wartende Threads die geänderten Daten übernehmen, wenn sie sie lesen. Auch hier müssen Sie das Qualifikationsmerkmal coherent für das Bild verwenden, mit dem Sie dies tun.

    
Nicol Bolas 18.05.2012, 13:58
quelle

Tags und Links