2012-05-18 13 views
8

miałem wcześniej już problem, który chciałem mieszanka wartości kolorów w jednostce obrazu wykonując coś takiego:GLSL, semafory?

vec4 texelCol = imageLoad(myImage, myTexel); 
imageStore(myImage, myTexel, texelCol+newCol); 

W scenariuszu, w którym wiele fragmenty mogą mieć taką samą wartość dla „myTexel”, to aparently nie jest możliwe, ponieważ nie można utworzyć atomowości między poleceniami imageLoad i imageStore, a inne wywołania shaderinokacji mogą zmienić kolor texel pomiędzy.

Teraz ktoś mi powiedział, że ludzie pracują nad całym tym problemem, tworząc semafory za pomocą komend atomowych na teksturach uint, tak, że shader czekał jakoś w pętli przed uzyskaniem dostępu do teksela i jak tylko jest wolny, atomowo zapisz itno teksturę całkowitą, aby zablokować inwokacje innych fragmentów cieniowania, przetwórz kolor texel i po zakończeniu atomowo całkowicie zwolnij liczbę całkowitą texel.

Ale nie rozumiem, jak to działa i jak taki kod mógłby wyglądać?

Czy to naprawdę możliwe? czy moduł cieniujący GLSL można ustawić tak, aby odczekał chwilę? Jeśli to możliwe, czy ktoś może dać przykład?

+0

Od [specyfikacja rozszerzenia] (http://www.opengl.org/registry/specs/EXT/shader_image_load_store.txt) wygląda na to, że musisz ustawić odpowiednie bariery pamięci, używając opcji 'MemoryBarrierEXT()' lub 'memoryBarrier()' w samych modułach cieniujących. – Flexo

+0

@awoodland: Bariery pamięci nie pozwalają innym programom cieniującym działającym na tym samym etapie odczytać pamięć. –

+0

Zobacz moją odpowiedź na http://stackoverflow.com/a/16802075/1388799 dla aktualnie działającego rozwiązania problemu semaforów GLSL na kartach Nvidia Kepler. –

Odpowiedz

6

Tak, możesz to zrobić, ale tylko tak długo, jak zamówienie, w którym rzeczy są zmieszane, nie ma znaczenia. W przeciwnym razie musisz użyć zwykłych technik.

Zasadniczo wdrażasz tylko wersję spinlock. Tylko zamiast jednej zmiennej kłódki masz całą wartość zamków.

Najpierw potrzebujesz obrazu o rozmiarze innego obrazu, który użyjesz do operacji atomowych. Musi to być tekstura całkowita o kodzie GL_R32UI i uimage w celu dopasowania. Powinien być zainicjalizowany przy pomocy 0. Zarówno obraz atomowy, jak i obraz "mieszający" muszą być uznane za "spójne".

  1. wykonać operację imageAtomicCompSwap w miejscu na atomowej całkowitej obrazu. Porównujesz go do 0, a wartość, którą ustawiasz to 1.

  2. Jeśli # 1 zwraca 1, oznacza to, że ktoś inny ma blokadę. Wróć do kroku 1.

  3. Jeśli # 1 zwraca 0, to masz teraz wyłączny dostęp do texela (ponieważ teraz texel ma 1 w nim, dzięki operacji porównania/wymiany). Dalej.

  4. Wykonaj operację mieszania. Emituj memoryBarrier po operacji mieszania.

  5. Wykonaj imageAtomicExchange, o wartości 0. Spowoduje to odblokowanie blokady spinlock.

Przyczyna tego działania wynika z atomów. GLSL zapewnia, że ​​atomiki są atomowe. imageAtomicCompareSwap wykonuje operację read/conditional-modify/write jako sekwencję atomową. A ponieważ jest atomowy, to inne wywołania modułu cieniującego uniemożliwiają lub przerywają operację. Oznacza to, że nie ma znaczenia, ile wątków modułu cieniującego jest uruchomionych: jeśli 100 z nich wywoła imageAtomicCompareSwap(..., 0, 1), dokładnie jeden z nich otrzyma 1 jako wartość zwracaną, a reszta otrzyma 0 (dla tego samego texela, oczywiście).

Więc tylko jeden wątek otrzyma blokadę; reszta musi poczekać.

Użycie funkcji memoryBarrier() zapewnia, że ​​inne oczekujące wątki będą pobierać zmodyfikowane dane po ich odczytaniu. Ponownie, musisz użyć kwalifikatora coherent dla obrazu, który robisz z tym.

+0

Nie rozumiem, dlaczego tekstura całkowita powinna być rozmiaru ekranu. Oznaczałoby to jedną wartość blokady na fragment. ale czy nie powinna być zapisana jedna wartość zamka na teksel obrazu? – Mat

+1

@Mat: Czy jest więcej tekseli obrazu niż pikseli na ekranie? Pomoże to poznać te rzeczy z góry. –

+0

czasami więcej, zwykle mniej. to zależy od przypadku. Czy moduł cieniujący pozostanie w pętli while, dopóki warunek nie zostanie faktycznie spełniony? czy GLSL nie jest w jakiś sposób gwarancją, że shadery powrócą i dlatego zabiją inwokację modułu cieniującego, jeśli obraca się zbyt długo? – Mat