Jak programiści wycisnęli z PlayStation 2 rzeczy niemożliwe. Emotion Engine i architektura sprzętu
Trudno uwierzyć, że God of War II, Final Fantasy XII, Gran Turismo 4 i Shadow of the Colossus działały na urządzeniu wyposażonym w 32 MB pamięci operacyjnej oraz zaledwie 4 MB pamięci graficznej. Główny procesor PlayStation 2 pracował z częstotliwością niespełna 300 MHz, a układ odpowiedzialny za wyświetlanie obrazu nie potrafił samodzielnie wykonywać krótkich programów wyliczających dla każdego punktu ekranu światło, kolor, odbicia czy wygląd powierzchni. Funkcja ta, nazywana programowalnym cieniowaniem pikseli, szybko stała się jednym z fundamentów rozwoju grafiki 3D, ale konstruktorzy PS2 obrali zupełnie inną drogę.
W zamian Sony stworzyło skomplikowany zestaw wyspecjalizowanych jednostek, które mogły wykonywać ogromną liczbę prostych operacji równocześnie. Pełną wydajność osiągały jednak dopiero wtedy, gdy programiści samodzielnie rozdzielili między nie zadania, przygotowali dane i dopilnowali ich idealnego przepływu. Andy Gavin z Naughty Dog po latach określił tę architekturę jako „absurdalnie trudną do programowania”. A mimo to właśnie z niej narodziły się jedne z najbardziej imponujących technicznie gier całej generacji. Skala późniejszych osiągnięć robi jeszcze większe wrażenie, gdy uświadomimy sobie, że możliwości konsoli przez całą generację praktycznie się nie zmieniły. Sony zmniejszało kolejne modele, integrowało podzespoły i ograniczało pobór energii, ale procesor, ilość pamięci oraz podstawowa konstrukcja układu graficznego pozostawały takie same. Na architekturze, którą pierwsze zespoły dopiero próbowały zrozumieć, kilka lat później uruchomiono gry działające w 60 klatkach na sekundę, wielkie światy doczytywane bez tradycyjnych ekranów ładowania i kolosy będące jednocześnie przeciwnikami oraz ruchomymi poziomami.
Postęp dokonywał się w silnikach, narzędziach i samym projektowaniu gier. Programiści uczyli się pisać własny mikrokod, dzielić zadania między jednostki wektorowe, precyzyjnie planować transfery danych oraz przygotowywać osobne sposoby wyświetlania postaci, terenu i efektów. W GTA III ograniczenia napędu wpływały na układ ulic i prędkość samochodów. W God of War II reżyserowana kamera pozwalała obliczać przede wszystkim te fragmenty monumentalnej scenografii, które rzeczywiście widział gracz. Przy Final Fantasy XII Square Enix stworzyło z kolei własne narzędzia do efektów, animacji i kompresji, umożliwiające natychmiastowe sprawdzanie tekstur oraz oświetlenia na prawdziwym PS2. Największe cuda tej konsoli wynikały z coraz dokładniejszego wykorzystywania każdego megabajta pamięci.
Dlaczego trzeba było podejmować aż takie działania?
Ponieważ PlayStation 2 nie przypominało ani typowego komputera, ani późniejszych konsol. Xbox był urządzeniem znacznie bardziej konwencjonalnym: miał procesor wywodzący się z Pentium III, układ graficzny NVIDIA i 64 MB zunifikowanej pamięci. GameCube oferował sprawne teksturowanie, sprzętową kompresję tekstur, większe pamięci podręczne i architekturę, którą łatwiej było wykorzystać bez pisania połowy silnika od zera. PS2 stawiało przed twórcami zestaw bardzo szybkich, ale wąsko wyspecjalizowanych elementów. Jeżeli działały równolegle i otrzymywały dane we właściwym momencie, konsola potrafiła dokonywać cudów. Jeżeli któryś z nich czekał, cała imponująca specyfikacja stawała się zbiorem ładnie nazwanych kawałków krzemu.
To właśnie jest sedno historii PlayStation 2. Nie była to po prostu najsłabsza konsola generacji, na której genialni programiści wyczyniali cuda. Była maszyną pełną skrajności: słabą w typowych zadaniach, potężną w kilku konkretnych, trudną do okiełznania i wyjątkowo podatną na specjalizację. Xbox i GameCube oferowały wyższą wydajność i były mimo wszystko łatwiejsze do okiełznania. PS2 najpierw wystawiało rachunek w assemblerze, mikrokodzie i nieprzespanych nocach, a dopiero później pokazywało, na co naprawdę je stać.
Emotion Engine, czyli procesor, który nie chciał pracować sam
Nazwa Emotion Engine do dziś brzmi jak hasło napisane przez dział marketingu po trzecim espresso. Sony twierdziło jednak, że nowy układ ma umożliwić „syntezę emocji” - generowanie w czasie rzeczywistym ruchu postaci, włosów, tkanin, cieczy i całych scen, zamiast odtwarzania wszystkiego z wcześniej przygotowanych animacji. Zapowiedzi naturalnie wyprzedzały rzeczywistość, ale sama konstrukcja procesora rzeczywiście została podporządkowana bardzo intensywnym obliczeniom potrzebnym grafice 3D.
Emotion Engine pracował z częstotliwością 294,912 MHz. Porównywanie tej liczby bezpośrednio z 733 MHz procesora pierwszego Xboksa nie mówi jednak całej prawdy. Układ Sony nie był pojedynczym CPU, który wykonywał po kolei wszystkie zadania gry. Składał się z głównego rdzenia MIPS R5900, dwóch jednostek wektorowych VU0 i VU1, kontrolera DMA, dekodera obrazu oraz interfejsów odpowiedzialnych za transport danych. W praktyce był to niewielki zestaw procesorów i układów pomocniczych zamknięty w jednym chipie. Główny rdzeń zajmował się logiką gry, obsługą kodu, częścią animacji, sztuczną inteligencją i koordynowaniem pozostałych elementów. Nie był szczególnie imponującym procesorem ogólnego przeznaczenia. Miał niewiele pamięci podręcznej i wyraźnie tracił wydajność, gdy gra wymagała częstego podejmowania decyzji, sprawdzania wielu zależności oraz przeskakiwania między różnymi zadaniami. Jego największą zaletą była możliwość przekazania dużej części obliczeń dwóm wyspecjalizowanym jednostkom wektorowym.
Czym była jednostka wektorowa? W grafice 3D niemal każdą operację wykonuje się na grupach liczb. Położenie punktu w przestrzeni opisują współrzędne X, Y i Z. Do tego może dojść czwarta wartość potrzebna w obliczeniach macierzowych. Zwykły procesor mógłby przeliczać te elementy kolejno. Jednostka wektorowa wykonywała tę samą operację na czterech składowych jednocześnie. Przy jednym modelu różnica wydaje się niewielka. Przy tysiącach wierzchołków, dziesiątkach postaci i 60 klatkach w każdej sekundzie robiła się ogromna.
VU0 znajdowało się blisko głównego rdzenia i mogło działać na dwa sposoby. W pierwszym było jego koprocesorem, czyli wykonywało zlecone obliczenia wektorowe. W drugim uruchamiało własny mikrokod i pracowało niezależnie. Dawało się je wykorzystać do animacji szkieletowej, fizyki, deformacji modeli, obsługi cząsteczek albo przygotowywania dodatkowej geometrii. Nie istniał jednak jeden przycisk „włącz VU0”. Studio musiało samo podzielić zadania, przygotować dane, napisać odpowiedni program i dopilnować, aby jego wykonanie nie kolidowało z resztą silnika.
VU1 było jeszcze ważniejsze dla grafiki. Dysponowało większą lokalną pamięcią i mogło bezpośrednio przesyłać wyniki do Graphics Synthesizera. Przeliczało pozycje wierzchołków, perspektywę, oświetlenie, deformację modeli i odrzucało elementy, które nie powinny znaleźć się na ekranie. Dopiero później gotowe polecenia trafiały do układu rysującego piksele. W najprostszym ujęciu VU1 przygotowywało trójwymiarową scenę, a Graphics Synthesizer zamieniał ją w obraz. Ten podział pozwala zrozumieć, dlaczego PS2 mogło jednocześnie mieć prymitywny układ graficzny i imponować liczbą animowanych obiektów. Spora część pracy, którą w komputerze wykonywałoby GPU, została przeniesiona do programowalnej jednostki wektorowej. Twórcy otrzymywali dzięki temu swobodę, ale musieli sami napisać kod realizujący potrzebne operacje.
Dobrym przykładem jest Ratchet & Clank. Mark Cerny przygotował wczesny kod VU wykorzystany w pierwszym silniku PS2 rozwijanym później przez Insomniac. Seria stopniowo wypełniała ekran przeciwnikami, pociskami, śrubami, eksplozjami i ruchomymi elementami otoczenia, często utrzymując 60 klatek na sekundę. Nie oznacza to, że jednostki wektorowe samodzielnie „generowały grafikę”. Pozwalały jednak szybko przeliczać duże porcje geometrii i animacji, podczas gdy główny procesor zajmował się rozgrywką, a Graphics Synthesizer rysował przygotowany obraz.
Naughty Dog poszło jeszcze dalej. Przy Jak & Daxter studio stworzyło kilka wyspecjalizowanych sposobów renderowania różnych elementów świata oraz własny język programowania GOAL. Gra oferowała daleki obszar renderowania, płynnie doczytywane lokacje i świat pozbawiony klasycznych ekranów ładowania. Jednostki wektorowe przeliczały kolejne partie geometrii, ale sukces zależał też od agresywnego systemu LOD. Obiekty znajdujące się daleko od gracza zastępowano prostszymi wersjami, a najbardziej oddalone fragmenty świata mogły zostać zredukowane do płaskich reprezentacji. PS2 nie rysowało wszystkiego z jednakową dokładnością. Rysowało dokładnie tyle, ile w danym miejscu miało sens.
Podobna zasada napędzała najbardziej szalone efekty w Shadow of the Colossus. Jednostki wektorowe dobrze nadawały się do obliczeń związanych z transformacją modeli, animacją i dopasowywaniem ruchu postaci do otoczenia. Gra wykorzystywała inverse kinematics, czyli system wyliczający pozycję stawów na podstawie miejsca, w którym miała znaleźć się dłoń albo stopa. Dzięki temu nogi kolosów mogły lepiej reagować na nierówności terenu, kończyny Agro dopasowywały się do podłoża, a Wander przekonująco poruszał się po grzbiecie olbrzyma. Zamiast odtwarzać jedną sztywną animację, system na bieżąco korygował ułożenie ciała.
Cały ten potencjał mieścił się w absurdalnie małej przestrzeni. VU0 miało 4 KB pamięci na kod i 4 KB na dane. VU1 oferowało po 16 KB. Mikrokod musiał więc być krótki, wyspecjalizowany i przygotowany pod konkretną partię pracy. Nie dało się wrzucić do VU1 całego rozbudowanego systemu renderowania. Programista ładował niewielki program, przetwarzał nim porcję geometrii, a następnie mógł podmienić go na inny. Osobny mikrokod obsługiwał postacie, inny teren, kolejny efekty albo odległe tło. Właśnie dlatego dobrze zoptymalizowany silnik PS2 przypominał zestaw wyspecjalizowanych procedur, a nie jedno uniwersalne rozwiązanie. Programista wiedział, że dany typ obiektu zawsze posiada określoną budowę, używa konkretnego formatu danych i wymaga dokładnie wskazanych obliczeń. Mógł więc usunąć wszystko, co zbędne. Tak powstawała wydajność, której nie dało się osiągnąć przez napisanie ogólnego kodu i liczenie, że kompilator załatwi resztę.
Sony reklamowało Emotion Engine jako procesor 128-bitowy. To określenie nie było całkowitym kłamstwem, ale wymaga dopowiedzenia. Rdzeń bazował na 64-bitowej architekturze MIPS, natomiast zawierał 128-bitowe rejestry, jednostki multimedialne i ścieżki przesyłania danych. Mógł więc jednocześnie obrabiać większe pakiety liczb. Nie oznaczało to jednak, że PlayStation 2 było „dwa razy bardziej zaawansowane” od sprzętu 64-bitowego. Wojna na bity miała już wtedy coraz mniej wspólnego z rzeczywistą wydajnością, ale na pudełku wyglądała znakomicie. Podobnie należy traktować 6,2 GFLOPS i 75 milionów polygonów na sekundę. GFLOPS określa miliardy operacji zmiennoprzecinkowych wykonywanych w ciągu sekundy, ale wartość szczytowa zakłada idealny rodzaj obliczeń oraz pełne wykorzystanie wszystkich odpowiednich jednostek. Autorzy technicznego opracowania o VU podawali łącznie 5,52 GFLOPS dla obu jednostek wektorowych. Nadal był to świetny wynik jak na 2000 rok, lecz nie mówił, ile szczegółowych postaci z teksturami, oświetleniem, animacją i sztuczną inteligencją da się umieścić w prawdziwej grze.
Tak samo wyglądało 75 milionów polygonów. Liczbę można było osiągnąć w warunkach pozbawionych większości operacji potrzebnych do stworzenia kompletnego obrazu. Po dodaniu oświetlenia, tekstur, przezroczystości, animacji, kolizji, efektów i całej logiki gry realna wydajność spadała wielokrotnie. Zresztą sam polygon nie jest miarą jakości. Model złożony z większej liczby trójkątów może wyglądać gorzej od prostszego, jeżeli ma słabe tekstury, kiepską animację i nieprzekonujące oświetlenie. Final Fantasy XII znakomicie to pokazuje: główni bohaterowie mieli po około 1500 polygonów, a mimo to do dziś wyglądają znacznie lepiej niż wiele bardziej złożonych technicznie modeli z tamtego okresu.
Kolejnym problemem była niewielka pamięć podręczna głównego procesora: 16 KB na instrukcje i 8 KB na dane. Do tego dochodziło 16 KB szybkiego scratchpada, czyli pamięci, którą programista mógł wykorzystać jako kontrolowany obszar roboczy. Jeżeli potrzebne dane znajdowały się w odpowiednim miejscu, procesor działał sprawnie. Jeśli kod chaotycznie sięgał do różnych fragmentów 32 MB RAM-u, tracił czas na oczekiwanie. PS2 wymagało więc obrabiania danych partiami. Silnik przygotowywał zestaw wierzchołków, animacji albo poleceń, umieszczał go w przewidywalnym miejscu i przekazywał dalej. Nie można było bez końca przerzucać pojedynczych elementów między procesorami i liczyć, że sprzęt jakoś sobie poradzi. Najlepsze rezultaty dawała ciągła praca: DMA pobierało kolejną porcję danych, VU przeliczało aktualną, a Graphics Synthesizer rysował wcześniej przygotowaną. Każda jednostka wykonywała swoją część zadania równocześnie.
Tutaj dochodzimy do najważniejszej cechy Emotion Engine. Jego siłą nie była wydajność pojedynczego rdzenia. PS2 stawało się potężne dopiero wtedy, gdy gra potrafiła rozdzielić pracę między CPU, VU0, VU1, DMA oraz Graphics Synthesizer i utrzymać wszystkie elementy w ruchu. Przestój jednej jednostki potrafił zablokować następną. Prawidłowo przygotowany potok pozwalał natomiast wykonywać logikę gry, przeliczać kolejną porcję świata i rysować poprzednią praktycznie w tym samym czasie. Dlatego pierwsze produkcje tak mocno różniły się od późniejszych. W 2000 roku studia dopiero poznawały sprzęt, pisały podstawowe biblioteki i odkrywały, które zadania warto przenieść na jednostki wektorowe. Kilka lat później Naughty Dog miało GOAL i własne renderery, Insomniac rozwinięty kod VU, Square Enix zestaw specjalistycznych narzędzi, a Sony Santa Monica silnik oraz pipeline budowane wokół precyzyjnie kontrolowanej kamery. Konsola się nie zmieniła. Zmieniła się liczba rzeczy, które programiści potrafili wykonywać jednocześnie.
Cztery megabajty i zero litości
Jednostki wektorowe mogły przeliczać geometrię, animację i oświetlenie, ale na końcu ktoś musiał zamienić te wszystkie dane w gotowy obraz. Tym zajmował się Graphics Synthesizer - układ graficzny PlayStation 2, równie niezwykły jak Emotion Engine i zbudowany według filozofii, która bardzo szybko zaczęła odróżniać konsolę Sony od pecetów, GameCube’a oraz pierwszego Xboksa. Graphics Synthesizer nie przypominał współczesnego GPU. Nie otrzymał programowalnych shaderów pikseli, czyli niewielkich programów określających wygląd każdego punktu powierzchni. Nie potrafił w jednym przebiegu łączyć wielu tekstur, wykonywać skomplikowanych operacji na materiałach ani automatycznie realizować efektów, które na konkurencyjnych układach można było uruchomić za pomocą gotowej funkcji. Był przede wszystkim bardzo szybkim rasteryzatorem. Otrzymywał przygotowane polygony, pokrywał je teksturami, sprawdzał głębię sceny, mieszał kolory i zapisywał wynik w pamięci obrazu.
Rasteryzacja to moment, w którym matematyczny model 3D zostaje zamieniony w piksele widoczne na ekranie. Jednostki wektorowe mogły dokładnie obliczyć, gdzie znajduje się każdy wierzchołek modelu, ale dopiero Graphics Synthesizer wypełniał przestrzeń pomiędzy nimi kolorem i teksturami. Sony zrezygnowało z rozbudowanych funkcji i postawiło na ogromną szybkość wykonywania kilku podstawowych operacji. Jeżeli twórcy potrzebowali bardziej złożonego efektu, musieli rozłożyć go na kilka prostszych etapów i narysować ten sam fragment sceny wielokrotnie. Najbardziej niezwykłym elementem GS były 4 MB pamięci eDRAM umieszczone bezpośrednio w układzie. Nie była to więc osobna kość połączona z procesorem graficznym stosunkowo wąską magistralą. Sony zbudowało między jednostkami renderującymi a pamięcią około pięciu tysięcy wewnętrznych połączeń, uzyskując przepustowość sięgającą 48 GB/s. Dla porównania główne 32 MB pamięci RDRAM oferowały około 3,2 GB/s. Różnica była olbrzymia.
Jeden z konstruktorów PS2 po latach tłumaczył, że przy ówczesnych rozdzielczościach Graphics Synthesizer mógł teoretycznie nadpisać cały ekran ponad sto razy w czasie jednej klatki. Nie oznaczało to oczywiście, że każda gra naprawdę rysowała kompletny obraz sto razy. Pokazuje jednak, dlaczego konsola tak dobrze radziła sobie z efektami wymagającymi wielokrotnego mieszania warstw: ogniem, dymem, pyłem, smugami światła, rozmyciem ruchu, poświatą czy półprzezroczystymi cząsteczkami. Problem polegał na tym, że te fenomenalnie szybkie 4 MB musiały pomieścić niemal wszystko, czego GS potrzebował do zbudowania aktualnej klatki. Trafiał tam bufor z gotowym obrazem, często drugi bufor z kolejną przygotowywaną klatką, Z-buffer przechowujący informacje o głębi oraz aktualnie używane tekstury. Z-buffer pozwala ustalić, który obiekt znajduje się bliżej kamery. Kiedy bohater stoi przed ścianą, system zapisuje odległość obu powierzchni i dzięki temu wie, że ciało postaci powinno zasłonić fragment ściany, a nie odwrotnie.
Skalę ograniczenia najlepiej pokazuje proste obliczenie. Obraz o rozdzielczości 640 x 448 pikseli zapisany w 32-bitowym kolorze zajmuje około 1,1 MB. Dwa takie bufory pochłaniają już ponad 2,2 MB. Jeżeli dołożymy równie dokładny Z-buffer, łączne zużycie przekroczy 3,3 MB. Z czterech megabajtów zostaje mniej niż jeden, a nie umieściliśmy jeszcze w pamięci ani jednej tekstury. Twórcy musieli więc obniżać rozdzielczość, korzystać z 16-bitowych formatów obrazu i głębi, zmieniać układ buforów oraz bardzo ostrożnie decydować, które dane są potrzebne właśnie teraz. To jedna z głównych przyczyn charakterystycznego obrazu gier z PS2. Wiele z nich działało w rozdzielczościach niższych od 640 x 480, korzystało z przeplotu i miało problemy z migotaniem cienkich krawędzi. Przeplot oznaczał, że telewizor nie otrzymywał od razu całego obrazu. Najpierw wyświetlał jedną połowę linii, a następnie drugą. Na kineskopowym ekranie i przy spokojnym obrazie mogło to wyglądać poprawnie, ale szybki ruch kamery, metalowa siatka albo cienka gałąź łatwo zaczynały drżeć.
Niewielka pojemność eDRAM-u wpływała także na tekstury. Graphics Synthesizer nie miał sprzętowej kompresji tekstur porównywalnej z rozwiązaniami GameCube’a czy Xboksa, dlatego każdy materiał należało bardzo dokładnie dopasować do dostępnej pamięci i przepustowości. Często używano tekstur 4- oraz 8-bitowych z paletą kolorów. Zamiast zapisywać pełną informację o kolorze każdego punktu, tekstura przechowywała krótki numer odsyłający do osobnej tablicy barw. Pozwalało to radykalnie zmniejszyć rozmiar grafiki, choć przy źle przygotowanym materiale prowadziło do pasm kolorów, utraty subtelnych przejść i charakterystycznej ziarnistości. Tekstury nie musiały jednak przez cały czas znajdować się w 4 MB eDRAM-u. Mogły być przechowywane w głównej pamięci i przesyłane do Graphics Synthesizera wtedy, gdy stawały się potrzebne. Cała sztuka polegała na tym, aby transfer zakończył się przed rozpoczęciem rysowania danego obiektu. Jeżeli silnik ładował teksturę za późno, GS czekał bezczynnie albo wyświetlał niewłaściwe dane. Jeżeli przesłano ją zbyt wcześnie, mogła zająć miejsce potrzebne innemu elementowi sceny.
Dobre silniki traktowały więc eDRAM nie jak klasyczny magazyn wszystkich tekstur poziomu, lecz jak bardzo szybki obszar roboczy. Zawartość pamięci zmieniała się podczas budowania klatki. Gra mogła wczytać materiały potrzebne do narysowania tła, wykorzystać je, a następnie zastąpić teksturami postaci lub efektów znajdujących się bliżej kamery. Wymagało to precyzyjnego planowania, ale pozwalało pokazać znacznie więcej, niż sugerowała sama liczba czterech megabajtów. Graphics Synthesizer miał też tylko jedną jednostkę teksturującą. Jeżeli twórcy chcieli połączyć podstawową teksturę powierzchni z dodatkową warstwą światła, odbiciem albo innym efektem, często musieli narysować obiekt ponownie. Tak działał rendering wieloprzebiegowy: pierwszy przebieg tworzył podstawowy kolor, następny dokładał światło, kolejny odbicie albo poświatę. Na wielu układach takie ponowne rysowanie szybko zabijało wydajność. PS2 częściowo nadrabiało ograniczenia ogromnym fillrate’em, czyli zdolnością do zapisywania bardzo dużej liczby pikseli w ciągu sekundy.
Dlatego niektóre gry wyglądały na tej konsoli najlepiej wtedy, gdy zamiast walczyć z konstrukcją GS, bezczelnie wykorzystywały jej najważniejszą przewagę. Zone of the Enders: The 2nd Runner wypełniało ekran laserami, smugami, płomieniami, eksplozjami i półprzezroczystymi efektami. Burnout 3: Takedown łączył rozmycie obrazu, odbicia, iskry i szczątki rozpadających się pojazdów przy 60 klatkach na sekundę. Black budował wrażenie totalnej demolki przez dziesiątki śladów pocisków, odprysków, obłoków pyłu i efektów wybuchów. Graphics Synthesizer nie był najbardziej wszechstronnym układem swojej generacji, ale w dobrze dobranym zadaniu potrafił pracować z imponującą szybkością.
Wcześniej pokazało to już Metal Gear Solid 2. Deszcz na tankowcu składał się z ogromnej liczby przezroczystych smug, powierzchnie statku reagowały na wodę i światło, a wnętrza pełne były drobnych interaktywnych przedmiotów. Gra celowała przy tym w 60 klatek na sekundę. Konami nie korzystało z programowalnych shaderów znanych z późniejszych konsol. Złożony obraz budowano z geometrii przygotowanej przez Emotion Engine, kilku prostych warstw oraz bardzo szybkich operacji wykonywanych bezpośrednio w pamięci obrazu.
Same VU i GS nadal nie wystarczały. W PlayStation 2 najważniejsze było dostarczanie danych do odpowiedniego układu we właściwym momencie. Służył do tego dziesięciokanałowy kontroler DMA oraz interfejsy VIF i GIF. DMA przenosiło duże bloki danych między pamięcią i poszczególnymi podzespołami bez konieczności kopiowania każdej wartości przez główny procesor. CPU mógł w tym czasie wykonywać logikę gry, zamiast tracić tysiące cykli na mechaniczne przekładanie informacji. VIF obsługiwał przesyłanie danych do jednostek wektorowych. Potrafił rozpakowywać skompresowane informacje o wierzchołkach, ładować mikrokod i przygotowywać kolejne porcje geometrii. GIF odbierał gotowe pakiety poleceń i przekazywał je do Graphics Synthesizera. Dane nie wędrowały więc przypadkowo. Gra budowała dokładnie zaplanowany ciąg operacji: pobranie geometrii z pamięci, rozpakowanie, przeliczenie przez VU1, utworzenie poleceń rysowania i wysłanie ich do GS.
Największą wydajność uzyskiwano wtedy, gdy poszczególne etapy działały równolegle. VU1 przeliczało jedną partię geometrii, DMA dostarczało następną, a Graphics Synthesizer rysował jeszcze poprzednią. Pomagało w tym podwójne buforowanie. Jedna część pamięci była właśnie przetwarzana, podczas gdy druga otrzymywała świeże dane. Po zakończeniu pracy bufory zamieniały się rolami i cały proces zaczynał się od początku. Jeżeli którakolwiek jednostka nie otrzymała danych na czas, powstawał przestój. GS czekał na geometrię, VU1 na kolejną porcję wierzchołków, a CPU próbował ustalić, co właściwie się zatrzymało. Właśnie dlatego teoretyczna wydajność PS2 tak mocno odbiegała od rezultatów słabo zoptymalizowanych gier. Konsola nie posiadała jednego potężnego układu, który sam przejmował większość pracy. Programiści musieli świadomie podzielić zadania, zaplanować transfery i zsynchronizować kilka niezależnych elementów.
To również tłumaczy, dlaczego początki były tak bolesne. Andy Gavin z Naughty Dog określił PlayStation 2 jako sprzęt „absurdalnie trudny do programowania”, szczególnie w okresie, gdy brakowało dojrzałych bibliotek oraz działających przykładów. Sony dostarczyło dokumentację i zestawy deweloperskie, lecz studia nadal musiały zbudować własne renderery, mikrokod, systemy profilowania, narzędzia dla artystów oraz metody analizowania wydajności. Uruchomienie gry było dopiero początkiem. Prawdziwym wyzwaniem pozostawało doprowadzenie do sytuacji, w której żadna część tej skomplikowanej architektury nie czekała bezczynnie.
Kiedy programiści nauczyli się sterować chaosem
Różnicę między poznaniem podstaw, a rzeczywistym opanowaniem sprzętu najlepiej pokazuje Jak & Daxter: The Precursor Legacy. Naughty Dog chciało stworzyć jeden połączony świat, bez tradycyjnych ekranów ładowania i wyraźnego podziału na osobne plansze. Gracz miał zobaczyć charakterystyczną budowlę daleko na horyzoncie, przejść przez kilka obszarów i rzeczywiście do niej dotrzeć. W 2001 roku, przy 32 MB pamięci i stosunkowo wolnym napędzie optycznym, nie było to jeszcze standardem. Było jednym z głównych problemów całej produkcji.
Świat podzielono na fragmenty wczytywane i usuwane z pamięci zależnie od położenia gracza. Silnik nie mógł doczytać kolejnej lokacji dopiero wtedy, gdy Jak przekroczył jej granicę, ponieważ spowodowałoby to zatrzymanie gry. Musiał przewidzieć kierunek ruchu i wcześniej rozpocząć pobieranie potrzebnych modeli, tekstur, animacji, dźwięków oraz danych kolizji. Wymuszało to ścisłą współpracę projektantów poziomów z programistami. Droga pomiędzy obszarami musiała być odpowiednio długa, widok nie mógł odsłonić zbyt wielu szczegółowych lokacji jednocześnie, a gracz nie powinien otrzymać możliwości dotarcia do następnego punktu szybciej, niż pozwalał system streamingu.
Naughty Dog rozbudowało też kilka systemów LOD, czyli poziomów szczegółowości. Model znajdujący się blisko kamery otrzymywał pełną geometrię. W większej odległości zastępowała go prostsza wersja, a najdalsze elementy mogły zostać zredukowane do płaskich obiektów. Zmiana musiała odbywać się na tyle dyskretnie, aby gracz nie zauważał nagłego przeskakiwania między modelami. Jednocześnie odległa góra albo budowla musiała zachować właściwy kształt, ponieważ pełniła funkcję prawdziwego punktu orientacyjnego, a nie tylko obrazka namalowanego w tle. Przetworzenie całego świata wymagało pracy na lokacjach zawierających miliony polygonów, chociaż oczywiście tylko niewielka część trafiała jednocześnie na ekran. Silnik bezustannie wybierał potrzebne elementy, zmniejszał ich szczegółowość, usuwał obiekty niewidoczne i przygotowywał kolejne porcje geometrii dla jednostek wektorowych. Osiągnięcie Naughty Dog nie polegało więc na brutalnym narysowaniu wszystkiego. Polegało na konsekwentnym niedopuszczaniu, aby konsola zajmowała się czymkolwiek, czego gracz w danej chwili nie potrzebował.
Studio stworzyło również własny język programowania GOAL, oparty na Lispie. Niemal cały kod działający podczas gry - około pół miliona linii - napisano właśnie w nim. GOAL pozwalał skompilować zmienioną funkcję i przesłać ją do uruchomionej gry bez ponownego budowania oraz restartowania całego programu. Zachowanie przeciwnika, parametry kamery albo element logiki można było poprawić i niemal natychmiast sprawdzić na konsoli. Rozwiązanie znacząco przyspieszało eksperymentowanie, ale tworzyło również własne problemy. Naughty Dog zrezygnowało z popularnych debuggerów, profilerów i gotowych bibliotek, ponieważ nie współpracowały z autorskim językiem. Kompilator oraz najważniejsze narzędzia utrzymywała bardzo mała liczba osób. Jeżeli pojawiał się błąd, studio musiało poprawić nie tylko grę, ale czasami także język albo środowisko, w którym ją tworzono. GOAL dawał Naughty Dog przewagę, której konkurenci nie mogli łatwo skopiować, ale kosztował wiele miesięcy pracy, zanim stał się równie niezawodny do projektowania dużych produkcji.
Jeszcze lepiej wpływ sprzętu na projekt samej gry widać w Grand Theft Auto III. Najtrudniejszym zadaniem Rockstar North nie było narysowanie Liberty City, lecz utrzymanie miasta w ruchu przy zaledwie 32 MB pamięci. W RAM-ie znajdowało się tylko najbliższe otoczenie gracza. Budynki, pojazdy, piesi, skrypty, odgłosy i muzyka były na bieżąco wczytywane z płyty oraz usuwane, gdy przestawały być potrzebne. Samochody natychmiast komplikowały cały system. Pieszy poruszał się wystarczająco wolno, aby napęd spokojnie doczytał kolejną ulicę. Szybkie auto pozwalało w ciągu kilkunastu sekund przeciąć znaczną część dzielnicy. Streaming stawał się wyścigiem między pojazdem gracza, a głowicą napędu. Jeżeli samochód wygrał, przed nim mogła znaleźć się pusta przestrzeń albo obiekty pozbawione właściwych tekstur.
Programiści układali więc pliki na płycie tak, aby dane budynków sąsiadujących ze sobą w Liberty City znajdowały się blisko siebie również na fizycznym nośniku. Napęd nie musiał wtedy wykonywać długich przeskoków pomiędzy odległymi obszarami płyty. Skracało to czas dostępu, ale nadal nie rozwiązywało wszystkich problemów. W Portland istniała długa prosta, na której gracz mógł rozpędzić samochód i dotrzeć do następnego fragmentu miasta przed zakończeniem jego wczytywania. Projektanci zmienili więc układ dzielnicy i ustawili na trasie budynek wymuszający objazd. W innych problematycznych miejscach silnik zwiększał opór powietrza pojazdów o około 5-10 procent. Samochód zwalniał na tyle nieznacznie, że gracz zwykle tego nie zauważał, ale napęd otrzymywał dodatkowy czas na dostarczenie danych.
Ograniczona pamięć odpowiadała również za powtarzające się modele aut. Według byłego dyrektora technicznego Rockstar North w pamięci mieściło się jednocześnie tylko siedem typów pojazdów. Część miejsc mogła zostać zajęta przez samochody wymagane w misji, karetkę wezwaną do rannego przechodnia albo pojazdy służb związane z poziomem poszukiwania. Przy maksymalnym pościgu gra potrzebowała radiowozów, furgonetek SWAT, samochodu FBI i helikoptera. Dla zwykłego ruchu ulicznego pozostawały wtedy dwa lub trzy modele, które zaczynały występować ze znacznie większą częstotliwością. San Andreas doprowadziło ten system do granic możliwości. Trzy miasta, lasy, tereny wiejskie, pustynia, lotniska, samoloty, łodzie, pociągi, rozbudowane misje i ogrom aktywności nadal mieściły się w architekturze stworzonej dla znacznie mniejszych gier. Rockstar początkowo rozważał podział świata na trzy osobne mapy, ponieważ 32 MB RAM-u wydawały się zbyt poważnym ograniczeniem. Ostatecznie powstała jedna połączona przestrzeń, ale nie dlatego, że w Emotion Engine odkryto nagle dodatkową moc. Zespół miał za sobą GTA III i Vice City, znacznie dojrzalszy system streamingu oraz kilka lat doświadczenia w zarządzaniu każdym megabajtem pamięci.
Przy Final Fantasy XII ograniczenie nie polegało na szybkości przemieszczania się przez miasto, lecz na liczbie oraz różnorodności zasobów. Modele Ashe i Vaana składały się z około 1500 polygonów każdy. Dzisiaj podobny budżet można przeznaczyć na fragment wyposażenia postaci, ale Square Enix musiało zmieścić w grze pełną drużynę, przeciwników, rozległe lokacje, efekty oraz płynny system walki. Niski polygon count nie oznaczał automatycznie prostego wyglądu. Twórcy bardzo dokładnie rozmieszczali wierzchołki w miejscach wpływających na sylwetkę, twarz oraz animację. Dobre tekstury sugerowały szczegóły, których nie było w geometrii, a starannie przygotowane oświetlenie i ruch postaci odciągały uwagę od kanciastych fragmentów modeli. Gracz oceniał spójny obraz, nie liczbę trójkątów.
Jednocześnie Final Fantasy XII zawierało około 250 rodzajów potworów, 30 bossów i tysiąc postaci niezależnych. Dla porównania w Final Fantasy X było niewiele ponad dwustu NPC-ów. Wyzwaniem nie było więc stworzenie jednego wyjątkowo szczegółowego bohatera, lecz utrzymanie ogromnej liczby modeli, animacji, tekstur i efektów przy bardzo ograniczonej pamięci. Square Enix przygotowało do tego własny zestaw narzędzi. Model-San służył do pracy nad efektami przypisanymi modelom. ZEEK3 umożliwiał edycję dwuwymiarowych animacji używanych między innymi w cząsteczkach i od początku uwzględniał limity tekstur oraz płynności PS2. Effect-Chan łączył efekty z kamerą, dźwiękiem i wibracjami kontrolera. Motion-Chan odpowiadał za animacje postaci oraz ich kompresję.
Najważniejsza była możliwość sprawdzania zmian bezpośrednio na docelowym sprzęcie. Tekstura wyglądająca poprawnie w Mayi mogła po zmniejszeniu, ograniczeniu palety kolorów i wyświetleniu z przeplotem stracić ostrość albo zacząć migotać. Artyści aktualizowali więc materiały oraz oświetlenie na zestawie deweloperskim i oglądali rezultat na prawdziwym telewizorze. Przy PS2 narzędzia stanowiły jeden z głównych warunków osiągnięcia wysokiej jakości.
Gry, które nie miały prawa tak wyglądać
Najbardziej bezczelnym pokazem możliwości konsoli pozostaje Shadow of the Colossus. Studio Team Ico połączyło wielki świat doczytywany bez klasycznych ekranów ładowania z kolosami, które były jednocześnie przeciwnikami, ruchomymi elementami otoczenia i poziomami, po których poruszał się bohater. Każdy olbrzym musiał reagować na nierówności terenu, wykonywać rozbudowane animacje, przyjmować uderzenia i utrzymywać Wanderera na swoim ciele. Do tego dochodziły futro, dynamiczne cienie, pył, zmienne oświetlenie oraz kamera obejmująca ogromną część krajobrazu.
Futro nie składało się z tysięcy osobno symulowanych włosów. Twórcy nakładali na model kilka lekko odsuniętych od siebie warstw geometrii. Każda otrzymywała teksturę z przezroczystymi fragmentami przedstawiającymi włosy na innej głębokości. Gdy warstwy wyświetlano jednocześnie, powstawało wrażenie puszystej powierzchni. Dodatkowe płaskie kępki wystawały ponad główny obrys i maskowały warstwową budowę efektu. Rozwiązanie było pomysłowe, ale kosztowne. Ten sam fragment ciała kolosa trzeba było narysować kilka razy, a każdy przebieg zawierał przezroczyste elementy. To właśnie overdraw: wielokrotne przetwarzanie tych samych pikseli, zanim powstanie ich ostateczny kolor. W wielu układach graficznych tak duża liczba warstw szybko obniżyłaby wydajność. Graphics Synthesizer ze swoją szybką pamięcią obrazu był do podobnych operacji wyjątkowo dobrze przygotowany, chociaż nawet on nie wykonywał ich za darmo.
Gra stosowała również rozwiązanie imitujące HDR oraz adaptację wzroku. Prawdziwy rendering HDR przechowuje znacznie szerszy zakres jasności, niż można bezpośrednio pokazać na ekranie, a następnie przekształca go w gotowy obraz. PS2 nie realizowało tego w sposób znany ze współczesnych silników. Team Ico analizowało jednak jasność sceny, zmieniało ekspozycję i dodawało bloom - miękką poświatę powstającą wokół najmocniejszych źródeł światła. Gdy Wander wychodził z ciemnego wnętrza na otwartą przestrzeń, obraz przez chwilę stawał się prześwietlony, po czym stopniowo wracał do normalnej jasności. Symulowało to zachowanie ludzkiego wzroku, który potrzebuje chwili na dostosowanie się do gwałtownej zmiany oświetlenia. Efekt nie był fizycznie dokładnym HDR-em, ale dawał bardzo podobne wrażenie i stał się jednym z najbardziej rozpoznawalnych elementów oprawy gry.
Rozmycie ruchu również nie wymagało śledzenia drogi każdego piksela. Gra wykorzystywała informacje z poprzednich klatek i mieszała je z aktualnym obrazem. Podczas gwałtownego obrotu kamery albo ruchu kolosa wcześniejsza klatka pozostawała przez moment widoczna, tworząc charakterystyczną smugę. Metoda potrafiła generować artefakty i nie wyglądała tak czysto jak współczesne rozwiązania wykorzystujące wektory ruchu, ale znakomicie podkreślała ciężar potworów i maskowała część problemów z płynnością. Team Ico korzystało także z "inverse kinematics". W zwykłej animacji artysta ustala położenie kolejnych stawów, a stopa trafia w miejsce wynikające z gotowej sekwencji. IK zaczyna od końca: system określa punkt, w którym powinna znaleźć się stopa albo dłoń, a następnie wylicza odpowiednie ułożenie pozostałych części kończyny. Dzięki temu nogi kolosów mogły lepiej reagować na teren, kopyta Agro dopasowywały się do podłoża, a kończyny Wanderera przekonująco podążały za ruchem olbrzyma.
Ogromne znaczenie miały również uproszczone modele kolizji. Bohater nie sprawdzał kontaktu z każdym polygonem szczegółowego ciała kolosa. Byłoby to zbyt kosztowne i podatne na błędy. Gra używała prostszych powierzchni opisujących fragmenty, po których można było chodzić albo się wspinać. Musiały one jednak odkształcać się razem z animowanym potworem. Kolos nie był nieruchomą mapą ubraną w efektowny model. Jego ciało poruszało się, obracało i zmieniało kształt, a system musiał stale aktualizować podłoże znajdujące się pod bohaterem. Rachunek za tę ambicję przychodził w postaci płynności. Shadow of the Colossus regularnie spadało poniżej 30 klatek na sekundę, a w najbardziej wymagających scenach działało jeszcze wolniej. Trudno więc przedstawiać tę produkcję jako wzór idealnej optymalizacji. Był to raczej świadomy wybór priorytetów. Twórcy uznali, że skala kolosów, futro, światło, pył i ruch świata są ważniejsze niż stabilny licznik. Technicznie gra często znajdowała się na granicy wydolności konsoli. Właśnie dlatego tak dobrze pokazywała, gdzie ta granica naprawdę przebiegała.
Santa Monica Studio wybrało zupełnie inną drogę przy God of War, a szczególnie przy God of War II. Największą przewagę dawała reżyserowana kamera. Gracz nie mógł swobodnie obracać widoku, więc twórcy z góry wiedzieli, które fragmenty świata znajdą się w kadrze, jak duże będą poszczególne obiekty i w którym momencie należy rozpocząć doczytywanie następnego obszaru. Pozwalało to agresywnie odrzucać niewidoczną geometrię. Element znajdujący się za kamerą nie musiał być wysyłany do Graphics Synthesizera. Odległa konstrukcja mogła korzystać z uproszczonego modelu, a szczegóły widoczne tylko przez kilka sekund otrzymywały dokładnie taki budżet, jakiego wymagało dane ujęcie. Jeśli kamera nigdy nie pokazywała tylnej części wielkiego obiektu, ten fragment mógł być bardzo prosty albo nie istnieć wcale.
Reżyserowany widok ułatwiał także ukrywanie streamingu. Podczas przechodzenia przez wąski korytarz, wspinaczki albo krótkiej animacji otwierania przejścia silnik usuwał poprzednie zasoby i pobierał kolejną część poziomu. Duże panoramy projektowano tak, aby odległe elementy wyglądały monumentalnie, ale nie wymagały pełnej geometrii, dokładnych tekstur i rozbudowanej kolizji. Skala pozostawała prawdziwa z perspektywy gracza, nawet jeżeli technicznie była zbiorem bardzo dokładnie ustawionych kompromisów. Dlatego God of War II mogło rozpocząć się walką z Kolosem Rodyjskim, a później regularnie prezentować ogromne mechanizmy, ruchome konstrukcje, olbrzymich przeciwników i rozległe panoramy. Konsola nie przechowywała w pamięci całego spektaklu. W każdej chwili utrzymywała tylko te jego części, które rzeczywiście budowały aktualny kadr. Santa Monica zamieniło ograniczenie kamery w jedno z najskuteczniejszych narzędzi optymalizacji całej generacji.
Inne gry trafiały bezpośrednio w największą przewagę Graphics Synthesizera. Zone of the Enders: The 2nd Runner wypełniało ekran laserami, smugami, eksplozjami i półprzezroczystymi warstwami, a cel-shading ograniczał potrzebę stosowania skomplikowanych materiałów. Prostszy sposób cieniowania modeli nie oznaczał gorszej grafiki. Pozwalał przeznaczyć wydajność na szybkość, liczbę przeciwników i efekty, które nadawały walkom charakterystyczną intensywność.
Burnout 3: Takedown utrzymywał 60 klatek na sekundę, pokazując jednocześnie gęsty ruch, rozbudowane kraksy, refleksy na karoserii, rozmycie obrazu, smugi świateł, iskry i dziesiątki szczątków. Wysoka płynność była tutaj kluczowa, ponieważ przy dużej prędkości każda dłuższa klatka natychmiast psułaby sterowanie i poczucie pędu. Criterion podporządkowało więc cały obraz jednemu celowi: gracz miał czuć prędkość nawet wtedy, gdy szczegółowość tekstur i otoczenia musiała ustąpić miejsca ruchowi.
Black korzystał z podobnej filozofii, ale zamiast prędkości sprzedawał siłę broni. Kurz, iskry, odpryski, ślady pocisków, płomienie, rozbite elementy i niezwykle agresywny dźwięk tworzyły wrażenie, że każdy strzał rozrywa otoczenie. Nie był to pełny system dowolnej destrukcji. Część obiektów miała przygotowane reakcje, inne pozostawały całkowicie niezniszczalne. Criterion nie symulowało całego budynku rozpadającego się według praw fizyki. Dokładnie wybierało miejsca, w których odpowiednio ustawiony efekt miał przekonać gracza, że właśnie to zrobiło.
Gran Turismo 4 pokazywało natomiast siłę specjalizacji w znacznie spokojniejszym wydaniu. Tor wyścigowy jest środowiskiem łatwiejszym do kontrolowania niż otwarte miasto. Ma znany przebieg, określoną liczbę samochodów oraz przewidywalny kierunek jazdy. Polyphony Digital mogło wcześniej przygotować poziomy szczegółowości, dokładnie rozmieścić obiekty, ustalić momenty doczytywania i poświęcić dużą część budżetu na modele pojazdów, odbicia oraz płynność. Gra działała w 60 klatkach na sekundę, obsługiwała tryb progresywny 480p, a w amerykańskiej wersji pozwalała również wysłać do telewizora sygnał 1080i. Nie był to jednak natywny obraz 1920 x 1080, jak nadal można przeczytać w wielu zestawieniach. PS2 renderowało obraz w niższej rozdzielczości, a następnie odpowiednio go przekształcało i skalowało. Nadal było to imponujące osiągnięcie jak na 2004 rok, zwłaszcza że większość graczy korzystała wówczas z telewizorów kineskopowych. Po prostu nie był to cud dokładnie tego rodzaju, jaki po latach dopisała mu internetowa legenda.
PlayStation 2 pozostanie legendarne na wieki
Właśnie na tym polegała największa siła późnych gier na PlayStation 2. Nie próbowały wykonywać wszystkich zadań w taki sam sposób jak Xbox, GameCube czy komputer. Każde studio wybierało inną drogę. Team Ico zaakceptowało spadki płynności, aby zbudować kolosy i niezwykłe oświetlenie. Santa Monica podporządkowało świat kamerze. Polyphony zamknęło gracza na precyzyjnie kontrolowanych torach. Criterion wykorzystało fillrate do zasypania ekranu efektami, a Naughty Dog i Rockstar uczyniły ze streamingu część konstrukcji swoich światów.
PS2 nie przestało mieć 32 MB RAM-u i 4 MB eDRAM-u. Programiści po prostu nauczyli się, których danych nie przechowywać, których obiektów nie rysować, kiedy zmniejszyć ich szczegółowość i w którym momencie podmienić zawartość pamięci. Największe techniczne osiągnięcia tej konsoli nie polegały na ignorowaniu ograniczeń. Polegały na wykorzystaniu ich tak dokładnie, że gracz przestawał je zauważać.
Przeczytaj również
Komentarze (8)
SORTUJ OD: Najnowszych / Najstarszych / Popularnych