Urządzenie HardDoom™¶
Contents
Grafika w grze Doom¶
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 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
0x1993
.
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ść 4kiB, 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.
Urządzenie sterowane jest w większości przez wysyłanie mu poleceń. Każde
polecenie jest 32-bitowym słowem, z którego wysokie 6 bitów to typ polecenia,
a niskie 26 bitów to parametry polecenia. Polecenia mogą być wysyłane
bezpośrednio przez rejestr 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
.
Bufory i blok stronicowania¶
Operacje rysowania używają następujących buforów (opisanych bardziej szczegółowo niżej):
- bufory ramki (“surface”) – stronicowane, zmiennego rozmiaru.
- tekstury kolumnowe (“texture”) – stronicowane, zmiennego rozmiaru.
- tekstury płaskie (“flat”) – niestronicowane, zawsze rozmiaru 2**12 bajtów i wyrównane do 2**12 bajtów.
- mapy kolorów (“colormap”) – niestronicowane, zawsze rozmiaru 2**8 bajtów i wyrównane do 2**8 bajtów.
Urządzenie pisze tylko do bufora ramki – pozostałe bufory są używane tylko do odczytu.
Bufory stronicowane wybiera się przez podanie adresu ich tabeli stron. W każdej chwili wybrane są 3 bufory stronicowane:
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 poleceniaCOPY_RECT
).TEXTURE
: tekstura kolumnowa, z której urządzenie będzie rysować (dla poleceniaDRAW_COLUMN
).
Do zmiany wybranych buforów stronicowanych służą następujące polecenia:
- Polecenia
SURF_DST_PT
,SURF_SRC_PT
,TEXTURE_PT
: Ustawia adres tabeli stron opisującej dany bufor. Pola:
- bity 0-25:
ADDR
– bity 6-31 adresu początkowego tabeli stron (bity 0-5 są zawsze równe 0). - bity 26-31:
TYPE
– typ polecenia, równy:0x20
:SURF_DST_PT
0x21
:SURF_SRC_PT
0x22
:TEXTURE_PT
Wykonanie tego polecenia resetuje jednocześnie odpowiedni bufor TLB. Wykonanie polecenia
TEXTURE_PT
czyści jednocześnie pamięć podręczną tekstury kolumnowej.- bity 0-25:
Urządzenie używa stron o wielkości 4kiB. Tabele stron mogą zawierać maksymalnie 1024 wpisy (czyli opisywać 4MiB pamięci) i muszą być wyrównane do 64 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łądPAGE_FAULT
i wyłączenie odpowiedniego bloku wENABLE
(XY
dlaSURF_*
,TEX
dlaTEXTURE
). - bity 1-11: nieużywane, powinny być równe 0.
- bity 12-31:
ADDR
– bity 12-31 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 (maksymalny możliwy offset wynika z SURF_DIMS
w przypadku
bufora ramki, TEXTURE_DIMS
w przypadku tekstury).
Aby nie czytać ciągle tabeli stron, urządzenie może zapamiętywać
dane z tabeli stron w buforach TLB. Wysłanie polecenia *_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 niestronicowane wybiera się bezpośrednio przez podanie ich adresu.
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 * width + y
.
- Polecenie
SURF_DIMS
: Ustawia wymiary buforów ramek. Pola:
- bity 0-5:
WIDTH
– bity 6-11 szerokości ramek (bity 0-5 szerokości są równe 0). - bity 8-19:
HEIGHT
– wysokość ramek. - bity 6-7, 20-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x26
.
- bity 0-5:
Po wysłaniu ustawień buforów ramek, urządzenie używa ich dla wszystkich następnych poleceń rysowania, aż do wysłania innych ustawień.
Urządzenie sprawdza współrzędne pikseli, których używa – przekroczenie
szerokości lub wysokoś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). Urządzenie obsługuje tekstury o wielkościach do 4MB.
- Polecenie
TEXTURE_DIMS
: Ustawia rozmiar tekstury. Pola:
- bity 0-9:
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. - bity 12-25:
SIZE_M1
– rozmiar tekstury w 256-bajtowych blokach, pomniejszony o 1 (dla tekstury 1024-bajtowej należy tu wpisać 3). - bity 10-11: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x27
.
- bity 0-9:
Próba czytania adresu z poza zakresu 0 .. SIZE_M1 << 8 | 0xff
zostanie
zablokowana przez urządzenie i spowoduje użycie do teksturowania tekseli
zerowych.
Urządzenie może zapamiętywać dane z używanej tekstury w swojej
pamięci podręcznej – aby wyczyścić tą pamięć, wystarczy wysłać polecenie
TEXTURE_PT
(to zresetuje pamięć podręczną nawet, jeśli nie zmieni
się przez to adres aktywnej tabeli stron).
Tekstura (i wiele innych parametrów) nie jest w żaden sposób używana
w przypadku rysowania z opcją FUZZ
.
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 teksele, zajmują 2**12
bajtów, a ich adres również musi być wyrównany do 2**12 bajtów.
Nie używają bloku stronicowania. W każdym momencie aktywna jest
dokładnie jedna tekstura płaska, którą można zmienić poleceniem:
- Polecenie
FLAT_ADDR
: Ustawia aktywną teksturę płaską i czyści pamięć podręczną tekstury płaskiej. Pola:
- bity 0-19:
ADDR
– bity 12-31 adresu tekstury (bity 0-11 adresu są zawsze równe 0). - bity 20-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x23
.
- bity 0-19:
Analogicznie do tekstury kolumnowej, urządzenie może zapamiętywać dane
z tekstury płaskiej w pamięci podręcznej. Wysłanie polecenia FLAT_ADDR
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. Nie są stronicowane, a ich adres musi być 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 dwie aktywne mapy kolorów, które można zmienić poleceniami:
- Polecenie
COLORMAP_ADDR
,TRANSLATION_ADDR
: Ustawia aktywną mapę kolorów i czyści odpowiadającą pamięć podręczną. Pola:
- bity 0-23:
ADDR
– bity 8-31 adresu mapy (bity 0-7 adresu są zawsze równe 0). - bity 24-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia:0x24
:COLORMAP_ADDR
– ustawia główną mapę kolorów, używaną do efektów.0x25
:TRANSLATION_ADDR
– ustawia mapę kolorów używaną do zamiany palety.
- bity 0-23:
Podobnie do tekstur, urządzenie może kopiować dane map
do pamięci podręcznej. Wysłanie polecenia *_ADDR
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
lub FUZZ
dla
mapy COLORMAP_ADDR
, TRANSLATE
dla mapy TRANSLATION_ADDR
.
Blok rysujący¶
Blok rysujący potrafi wykonywać następujące operacje:
COPY_RECT
: kopiuje prostokąt z jednego bufora ramki do drugiego.FILL_RECT
: wypełnia prostokąt w buforze ramki jednolitym kolorem.DRAW_LINE
: rysuje linię między podanymi punktami jednolitym kolorem.DRAW_BACKGROUND
: wypełnia cały bufor ramki powtarzającymi się kopiami tekstury płaskiej.DRAW_COLUMN
: rysuje teksturowaną kolumnę pikseli.DRAW_SPAN
: rysuje teksturowany pasek pikseli.
Parametry¶
Następujące polecenia służą do ustawiania parametrów używanych przez wiele typów operacji:
- Polecenie
FILL_COLOR
: Ustawia kolor wypełnienia dla
FILL_RECT
i/lub kolor linii dlaDRAW_LINE
.- bity 0-7:
COLOR
– kolor - bity 8-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x28
.
- bity 0-7:
- Polecenie
DRAW_PARAMS
: Ustawia parametry rysowania dla operacji
DRAW_COLUMN
orazDRAW_SPAN
.- bit 0:
FUZZ
– używany tylko przezDRAW_COLUMN
, włącza rysowanie efektu cienia, używając mapy kolorów zCOLORMAP_ADDR
do przyciemniania pikseli już znajdujących się w buforze ramki. Jeśli włączony, flagiTRANSLATION
iCOLORMAP
powinny być wyłączone, a tekstura i związane z nią parametry nie są używane. - bit 1:
TRANSLATE
– włącza zamianę palety kolorów. Jeśli włączony, kolory z tekstury są tłumaczone przez mapę kolorów zTRANSLATION_ADDR
. - bit 2:
COLORMAP
– włącza mapowanie rysowanych kolorów. Jeśli włączony, kolory z tekstury są tłumaczone przez mapę kolorów zCOLORMAP_ADDR
(poTRANSLATION_ADDR
, jeśli obydwie mapy są włączone). - bity 3-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x29
.
- bit 0:
- Polecenie
XY_A
,XY_B
: Ustawia współrzędne punktu będącego parametrem operacji.
- bity 0-10:
X
- bity 12-22:
Y
- bity 11, 23-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia:0x2a
:XY_A
– pierwszy (lub jedyny) punkt.0x2b
:XY_B
– drugi punkt.
- bity 0-10:
- Polecenia
USTART
,VSTART
: Ustawia współrzędne w teksturze używane dla skrajnie lewego piksela paska (dla
DRAW_SPAN
) bądź górnego piksela kolumny (dlaDRAW_COLUMN
).- bity 0-25:
COORD
– współrzędna w teksturze dla pierwszego rysowanego piksela. Liczba stałoprzecinkowa – 10 wysokich bitów to część całkowita, a 16 niskich to część ułamkowa. Nie jest używana, jeśli flagaFUZZ
jest włączona. - bity 26-31:
TYPE
– typ polecenia:0x2c
:USTART
– współrzędna U w teksturze (używane przezDRAW_COLUMN
iDRAW_SPAN
).0x2d
:VSTART
– współrzędna V w teksturze (używane tylko przezDRAW_SPAN
).
- bity 0-25:
- Polecenia
USTEP
,VSTEP
: Ustawia pochodną współrzędnych w teksturze względem współzędnej x lub y w buforze ramki.
- bity 0-25:
DELTA
– pochodna współrzędnej w teksturze względem x (DRAW_SPAN
) lub y (DRAW_COLUMN
) w buforze ramki. Liczba stałoprzecinkowa – 10 wysokich bitów to część całkowita, a 16 niskich to część ułamkowa. Nie jest używana, jeśli flagaFUZZ
jest włączona. - bity 26-31:
TYPE
– typ polecenia:0x2e
:USTEP
– pochodna współrzędnej U w teksturze (używane przezDRAW_COLUMN
iDRAW_SPAN
).0x2f
:VSTEP
– pochodna współrzędnej V w teksturze (używane tylko przezDRAW_SPAN
).
- bity 0-25:
Każdy wysłany parametr jest zapamiętywany do momentu nadpisania go przez kolejne polecenie tego samego typu – jeśli wykonujemy kilka operacji z taką samą wartością danego parametru, nie ma potrzeby wysyłac go wielokrotnie.
Operacja 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.
Jej parametry to: pozycja lewego górnego rogu prostokąta docelowego
(XY_A
), pozycja lewego górnego rogu prostokąta źródłówego (XY_B
),
wymiary prostokąta (podane przy wywołaniu operacji).
- Polecenie
COPY_RECT
: Wykonuje operację kopiowania prostokąta.
- bity 0-11:
WIDTH
– szerokość prostokąta. - bity 12-23:
HEIGHT
– wysokość prostokąta. - bity 24-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x30
.
- bity 0-11:
Operacja COPY_RECT
nie powinna być wykonywana, 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 wysłać polecenie
INTERLOCK
(opisane niżej).
Operacja jest używana w grze do skopiowania przygotowanego wcześniej panelu dolnego oraz do efektu przejścia (“melt”).
Operacja FILL_RECT
¶
Polega na wypełnieniu zadanego prostokąta w buforze ramki (SURF_DST_PT
)
jednym kolorem. Jej parametry to: pozycja lewego górnego rogu prostokąta
(XY_A
), wymiary prostokąta, kolor (FILL_COLOR
).
- Polecenie
FILL_RECT
: Wykonuje operację wypełniania prostokąta.
- bity 0-11:
WIDTH
– szerokość prostokąta. - bity 12-23:
HEIGHT
– wysokość prostokąta. - bity 24-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x31
.
- bity 0-11:
Jest używana w grze do rysowania tła mapy (dostępnej pod klawiszem Tab).
Operacja DRAW_LINE
¶
Rysuje jednokolorową linię prostą o szerokości 1 piksela między podanymi
dwoma punktami w zadanym buforze ramki (SURF_DST_PT
). Jej parametry
to: pozycje punktu początkowego (XY_A
) i końcowego (XY_B
) oraz
kolor (FILL_COLOR
).
- Polecenie
DRAW_LINE
: Rysuje linię.
- bity 0-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x32
.
Jest używana w grze do rysowania mapy (dostępnej pod klawiszem Tab).
Operacja DRAW_BACKGROUND
¶
Wypełnia cały bufor ramki (SURF_DST_PT
) powtarzającymi się kopiami
tekstury płaskiej (FLAT_ADDR
). Nie przyjmuje parametrów.
- Polecenie
DRAW_BACKGROUND
: Rysuje powtarzające się tło.
- bity 0-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x33
.
Jest używana 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 -).
Operacja DRAW_COLUMN
¶
- Polecenie
DRAW_COLUMN
: Rysuje teksturowaną kolumnę do bufora ramki (
SURF_DST_PT
). Używa parametrówXY_A
,XY_B
,DRAW_PARAMS
(i odpowiednich map kolorów). Jeśli flagaFUZZ
nie jest włączona, używa równieżUSTART
,USTEP
i aktywnej tekstury kolumnowej.- bity 0-21:
COLUMN_OFFSET
– offset początku danych kolumny w teksturze w bajtach. Nieużywane, jeśli flagaFUZZ
jest ustawiona. - bity 22-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x34
.
- bity 0-21:
Polecenie rysuje kolumnę pikseli do bufora ramki na
współrzędnych XY_A.X, XY_A.Y
do XY_B.X, XY_B.Y
. XY_A.X
powinno
być równe XY_B.X
, a XY_A.Y
powinno być mniejsze od lub równe XY_B.Y
(inaczej zachowanie urządzenia jest niezdefiniowane).
Jeśli flaga FUZZ
jest włączona, urządzenie rysuje efekt cienia używając
mapy kolorów z COLORMAP_ADDR
i nie używa tekstury (ani żadnych parametrów
z nią związanych), W przeciwnym wypadku, rysowana kolumna jest teksturowana
za pomocą następującego algorytmu:
# Obliczenie koloru dla piksela (x, y).
coord = (USTART + USTEP * (y - XY_A.Y)) >> 16
if TEXTURE_DIMS.HEIGHT != 0:
coord %= TEXTURE_DIMS.HEIGHT
tex_offset = COLUMN_OFFSET + coord
if tex_offset < 0 or tex_offset > TEXTURE_DIMS.SIZE_M1:
color = 0;
else:
color = read_paged(TEXTURE_PT, tex_offset)
if TRANSLATE:
color = TRANSLATION_ADDR[color]
if COLORMAP:
color = COLORMAP_ADDR[color]
Operacja DRAW_SPAN
¶
- Polecenie
DRAW_SPAN
: Rysuje teksturowany pasek do bufora ramki (
SURF_DST_PT
). Używa parametrówXY_A
,XY_B
,DRAW_PARAMS
(bez bituFUZZ
),USTART
,VSTART
,USTEP
,VSTEP
, aktywnej tekstury płaskej i odpowiednich map kolorów.- bity 0-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x35
.
Polecenie rysuje pasek pikseli do bufora ramki na
współrzędnych XY_A.X, XY_A.Y
do XY_B.X, XY_B.Y
. XY_A.Y
powinno
być równe XY_B.Y
, a XY_A.X
powinno być mniejsze od lub równe XY_B.X
(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 - XY_A.X)) >> 16 & 0x3f
v = (VSTART + VSTEP * (x - XY_A.X)) >> 16 & 0x3f
color = FLAT_ADDR[u | v << 6]
if TRANSLATE:
color = TRANSLATION_ADDR[color]
if COLORMAP:
color = COLORMAP_ADDR[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żda operacja będzie używała stanu parametrów (w tym adresów buforów) z momentu jej rozpoczęcia.
- jeśli wyślemy polecenie resetujące pamięć podręczną bądź bufor TLB, każda operacja wysłana później będzie widziała dane wczytane już po wykonaniu tego resetu.
- dla konkretnego piksela w docelowym buforze ramki, operacje 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ń
FENCE
w locie (wczytanych do FIFO, ale jeszcze nie wykonanych) – dopóki nasz bufor poleceń jest mniejszy niż2**26 - 2048
, nie musimy się przejmować, że skończą nam się wolne identyfikatory doFENCE
.
W praktyce, daje to efekty identyczne do wykonania sekwencyjnego, z jednym
ważnym wyjątkiem – operacja COPY_RECT
może wczytać piksele danego
bufora ramki zanim poprzednie operacje zdążą je zapisać. Aby uniknąć
tego problemu, należy wykryć taką możliwość w sterowniku
i użyć następującego polecenia:
- Polecenie
INTERLOCK
: Blokuje rozpoczęcie wczytywania danych przez późniejsze polecenia
COPY_RECT
do momentu pełnego zakończenia wcześniejszych operacji rysujących.- bity 0-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x3f
.
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 INTERLOCK
.
Do elastycznego oczekiwania na wykonanie operacji przez urządzenie służy następujące polecenie i rejestry MMIO:
- Polecenie
FENCE
: Zapewnia pełne wykonanie wszystkich wysłanych wcześniej poleceń, a następnie zapisuje do rejestru
FENCE_LAST
podany parametr. Jednocześnie z tym zapisem, jeżeli podany parametr jest równy wartości rejestruFENCE_WAIT
, wyzwala przerwanieFENCE
. Pola:- bity 0-25:
VALUE
– dowolna 26-bitowa wartość. - bity 26-31:
TYPE
– typ polecenia, równy0x3c
.
- bity 0-25:
BAR0 + 0x10: FENCE_LAST
- Rejestr do odczytu i zapisu, 26-bitowy (wysokie 6 bitów jest nieużywane
i zawsze równe 0). Polecenie
FENCE
zapisuje tutaj swój parametr. BAR0 + 0x14: FENCE_WAIT
- Rejestr do odczytu i zapisu, 26-bitowy (tak jak
FENCE_LAST
). Gdy zakończy się polecenieFENCE
z parametrem równym wartości tego rejestru, zostanie wyzwolone przerwanieFENCE
.
FENCE_WAIT
pozwala na zaawansowaną implementację oczekiwania na wysłane
wcześniej polecenie FENCE
. Przykładowy mechanizm użycia wygląda następująco:
- po każdym poleceniu, na które potencjalnie możemy chcieć oczekiwać,
wysyłamy polecenie
FENCE
z kolejnymi liczbami (modulo 2**26). - nie dopuszczamy, by kiedykolwiek było więcej niż 2**26 poleceń
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_LAST
i sprawdzamy, czy polecenie już się wykonało. - jeśli się nie wykonało, czekamy na wyzwolenie przerwania
FENCE
.
- czyścimy przerwanie
Przed rozpoczęciem pracy, sterownik może zainicjować FENCE_LAST
na
pożądaną wartość początkową (prawdopodobnie 0). Pisanie do tego rejestru,
gdy urządzenie jest już aktywne, jest prawdopodobnie złym pomysłem.
Sterownik ma również do dyspozycji proste polecenia wyzwalające przerwania:
- Polecenie
PING_SYNC
: Zapewnia zakończenie wykonania wszystkich wcześniejszych poleceń, po czym wyzwala przerwanie
PONG_SYNC
.- bity 0-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x3d
.
- Polecenie
PING_ASYNC
: Wyzwala przerwanie
PONG_ASYNC
, gdy tylko zostanie wczytane z kolejki przez blok rysowania.- bity 0-25: nieużywane, powinny być równe 0.
- bity 26-31:
TYPE
– typ polecenia, równy0x3e
.
Wysyłanie poleceń¶
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 + 0x30: FIFO_FREE
- Rejestr tylko do odczytu. Odczytana wartość jest liczbą wolnych miejsc
w kolejce poleceń (tyle zapisów do
FIFO_SEND
można wykonać natychmiast bez obaw oFIFO_OVERFLOW
). Kolejka ta ma maksymalną pojemność 512 poleceń. BAR0 + 0x30: FIFO_SEND
- Rejestr tylko do zapisu. Zapis powoduje dopisanie zapisanego słowa
na koniec kolejki poleceń. Jeśli kolejka jest już pełna (
FIFO_FREE == 0
), zamiast tego wyzwalane jest przerwanieFIFO_OVERFLOW
, a blokFIFO
jest wyłączany wENABLE
.
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 + 0x18: CMD_READ_PTR
- 32-bitowy wskaźnik na następne polecenie do wczytania. Zawsze musi być wyrównany do wielokrotności 4 bajtów (niskie 2 bity są zawsze równe 0).
BAR0 + 0x1c: CMD_WRITE_PTR
- 32-bitowy wskaźnik na miejsce, gdzie procesor ma zapisać następne polecenie.
Jeśli
CMD_WRITE_PTR == CMD_READ_PTR
, blok wczytywania poleceń zostanie zatrzymany, aż procesor załaduje więcej poleceń i przesunieCMD_WRITE_PTR
. Zawsze musi być wyrównany do wielokrotności 4 bajtów.
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_PTR != CMD_WRITE_PTR
- jest miejsce w kolejce poleceń, tzn.
FIFO_FREE != 0
Polecenie wczytywane jest z adresu CMD_READ_PTR
, jest on zwiększany o 4,
po czym polecenie jest wykonywane (jeśli jest poleceniem JUMP
) lub
dopisywane do kolejki (tak, jakby zostało wpisane do FIFO_SEND
).
Aby wrócić na początek bufora poleceń, bądź przejść do innego bufora, używane
jest polecenie JUMP
:
- Polecenie
JUMP
: Ustawia rejestr
CMD_READ_PTR
na zadaną wartość, powodując wczytanie następnych poleceń z nowego adresu. Jest poprawne tylko w buforze poleceń (nie można go wysłać bezpośrednio doFIFO_SEND
). Pola:- bity 0-29:
PTR
– bity 2-31 nowej wartościCMD_READ_PTR
. - bity 30-31:
TYPE_HI
– musi być równe0x0
.
- bity 0-29:
Warning
Po resecie urządzenia, CMD_READ_PTR
nie musi być równe CMD_WRITE_PTR
–
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.
Rejestry sterujące¶
Blok sterujący zajmuje się nadzorowaniem pracy całego urządzenia. Jego rejestry to:
BAR0 + 0x00: 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:
FETCH_CMD
– blok wczytywania poleceń. - bit 1:
FIFO
– blok rysujący, dostęp do kolejki poleceń przezFIFO_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, efektFUZZ
. - 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, 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
iFE_CODE_WINDOW
- zresetowaniu wszystkich bloków w
RESET
, - zainicjowaniu rejestrów
CMD_*_PTR
(jeśli używamy bloku wczytywania poleceń) - wyzerowaniu przerwań (w
INTR
)
- bit 0:
BAR0 + 0x04: 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 1:
FIFO
– główna kolejka poleceń bloku rysującego. - 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, efektFUZZ
. - 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, zapis do bufora ramki. - bit 10:
FE2XY
– wewnętrzna kolejka urządzenia. - bit 11:
FE2TEX
– wewnętrzna kolejka urządzenia. - bit 12:
FE2FLAT
– wewnętrzna kolejka urządzenia. - bit 13:
FE2FUZZ
– wewnętrzna kolejka urządzenia. - bit 14:
FE2OG
– wewnętrzna kolejka urządzenia. - bit 15:
XY2SW
– wewnętrzna kolejka urządzenia. - bit 16:
XY2SR
– wewnętrzna kolejka urządzenia. - bit 17:
SR2OG
– wewnętrzna kolejka urządzenia. - bit 18:
TEX2OG
– wewnętrzna kolejka urządzenia. - bit 19:
FLAT2OG
– wewnętrzna kolejka urządzenia. - bit 20:
FUZZ2OG
– wewnętrzna kolejka urządzenia. - bit 21:
OG2SW
– wewnętrzna kolejka urządzenia. - bit 22:
OG2SW_C
– wewnętrzna kolejka urządzenia. - bit 23:
SW2XY
– wewnętrzna kolejka urządzenia. - bit 24:
STATS
– blok statystyk. Wszystkie liczniki są ustawiane na 0. - bit 25:
TLB
– bufory TLB. Wszystkie wpisy tabeli stron zapisane w TLB są kasowane i, w razie potrzeby, zostaną wczytane na nowo. - bit 26:
TEX_CACHE
– pamięć podręczna tekstury kolumnowej. - bit 27:
FLAT_CACHE
– pamięć podręczna tekstury płaskiej.
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ąc0xffffffe
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_*_PTR
.- bit 1:
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 zostanie wykonane polecenieFENCE
z parametrem równymFENCE_WAIT
.PONG_SYNC
– wyzwalane przez poleceniePING_SYNC
.PONG_ASYNC
– wyzwalane przez poleceniePING_ASYNC
.FE_ERROR
– wyzwalane, gdy blok rysujący zauważy błędne polecenie.FIFO_OVERFLOW
– wyzwalane, gdy sterownik spróbuje pisać doFIFO_SEND
, gdy nie ma już wolnego miejsca w kolejce, lub blokFIFO
jest wyłączony.SURF_DST_OVERFLOW
– wyzwalane, gdy blok rysujący spróbuje pisać lub czytać piksel o współrzędnych poza granicami docelowego bufora ramki (ustalonych przezSURF_DIMS
).SURF_SRC_OVERFLOW
– wyzwalane, gdy blok rysujący spróbuje lub czytać piksel o współrzędnych poza granicami źródłowego bufora ramki (ustalonych przezSURF_DIMS
).PAGE_FAULT_SURF_DST
– wyzwalane, gdy blok rysujący spróbuje użyć strony oznaczonej w tabeli stron jako nieobecna 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.
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
FIFO_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 + 0x08: INTR
Rejestr statusu przerwań. Ma 10 bitów, każdy odpowiadający jednemu rodzajowi przerwań:
- bit 0:
FENCE
, - bit 1:
PONG_SYNC
, - bit 2:
PONG_ASYNC
, - bit 3:
FE_ERROR
, - bit 4:
FIFO_OVERFLOW
- bit 5:
SURF_DST_OVERFLOW
- bit 6:
SURF_SRC_OVERFLOW
- bit 7:
PAGE_FAULT_SURF_DST
- bit 8:
PAGE_FAULT_SURF_SRC
- bit 9:
PAGE_FAULT_TEXTURE
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ń
FIFO_OVERFLOW
orazPONG_SYNC
.- bit 0:
BAR0 + 0x0c: 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/harddoom/blob/master/doomcode.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/harddoom/blob/master/doomcode.h .
Do ładowania mikrokodu służą następujące rejestry:
BAR0 + 0x20: FE_CODE_ADDR
- Indeks w tablicy, który będziemy widoczny przez
FE_CODE_WINDOW
(dostępny do odczytu i zapisu). BAR0 + 0x24: FE_CODE_WINDOW
- Okno do tablicy mikrokodu – odczytuje bądź zapisuje komórkę wybrana
przez
FE_CODE_ADDR
, po czym zwiększaFE_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
doomcode.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
0xffffffe
doRESET
, - zainicjować
CMD_*_PTR
, jeśli chcemy użyć bloku wczytywania pleceń, - wyzerować
INTR
przez zapis0x3ff
, - włączyć używane przez nas przerwania w
INTR_ENABLE
, - zainicjować
FENCE_*
, jeśli czujemy taką potrzebę, - włączyć wszystkie bloki urządzenia w
ENABLE
(być może z wyjątkiemFETCH_CMD
).
Po wykonaniu tej procedury można rozpocząć wysyłanie poleceń do urządzenia
(przez FIFO_SEND
lub CMD_WRITE_PTR
).
Ż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 + 0x04: 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:
FETCH_CMD
– blok wczytywania poleceń (ten bit jest efektywnie równyCMD_READ_PTR != CMD_WRITE_PTR
). - bit 1:
FIFO
– główna kolejka poleceń bloku rysującego. - 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, efektFUZZ
. - 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, zapis do bufora ramki. - bit 10:
FE2XY
– wewnętrzna kolejka urządzenia. - bit 11:
FE2TEX
– wewnętrzna kolejka urządzenia. - bit 12:
FE2FLAT
– wewnętrzna kolejka urządzenia. - bit 13:
FE2FUZZ
– wewnętrzna kolejka urządzenia. - bit 14:
FE2OG
– wewnętrzna kolejka urządzenia. - bit 15:
XY2SW
– wewnętrzna kolejka urządzenia. - bit 16:
XY2SR
– wewnętrzna kolejka urządzenia. - bit 17:
SR2OG
– wewnętrzna kolejka urządzenia. - bit 18:
TEX2OG
– wewnętrzna kolejka urządzenia. - bit 19:
FLAT2OG
– wewnętrzna kolejka urządzenia. - bit 20:
FUZZ2OG
– wewnętrzna kolejka urządzenia. - bit 21:
OG2SW
– wewnętrzna kolejka urządzenia. - bit 22:
OG2SW_C
– wewnętrzna kolejka urządzenia. - bit 23:
SW2XY
– wewnętrzna kolejka urządzenia.
- bit 0:
BAR0 + 0x28: 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_HEIGHT_ZERO
– zerowa wysokość bufora ramki.0x04
:SURF_WIDTH_OVF
– bufor ramki szerszy niż 2048 pikseli.0x05
:SURF_HEIGHT_OVF
– bufor ramki wyższy niż 2048 pikseli.0x06
:RECT_DST_X_OVF
– prostokąt docelowy wCOPY_RECT
lubFILL_RECT
wystaje poza szerokość bufora ramki.0x07
:RECT_DST_Y_OVF
– prostokąt docelowy wCOPY_RECT
lubFILL_RECT
wystaje poza wysokość bufora ramki.0x08
:RECT_SRC_X_OVF
– prostokąt źródłowy wCOPY_RECT
wystaje poza szerokość bufora ramki.0x09
:RECT_SRC_Y_OVF
– prostokąt źródłowy wCOPY_RECT
wystaje poza wysokość bufora ramki.0x0a
:DRAW_COLUMN_REV
– pierwszy piksel kolumny ma większą współrzędną Y niż drugi.0x0b
:DRAW_SPAN_REV
– pierwszy piksel paska ma większą współrzędną X niż drugi.
BAR0 + 0x2c: FE_ERROR_DATA
- Polecenie, którego dotyczy ostatnio zgłoszony błąd
FE_ERROR
. BAR0 + 0x200: XY_SURF_DIMS
Wymiary bufora ramki obowiązujące w momencie zgłoszenia błędu
SURF_OVERFLOW
. Bity:- bity 0-5:
WIDTH
– jak w poleceniuSURF_DIMS
. - bity 8-19:
HEIGHT
– jak w poleceniuSURF_DIMS
.
- bity 0-5:
BAR0 + 0x208: XY_DST_CMD
W przypadku błędów
PAGE_FAULT_SURF_DST
orazSURF_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 + 0x20c: XY_SRC_CMD
- Jak wyżej, ale do
PAGE_FAULT_SURF_SRC
iSURF_SRC_OVERFLOW
. BAR0 + 0x300: TLB_PT_SURF_DST
- Adres początku tabeli stron używanej w momencie wyzwolenia błędu
PAGE_FAULT_SURF_DST
. BAR0 + 0x304: TLB_PT_SURF_SRC
- Adres początku tabeli stron używanej w momencie wyzwolenia błędu
PAGE_FAULT_SURF_SRC
. BAR0 + 0x308: TLB_PT_TEXTURE
- Adres początku tabeli stron używanej w momencie wyzwolenia błędu
PAGE_FAULT_TEXTURE
. BAR0 + 0x320: TLB_VADDR_SURF_DST
- Adres wirtualny, który spowodował błąd
PAGE_FAULT_SURF_DST
. Niskie 6 bitów nie jest zapisywane (jest zawsze równe 0). BAR0 + 0x324: TLB_VADDR_SURF_SRC
- Adres wirtualny, który spowodował błąd
PAGE_FAULT_SURF_SRC
. Niskie 6 bitów nie jest zapisywane (jest zawsze równe 0). BAR0 + 0x328: TLB_VADDR_TEXTURE
- Adres wirtualny, który spowodował błąd
PAGE_FAULT_TEXTURE
. 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 + 0x100: STAT_FE_COPY_RECT_HORIZONTAL
– polecenieCOPY_RECT
realizowane poziomoBAR0 + 0x104: STAT_FE_COPY_RECT_LINE
– jedna linia poziomego poleceniaCOPY_RECT
BAR0 + 0x108: STAT_FE_COPY_RECT_VERTICAL
– polecenieCOPY_RECT
realizowane pionowoBAR0 + 0x10c: STAT_FE_FILL_RECT_HORIZONTAL
– polecenieFILL_RECT
realizowane poziomoBAR0 + 0x110: STAT_FE_FILL_RECT_LINE
– jedna linia poziomego poleceniaFILL_RECT
BAR0 + 0x114: STAT_FE_FILL_RECT_VERTICAL
– polecenieFILL_RECT
realizowane pionowoBAR0 + 0x118: STAT_FE_DRAW_LINE_HORIZONTAL
– polecenieDRAW_LINE
realizowane poziomoBAR0 + 0x11c: STAT_FE_DRAW_LINE_VERTICAL
– polecenieDRAW_LINE
realizowane pionowoBAR0 + 0x120: STAT_FE_DRAW_LINE_H_CHUNK
– rysowanie prostokąta N×1 linii poziomejBAR0 + 0x124: STAT_FE_DRAW_LINE_V_CHUNK
– rysowanie prostokąta 1×N linii pionowejBAR0 + 0x128: STAT_FE_DRAW_LINE_H_PIXEL
– rysowanie piksela linii poziomejBAR0 + 0x12c: STAT_FE_DRAW_LINE_V_PIXEL
– rysowanie piksela linii pionowejBAR0 + 0x130: STAT_FE_DRAW_BACKGROUND
– polecenieDRAW_BACKGROUND
BAR0 + 0x134: STAT_FE_DRAW_COLUMN_TEX_BATCH
– grupa poleceńDRAW_COLUMN
z teksturą przetwarzana równolegleBAR0 + 0x138: STAT_FE_DRAW_COLUMN_FUZZ_BATCH
– grupa poleceńDRAW_COLUMN
z efektemFUZZ
przetwarzana równolegleBAR0 + 0x13c: STAT_FE_DRAW_SPAN
– polecenieDRAW_SPAN
BAR0 + 0x140: STAT_FE_CMD
– przetworzenie polecenia od użytkownika przez urządzenieBAR0 + 0x144: STAT_XY_CMD
– przetworzenie polecenia wewnętrznego przez jednostkęXY
BAR0 + 0x148: STAT_TEX_CMD
– przetworzenie polecenia wewnętrznego przez jednostkęTEX
BAR0 + 0x14c: STAT_FLAT_CMD
– przetworzenie polecenia wewnętrznego przez jednostkęFLAT
BAR0 + 0x150: STAT_FUZZ_CMD
– przetworzenie polecenia wewnętrznego przez jednostkęFUZZ
BAR0 + 0x154: STAT_OG_CMD
– przetworzenie polecenia wewnętrznego przez jednostkęOG
BAR0 + 0x158: STAT_SW_CMD
– przetworzenie polecenia wewnętrznego przez jednostkęSW
BAR0 + 0x15c: STAT_SR_BLOCK
– wczytanie bloku pikseli z bufora ramkiBAR0 + 0x160: STAT_TEX_BLOCK
– oteksturowanie bloku pikseli teksturą kolumnowąBAR0 + 0x164: STAT_FLAT_BLOCK
– oteksturowanie bloku pikseli teksturą płaską bądź wczytanie bloku pikseli przezDRAW_BACKGROUND
BAR0 + 0x168: STAT_FUZZ_BLOCK
– nałożenie efektuFUZZ
na blok pikseliBAR0 + 0x16c: STAT_SW_BLOCK
– zapisanie bloku pikseli do bufora ramkiBAR0 + 0x170: STAT_TLB_SURF_DST_HIT
– trafienie w buforze TLB dla docelowego bufora ramki.BAR0 + 0x174: STAT_TLB_SURF_DST_MISS
– chybienie w tym buforze (czyli wczytanie wpisu z tabeli stron).BAR0 + 0x178: STAT_TLB_SURF_SRC_HIT
– j/w, źródłowy bufor ramki.BAR0 + 0x17c: STAT_TLB_SURF_SRC_MISS
– j/w, źródłowy bufor ramki.BAR0 + 0x180: STAT_TLB_TEXTURE_HIT
– j/w, tekstura kolumnowa.BAR0 + 0x184: STAT_TLB_TEXTURE_MISS
– j/w, tekstura kolumnowa.BAR0 + 0x188: STAT_TLB_REBIND_SURF_DST
– zmiana aktywnego docelowego bufora ramki (i spłukanie TLB)BAR0 + 0x18c: STAT_TLB_REBIND_SURF_SRC
– zmiana aktywnego źródłowego bufora ramki (i spłukanie TLB)BAR0 + 0x190: STAT_TLB_REBIND_TEXTURE
– zmiana aktywnej tekstury kolumnowej (i spłukanie TLB oraz pamięci podręcznej)BAR0 + 0x194: STAT_XY_INTERLOCK
– przetworzenie poleceniaINTERLOCK
BAR0 + 0x198: STAT_TEX_COLUMN
– przetworzenie poleceniaDRAW_COLUMN
z teksturąBAR0 + 0x19c: STAT_TEX_PIXEL
– narysowanie piksela przezDRAW_COLUMN
z teksturąBAR0 + 0x1a0: STAT_TEX_CACHE_HIT
– trafienie teksela w pamięci podręcznej tekstury kolumnowejBAR0 + 0x1a4: STAT_TEX_CACHE_SPEC_HIT
– trafienie spekulatywnego teksela w pamięci podręcznej tekstury kolumnowejBAR0 + 0x1a8: STAT_TEX_CACHE_MISS
– chybienie teksela (czyli wczytanie 64 bajtów z tekstury)BAR0 + 0x1ac: STAT_TEX_CACHE_SPEC_MISS
– chybienie spekulatywnego teksela (czyli porzucenie spekulatywnego teksturowania danej kolumny)BAR0 + 0x1b0: STAT_FLAT_REBIND
– zmiana aktywnej tekstury płaskiej (i spłukanie pamięci podręcznej)BAR0 + 0x1b4: STAT_FLAT_READ_BLOCK
– wczytanie bloku pikseli przezDRAW_BACKGROUND
BAR0 + 0x1b8: STAT_FLAT_SPAN_BLOCK
– oteksturowanie bloku pikseli teksturą płaskąBAR0 + 0x1bc: STAT_FLAT_SPAN_PIXEL
– oteksturowanie piksela teksturą płaskąBAR0 + 0x1c0: STAT_FLAT_CACHE_HIT
– trafienie teksela w pamięci podręcznej tekstury płaskiejBAR0 + 0x1c4: STAT_FLAT_CACHE_MISS
– chybienie teksela (czyli wczytanie 64 bajtów z tekstury)BAR0 + 0x1c8: STAT_FUZZ_COLUMN
– rysowanie kolumny z efektemFUZZ
BAR0 + 0x1cc: STAT_OG_COLORMAP_FETCH
– wczytanie głównej mapy kolorówBAR0 + 0x1d0: STAT_OG_TRANSLATION_FETCH
– wczytanie mapy kolorów do zmiany paletyBAR0 + 0x1d4: STAT_OG_DRAW_BUF_BLOCK
– rysowanie bloku pikseli przezFILL_RECT
,DRAW_LINE
lubDRAW_BACKGROUND
BAR0 + 0x1d8: STAT_OG_DRAW_BUF_PIXEL
– rysowanie piksela przezFILL_RECT
,DRAW_LINE
lubDRAW_BACKGROUND
BAR0 + 0x1dc: STAT_OG_COPY_BLOCK
– rysowanie bloku pikseli przezCOPY_RECT
BAR0 + 0x1e0: STAT_OG_COPY_PIXEL
– rysowanie piksela przezCOPY_RECT
BAR0 + 0x1e4: STAT_OG_FUZZ_PIXEL
– rysowanie piksela przezDRAW_COLUMN
zFUZZ
BAR0 + 0x1e8: STAT_OG_TRANSLATE_BLOCK
– przetwarzanie bloku pikseli przez flagęTRANSLATE
BAR0 + 0x1ec: STAT_OG_COLORMAP_BLOCK
– przetwarzanie bloku pikseli przez flagęCOLORMAP
BAR0 + 0x1f0: STAT_SW_FENCE
– przetworzenie poleceniaFENCE
BAR0 + 0x1f4: STAT_SW_FENCE_INTR
– przetworzenie poleceniaFENCE
powodującego przerwanieBAR0 + 0x1f8: STAT_SW_PIXEL
– rysowanie piksela jakiegokolwiek typuBAR0 + 0x1fc: STAT_SW_XFER
– rysowanie ciągłej grupy pikseli
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.