Urządzenie HardDoom ][™

Grafika w grze Doom 2

Rzutowanie dowolnej geometrii trójwymiarowej na dwuwymiarową płaszczyznę jest dość skomplikowane obliczeniowo. Jednym z ważniejszych elementów jest obliczenie współczynnika perspektywy dla każdego rysowanego piksela – wymaga to obliczenia odwrotności pierwiastka kwadratowego. Jest to bardzo kosztowna operacja i wykonanie jej dla każdego piksela ekranu jest niemożliwe przy zachowaniu rozsądnej ilości ramek na sekundę, nawet dla najnowocześniejszych i napotężniejszych procesorów i486, nie mówiąc już o procesorach i386 używanych obecnie przez większość graczy.

Gra Doom 2 zalicza się do tzw. gier 2.5D – choć grafika wygląda na trójwymiarową (i jest bardzo realistyczna), użyta geometria oraz punkt widzenia są bardzo ograniczone. Użytkownik może patrzeć tylko przed siebie (a nie w górę czy w dół), a w świecie gry spotkamy tylko 3 typy obiektów:

  • pionowe ściany – po zrzutowaniu na ekran, każda pokryta kolumna pikseli składa się z pikseli o równym współczynniku perspektywy, pozwalając na wyliczenie go tylko raz na każdą kolumnę.
  • poziome płaszczyzny (podłogi i sufity) – po zrzutowaniu na ekran, każda pokryta linia pikseli składa się z pikseli o równym współczynniku perspektywy.
  • obiekty ruchome, rysowane przez skopiowanie prosto na ekran przeskalowanych tzw. sprite’ów, czyli przygotowanych przez autorów zdjęć, zrobionych z 8 różnych kątów.

Główna praca rysowania świata gry spada na dwie gorące funkcje:

  • R_DrawColumn – rysuje kolumnę pikseli z podanej kolumny tekstury i z podanym współczynnikiem skalowania. Używane do rysowania ścian, obiektów oraz grafiki interfejsu.
  • R_DrawSpan – rysuje poziomy pasek pikseli, teksturując podaną teksturą płaszczyzny (wycinając z tej tekstury linię pod dowolnym kątem i nakładając ją na rysowany pasek).

Urządzenie HardDoom ][™ dostarcza sprzętową implementację powyższych funkcji, przejmując większość obciążenia z głównego procesora i pozwalając na grę w wysokich rozdzielczościach (płynna rozgrywka na 640×480!) nawet na starszych procesorach. Oprócz tych funkcji, urządzenie dostarcza również kilka pomniejszych funkcji pomocniczych, pozwalając na rysowanie całej grafiki gry na urządzeniu.

Urządzenie

Urządzenie jest podłączane do komputera przez szynę PCI – identyfikator producenta to 0x0666, a identyfikator urządzenia to 0x1994.

Urządzenie nie posiada własnej pamięci i operuje na buforach w głównej pamięci komputera przez bezpośredni dostęp do pamięci (DMA). Ponieważ główna pamięć komputera podlega fragmentacji, a bufory mogą być całkiem duże (urządzenie obsługuje 2048×2048 pikseli), urządzenie wykonuje dostęp do większości buforów przez tablicę stron w swoim własnym formacie.

Urządzeniem steruje się przez rejestry wejścia/wyjścia zmapowane do pamięci (MMIO). Ten obszar MMIO jest pierwszym i jedynym obszarem BAR używanym przez urządzenie (BAR0). Urządzenie wykorzystuje również jedną linię przerwania PCI.

Obszar MMIO ma wielkość 8kiB, ale tylko niektóre bajty z tego zakresu są używane na rejestry. Wszystkie udokumentowane rejestry są 32-bitowe w formacie little-endian i powinny być używane tylko przez wyrównane 32-bitowe odczyty i zapisy.

Bufory i blok stronicowania

Urządzenie używa następujących buforów (opisanych bardziej szczegółowo niżej):

  • bufor poleceń – zmiennego rozmiaru.
  • bufory ramki (“surface”) – zmiennego rozmiaru.
  • atlas tekstur kolumnowych (“texture”) – zmiennego rozmiaru.
  • atlas tekstur płaskich (“flat”) – zmiennego rozmiaru, wielokrotność 2**12 bajtów.
  • atlas map kolorów (“colormap”) – zmiennego rozmiaru, wielokrotność 2**8 bajtów.
  • mapa przezroczystości (“tranmap”) – zawsze rozmiaru 2**16 bajtów.

Urządzenie pisze tylko do bufora ramki – pozostałe bufory są używane tylko do odczytu.

Bufory wybiera się przez podanie adresu ich tabeli stron. W każdej chwili wybrane jest 8 buforów:

  • CMD: bufor poleceń, z którego urządzenie wczytuje polecenia.
  • SURF_DST: bufor ramki, do którego urządzenie będzie rysować.
  • SURF_SRC: bufor ramki, z którego urządzenie będzie kopiować dane (dla polecenia COPY_RECT).
  • TEXTURE: atlas tekstur kolumnowych, z których urządzenie będzie rysować (dla polecenia DRAW_COLUMN).
  • FLAT: atlas tekstur płaskich, z których urządzenie będzie rysować (dla poleceń DRAW_BACKGROUND, DRAW_SPAN).
  • COLORMAP: atlas map kolorów do oświetlenia i efektów specjalnych.
  • TRANSLATION: atlas map kolorów do zmiany palety kolorów.
  • TRANMAP: mapa przezroczystości.

Urządzenie używa 40-bitowych adresów fizycznych (zarówno dla buforów jak i dla tabel stron).

Wybrany bufor poleceń ustawia się przez zapis rejestru CMD_PT. Pozostałe bufory ustawia się przez wysłanie polecenia SETUP. W każdym wypadku, wybrany bufor podaje się jako 32-bitową wartość, która jest przesuniętym wskaźnikiem adresu tabeli stron bufora (bity 8-39 adresu fizycznego tabeli stron to podana wartość, pozostałe bity adresu są zerami).

Urządzenie używa stron o wielkości 4kiB. Tabele stron mogą zawierać maksymalnie 1024 wpisy (czyli opisywać 4MiB pamięci – maksymalny rozmiar bufora) i muszą być wyrównane do 256 bajtów. Wpisy tabeli stron mają 4 bajty i odpowiadają bezpośrednio kolejnym stronom bufora. Wpisy tabeli stron są 32-bitowymi słowami o następującym formacie:

  • bit 0: VALID – jeśli ustawiony, wpis jest poprawny i może być użyty. Jeśli nie jest ustawiony, próba użycia wpisu spowoduje błąd PAGE_FAULT i wyłączenie odpowiedniego bloku w ENABLE (XY dla SURF_*, TEX dla TEXTURE). [XXX: FE]
  • bit 1: WRITABLE – jeśli ustawiony, ta strona jest dostępna do odczytu i zapisu. Jeśli nie jest ustawiony, ta strona jest dostępna tylko do odczytu, a próba zapisu spowoduje błąd PAGE_FAULT i wyłączenie odpowiedniego bloku w ENABLE.
  • bity 2-3: nieużywane, powinny być równe 0.
  • bity 4-31: ADDR – bity 12-39 adresu fizycznego strony.

Rozmiar tabeli stron nie jest nigdzie podawany – urządzenie w żaden sposób nie sprawdza, czy użyty offset w buforze zmieści się w tabeli stron. Sterownik powinien zapewnić, że tabela będzie odpowiednio duża i pilnować wysyłanych poleceń, czyli:

  • weryfikować, że wysyłane współrzędne y mieszczą się w wysokości buforów ramek,
  • limitować odczyt tekseli z tekstur kolumnowych przez użycie TEXTURE_LIMIT,
  • weryfikować, że FLAT_IDX, COLORMAP_IDX, TRANSLATION_IDX mieszczą się w rozmiarze odpowiednich atlasów.

Aby nie czytać ciągle tabeli stron, urządzenie może zapamiętywać dane z tabeli stron w buforach TLB. Zmiana aktywnego bufora (przez polecenie SETUP bądź zapis CMD_PT) czyści bufory TLB odpowiadające danemu buforowi, a użycie bitu TLB w rejestrze RESET czyści wszystkie bufory TLB.

W razie wystąpienia błędu PAGE_FAULT, urządzenie można zrestartować przez wpisanie odpowiedniej wartości w tabelę stron, skasowanie TLB, oraz włączenie z powrotem odpowiedniego bloku w ENABLE – kontynuuje wtedy pracę od momentu w którym trafiło na błąd strony.

Bufory ramek

Bufor ramki to obszar w pamięci służący do rysowania. Jest to po prostu dwuwymiarowa tablicą pikseli. Ponieważ urządzenie było projektowane zanim wynaleziono kolor 24-bitowy (albo nawet 16-bitowy), każdy piksel jest po prostu bajtem – odpowiadającym jakiemuś kolorowi z palety (obsługą palety zajmuje się urządzenie wyświetlające i nie musimy się nią przejmować). Urządzenie obsługuje bufory ramki o dowolnej dodatniej szerokości podzielnej przez 64 i nie większej niż 2048 piksele. Wysokość natomiast może być dowolna z zakresu 1 .. 2048. Bufor ramki jest prostą tablicą bajtów – adres piksela (x, y) wewnątrz bufora to po prostu x + y * width.

Szerokość aktywnych buforów ramki jest ustawiana poleceniem SETUP.

Urządzenie sprawdza współrzędną x pikseli, których używa – przekroczenie szerokości bufora spowoduje błąd SURF_DST_OVERFLOW lub SURF_SRC_OVERFLOW i wyłączenie bloku XY w ENABLE.

Tekstury kolumnowe

Tekstury kolumnowe zawierają dane obrazu, który polecenie DRAW_COLUMN będzie rysowało do bufora ramki (po przeskalowaniu i przetworzeniu). Mają dość skomplikowany format i składają z tekseli pogrupowanych w kolumny (które nie muszą pokrywać całej powierzchni tekstury – tekstury kolumnowe mogą mieć dziury). Urządzenie nie przejmuje się dokładnym formatem tych tekstur – znalezienie w nim początku odpowiedniej kolumny jest zadaniem silnika gry. Tekstury kolumnowe mogą mieć dość dowolny rozmiar (w praktyce od kilkudziesięciu bajtów do kilkudziesięciu kilobajtów, zazwyczaj ok. 2 kiB) i mogą być grupowane w atlasy (bufory zawierające wiele tekstur). Urządzenie obsługuje atlasy o wielkościach do 4MiB.

Aktywny atlas tekstur kolumnowych ustawia się poleceniem SETUP. Aktywną teksturę (a właściwie kolumnę z tekstury) wybiera się przy wysyłaniu polecenia DRAW_COLUMN przez podanie parametrów TEXTURE_OFFSET, TEXTURE_HEIGHT i TEXTURE_LIMIT. Wysokość jest używana do powtarzania tekstury w pionie – współrzędne w kolumnie tekstury będą brane modulo wysokość.

Próba czytania adresu z poza zakresu 0 .. TEXTURE_LIMIT << 6 | 0x3f zostanie zablokowana przez urządzenie i spowoduje użycie do teksturowania tekseli zerowych.

Urządzenie może zapamiętywać dane z używanego atlasu tekstur w swojej pamięci podręcznej – aby wyczyścić tą pamięć, wystarczy zmienić aktywny atlas przez wysłanie polecenia SETUP z flagą TEXTURE (to zresetuje pamięć podręczną nawet, jeśli nie zmieni się przez to adres aktywnej tabeli stron).

Note

Aby nie mylić pojęć z odpowiadającymi pojęciami w buforach ramki, w grafice komputerowej przyjęło się nazywać współrzędne w teksturze U oraz V (zamiast X i Y), a pojedynczy element – tekselem (zamiast piksela).

Tekstury płaskie

Tekstury płaskie są używane przez polecenie DRAW_SPAN do rysowania podłóg i sufitów. Mają zawsze wymiary 64×64 tekseli, zajmują 2**12 bajtów, a ich adres początkowy musi być wyrównany do 2**12 bajtów. Podobnie do tekstur kolumnowych, mogą być grupowane w atlasy tekstur płaskich.

Aktywny atlas tekstur płaskich ustawia się poleceniem SETUP z flagą FLAT. Aktywną teksturę wybiera sie przy wysyłaniu polecenia DRAW_SPAN bądź DRAW_BACKGROUND przez parametr FLAT_IDX (wybrana tekstura płaska jest pod adresem FLAT_IDX * 2 ** 12 wewnątrz bufora).

Analogicznie do tekstury kolumnowej, urządzenie może zapamiętywać dane z tekstury płaskiej w pamięci podręcznej. Wysłanie polecenia SETUP z flagą FLAT czyści tą pamięć.

Mapy kolorów

Mapy kolorów są po prostu tablicami mapującymi kolory z palety na inne kolory – mają przez to zawsze dokładnie 256 bajtów. Ich adres musi być również wyrównany do 256 bajtów. Są używane do wielu efektów:

  • zamiana palety kolorów, aby umożliwić użycie tej samej tekstury do kilku wersji kolorystycznych (tzw. palette swap) – w końcu pamięć jest droga
  • ściemnianie kolorów (do symulacji słabego oświetlenia)
  • zmiana skali kolorów (np. przefarbowanie wszystkiego na niebiesko pod wodą)

Urządzenie ma dwa aktywne atlasy map kolorów, wybierane poleceniem SETUP z flagami COLORMAP i TRANSLATION. Aktywną mapę kolorów można wybrać dla każdego polecenia przez podanie indeksu w odpowiednim atlasie (wybrana mapa kolorów znajduje się pod adresem indeks * 256 w odpowienim buforze).

Podobnie do tekstur, urządzenie może kopiować dane map do pamięci podręcznej. Wysłanie polecenia SETUP z flagą COLORMAP bądż TRANSLATION czyści zawartość odpowiadającej pamięci.

Ustawione mapy kolorów są używane przez polecenia DRAW_COLUMN i DRAW_SPAN tylko wtedy, gdy ustawione są odpowiednie flagi – COLORMAP dla mapy COLORMAP_*, TRANSLATION dla mapy TRANSLATION_*. Polecenie DRAW_FUZZ zawsze używa mapy COLORMAP_* do efektu cienia.

Mapy przezroczystości

Aby uzyskać efekt przezroczystości w grafice komputerowej, potrzebna jest jakaś funkcja scalająca dwa kolory – kolor tła oraz kolor rysowanego obiektu. W przypadku grafiki używającej schematu True Color, wystarczyłoby zsumować składowe kolorów z odpowiednimi wagami. Jednak w przypadku grafiki używającej palety kolorów, trzeba to zrobić używając obliczonej wcześniej tabeli – mapy przezroczystości. Mapa przezroczystości jest dwuwymiarową tablicą bajtów o rozmiarze 256×256. Jest to po prostu tablica mapująca pary kolorów na scalony kolor.

Urządzenie ma jedną aktywną mapę przezroczystości, wybieraną poleceniem SETUP z flagą TRANMAP. Znajduje się ona pod adresem 0 w wybranym buforze.

Podobnie do tekstur i map kolorów, dane z mapy kolorów mogą być przechowywane przez urządzenie w pamięci podręcznej.

Wysyłanie poleceń

Urządzenie sterowane jest w większości przez wysyłanie mu poleceń. Każde polecenie jest pakietem złożonym z ośmiu 32-bitowych słów. Polecenia mogą być wysyłane bezpośrednio przez rejestry MMIO (jest to mniej wydajna opcja), bądź przez wskazanie bufora w pamięci, z którego urządzenie powinno wczytywać polecenia (bardziej wydajna opcja). W przypadku wysłania niepoprawnego polecenia, wyzwalane jest przerwanie FE_ERROR, a blok FE zostanie wyłączony w rejestrze ENABLE.

Urządzenie obsługuje 8 różnych poleceń:

  • 0: COPY_RECT – kopiuje prostokątny obszar między dwoma buforami ramki.
  • 1: FILL_RECT – wypełnia prostokątny obszar jednym kolorem.
  • 2: DRAW_LINE – rysuje prostą jednokolorową linię między dwoma punktami.
  • 3: DRAW_BACKGROUND – rysuje tło – wypełnia prostokątny obszar powtarzaną w nieskończoność teksturą płaską.
  • 4: DRAW_COLUMN – rysuje kolumnę pikseli używając tekstury kolumnowej.
  • 5: DRAW_FUZZ – aplikuje efekt rozmytego cienia na kolumnie pikseli.
  • 6: DRAW_SPAN – rysuje pasek pikseli używając tekstury płaskiej.
  • 7: SETUP – zmiena bufory używane przez urządzenie.

Urządzenie przyjmuje polecenia w jednym z dwóch formatów. Format pierwszy jest używany dla wszystkich poleceń poza SETUP i wygląda następująco:

  • słowo 0:
    • bity 0-3: CMD_TYPE – typ polecenia (z powyższej listy).
    • bit 4: INTERLOCK – zapewnia zakończenie wszystkich wcześniejeszych poleceń przed rozpoczęciem wczytywania danych dla tego polecenia (i wszystkich późniejszych).
    • bit 5: PING_ASYNC – wyzwala przerwanie po wczytaniu tego polecenia.
    • bit 6: PING_SYNC – wyzwala przerwanie po zakończeniu przetwarzania tego polecenia.
    • bit 7: FENCE – zwiększa licznik FENCE_COUNTER po zakończeniu przetwarzania tego polecenia (i wszystkich wcześniejszych).
    • bit 8: TRANSLATION – włącza zamianę palety kolorów. Jeśli włączony, kolory z tekstury są tłumaczone przez mapę kolorów z TRANSLATION_IDX.
    • bit 9: COLORMAP – włącza mapowanie rysowanych kolorów. Jeśli włączony, kolory z tekstury są tłumaczone przez mapę kolorów z COLORMAP_IDX (po TRANSLATION_IDX, jeśli obydwie mapy są włączone).
    • bit 10: TRANMAP – włącza przezroczystość. Jeśli włączony, rysowane kolory są scalane z obecnymi kolorami w buforze ramki przez mapę przezroczystości (TRANMAP_PT).
  • słowo 1:
    • bity 0-13: TRANSLATION_IDX – indeks użytej mapy kolorów dla zmiany palety w DRAW_COLUMN i DRAW_SPAN. Użyta mapa kolorów pochodzi z adresu TRANSLATION_IDX * 2**8 wewnątrz bufora wyznaczonego przez TRANSLATION_PT
    • bity 16-29: COLORMAP_IDX – indeks użytej mapy kolorów dla oświetlenia i efektów dla DRAW_COLUMN, DRAW_SPAN, oraz DRAW_FUZZ. Użyta mapa kolorów pochodzi z adresu COLORMAP_IDX * 2**8 wewnątrz bufora wyznaczonego przez COLORMAP_PT
  • słowo 2:
    • bity 0-10: X_A – współrzędna x pierwszego punktu będącego parametrem operacji (interepretacja zależy od konkretnego polecenia, nie wszystkie polecenia tego używają).
    • bity 11-21: Y_A – współrzędna y pierwszego punktu będącego parametrem operacji.
    • bity 22-31: FLAT_IDX – indeks użytej tekstury płaskiej w aktywnym atlasie tekstur płaskich (dla DRAW_BACKGROUND, DRAW_SPAN).
  • słowo 3:
    • bity 0-10: X_B – współrzędna x drugiego punktu będącego parametrem operacji.
    • bity 11-21: Y_B – współrzędna y drugiego punktu będącego parametrem operacji.
  • słowo 4: USTART – współrzędna u w teksturze używana dla skrajnie lewego piksela paska (dla DRAW_SPAN) bądź górnego piksela kolumny (dla DRAW_COLUMN). Jest to liczba stałoprzecinkowa – 16 wysokich bitów to część całkowita, a 16 niskich to część ułamkowa.
  • słowo 5: USTEP – pochodna współrzędnej u w teksturze względem współrzędnej x lub y w buforze ramki. Liczba stałoprzecinkowa ze znakiem.
  • słowo 6:
    • dla poleceń COPY_RECT, FILL_RECT, DRAW_LINE, DRAW_BACKGROUND:
      • bity 0-11: WIDTH – szerokość prostokąta (dla COPY_RECT, FILL_RECT, DRAW_BACKGROUND).
      • bity 12-23: HEIGHT – wysokość prostokąta.
      • bity 24-31: FILL_COLOR – kolor wypełnienia dla FILL_RECT, kolor linii dla DRAW_LINE.
    • dla polecenia DRAW_COLUMN:
      • bity 0-21: TEXTURE_OFFSET – offset początku danych kolumny w aktywnym atlasie tekstur kolumnowych w bajtach.
    • dla polecenia DRAW_SPAN: VSTART – współrzędna v w teksturze używana dla skrajnie lewego piksela paska (dla DRAW_SPAN). Również liczba stałoprzecinkowa.
    • dla polecenia DRAW_FUZZ:
      • bity 0-10: FUZZ_START – współrzędna y początku pola widzenia.
      • bity 12-22: FUZZ_END – współrzędna y końca pola widzenia.
      • bity 24-29: FUZZ_POS – źródło losowości dla efektu cienia.
  • słowo 7:
    • dla polecenia DRAW_COLUMN:
      • bity 0-15: TEXTURE_LIMIT – określa ostatni poprawny adres w teksturze kolumnowej, liczony w 64-bajtowych blokach (adres ostatniego poprawnego bajtu to TEXTURE_LIMIT << 6 | 0x3f).
      • bity 16-31: TEXTURE_HEIGHT – wysokość tekstury w tekselach, jeśli tekstura ma być powtarzana w pionie (współrzędne w kolumnie tekstury będą brane modulo wysokość) bądź 0, jeśli tekstura nie ma być powtarzana.
    • dla polecenia DRAW_SPAN: VSTEP – pochodna współrzędnej u w teksturze względem współrzędnej x lub y w buforze ramki. Liczba stałoprzecinkowa ze znakiem.
    • dla pozostałych poleceń: nieużywane.

Format drugi jest używany dla polecenia SETUP i jest opisany razem z nim.

Wszystkie nieużywane pola (czy to kompletnie niezdefiniowane, czy nie stosujące się dla danego typu polecenia) muszą być ustawione na 0 – w przeciwnym wypadku, zachowanie urządzenia nie jest zdefiniowane.

Bezpośredni dostęp

Polecenia można wysyłać do urządzenia bezpośrednio przez MMIO, używając następujących rejestrów:

BAR0 + 0x0070: CMD_FREE
Rejestr tylko do odczytu. Odczytana wartość jest liczbą wolnych miejsc w kolejce poleceń (tyle poleceń można natychmiast zapisać do CMD_SEND bez obaw o CMD_OVERFLOW). Kolejka ta ma maksymalną pojemność 512 poleceń.
BAR0 + 0x0040 + i * 4, i < 8: CMD_SEND
Rejestry tylko do zapisu. Można wysłać polecenie do urządzenia, zapisując jego kolejne słowa do kolejnych rejestrów z tej tablicy (i-te słowo do i-tego rejestru, w kolejności). Zapis ostatniego słowa powoduje dopisanie zapisanego polecenia na koniec kolejki poleceń. Jeśli kolejka jest już pełna (CMD_FREE == 0), zamiast tego wyzwalane jest przerwanie CMD_OVERFLOW, a blok CMD_SEND jest wyłączany w ENABLE.

Blok wczytywania poleceń

Blok wczytywania poleceń pozwala na efektywne sterowanie urządzeniem (bez konieczności ręcznego wysyłania każdego polecenia przez MMIO) przez samodzielne wczytywanie poleceń z pamięci. Rejestry bloku wczytywania poleceń sa następujące:

BAR0 + 0x0060: CMD_PT
Wskaźnik na tabelę stron opisującą bufor poleceń, przesunięty w prawo o 8 bitów (rejestr przechowuje bity 8-39 adresu fizycznego). Zapis tego rejestru powoduje spłukanie bufora TLB dotyczącego bufora poleceń.
BAR0 + 0x0064: CMD_SIZE
Rozmiar bufora poleceń, liczony w poleceniach (czyli w 32-bajtowych pakietach). Gdy urządzenie zwiększa CMD_READ_IDX, a obecną wartością jest CMD_SIZE-1, zachodzi zawinięcie bufora i nową wartością będzie 0.
BAR0 + 0x0068: CMD_READ_IDX
Indeks następnego polecenie do wczytania (liczony w 32-bajtowych pakietach).
BAR0 + 0x006c: CMD_WRITE_IDX
Indeks miejsca, gdzie procesor ma zapisać następne polecenie. Jeśli CMD_WRITE_IDX == CMD_READ_IDX, blok wczytywania poleceń zostanie zatrzymany, aż procesor załaduje więcej poleceń i przesunie CMD_WRITE_IDX.

Blok wczytywania poleceń będzie wczytywał polecenia zawsze, gdy zachodzą wszystkie z następujących warunków:

  • blok wczytywania poleceń jest włączony w ENABLE
  • są jakieś nieprzetworzone polecenia, tzn. CMD_READ_IDX != CMD_WRITE_IDX
  • jest miejsce w kolejce poleceń, tzn. CMD_FREE != 0

Polecenie wczytywane jest z indeksu CMD_READ_IDX, jest on zwiększany o 1 (ewentualnie jest zawijany do 0, jesli wynosi obecnie CMD_SIZE-1), po czym polecenie jest dopisywane do kolejki (tak, jakby zostało wpisane do CMD_SEND).

Warning

Po resecie urządzenia, CMD_READ_IDX nie musi być równe CMD_WRITE_IDX – blok wczytywania poleceń może więc próbować wczytać jakieś polecenia po włączeniu go w ENABLE. Aby tego uniknąć, należy zainicjować te rejestry.

Opis poleceń

Polecenie SETUP

Polecenie SETUP służy do zmiany aktywnych buforów. Ma specjalny format, inny od pozostałych poleceń:

  • słowo 0:
    • bity 0-3: CMD_TYPE – typ polecenia (z powyższej listy).
    • bit 4: INTERLOCK – zapewnia zakończenie wszystkich wcześniejeszych poleceń przed rozpoczęciem wczytywania danych dla tego polecenia (i wszystkich późniejszych).
    • bit 5: PING_ASYNC – wyzwala przerwanie po wczytaniu tego polecenia.
    • bit 6: PING_SYNC – wyzwala przerwanie po zakończeniu przetwarzania tego polecenia.
    • bit 7: FENCE – zwiększa licznik FENCE_COUNTER po zakończeniu przetwarzania tego polecenia (i wszystkich wcześniejszych).
    • bit 9: SURF_DST – zmienia aktywny docelowy bufor ramki.
    • bit 10: SURF_SRC – zmienia aktywny źródłowy bufor ramki.
    • bit 11: TEXTURE – zmienia aktywną teksturę kolumnową.
    • bit 12: FLAT – zmienia aktywną teksturę płaską.
    • bit 13: TRANSLATION – zmienia aktywny atlas map kolorów do zmiany palety.
    • bit 14: COLORMAP – zmienia aktywny atlas map kolorów do efektów i oświetlenia.
    • bit 15: TRANMAP – zmienia aktywną mapę przezroczystości.
    • bity 16-21: SURF_DST_WIDTH – bity 6-11 szerokości ramki docelowej (bity 0-5 szerokości są równe 0). Ignorowane, jeśli nie jest ustawiony bit SURF_DST.
    • bity 24-29: SURF_SRC_WIDTH – bity 6-11 szerokości ramki źródłowej (bity 0-5 szerokości są równe 0). Ignorowane, jeśli nie jest ustawiony bit SURF_SRC.
  • słowo 1: SURF_DST_PT: bity 8-39 adresu tabeli stron opisującej docelowy bufor ramki. Ignorowane, jeśli nie jest ustawiony bit SURF_DST.
  • słowo 2: SURF_SRC_PT: jak wyżej, źródłowy bufor ramki.
  • słowo 3: TEXTURE_PT: jak wyżej, bufor tekstury kolumnowej.
  • słowo 4: FLAT_PT: jak wyżej, bufor tekstury płaskiej.
  • słowo 5: TRANSLATION_PT: jak wyżej, atlas map kolorów do zmiany palety.
  • słowo 6: COLORMAP_PT: jak wyżej, atlas map kolorów do efektów i oświetlenia.
  • słowo 7: TRANMAP_PT: jak wyżej, mapa przezroczystości.

Jednym poleceniem SETUP można zmienić dowolny podzbiór ustawień (wybrany przez bity w słowie 0). Będą one obowiązywały aż do zmiany ich przez kolejne polecenie SETUP.

Wykonanie tego polecenia resetuje jednocześnie bufory TLB dla wszystkich buforów wybranych w słowie 0 (nawet, jeśli wybrany adres tabeli stron jest identyczny z wcześniej obowiązującym). Analogicznie, dla wybranych buforów czyszczona jest pamięć podręczna.

Polecenie COPY_RECT

Polega na skopiowaniu zadanego prostokąta z jednego bufora ramki (SURF_SRC_PT) do drugiego (SURF_DST_PT). Obydwa bufory ramki muszą być tych samych rozmiarów. Jego parametry to:

  • pozycja lewego górnego rogu prostokąta docelowego (X_A, Y_A),
  • pozycja lewego górnego rogu prostokąta źródłówego (X_B, Y_B),
  • wymiary prostokąta (WIDTH, HEIGHT).

Polecenie COPY_RECT nie powinno być wykonywane, gdy kopiujemy wewnątrz jednego bufora, a prostokąt źródłowy ma część wspólną z prostokątem docelowym – wynik jest wtedy niedeterministyczny.

Warning

Urządzenie może wczytywać dane źródłowe dla COPY_RECT asynchronicznie do procesu rysowania. Aby zapewnić, że urządzenie zakończyło wcześniejesze operacje rysowania do źródłowego prostokąta zanim zacznie z niego czytać, należy ustawić flagę INTERLOCK (opisane niżej).

Polecenie jest używane w grze do skopiowania przygotowanego wcześniej panelu dolnego oraz do efektu przejścia (“melt”).

Polecenie FILL_RECT

Polega na wypełnieniu zadanego prostokąta w buforze ramki (SURF_DST_PT) jednym kolorem. Jego parametry to:

  • pozycja lewego górnego rogu prostokąta (X_A, Y_A),
  • wymiary prostokąta (WIDTH, HEIGHT),
  • kolor (FILL_COLOR).

Jest używane w grze do rysowania tła mapy (dostępnej pod klawiszem Tab).

Polecenie DRAW_LINE

Rysuje jednokolorową linię prostą o szerokości 1 piksela między podanymi dwoma punktami w zadanym buforze ramki (SURF_DST_PT). Jego parametry to:

  • pozycja punktu początkowego (X_A, Y_A),
  • pozycja punktu końcowego (X_B, Y_B),
  • kolor (FILL_COLOR).

Jest używane w grze do rysowania mapy (dostępnej pod klawiszem Tab).

Polecenie DRAW_BACKGROUND

Wypełnia zadany prostokąt w buforze ramki (SURF_DST_PT) powtarzającymi się kopiami tekstury płaskiej (FLAT_PT). Jego parametry to:

  • pozycja lewego górnego rogu prostokąta (X_A, Y_A),
  • wymiary prostokąta (WIDTH, HEIGHT),

Jest używane w grze do rysowania tła do ekranu opcji, tła do tekstu “fabuły” wyświetlanego po ukończeniu niektórych poziomów, oraz jako obramowanie ekranu w przypadku wybrania pola widzenia mniejszego niż ekran (klawisz -).

Polecenie DRAW_COLUMN

Rysuje teksturowaną kolumnę do bufora ramki (SURF_DST_PT).

Jego parametry to:

  • współrzędne górnego punktu kolumny (X_A, Y_A),
  • współrzędne dolnego punktu kolumny (X_B, Y_B),
  • flagi TRANSLATION, COLORMAP, TRANMAP,
  • wartość początkowa współrzędnej u w teksturze (USTART),
  • pochodna współrzędnej u po współrzędnej y (USTEP),
  • offset początku danych kolumny w teksturze kolumnowej (TEXTURE_OFFSET),
  • mapa kolorów do efektów i oświetlenia (COLORMAP_IDX) – jeśli ustawiona jest flaga COLORMAP,
  • mapa kolorów do zmiany palety (TRANSLATION_IDX – jeśli ustawiona jest flaga TRANSLATION.

Polecenie rysuje kolumnę pikseli do bufora ramki na współrzędnych X_A, Y_A do X_B, Y_B. X_A powinno być równe X_B, a Y_A powinno być mniejsze od lub równe Y_B (inaczej zachowanie urządzenia jest niezdefiniowane).

Rysowana kolumna jest teksturowana za pomocą następującego algorytmu:

# Obliczenie koloru dla piksela (x, y).
coord = (USTART + USTEP * (y - Y_A)) >> 16
if TEXTURE_DIMS.HEIGHT != 0:
    coord %= TEXTURE_HEIGHT
tex_offset = TEXTURE_OFFSET + coord
if tex_offset < 0 or (tex_offset >> 6) > TEXTURE_LIMIT:
    color = 0;
else:
    color = read_paged(TEXTURE_PT, tex_offset)
if TRANSLATION:
    color = read_paged(TRANSLATION_PT, TRANSLATION_IDX << 8 | color)
if COLORMAP:
    color = read_paged(COLOR_PT, COLOR_IDX << 8 | color)
if TRANMAP:
    bg_color = surf_read(SURF_DST_PT, x, y);
    color = read_paged(TRANMAP_PT, bg_color << 8 | color)

Polecenie DRAW_FUZZ

Aplikuje efekt rozmytego cienia na kolumnie w buforze ramki (SURF_DST_PT).

Jego parametry to:

  • współrzędne górnego punktu kolumny (X_A, Y_A),
  • współrzędne dolnego punktu kolumny (X_B, Y_B),
  • mapa kolorów do efektu cienia (COLORMAP_IDX),
  • początkowa współrzędna y pola widzenia (FUZZ_START) – potrzebna, by efekt rozmycia nie użył pikseli z poza rysowanego obszaru ramki,
  • końcowa współrzędna y pola widzenia (FUZZ_END),
  • źródło losowości dla efektu cienia (FUZZ_POS) – liczba z zakresu 0-55,

Polecenie modyfikuje kolumnę pikseli w buforze ramki na współrzędnych X_A, Y_A do X_B, Y_B. X_A powinno być równe X_B, a współrzędnie y powinny spełniać nierówność FUZZ_START Y_A Y_B FUZZ_END (inaczej zachowanie urządzenia jest niezdefiniowane). Urządzenie może przeczytać piksele z wybranej kolumny o współrzędnych y z zakresu [FUZZ_START, FUZZ_END].

Polecenie DRAW_SPAN

Rysuje teksturowany pasek do bufora ramki (SURF_DST_PT).

Jego parametry to:

  • współrzędne lewego punktu paska (X_A, Y_A),
  • współrzędne prawego punktu paska (X_B, Y_B),
  • flagi TRANSLATE, COLORMAP, TRANMAP
  • wartość początkowa współrzędnych u i v w teksturze (USTART, VSTART),
  • pochodna współrzędnych u i v po współrzędnej x (USTEP, VSTEP),
  • mapa kolorów do efektów i oświetlenia (COLORMAP_IDX) – jeśli ustawiona jest flaga COLORMAP,
  • mapa kolorów do zmiany palety (TRANSLATION_IDX – jeśli ustawiona jest flaga TRANSLATE.

Polecenie rysuje pasek pikseli do bufora ramki na współrzędnych X_A, Y_A do X_B, Y_B. Y_A powinno być równe Y_B, a X_A powinno być mniejsze od lub równe X_B (inaczej zachowanie urządzenia jest niezdefiniowane).

Rysowany pasek jest teksturowany za pomocą następującego algorytmu:

# Obliczenie koloru dla piksela (x, y).
u = (USTART + USTEP * (x - X_A)) >> 16 & 0x3f
v = (VSTART + VSTEP * (x - X_A)) >> 16 & 0x3f
color = read_paged(FLAT_PT, u | v << 6)
if TRANSLATE:
    color = read_paged(TRANSLATION_PT, TRANSLATION_IDX << 8 | color)
if COLORMAP:
    color = read_paged(COLOR_PT, COLOR_IDX << 8 | color)
if TRANMAP:
    bg_color = surf_read(SURF_DST_PT, x, y);
    color = read_paged(TRANMAP_PT, bg_color << 8 | color)

Synchronizacja

Blok rysujący działa wysoce asynchronicznie i równolegle. W szczególności, urządzenie może:

  • wczytywać nowe polecenia przed zakończeniem wykonania poprzednich.
  • wczytywać dane źródłowe dla polecenia przed zakończeniem wykonywania poprzednich poleceń (należy na to uważać przy operacji COPY_RECT!).
  • rozpocząć rysowanie pikseli dla nowej operacji przed zakończeniem poprzedniej operacji (ale tylko, jeśli operacje te operują na rozłącznych pikselach w buforze ramki).
  • opóźnić rozpoczęcie wykonywania operacji do momentu wysłania kolejnych poleceń (aby spróbować połączyć je w większą paczkę wewnętrznych operacji).

Mamy jednak następujące gwarancje:

  • każde polecenie będzie używało stanu parametrów (adresów i rozmiarów buforów) z momentu jego rozpoczęcia.
  • jeśli wyślemy polecenie resetujące pamięć podręczną bądź bufor TLB, każde polecenie wysłane później będzie widziało dane wczytane już po wykonaniu tego resetu.
  • dla konkretnego piksela w docelowym buforze ramki, polecenia będą wykonywane zgodnie z kolejnością wysyłania (czyli wygra ostatni zapis).
  • polecenie COPY_RECT wczyta wszystkie swoje dane źródłowe przed rozpoczęciem rysowania późniejszych poleceń.
  • urządzenie nie może mieć więcej niż 2048 poleceń w locie (wczytanych do FIFO, ale jeszcze nie wykonanych) – dopóki nasz bufor poleceń jest mniejszy niż 2**32 - 2048, nie musimy się przejmować, że skończą nam się wolne identyfikatory do FENCE_COUNTER.
  • wysłanie polecenia z flagą FENCE bądź PING_SYNC spowoduje wykonanie go w skończonym czasie (bez tych flag, mikrokod może oczekiwać na kolejne polecenia, by spróbować połączyć je w większe paczki).

Flaga INTERLOCK

W praktyce, wykonanie przez urządzenie daje efekty identyczne do wykonania sekwencyjnego, z jednym ważnym wyjątkiem – polecenie COPY_RECT może wczytać piksele danego bufora ramki zanim poprzednie polecenia zdążą je zapisać. Aby uniknąć tego problemu, należy wykryć taką możliwość w sterowniku i użyć flagi INTERLOCK w poleceniu. Flaga INTERLOCK blokuje rozpoczęcie wczytywania danych przez obecne i późniejsze polecenia COPY_RECT do momentu pełnego zakończenia wcześniejszych operacji rysujących.

Aby wszystko działało poprawnie, wystarczy zapewnić, że między operacją rysowania do danego bufora a operacją COPY_RECT czytającą z niego znajdzie się co najmniej jedno polecenie z ustawioną flagą INTERLOCK.

Flagi PING_SYNC i PING_ASYNC

W każdym poleceniu możemy ustawić flagi PING_SYNC oraz PING_ASYNC. Jeśli ustawiona jest flaga PING_SYNC, urządzenie wyzwoli przerwanie PONG_SYNC po pełnym zakończeniu wykonywania danego polecenia. Jeśli ustawiona jest flaga PING_ASYNC, urządzenie wyzwoli przerwanie PONG_ASYNC gdy tylko polecenie zostanie wczytane z kolejki i zacznie się wykonywać.

Licznik poleceń

Do elastycznego oczekiwania na wykonanie operacji przez urządzenie służy licznik poleceń, dostępny w następujących rejestrach MMIO:

BAR0 + 0x0010: FENCE_COUNTER
Rejestr do odczytu i zapisu, 32-bitowy. Zlicza zakończone polecenia z ustawioną flagą FENCE – licznik jest zwiększany o 1 (modulo 2**32), gdy dane polecenie (i wszystkie poprzednie polecenia) zostanie w pełni zakończone. (Jeśli licznik na początku wynosi 0 i zaczniemy wysyłać polecenia, po czym odczytamy wartość x, oznacza to, że polecenia 0..x-1 zostały w pełni zakońćzone.)
BAR0 + 0x0014: FENCE_WAIT
Rejestr do odczytu i zapisu, 32-bitowy (tak jak FENCE_COUNTER). Gdy FENCE_COUNTER zostanie zwiększony przez urządzenie i osiągnie przez to wartość równą wartości tego rejestru, zostanie wyzwolone przerwanie FENCE.

FENCE_WAIT pozwala na zaawansowaną implementację oczekiwania na wysłane wcześniej polecenia. Przykładowy mechanizm użycia wygląda następująco:

  • przed włączeniem urządzenia, inicjujemy FENCE_COUNTER na 0.
  • na końcu każdej paczki poleceń, na zakończenie której chcemy czekać, wysyłamy polecenie z ustawioną flagą FENCE.
  • dla każdego wysłanego polecenia z flagą FENCE pamiętamy jego odpowiadającą wartość FENCE_COUNTER (dla kolejnych poleceń, kolejno 1, 2, 3, ..., zawijając się modulo 2**32).
  • nie dopuszczamy, by kiedykolwiek było więcej niż 2**32 poleceń z flagą FENCE “w locie” (w razie potrzeby czekając na zakończenie poprzednich poleceń przed wysłaniem kolejnego).
  • jeśli w pewnym momencie uznamy, że chcemy oczekiwać na wykonanie wysłanego wcześniej polecenia:
    • czyścimy przerwanie FENCE.
    • ustawiamy FENCE_WAIT na numer polecenia, na które chcemy oczekiwać.
    • czytamy FENCE_COUNTER i sprawdzamy, czy polecenie już się wykonało.
    • jeśli się nie wykonało, czekamy na wyzwolenie przerwania FENCE.

Przed rozpoczęciem pracy, sterownik może zainicjować FENCE_COUNTER na pożądaną wartość początkową (prawdopodobnie 0). Pisanie do tego rejestru, gdy urządzenie jest już aktywne, jest prawdopodobnie złym pomysłem.

Rejestry sterujące

Blok sterujący zajmuje się nadzorowaniem pracy całego urządzenia. Jego rejestry to:

BAR0 + 0x0000: ENABLE

Rejestr kontrolujący pracę pozostałych bloków, dostępny do odczytu i zapisu. Ma wiele bitów, z których każdy kontroluje pracę jednego bloku urządzenia (1 – blok jest aktywny i może wykonywać pracę, 0 – blok jest nieaktywny). Wyłączenie bloku w tym rejestrze nie spowoduje jego resetu – po ponownym włączeniu, blok kontynuuje pracę od momentu, w którym skończył. Bity:

  • bit 0: CMD_FETCH – blok wczytywania poleceń.
  • bit 1: CMD_SEND – dostęp do kolejki poleceń przez CMD_SEND.
  • bit 2: FE – blok rysujący, przetwarzanie poleceń.
  • bit 3: XY – blok rysujący, przeliczanie współrzędnych na adresy.
  • bit 4: TEX – blok rysujący, obsługa tekstur kolumnowych.
  • bit 5: FLAT – blok rysujący, obsługa tekstur płaskich.
  • bit 6: FUZZ – blok rysujący, efekt FUZZ.
  • bit 7: SR – blok rysujący, wczytywanie pikseli z bufora ramki.
  • bit 8: OG – blok rysujący, zbieranie danych i mapy kolorów
  • bit 9: SW – blok rysujący, mapy przezroczystości i zapis do bufora ramki.

Rejestr jest ustawiany na 0 przez reset maszyny, blokując urządzenie do momentu załadowania sterownika. W przypadku zgłoszenia błędu przez blok rysujący, urządzenie wyzeruje odpowiedni bit w tym rejestrze, zatrzymując blok do momentu naprawienia problemu przez sterownik.

Warning

Przed włączeniem urządzenia, należy pamiętać o:

  • załadowaniu mikrokodu przez FE_CODE_ADDR i FE_CODE_WINDOW
  • zresetowaniu wszystkich bloków w RESET,
  • zainicjowaniu rejestrów CMD_*_IDX (jeśli używamy bloku wczytywania poleceń)
  • wyzerowaniu przerwań (w INTR)
BAR0 + 0x0004: RESET

Rejestr resetowania stanu urządzenia, dostępny tylko do zapisu. Ma wiele bitów, odpowiadających blokom urządzenia. Przy zapisie, wszystkie bloki, których bity są równe 1 w zapisanej wartości, są resetowane: wszystkie polecenia w trakcie wykonywania są przerywane i kasowane, kolejki poleceń i pamięci podręczne są czyszczone. Bity:

  • bit 2: FE – blok rysujący, przetwarzanie poleceń.
  • bit 3: XY – blok rysujący, przeliczanie współrzędnych na adresy.
  • bit 4: TEX – blok rysujący, obsługa tekstur kolumnowych.
  • bit 5: FLAT – blok rysujący, obsługa tekstur płaskich.
  • bit 6: FUZZ – blok rysujący, efekt FUZZ.
  • bit 7: SR – blok rysujący, wczytywanie pikseli z bufora ramki.
  • bit 8: OG – blok rysujący, zbieranie danych i mapy kolorów
  • bit 9: SW – blok rysujący, mapy przezroczystości i zapis do bufora ramki.
  • bit 10: STATS – blok statystyk. Wszystkie liczniki są ustawiane na 0.
  • bit 11: TLB – bufory TLB. Wszystkie wpisy tabeli stron zapisane w TLB są kasowane i, w razie potrzeby, zostaną wczytane na nowo.
  • bit 12: TEX_CACHE – pamięć podręczna tekstury kolumnowej.
  • bit 13: FLAT_CACHE – pamięć podręczna tekstury płaskiej.
  • bit 14: SW_CACHE – pamięć podręczna mapy przezroczystości.
  • bit 16: FIFO_FECMD – główna kolejka poleceń bloku rysującego.
  • bit 17: FIFO_XYCMD – wewnętrzna kolejka urządzenia.
  • bit 18: FIFO_TEXCMD – wewnętrzna kolejka urządzenia.
  • bit 19: FIFO_FLATCMD – wewnętrzna kolejka urządzenia.
  • bit 20: FIFO_FUZZCMD – wewnętrzna kolejka urządzenia.
  • bit 21: FIFO_OGCMD – wewnętrzna kolejka urządzenia.
  • bit 22: FIFO_SWCMD – wewnętrzna kolejka urządzenia.
  • bit 24: FIFO_XYOUTR – wewnętrzna kolejka urządzenia.
  • bit 25: FIFO_XYOUTW – wewnętrzna kolejka urządzenia.
  • bit 26: FIFO_SROUT – wewnętrzna kolejka urządzenia.
  • bit 27: FIFO_TEXOUT – wewnętrzna kolejka urządzenia.
  • bit 28: FIFO_FLATOUT – wewnętrzna kolejka urządzenia.
  • bit 29: FIFO_FUZZOUT – wewnętrzna kolejka urządzenia.
  • bit 30: FIFO_OGOUT – wewnętrzna kolejka urządzenia.
  • bit 31: FIFO_XYSYNC – wewnętrzna kolejka urządzenia.

Użycie bitów TLB, STATS i *_CACHE w dowolnym momencie nie wpłynie negatywnie na pracę urządzenia. Wszystkie pozostałe bity powinny być używane w zasadzie tylko wtedy, gdy resetujemy całe urządzenie (gdyż w przeciwnym przypadku stan poszczególnych bloków się rozsynchronizuje).

Warning

Przed użyciem urządzenia (włączeniem bloku rysującego w ENABLE) należy zresetować cały blok rysujący (zapisując 0xff7f7ffc do tego rejestru) – w przeciwnym wypadku, wewnętrzne rejestry stanu urządzenia mogą zawierać śmieci, powodując wykonanie nieokreślonych poleceń przez urządzenie (w tym zapisu do dowolnej pamięci) bądź zawieszenie urządzenia.

Blok wczytywania poleceń nie ma swojego bitu resetującego – jeśli sterownik chce go użyć, powinien zamiast tego zainicjować rejestry CMD_*_IDX.

Przerwania

Urządzenie wewnętrznie używa 10 przerwań (które są agregowane w jedno przerwanie PCI):

  • FENCE – przerwanie używane do powiadomienia sterownika o wykonaniu polecenia. Wyzwalane, gdy licznik poleceń osiągnie wartość FENCE_WAIT.
  • PONG_SYNC – wyzwalane przez polecenie z flagą PING_SYNC.
  • PONG_ASYNC – wyzwalane przez polecenie z flagą PING_ASYNC.
  • FE_ERROR – wyzwalane, gdy blok rysujący zauważy błędne polecenie.
  • CMD_OVERFLOW – wyzwalane, gdy sterownik spróbuje pisać do CMD_SEND, gdy nie ma już wolnego miejsca w kolejce, lub blok CMD_SEND jest wyłączony.
  • SURF_DST_OVERFLOW – wyzwalane, gdy blok rysujący spróbuje pisać lub czytać piksel o współrzędnych poza szerokością docelowego bufora ramki (ustaloną przez SURF_DST_WIDTH).
  • SURF_SRC_OVERFLOW – wyzwalane, gdy blok rysujący spróbuje lub czytać piksel o współrzędnych poza szerokością źródłowego bufora ramki (ustaloną przez SURF_SRC_WIDTH).
  • PAGE_FAULT_CMD – wyzwalane, gdy blok wczytywania poleceń użyć strony oznaczonej w tabeli stron jako nieobecna.
  • PAGE_FAULT_SURF_DST – wyzwalane, gdy blok rysujący spróbuje użyć strony oznaczonej w tabeli stron jako nieobecna bądź tylko do odczytu przy pisaniu lub czytaniu docelowego bufora ramki.
  • PAGE_FAULT_SURF_SRC – jak wyżej, ale do źródłowego bufora ramki.
  • PAGE_FAULT_TEXTURE – jak wyżej, ale do czytania tekstury kolumnowej.
  • PAGE_FAULT_FLAT – jak wyżej, ale do czytania tekstury płaskiej.
  • PAGE_FAULT_TRANSLATION – jak wyżej, ale do czytania map kolorów do zmiany palety.
  • PAGE_FAULT_COLORMAP – jak wyżej, ale do czytania map kolorów do efektów i oświetlenia.
  • PAGE_FAULT_TRANMAP – jak wyżej, ale do czytania mapy przezroczystości.

Warning

Wyzwolenie przerwania SURF_*_OVERFLOW jest zasadniczo błędem krytycznym – nie ma sensownej możliwości obsługi tego błędu innej niż pełny reset urządzenia. To przerwanie (tak jak i FE_ERROR czy CMD_OVERFLOW) nie powinno się nigdy zdarzyć z poprawnym sterownikiem. Przerwania PAGE_FAULT_* teoretycznie mogą zostać użyte do ładowania stron na żądanie, ale w praktyce nie jest to zbyt przydatne i w zasadzie służą również do wykrywania błędów sterownika.

Każde z powyższych przerwań może być w danej chwili aktywne bądź nie. Przerwanie staje się aktywne, gdy zajdzie odpowiednie zdarzenie. Przerwanie staje się nieaktywne, gdy sterownik zapisze 1 do odpowiedniego bitu w rejestrze INTR. Aby sprawdzić, które przerwania są aktywne, należy przeczytać rejestr INTR.

Niezależnie, każde z powyższych przerwań może być w danej chwili włączone bądź nie. Sterownik może ustawić włączony podzbiór przerwań przez zapis odpowiedniej maski do rejestru INTR_ENABLE. Urządzenie zgłasza przerwanie na swojej linii przerwań PCI wtedy i tylko wtedy, gdy istnieje włączone i aktywne przerwanie.

BAR0 + 0x0008: INTR

Rejestr statusu przerwań. Ma 15 bitów, każdy odpowiadający jednemu rodzajowi przerwań:

  • bit 0: FENCE,
  • bit 1: PONG_SYNC,
  • bit 2: PONG_ASYNC,
  • bit 4: FE_ERROR,
  • bit 5: CMD_OVERFLOW
  • bit 6: SURF_DST_OVERFLOW
  • bit 7: SURF_SRC_OVERFLOW
  • bit 8: PAGE_FAULT_CMD
  • bit 9: PAGE_FAULT_SURF_DST
  • bit 10: PAGE_FAULT_SURF_SRC
  • bit 11: PAGE_FAULT_TEXTURE
  • bit 12: PAGE_FAULT_FLAT
  • bit 13: PAGE_FAULT_TRANSLATION
  • bit 14: PAGE_FAULT_COLORMAP
  • bit 15: PAGE_FAULT_TRANMAP

Odczyt tego rejestru zwróci 1 dla aktywnych przerwań, 0 dla nieaktywnych. Zapis spowoduje wyzerowanie (ustawienie na nieaktywne) wszystkich przerwań, dla których został zapisany bit 1. Przykładowo, zapisanie 0x12 spowoduje wyzerowanie przerwań FE_ERROR oraz PONG_SYNC.

BAR0 + 0x000c: INTR_ENABLE
Rejestr włączania przerwań, dostępny do odczytu i zapisu. Ma takie same bity jak INTR. 1 oznacza przerwanie włączone, a 0 – przerwanie wyłączone. Przy resecie maszyny, rejestr zostaje ustawiony na 0, blokując możliwość zgłaszania przerwania PCI przez urządzenie do momentu załadowania sterownika.

Mikrokod

Blok rysujący opiera się na zaawansowanym procesorze odpowiadającym za przetwarzanie poleceń. Przed włączeniem bloku rysującego w ENABLE, sterownik musi załadować odpowiedni mikrokod na urządzenie – w przeciwnym wypadku, zachowanie urządzenia jest kompletnie niezdefiniowane. Mikrokod jest tablicą 32-bitowych słów, maksymalnie 4096-elementową. Jest dostarczany w pliku https://github.com/koriakin/harddoom2/blob/master/doomcode2.bin w formacie little-endian, a jego format i działanie jest tajemnicą handlową firmy DoomDevices® (i nie należy zadawać niewygodnych pytań na jego temat). Można go również pobrać jako plik nagłówkowy gotowy do załączenia do kodu w C: https://github.com/koriakin/harddoom2/blob/master/doomcode2.h . Do ładowania mikrokodu służą następujące rejestry:

BAR0 + 0x0100: FE_CODE_ADDR
Indeks w tablicy, który będziemy widoczny przez FE_CODE_WINDOW (dostępny do odczytu i zapisu).
BAR0 + 0x0104: FE_CODE_WINDOW
Okno do tablicy mikrokodu – odczytuje bądź zapisuje komórkę wybrana przez FE_CODE_ADDR, po czym zwiększa FE_CODE_ADDR o 1 (pozwalając na szybki sekwencyjny odczyt bądź zapis wielu komórek tablicy).

Uruchomienie urządzenia

Poprawna procedura uruchamiania urządzenia jest następująca (użycie dowolnej innej procedury spowoduje utratę gwarancji i brak możliwości zwrotu urządzenia):

  • zapisać 0 do FE_CODE_ADDR,
  • wczytać zawartość pliku doomcode2.bin jako tablicę 32-bitowych słów little-endian,
  • kolejno zapisać wszystkie wczytane słowa do FE_CODE_WINDOW,
  • zresetować wszystkie bloki urządzenia przez zapis 0xff7f7ffc do RESET,
  • zainicjować CMD_PT, CMD_SIZE i CMD_*_IDX, jeśli chcemy użyć bloku wczytywania pleceń,
  • wyzerować INTR przez zapis 0xfff7,
  • włączyć używane przez nas przerwania w INTR_ENABLE,
  • zainicjować FENCE_COUNTER, jeśli czujemy taką potrzebę,
  • włączyć wszystkie bloki urządzenia w ENABLE (być może z wyjątkiem CMD_FETCH).

Po wykonaniu tej procedury można rozpocząć wysyłanie poleceń do urządzenia (przez CMD_SEND lub CMD_WRITE_IDX).

Żeby wyłączyć urządzenie, wystarczy zapisać 0 do ENABLE oraz INTR_ENABLE, po czym przeczytać dowolny rejestr urządzenia.

Inne rejestry

Dokumentacja sprzętowa nigdy nie mówi całej prawdy (i rzadko mówi tylko prawdę). Urządzenie może mieć inne rejestry i polecenia ponad wyżej wymienione, lecz używanie ich w ostatecznym sterowniku jest złym pomysłem – są to po prostu szczegóły implementacyjne. Mogą jednak być przydatne przy debugowaniu…

Poniższe rejestry nie są potrzebne do napisania sterownika, ale mają sporą szansę się przydać (oprócz nich, urządzenie zawiera wiele nieudokumentowanych rejestrów).

Rejestry błędów

W przypadku popełnienia błędu przez sterownik, przydatne może być przeczytanie następujących rejestrów:

BAR0 + 0x004: STATUS

Rejestr statusu, tylko do odczytu. Ma wiele bitów, odpowiadających blokom urządzenia. Gdy bit jest równy 1, dany blok ma pracę do wykonania (i, jeśli odpowiedni bit w ENABLE jest równy 1, będzie próbował ją wykonać). Gdy bit jest równy 0, dany blok nie ma nic do zrobienia (ale może się to w każdej chwili zmienić, jeżeli inny blok zleci mu jakieś zadania). Bity:

  • bit 0: CMD_FETCH – blok wczytywania poleceń (ten bit jest efektywnie równy CMD_READ_IDX != CMD_WRITE_IDX).
  • bit 2: FE – blok rysujący, przetwarzanie poleceń.
  • bit 3: XY – blok rysujący, przeliczanie współrzędnych na adresy.
  • bit 4: TEX – blok rysujący, obsługa tekstur kolumnowych.
  • bit 5: FLAT – blok rysujący, obsługa tekstur płaskich.
  • bit 6: FUZZ – blok rysujący, efekt FUZZ.
  • bit 7: SR – blok rysujący, wczytywanie pikseli z bufora ramki.
  • bit 8: OG – blok rysujący, zbieranie danych i mapy kolorów
  • bit 9: SW – blok rysujący, mapy przezroczystości i zapis do bufora ramki.
  • bit 16: FIFO_FECMD – główna kolejka poleceń bloku rysującego.
  • bit 17: FIFO_XYCMD – wewnętrzna kolejka urządzenia.
  • bit 18: FIFO_TEXCMD – wewnętrzna kolejka urządzenia.
  • bit 19: FIFO_FLATCMD – wewnętrzna kolejka urządzenia.
  • bit 20: FIFO_FUZZCMD – wewnętrzna kolejka urządzenia.
  • bit 21: FIFO_OGCMD – wewnętrzna kolejka urządzenia.
  • bit 22: FIFO_SWCMD – wewnętrzna kolejka urządzenia.
  • bit 24: FIFO_XYOUTR – wewnętrzna kolejka urządzenia.
  • bit 25: FIFO_XYOUTW – wewnętrzna kolejka urządzenia.
  • bit 26: FIFO_SROUT – wewnętrzna kolejka urządzenia.
  • bit 27: FIFO_TEXOUT – wewnętrzna kolejka urządzenia.
  • bit 28: FIFO_FLATOUT – wewnętrzna kolejka urządzenia.
  • bit 29: FIFO_FUZZOUT – wewnętrzna kolejka urządzenia.
  • bit 30: FIFO_OGOUT – wewnętrzna kolejka urządzenia.
  • bit 31: FIFO_XYSYNC – wewnętrzna kolejka urządzenia.
BAR0 + 0x0110: FE_ERROR_CODE

Kod ostatnio zgłoszonego błędu FE_ERROR. Zdefiniowane są następujące kody:

  • 0x00: RESERVED_TYPE – nieznany typ polecenia.
  • 0x01: RESERVED_BIT – nieużywany bit nie jest ustawiony na 0.
  • 0x02: SURF_WIDTH_ZERO – zerowa szerokość bufora ramki.
  • 0x03: SURF_WIDTH_OVF – bufor ramki szerszy niż 2048 pikseli.
  • 0x04: DRAW_COLUMN_REV – pierwszy piksel kolumny ma większą współrzędną Y niż drugi.
  • 0x05: DRAW_FUZZ_REV – pierwszy piksel kolumny ma większą współrzędną Y niż drugi.
  • 0x06: DRAW_SPAN_REV – pierwszy piksel paska ma większą współrzędną X niż drugi.
BAR0 + 0x0180 + i * 4, i < 8: FE_REG
Polecenie, którego dotyczy ostatnio zgłoszony błąd FE_ERROR.
BAR0 + 0x0600: XY_STATE

Szerokości buforów ramki obowiązujące w momencie zgłoszenia błędu SURF_OVERFLOW. Bity:

  • bity 0-5: SURF_DST_WIDTH.
  • bity 8-13: SURF_SRC_WIDTH.
BAR0 + 0x0608: XY_DST_DATA

W przypadku błędów PAGE_FAULT_SURF_DST oraz SURF_DST_OVERFLOW można tu przeczytać współrzędne, które wywołały błąd:

  • bity 0-4: bity 6-10 współrzędnej x (bity 0-5 nie są zapisywane)
  • bity 5-15: współrzędna y
BAR0 + 0x060c: XY_SRC_DATA
Jak wyżej, ale do PAGE_FAULT_SURF_SRC i SURF_SRC_OVERFLOW.

BAR0 + 0x0080: TLB_PT_CMD

BAR0 + 0x0084: TLB_PT_SURF_DST

BAR0 + 0x0088: TLB_PT_SURF_SRC

BAR0 + 0x008c: TLB_PT_TEXTURE

BAR0 + 0x0090: TLB_PT_FLAT

BAR0 + 0x0094: TLB_PT_TRANSLATION

BAR0 + 0x0098: TLB_PT_COLORMAP

BAR0 + 0x009c: TLB_PT_TRANMAP
Adres początku tabeli stron używanej w momencie wyzwolenia błędu PAGE_FAULT_* (przesunięty w prawo o 8 bitów, jak w poleceniu SETUP).

BAR0 + 0x00c0: TLB_VADDR_CMD

BAR0 + 0x00c4: TLB_VADDR_SURF_DST

BAR0 + 0x00c8: TLB_VADDR_SURF_SRC

BAR0 + 0x00cc: TLB_VADDR_TEXTURE

BAR0 + 0x00d0: TLB_VADDR_FLAT

BAR0 + 0x00d4: TLB_VADDR_TRANSLATION

BAR0 + 0x00d8: TLB_VADDR_COLORMAP

BAR0 + 0x00dc: TLB_VADDR_TRANMAP
Adres wirtualny, który spowodował błąd PAGE_FAULT_*. Niskie 6 bitów nie jest zapisywane (jest zawsze równe 0).

Blok statystyk

Blok rysujący zbiera różnorodne statystyki dotyczące pracy urządzenia. Są one bezpośrednio widoczne jako rejestry MMIO. Każdy taki rejestr jest 32-bitowym licznikiem (który może się przekręcić – urządzenie nie robi wtedy nic specjalnego). Te liczniki zliczają następujące zdarzenia:

  • BAR0 + 0x0400: STATS_FE_COPY_RECT_HORIZONTAL – polecenie COPY_RECT realizowane poziomo
  • BAR0 + 0x0404: STATS_FE_COPY_RECT_LINE – jedna linia poziomego polecenia COPY_RECT
  • BAR0 + 0x0408: STATS_FE_COPY_RECT_VERTICAL – polecenie COPY_RECT realizowane pionowo
  • BAR0 + 0x040c: STATS_FE_FILL_RECT_HORIZONTAL – polecenie FILL_RECT realizowane poziomo
  • BAR0 + 0x0410: STATS_FE_FILL_RECT_LINE – jedna linia poziomego polecenia FILL_RECT
  • BAR0 + 0x0414: STATS_FE_FILL_RECT_VERTICAL – polecenie FILL_RECT realizowane pionowo
  • BAR0 + 0x0418: STATS_FE_DRAW_BACKGROUND – polecenie DRAW_BACKGROUND
  • BAR0 + 0x041c: STATS_FE_DRAW_BACKGROUND_LINE – jedna linia polecenia DRAW_BACKGROUND
  • BAR0 + 0x0420: STATS_FE_DRAW_LINE_HORIZONTAL – polecenie DRAW_LINE realizowane poziomo
  • BAR0 + 0x0424: STATS_FE_DRAW_LINE_VERTICAL – polecenie DRAW_LINE realizowane pionowo
  • BAR0 + 0x0428: STATS_FE_DRAW_LINE_H_CHUNK – rysowanie prostokąta N×1 linii poziomej
  • BAR0 + 0x042c: STATS_FE_DRAW_LINE_V_CHUNK – rysowanie prostokąta 1×N linii pionowej
  • BAR0 + 0x0430: STATS_FE_DRAW_LINE_H_PIXEL – rysowanie piksela linii poziomej
  • BAR0 + 0x0434: STATS_FE_DRAW_LINE_V_PIXEL – rysowanie piksela linii pionowej
  • BAR0 + 0x0438: STATS_FE_DRAW_COLUMN_BATCH – grupa poleceń DRAW_COLUMN przetwarzana równolegle
  • BAR0 + 0x043c: STATS_FE_DRAW_FUZZ_BATCH – grupa poleceń DRAW_FUZZ przetwarzana równolegle
  • BAR0 + 0x0440: STATS_FE_DRAW_COLUMN – polecenie DRAW_COLUMN
  • BAR0 + 0x0444: STATS_FE_DRAW_FUZZ – polecenie DRAW_FUZZ
  • BAR0 + 0x0448: STATS_FE_DRAW_COLUMN_CHUNK – jeden pionowy segment grupy poleceń DRAW_COLUMN
  • BAR0 + 0x044c: STATS_FE_DRAW_FUZZ_CHUNK – jeden pionowy segment grupy poleceń DRAW_FUZZ
  • BAR0 + 0x0450: STATS_FE_PING_ASYNC – polecenie z flagą PING_ASYNC
  • BAR0 + 0x0454: STATS_FE_LOAD_FLAT – załadowanie nowej tekstury płaskiej
  • BAR0 + 0x0458: STATS_FE_LOAD_TRANSLATION – załadowanie nowej mapy kolorów do zmiany palety
  • BAR0 + 0x045c: STATS_FE_LOAD_COLORMAP – załadowanie nowej mapy kolorów do efektów
  • BAR0 + 0x0460: STATS_FE_BATCH_END_MISMATCH_COLORMAP – przerwanie paczki poleceń przez zmianę aktywnej mapy kolorów
  • BAR0 + 0x0464: STATS_FE_BATCH_END_MISMATCH_TEX_DIMS – przerwanie paczki poleceń przez zmianę aktywnej wysokości bądź limitu tekstury
  • BAR0 + 0x0468: STATS_FE_BATCH_END_MISMATCH_CMD – przerwanie paczki poleceń przez wysłanie nowego typu polecenia
  • BAR0 + 0x046c: STATS_FE_BATCH_END_MISMATCH_FUZZ – przerwanie paczki poleceń przez zmianę granic efektu DRAW_FUZZ
  • BAR0 + 0x0470: STATS_FE_BATCH_END_SIZE – przerwanie paczki poleceń przez osiągnięcie maksymalnego rozmiaru paczki
  • BAR0 + 0x0474: STATS_FE_BATCH_END_XY – przerwanie paczki poleceń przez niepasujące współrzędne kolejnej kolumny
  • BAR0 + 0x0478: STATS_FE_BATCH_END_SYNC – przerwanie paczki poleceń przez wysłanie flagi synchronizacyjnej (FENCE lub PING_SYNC)
  • BAR0 + 0x047c: STATS_FE_DRAW_SPAN – polecenie DRAW_SPAN
  • BAR0 + 0x0480: STATS_TLB_CMD_HIT – trafienie w buforze TLB dla bufora poleceń.
  • BAR0 + 0x0484: STATS_TLB_SURF_DST_HIT – j/w, docelowy bufor ramki.
  • BAR0 + 0x0488: STATS_TLB_SURF_SRC_HIT – j/w, źródłowy bufor ramki.
  • BAR0 + 0x048c: STATS_TLB_TEXTURE_HIT – j/w, tekstura kolumnowa.
  • BAR0 + 0x0490: STATS_TLB_FLAT_HIT – j/w, tekstura płaska.
  • BAR0 + 0x0494: STATS_TLB_TRANSLATION_HIT – j/w, mapa kolorów do zmiany palety.
  • BAR0 + 0x0498: STATS_TLB_COLORMAP_HIT – j/w, mapa kolorów do efektów.
  • BAR0 + 0x049c: STATS_TLB_TRANMAP_HIT – j/w, mapa przezroczystości.
  • BAR0 + 0x04a0: STATS_TLB_CMD_MISS – chybienie w buforze TLB dla bufora poleceń.
  • BAR0 + 0x04a4: STATS_TLB_SURF_DST_MISS – j/w, docelowy bufor ramki.
  • BAR0 + 0x04a8: STATS_TLB_SURF_SRC_MISS – j/w, źródłowy bufor ramki.
  • BAR0 + 0x04ac: STATS_TLB_TEXTURE_MISS – j/w, tekstura kolumnowa.
  • BAR0 + 0x04b0: STATS_TLB_FLAT_MISS – j/w, tekstura płaska.
  • BAR0 + 0x04b4: STATS_TLB_TRANSLATION_MISS – j/w, mapa kolorów do zmiany palety.
  • BAR0 + 0x04b8: STATS_TLB_COLORMAP_MISS – j/w, mapa kolorów do efektów.
  • BAR0 + 0x04bc: STATS_TLB_TRANMAP_MISS – j/w, mapa przezroczystości.
  • BAR0 + 0x04c0: STATS_TLB_CMD_CHANGE – zmiana aktywnej tabeli stron dla bufora ramki.
  • BAR0 + 0x04c4: STATS_TLB_SURF_DST_CHANGE – j/w, docelowy bufor ramki.
  • BAR0 + 0x04c8: STATS_TLB_SURF_SRC_CHANGE – j/w, źródłowy bufor ramki.
  • BAR0 + 0x04cc: STATS_TLB_TEXTURE_CHANGE – j/w, tekstura kolumnowa.
  • BAR0 + 0x04d0: STATS_TLB_FLAT_CHANGE – j/w, tekstura płaska.
  • BAR0 + 0x04d4: STATS_TLB_TRANSLATION_CHANGE – j/w, mapa kolorów do zmiany palety.
  • BAR0 + 0x04d8: STATS_TLB_COLORMAP_CHANGE – j/w, mapa kolorów do efektów.
  • BAR0 + 0x04dc: STATS_TLB_TRANMAP_CHANGE – j/w, mapa przezroczystości.
  • BAR0 + 0x04e0: STATS_TEX_CACHE_HIT – trafienie teksela w pamięci podręcznej tekstury kolumnowej
  • BAR0 + 0x04e4: STATS_TEX_CACHE_SPEC_HIT – trafienie spekulatywnego teksela w pamięci podręcznej tekstury kolumnowej
  • BAR0 + 0x04e8: STATS_TEX_CACHE_MISS – chybienie teksela (czyli wczytanie 64 bajtów z tekstury)
  • BAR0 + 0x04ec: STATS_TEX_CACHE_SPEC_MISS – chybienie spekulatywnego teksela (czyli porzucenie spekulatywnego teksturowania danej kolumny)
  • BAR0 + 0x04f0: STATS_FLAT_SPAN_BLOCK – oteksturowanie bloku pikseli teksturą płaską
  • BAR0 + 0x04f4: STATS_FLAT_SPAN_PIXEL – oteksturowanie piksela teksturą płaską
  • BAR0 + 0x04f8: STATS_FLAT_CACHE_HIT – trafienie teksela w pamięci podręcznej tekstury płaskiej
  • BAR0 + 0x04fc: STATS_FLAT_CACHE_MISS – chybienie teksela (czyli wczytanie 64 bajtów z tekstury)
  • BAR0 + 0x0500: STATS_OG_DRAW_BUF_BLOCK – rysowanie bloku pikseli przez FILL_RECT, DRAW_LINE lub DRAW_BACKGROUND
  • BAR0 + 0x0504: STATS_OG_DRAW_BUF_PIXEL – rysowanie piksela przez FILL_RECT, DRAW_LINE lub DRAW_BACKGROUND
  • BAR0 + 0x0508: STATS_OG_COPY_BLOCK – rysowanie bloku pikseli przez COPY_RECT
  • BAR0 + 0x050c: STATS_OG_COPY_PIXEL – rysowanie piksela przez COPY_RECT
  • BAR0 + 0x0510: STATS_OG_TRANSLATION_BLOCK – przetwarzanie bloku pikseli przez flagę TRANSLATION
  • BAR0 + 0x0514: STATS_OG_COLORMAP_BLOCK – przetwarzanie bloku pikseli przez flagę COLORMAP
  • BAR0 + 0x0518: STATS_OG_TRANSLATION_PIXEL – przetwarzanie piksela przez flagę TRANSLATION
  • BAR0 + 0x051c: STATS_OG_COLORMAP_PIXEL – przetwarzanie piksela przez flagę COLORMAP
  • BAR0 + 0x0520: STATS_OG_FUZZ_PIXEL – rysowanie piksela przez DRAW_COLUMN z FUZZ
  • BAR0 + 0x0524: STATS_SW_XFER – rysowanie ciągłej grupy pikseli
  • BAR0 + 0x0528: STATS_SW_FENCE – przetworzenie polecenia z flagą FENCE
  • BAR0 + 0x052c: STATS_SW_PING_SYNC – przetworzenie polecenia z flagą PING_SYNC
  • BAR0 + 0x0530: STATS_SW_TRANMAP_BLOCK – przetwarzanie bloku pikseli przez flagę TRANMAP
  • BAR0 + 0x0534: STATS_SW_TRANMAP_PIXEL – przetwarzanie piksela przez flagę TRANMAP
  • BAR0 + 0x0538: STATS_SW_TRANMAP_HIT – trafienie piksela w pamięci podręcznej mapy przezroczystościj
  • BAR0 + 0x053c: STATS_SW_TRANMAP_MISS – chybienie piksela w tej mapie (czyli wczytanie 64 bajtów z mapy)
  • BAR0 + 0x0540: STATS_FIFO_FECMD – przetworzenie polecenia od użytkownika przez urządzenie
  • BAR0 + 0x0544: STATS_FIFO_XYCMD – przetworzenie polecenia wewnętrznego przez jednostkę XY
  • BAR0 + 0x0548: STATS_FIFO_TEXCMD – przetworzenie polecenia wewnętrznego przez jednostkę TEX
  • BAR0 + 0x054c: STATS_FIFO_FLATCMD – przetworzenie polecenia wewnętrznego przez jednostkę FLAT
  • BAR0 + 0x0550: STATS_FIFO_FUZZCMD – przetworzenie polecenia wewnętrznego przez jednostkę FUZZ
  • BAR0 + 0x0554: STATS_FIFO_OGCMD – przetworzenie polecenia wewnętrznego przez jednostkę OG
  • BAR0 + 0x0558: STATS_FIFO_SWCMD – przetworzenie polecenia wewnętrznego przez jednostkę SW
  • BAR0 + 0x055c: STATS_FIFO_XYSYNC – przetworzenie polecenia z flagą INTERLOCK
  • BAR0 + 0x0560: STATS_FIFO_SROUT – wczytanie bloku pikseli z bufora ramki
  • BAR0 + 0x0564: STATS_FIFO_TEXOUT – oteksturowanie bloku pikseli teksturą kolumnową
  • BAR0 + 0x0568: STATS_FIFO_FLATOUT – oteksturowanie bloku pikseli teksturą płaską bądź wczytanie bloku pikseli przez DRAW_BACKGROUND
  • BAR0 + 0x056c: STATS_FIFO_FUZZOUT – nałożenie efektu FUZZ na blok pikseli
  • BAR0 + 0x0570: STATS_FIFO_OGOUT – zapisanie bloku pikseli do bufora ramki
  • BAR0 + 0x0574: STATS_FIFO_TEXOUT_PIXEL – narysowanie piksela przez DRAW_COLUMN
  • BAR0 + 0x0578: STATS_FIFO_OGOUT_PIXEL – rysowanie piksela jakiegokolwiek typu
  • BAR0 + 0x057c: STATS_FENCE_INTR – przetworzenie polecenia FENCE powodującego przerwanie

Blok pikseli to maksymalnie 64 piksele różniące się tylko niskimi 6 bitami współrzędnej X (urządzenie grupuje wszystkie rysowane oraz wczytywane piksele w takie bloki). Dzieląc statystyki *_PIXEL przez *_BLOCK można zmierzyć efektywność grupowania pikseli przez urządzenie. Dzieląc STAT_TEX_COLUMN przez STAT_FE_DRAW_COLUMN_TEX_BATCH można zmierzyć efektywność grupowania kolumn. Dzieląc statystyki *_HIT przez *_HIT + *_MISS można zmierzyć efektywność działania pamięci podręcznych i buforów TLB.

Zresetowanie bloku statystyk (w rejestrze RESET) jest równoznaczne z zapisem 0 do każdego z wyżej wymienionych liczników.