Jaki problem rozwiązuje podwójne lub potrójne buforowanie w nowoczesnych grach?

31

Chcę sprawdzić, czy moje rozumienie przyczyn używania podwójnego (lub potrójnego) buforowania jest prawidłowe:

Monitor z częstotliwością odświeżania 60 Hz wyświetla monitor 60 razy na sekundę. Jeśli monitor odświeży ekran monitora, aktualizuje piksel dla piksela i linia dla linii. Monitor żąda wartości kolorów pikseli z pamięci wideo.

Jeśli uruchomię teraz grę, ta gra ciągle manipuluje pamięcią wideo.

Jeśli ta gra nie używa strategii buforowania (podwójne buforowanie itp.), Może wystąpić następujący problem:

Monitor odświeża teraz swój monitor. W tym momencie monitor odświeżył już ekran monitora pierwszej połowy. W tym samym czasie gra zmanipulowała pamięć wideo nowymi danymi. Teraz dostęp do monitora dla monitora drugiej połowy wyświetla te nowe zmanipulowane dane z pamięci wideo. Problemy mogą być łzawienie lub migotanie.

Czy rozumiem przypadki użycia strategii buforowania? Czy są inne powody?

krokvskrok
źródło

Odpowiedzi:

62

Zasadniczo głównym celem renderowania jest to, aby każda klatka wyświetlana na monitorze prezentowała pojedynczy, spójny obraz. Istnieje kilka różnych strategii, które są lub były stosowane w celu osiągnięcia tego.

W dalszej części wspomnę o „vsync”. Vsync to moment, w którym monitor zaczyna rysować nowy obraz ekranowy; jest to punkt, w którym „vblank” zaczyna się na tradycyjnym ekranie CRT, gdzie linia skanowania na chwilę przestaje rysować i przesuwa się z powrotem na górę monitora. Ten moment jest bardzo ważny w przypadku wielu podejść do określania spójności.

„Łzawienie” nazywamy to, gdy ekran jest renderowany z dwóch różnych obrazów w ramach jednej klatki. Jeśli na przykład narysowałem dwa obrazy ekranowe, które mają być wyświetlane jeden po drugim, ale zamiast tego monitor wyświetlał górną połowę klatki pierwszej, a dolną połowę klatki drugiej, to „łzawienie”. Dzieje się tak z powodu zmiany danych, z których monitor odczytuje podczas rysowania monitora, zamiast podczas vblank. (W nowoczesnych programach dzieje się tak zwykle, ponieważ użytkownik wyłączył opcję oczekiwania na vsync w ustawieniach sterownika)

Zero-bufor

Na najstarszym sprzęcie często brakowało pamięci, aby pomieścić obraz pełnoekranowy, więc zamiast rysować obraz ekranowy, trzeba było określić kolory dla każdej linii skanowania osobno, podczas gdy monitor był w trakcie rysowania tej linii. Na przykład w Atari 2600 miałeś tylko 76 cykli instrukcji maszynowych, aby określić, jaki kolor ma każdy piksel linii skanowania, zanim telewizor zaczął rysować tę linię skanowania. A potem miałeś 76 cykli instrukcji, aby dostarczyć zawartość do następnego skanu i tak dalej.

Single-Buffer

Rysując w kontekście „pojedynczego bufora”, rysujesz bezpośrednio do pamięci VRAM odczytywanej przez monitor. W tym podejściu „ścigasz się po linii skanowania”. Ogólny pomysł jest taki, że kiedy linia skanowania zaczyna rysować zawartość poprzedniej klatki u góry ekranu, rysujesz za nią w VRAM . Tak więc, gdy linia skanowania rysuje obraz ekranowy dla ostatniej klatki, rysujesz kolejną ramkę za linią skanowania.

Zasadniczo próbujesz zakończyć rysowanie obrazu następnej klatki, zanim linia skanująca „okrąży” cię, zbliżając się ponownie i wyprzedzając rysowane piksele, a także nigdy nie wyprzedzając linii skanowanej, ani też nowego ramka może rysować w poprzedniej ramce.

Z tego powodu renderowanie pojedynczego bufora zwykle działało samo przez rysowanie linii skanowania, od góry do dołu i od lewej do prawej. Jeśli narysowałeś w innej kolejności, prawdopodobne jest, że linia skanowania pojawi się ponownie i dostrzeże fragmenty „następnego” obrazu, którego jeszcze nie narysowałeś.

Zwróć uwagę, że we współczesnych systemach operacyjnych zazwyczaj nie ma możliwości rysowania pojedynczego buforu, chociaż trzydzieści lat temu było to dość powszechne. (Kurcze, czy czuję się teraz stary - to właśnie robiłem, kiedy zaczynałem od tworzenia gier)

Podwójny bufor

Jest to o wiele, wiele prostsze niż którakolwiek ze strategii, które pojawiły się wcześniej.

W systemie podwójnego buforowania mamy wystarczającą ilość pamięci do przechowywania dwóch różnych obrazów ekranu, dlatego jeden z nich określamy jako „bufor przedni”, a drugi jako „bufor tylny”. „Bufor przedni” jest obecnie wyświetlany, a „bufor buforowy” to miejsce, w którym aktualnie rysujemy.

Po zakończeniu rysowania obrazu ekranowego do bufora tylnego czekamy na vsync, a następnie zamieniamy dwa bufory. W ten sposób bufor tylny staje się buforem przednim i odwrotnie, a cała zamiana miała miejsce, gdy monitor niczego nie rysował.

Potrójny bufor

Jednym z problemów często podnoszonych przy podejściu z podwójnym buforem jest to, że po zakończeniu rysowania do bufora tylnego musimy po prostu usiąść i czekać na vsync, zanim będziemy mogli zamienić bufory i kontynuować pracę; w tym czasie moglibyśmy wykonywać obliczenia! Co więcej, przez cały czas, gdy czekamy na zamianę między buforami, obraz w tym buforze tylnym starzeje się i starzeje, zwiększając w ten sposób postrzegane przez użytkownika opóźnienie.

W systemach z potrójnym buforem tworzymy trzy bufory - jeden bufor przedni i dwa bufory tylny. Chodzi o to:

Monitor wyświetla bufor przedni, a my zbliżamy się do bufora tylnego # 1. Jeśli zakończymy rysowanie do tylnego bufora # 1, zanim monitor skończy rysować bufor przedni, a następnie zamiast czekać na vsync, natychmiast zaczniemy rysować następną ramkę do tylnego bufora # 2. Jeśli skończymy, a vsync nadal nie nadejdzie, zaczniemy rysować z powrotem w buforze tylnym nr 1 i tak dalej. Chodzi o to, że gdy w końcu nastąpi vsync, jeden lub drugi z naszych tylnych buforów będzie kompletny i że można go zamienić na bufor przedni.

Zaletą potrójnego buforowania jest to, że nie tracimy czasu, który spędziliśmy na czekaniu na vsync w podejściu podwójnego buforowania, a obraz zamieniony na bufor przedni może być „świeższy” niż ten, który czekał na vsync dla 8ms. Minusem potrójnego buforowania jest to, że potrzebujemy dodatkowej pamięci do przechowywania dodatkowego obrazu ekranu, a nasze użycie procesora / karty graficznej będzie wyższe (ponownie, ponieważ nie zwalniamy, aby czekać na vsync).

Zazwyczaj współczesni kierowcy często wykonują potrójne buforowanie transparentnie, za kulisami. Piszesz swój kod, aby wykonać podwójne buforowanie, a sterownik faktycznie zwróci ci kontrolę wcześnie i po prostu wewnętrznie obsłuży przełączanie między tyloma buforami, których chce użyć, bez twojego kodu, który jest tego świadomy.

Dostawcy GPU obecnie nie zalecają samodzielnego wdrażania potrójnego buforowania - sterownik zrobi to za Ciebie automatycznie.

Trevor Powell
źródło
7
Jest to niezwykle szczegółowa odpowiedź, która wyjaśnia, dlaczego wiele rzeczy robi się tak, jak są (np. Przestrzeń współrzędnych ekranu itp.). Odpowiedziałem również na moje pytanie „dlaczego nie poczwórne bufory? Pięciokrotne?” Nie zdawałem sobie sprawy, że zamiana buforów miała miejsce w tle, co oznacza, że ​​dwa tylne bufory są maksymalnie potrzebne. Pozytywne.
lunchmeat317
W rzeczywistości istnieje buforowanie quadów. Jest to podwójne buforowanie dla widoku stereoskopowego. swiftless.com/tutorials/opengl/smooth_rotation.html
Narek
@Narek Nie. Cytowanie z linku: „Naprawdę nie można włączyć faktycznego buforowania quadów w środowisku grafiki komputerowej, ponieważ nie ma to żadnego sensu”. Sugerowanie, że podwójne buforowanie w dwóch różnych widokach jednocześnie byłoby „buforowaniem poczwórnym”, jest po prostu zabawną grą słów; nie coś prawdziwego.
Trevor Powell,
@TrevorPowell Dodając część, o której zapomniałeś dołączyć: „Cóż, typowo poczwórne buforowanie odnosi się do podwójnego buforowania w środowisku stereoskopowym. Na przykład: Masz dwa wyświetlacze, zazwyczaj do celów 3D, a każde oko jest podwójnie buforowane”. Teraz kontekst może być wyraźniejszy.
Narek
@TrevorPowell Twój punkt jest jednak całkowicie jasny. Nie ma sensu mieć więcej niż 3 bufory dla jednego bufora renderowania.
Narek,