Dawno, dawno temu, kiedy> było szybsze niż <… Zaraz, co?

280

Czytam niesamowity samouczek OpenGL . To naprawdę świetne, zaufaj mi. Tematem, w którym aktualnie jestem, jest bufor Z. Oprócz wyjaśnienia, o co w tym wszystkim chodzi, autor wspomina, że ​​możemy wykonywać niestandardowe testy głębokości, takie jak GL_LESS, GL_ALWAYS itp. Wyjaśnia również, że rzeczywiste znaczenie wartości głębokości (która jest najwyższa, a która nie) może być również dostosowane Jak dotąd rozumiem A potem autor mówi coś niewiarygodnego:

Zakres zNear może być większy niż zakres zFar; jeśli tak, to wartości przestrzeni okien będą odwrócone, jeśli chodzi o to, co stanowi najbliżej lub dalej od widza.

Wcześniej mówiono, że wartość Z w obszarze okien wynosząca 0 jest najbliższa, a 1 jest najdalsza. Jeśli jednak nasze wartości Z w przestrzeni klipu zostałyby zanegowane, głębokość 1 byłaby najbliższa widokowi, a głębokość 0 byłaby najdalsza. Jeśli jednak zmienimy kierunek testu głębokości (GL_LESS na GL_GREATER itp.), Otrzymamy dokładnie ten sam wynik. To naprawdę tylko konwencja. Rzeczywiście, odwrócenie znaku Z i test głębokości był kiedyś istotną optymalizacją wydajności dla wielu gier.

Jeśli dobrze rozumiem, pod względem wydajności odwrócenie znaku Z i test głębokości to nic innego jak zmiana <porównania na >porównanie. Tak więc, jeśli dobrze rozumiem, a autor nie kłamie ani nie wymyśla, to zmiana <na >dawną była niezbędną optymalizacją wielu gier.

Czy autor czyni rzeczy, mam nieporozumienie coś, czy to rzeczywiście jest tak, że raz <był wolniejszy ( niezwykle , jak mówi autor) niż >?

Dziękujemy za wyjaśnienie tej dość ciekawej sprawy!

Oświadczenie: Jestem w pełni świadomy, że złożoność algorytmu jest głównym źródłem optymalizacji. Co więcej, podejrzewam, że w dzisiejszych czasach zdecydowanie nie zrobiłoby to żadnej różnicy i nie proszę o to, aby cokolwiek zoptymalizować. Jestem po prostu bardzo, boleśnie, może zbyt ciekawie ciekawy.

Armen Tsirunyan
źródło
6
Wygląda na to, że link do tego samouczka (ostatnio) nie działa. :(
TZHX
@TZHX: Ponieważ autor tego samouczka jest autorem zaakceptowanej odpowiedzi, mamy nadzieję ją znaleźć ponownie. Zobacz mój ostatni komentarz do jego odpowiedzi :)
Armen Tsirunyan
3
Odnośny samouczek OpenGL jest dostępny tutaj .
Fons
(a <b) jest identyczne z (b> a), więc absolutnie nie ma potrzeby implementowania obu operacji porównywania sprzętowo. Różnica w wydajności wynika z tego, co dzieje się w wyniku operacji porównania. Jest to długa i kręta droga, aby wytłumaczyć wszystkie skutki uboczne, ale oto kilka wskazówek. Gry używane do wypełniania bufora głębokości, aby uniknąć droższego przetwarzania fragmentów dla fragmentów, które nie przeszły testu głębokości. Quake służył do dzielenia zakresu głębokości na dwie połowy, aby uniknąć czyszczenia bufora ramki, ponieważ gra zawsze wypełniała każdy piksel na ekranie i tak dalej.
t0rakka
2
@Fons wygląda na to, że link nie działa, ponownie :(
nalzok

Odpowiedzi:

350

Jeśli dobrze rozumiem, pod względem wydajności odwrócenie znaku Z i test głębokości to nic innego jak zmiana porównania <porównanie do>. Tak więc, jeśli dobrze rozumiem, a autor nie kłamie ani nie wymyśla, to zmiana <na> była kiedyś istotną optymalizacją wielu gier.

Nie wyjaśniłem tego szczególnie dobrze, ponieważ nie było to ważne. Po prostu czułem, że można dodać ciekawą ciekawostkę. Nie zamierzałem szczegółowo omawiać algorytmu.

Kontekst jest jednak kluczowy. Nigdy nie mówiłem, że <porównanie było szybsze niż> porównanie. Pamiętaj: mówimy o testach głębi sprzętu graficznego, a nie o procesorze. Nie operator<.

Miałem na myśli konkretną starą optymalizację, w której jedna ramka byłaby używana GL_LESSz zakresem [0, 0,5]. Następna klatka renderuje GL_GREATERw zakresie [1,0, 0,5]. Poruszasz się tam iz powrotem dosłownie „przerzucając znak Z i test głębokości” w każdej klatce.

Traci to odrobinę precyzji głębokości, ale nie trzeba było czyścić bufora głębokości, co kiedyś było dość powolną operacją. Ponieważ czyszczenie głębokości jest obecnie nie tylko bezpłatne, ale w rzeczywistości szybsze niż ta technika, ludzie już tego nie robią.

Nicol Bolas
źródło
1
Powód, dla którego czyszczenie bufora głębokości jest obecnie szybsze, ma dwa powody, oba oparte na fakcie, że GPU używa hierarchicznego bufora głębokości. W związku z tym wystarczy tylko wyczyścić stany kafelków, aby je wyczyścić (co jest szybkie), zmiana znaku porównania głębokości oznacza jednak, że cały bufor HiZ wymaga opróżnienia, ponieważ przechowuje tylko wartość minimalną lub maksymalną w zależności od znaku porównania.
Jasper Bekkers
3
@NicolBolas: komentarz PerTZHX, link do twojego tutoriala w moim pytaniu wygasł. Czy możesz dać nam znać, gdzie poruszają się samouczki i opcjonalnie edytować pytanie, proszę?
Armen Tsirunyan
2
Samouczki są dostępne w archiwum internetowym. Jeśli @NicolBolas na to pozwala, byłoby pomocne dla społeczności, gdybyśmy mogli przenieść je w bardziej dostępne miejsce. Może GitHub lub coś takiego. web.archive.org/web/20150215073105/http://arcsynthesis.org/…
ApoorvaJ
3

Odpowiedź jest prawie na pewno taka, że ​​niezależnie od zastosowanego wcielenia sterownika + chip, Hierarchical Z działał tylko w jednym kierunku - był to dość powszechny problem w tamtych czasach. Asemblowanie / rozgałęzienie niskiego poziomu nie ma z tym nic wspólnego - buforowanie Z odbywa się w sprzęcie o stałej funkcji i jest przetwarzane potokowo - nie ma spekulacji, a zatem nie ma przewidywania rozgałęzień.

Crowley9
źródło
0

Taka optymalizacja obniży wydajność wielu osadzonych rozwiązań graficznych, ponieważ sprawi, że buforowanie ramek będzie mniej wydajne. Wyczyszczenie bufora jest wyraźnym sygnałem dla sterownika, że ​​nie musi on przechowywać i przywracać bufora podczas binowania.

Niewielka ilość informacji w tle: rasterizer kafelków / binowania przetwarza ekran na wiele bardzo małych kafelków, które mieszczą się w pamięci na chipie. Zmniejsza to zapis i odczyt do pamięci zewnętrznej, co zmniejsza ruch na szynie pamięci. Kiedy ramka jest kompletna (wywoływana jest zamiana lub FIFO są opróżniane, ponieważ są pełne, wiązania wiązania ramki zmieniają się itp.) Bufor ramki musi zostać rozwiązany; oznacza to, że każdy pojemnik jest przetwarzany po kolei.

Sterownik musi założyć, że poprzednia zawartość musi zostać zachowana. Zachowanie oznacza, że ​​pojemnik musi zostać zapisany w pamięci zewnętrznej, a następnie przywrócony z pamięci zewnętrznej, gdy pojemnik zostanie ponownie przetworzony. Operacja czyszczenia informuje kierowcę, że zawartość pojemnika jest dobrze zdefiniowana: czysty kolor. Jest to sytuacja trywialna do optymalizacji. Istnieją również rozszerzenia do „odrzucania” zawartości bufora.

t0rakka
źródło
-8

Ma to związek z bitami flagowymi w wysoce zestrojonym zestawie.

x86 ma instrukcje jl i jg, ale większość procesorów RISC ma tylko jl i jz (bez jg).

Jozuego
źródło
2
Jeśli taka jest odpowiedź, rodzą się nowe pytania. Czy „odebranie gałęzi” było wolniejsze niż „zignorowanie gałęzi” we wczesnych procesorach RISC? Z pewnością nie jest to teraz w żaden wymierny sposób, o ile wiem. Czy miałeś wtedy pisać forpętle z bezwarunkową gałęzią do tyłu i warunkową, rzadko braną do przodu, aby wyjść z pętli? Brzmi dziwnie.
Pascal Cuoq,
54
-1: To pytanie nie ma nic wspólnego z procesorami . GL_LESS i GL_GREATER to operacje porównywania głębokości, które działają na procesorach graficznych.
Nicol Bolas,
8
Zabawne, ile przedstawicieli można uzyskać za odpowiedź, która jest zgodna z tytułem, ale ma niewiele wspólnego z rzeczywistym pytaniem.
Jozuego
7
+1 Nie, ta odpowiedź jest poprawna przynajmniej w części pytania. Pytanie brzmi: „Czy autor coś wymyślił, czy coś nie rozumiem, czy rzeczywiście jest tak, że kiedyś <było wolniejsze (jak mówi autor) niż>?”. Dostępne są trzy opcje. Ta odpowiedź odpowiada na możliwość opcji 3. Nigdzie w tym artykule nie podano technologii CPU / GPU, ani że nie musi to być GPU (pierwsze gry 3D na CPU). Ok ... Nie sądzę, żeby było wiele gier 3D na RISC :-)
xanatos
3
(a znacznik GPU został dodany o 20:34. Pierwsza wersja miała tylko znacznik CPU. Ta odpowiedź została napisana o 18:44)
xanatos