Dlaczego moduły cieniujące piksele nie pozwalają nam czytać bezpośrednio z bufora ramki lub bufora głębi?

18

Pozwól, że spróbuję buforowania klatek lub bufora głębi w module cieniującym piksele byłoby niezwykle przydatną funkcją. Przydałaby się nawet sama znajomość głębi lub koloru wszystkiego, co kryje się za bieżącym pikselem.

Dlaczego zarówno OpenGL, jak i DirectX nie pozwalają mi tego robić? Spodziewałem się pewnego ograniczenia sprzętowego, ale mieszanie alfa używa koloru w buforze ramki do obliczeń mieszania, a test Z pobiera bufor głębokości w bieżącej lokalizacji. Dlaczego nie udostępnić nam tych wartości bezpośrednio? Czy mogę liczyć na to w przyszłości?

Hannesh
źródło

Odpowiedzi:

20

Jest to ograniczenie sprzętowe. Moduł cieniujący fragmenty jest częścią programowalnego potoku, ale ostateczna mieszanka kolorów z docelowym buforem (buforami) nie jest w tym momencie programowalna w powszechnie dostępnym / towarowym sprzęcie (można go konfigurować poprzez stany mieszania, ale nie można pisać arbitralnie kod, który zastępuje wbudowane operacje mieszania GPU).

Powód, dla którego sprzęt nie jest do tego przeznaczony, prawdopodobnie wynika z faktu, że procesory graficzne są w dużej mierze równoległe; przetwarzają wiele fragmentów jednocześnie. Niektóre z tych fragmentów mogą ostatecznie oddziaływać ze sobą w obrębie buforów docelowych, ale ze względu na asynchroniczny charakter przetwarzania fragmentów nie można wiedzieć, jak to zrobić po przetworzeniu fragmentu i wyemitowaniu końcowego koloru ... który wygrał zawsze zdarza się deterministycznie.

To, że piksel A będzie za pikselem B w ostatniej klatce, nie oznacza, że ​​piksel A zawsze zakończy przetwarzanie fragmentów i zostanie zapisany w miejscu docelowym przed B, szczególnie w wielu klatkach renderowania. Tak więc wartość odczytana z bufora docelowego podczas przetwarzania piksela B nie zawsze będzie pikselem A - czasami będą to wyraźne wartości.

Podejrzewam więc, że uniemożliwienie odczytu bezpośrednich buforów docelowych podczas etapu fragmentowania ma znacznie więcej wspólnego z powstrzymaniem programisty shadera przed wystrzeleniem się w stopę poprzez uzyskanie potencjalnie niedeterministycznych wyników z tego odczytu niż z jakichkolwiek faktycznych technicznych ograniczeń w tworzeniu etapu mieszania w pełni- programowalny. Dzięki ścisłej kontroli operacji odczytu (na przykład testu głębokości) GPU zapewnia, że ​​operacje wykonywane z wartością odczytu mają pewien sens.

To powiedziawszy, może się również zdarzyć sprawa kosztów / korzyści. Uczynienie tego aspektu potoku GPU programowalnym nieco skomplikowałoby konstrukcję układu, a potrzeba / popyt na odczyty bufora docelowego był stosunkowo niski w porównaniu do innych funkcji.


źródło
Aby to rozwinąć, historycznym powodem powolnego dostępu do bufora ramki jest to, że instrukcje są bardzo mocno potokowane. Uzyskanie dostępu do danego piksela bufora ramki wymagałoby zablokowania bieżącego potoku, dopóki wszystkie inne potoki nie zostaną opróżnione, aby ukończyć renderowanie związane z odpytywanym pikselem. Nawet w dziwnym przypadku całkowicie nierównoległego procesora graficznego nadal przepłukiwałbyś cały potok dla każdego zapytania, co jest po prostu złym pomysłem. Bez wątpienia w świecie programowalnego sprzętu sytuacja wygląda nieco inaczej, ale spodziewam się, że obowiązuje podobna zasada.
Kylotan,
4

Irytujący, pozwala producentom sprzętu na optymalizację procesu renderowania na wiele przejrzystych sposobów.

Na przykład sprzęt PowerVR (z pewnością używany w przeszłości, nie używany przez długi czas) czeka na przesłanie całej renderowanej sceny, a następnie wykonuje automatyczne sortowanie głębokości za pomocą algorytmu malarzy i nie musi generować bufor głębokości. Dzieliłby ekran na kafelki i renderował każdy z nich kolejno.

Roger Perkins
źródło
4

Moduł cieniujący pikseli nie może odczytać z buforów kolorów i głębokości, ponieważ:

Piksele A i B mogą być cieniowane dokładnie w tym samym momencie w sprzęcie, chociaż B ostatecznie renderuje się na szczycie („po”) pikselu A.

Jeśli to zrobisz, aby sprzęt gwarantował cieniowanie A przed B, wtedy części sprzętu siedziały i nic nie robiłyby, podczas gdy A jest zacienione, a następnie części sprzętu siedziały i nie robiłyby nic, gdy B jest zacieniony.

W najgorszym możliwym przypadku wszystkie cieniowane piksele renderują się jeden na drugim, a tysiące wątków GPU - wszystkie oprócz jednego - siedzą bezczynnie. Ten jeden wątek cierpliwie przyciemnia piksel A, następnie B, a następnie C ...

bmcnett
źródło