Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Format BC6H to format kompresji tekstury przeznaczony do obsługi przestrzeni kolorów o wysokiej dynamic range (HDR) w danych źródłowych.
- o BC6H/DXGI_FORMAT_BC6H
- implementacji BC6H
- dekodowanie formatu BC6H
- format skompresowanego punktu końcowego BC6H
- rozszerzenie podpisywania dla wartości punktu końcowego
- przekształć inwersję dla wartości punktu końcowego
- unquantization of Color Endpoints
- Tematy pokrewne
Informacje o BC6H/DXGI_FORMAT_BC6H
Format BC6H zapewnia wysokiej jakości kompresję obrazów, które używają trzech kanałów kolorów HDR, z 16-bitową wartością dla każdego kanału kolorów wartości (16:16:16). Brak obsługi kanału alfa.
BC6H jest określony przez następujące wartości wyliczenia DXGI_FORMAT:
- DXGI_FORMAT_BC6H_TYPELESS.
- DXGI_FORMAT_BC6H_UF16. Ten format BC6H nie używa bitu logowania w 16-bitowych wartościach kanału kolorów zmiennoprzecinkowych.
- DXGI_FORMAT_BC6H_SF16. Ten format BC6H używa bitu logowania w 16-bitowych wartościach kanału kolorów zmiennoprzecinkowych.
Nuta
16-bitowy format zmiennoprzecinkowy dla kanałów kolorów jest często nazywany formatem zmiennoprzecinkowym "pół". Ten format ma następujący układ bitowy:
| Format | Układ bitowy |
|---|---|
| UF16 (niepodpisany zmiennoprzecinkowy) | 5 bitów wykładniczych + 11 bitów mantissa |
| SF16 (podpisany zmiennoprzecinkowy) | 1 bit znaku + 5 bitów wykładniczych + 10 bitów mantissa |
Format BC6H może służyć do Texture2D (w tym tablic), Texture3D lub TextureCube (w tym tablic). Podobnie ten format dotyczy wszystkich powierzchni mapy MIP skojarzonych z tymi zasobami.
BC6H używa stałego rozmiaru bloku 16 bajtów (128 bitów) i stałego rozmiaru kafelka 4x4 texels. Podobnie jak w przypadku poprzednich formatów BC, obrazy tekstur większe niż obsługiwany rozmiar kafelka (4x4) są kompresowane przy użyciu wielu bloków. Ta tożsamość adresowania dotyczy również obrazów trójwymiarowych, map MIP, map modułów i tablic tekstur. Wszystkie kafelki obrazów muszą mieć ten sam format.
Kilka ważnych uwag dotyczących formatu BC6H:
- BC6H obsługuje denormalizację zmiennoprzecinkową, ale nie obsługuje funkcji INF (nieskończoność) i NaN (nie liczby). Wyjątkiem jest podpisany tryb BC6H (DXGI_FORMAT_BC6H_SF16), który obsługuje -INF (nieskończoność ujemna). Należy pamiętać, że ta obsługa -INF jest tylko artefaktem samego formatu i nie jest specjalnie obsługiwana przez kodery dla tego formatu. Ogólnie rzecz biorąc, gdy kodery napotykają dane wejściowe INF (dodatnie lub ujemne) lub NaN, powinny one \ przekonwertować te dane na maksymalną dozwoloną wartość reprezentacji inf i mapować wartość NaN na 0 przed kompresją.
- BC6H nie obsługuje kanału alfa.
- Dekoder BC6H wykonuje dekompresję przed wykonaniem filtrowania tekstur.
- Dekompresja BC6H musi być nieco dokładna; oznacza to, że sprzęt musi zwracać wyniki identyczne z dekoderem opisanym w tej dokumentacji.
Implementacja BC6H
Blok BC6H składa się z bitów trybu, skompresowanych punktów końcowych, skompresowanych indeksów i opcjonalnego indeksu partycji. Ten format określa 14 różnych trybów.
Kolor punktu końcowego jest przechowywany jako potrójny RGB. BC6H definiuje paletę kolorów w przybliżonej linii w wielu zdefiniowanych punktach końcowych kolorów. Ponadto, w zależności od trybu, kafelek można podzielić na dwa regiony lub traktować jako jeden region, gdzie kafelek dwuregionowy ma oddzielny zestaw kolorowych punktów końcowych dla każdego regionu. BC6H przechowuje jeden indeks palety na texel.
W przypadku dwóch regionów istnieje 32 możliwe partycje.
Dekodowanie formatu BC6H
Poniższy pseudokod przedstawia kroki dekompresowania piksela (x,y) na podstawie bloku BC6H 16 bajtów.
decompress_bc6h(x, y, block)
{
mode = extract_mode(block);
endpoints;
index;
if(mode.type == ONE)
{
endpoints = extract_compressed_endpoints(mode, block);
index = extract_index_ONE(x, y, block);
}
else //mode.type == TWO
{
partition = extract_partition(block);
region = get_region(partition, x, y);
endpoints = extract_compressed_endpoints(mode, region, block);
index = extract_index_TWO(x, y, partition, block);
}
unquantize(endpoints);
color = interpolate(index, endpoints);
finish_unquantize(color);
}
Poniższa tabela zawiera liczbę bitów i wartości dla każdego z 14 możliwych formatów bloków BC6H.
| Tryb | Indeksy partycji | Partycja | Punkty końcowe kolorów | Bity trybu |
|---|---|---|---|---|
| 1 | 46 bitów | 5 bitów | 75 bitów (10,555, 10,555, 10,555) | 2 bity (00) |
| 2 | 46 bitów | 5 bitów | 75 bitów (7666, 7666, 7666) | 2 bity (01) |
| 3 | 46 bitów | 5 bitów | 72 bity (11.555, 11.444, 11.444) | 5 bitów (00010) |
| 4 | 46 bitów | 5 bitów | 72 bity (11.444, 11.555, 11.444) | 5 bitów (00110) |
| 5 | 46 bitów | 5 bitów | 72 bity (11.444, 11.444, 11.555) | 5 bitów (01010) |
| 6 | 46 bitów | 5 bitów | 72 bity (9555, 9555, 9555) | 5 bitów (01110) |
| 7 | 46 bitów | 5 bitów | 72 bity (8666, 8555, 8555) | 5 bitów (10010) |
| 8 | 46 bitów | 5 bitów | 72 bity (8555, 8666, 8555) | 5 bitów (10110) |
| 9 | 46 bitów | 5 bitów | 72 bity (8555, 8555, 8666) | 5 bitów (11010) |
| 10 | 46 bitów | 5 bitów | 72 bity (6666, 6666, 6666) | 5 bitów (11110) |
| 11 | 63 bity | 0 bitów | 60 bitów (10.10, 10.10, 10.10) | 5 bitów (00011) |
| 12 | 63 bity | 0 bitów | 60 bitów (11.9, 11.9, 11.9) | 5 bitów (00111) |
| 13 | 63 bity | 0 bitów | 60 bitów (12.8, 12.8, 12.8) | 5 bitów (01011) |
| 14 | 63 bity | 0 bitów | 60 bitów (16.4, 16.4, 16.4) | 5 bitów (01111) |
Każdy format w tej tabeli może być jednoznacznie identyfikowany przez bity trybu. Pierwsze dziesięć trybów jest używanych dla kafelków z dwoma regionami, a pole bitowe trybu może mieć długość dwóch lub pięciu bitów. Te bloki mają również pola dla skompresowanych punktów końcowych koloru (72 lub 75 bitów), partycji (5 bitów) i indeksów partycji (46 bitów).
W przypadku skompresowanych punktów końcowych kolorów wartości w poprzedniej tabeli zwracają uwagę na precyzję przechowywanych punktów końcowych RGB oraz liczbę bitów używanych dla każdej wartości koloru. Na przykład tryb 3 określa poziom dokładności punktu końcowego koloru 11, a liczba bitów używanych do przechowywania wartości różnicowych przekształconych punktów końcowych dla kolorów czerwony, niebieski i zielony (odpowiednio 5, 4 i 4). Tryb 10 nie używa kompresji różnicowej, a zamiast tego przechowuje wszystkie cztery kolorowe punkty końcowe jawnie.
Ostatnie cztery tryby bloków są używane dla kafelków z jednym regionem, gdzie pole trybu jest 5 bitów. Te bloki mają pola dla punktów końcowych (60 bitów) i skompresowanych indeksów (63 bity). Tryb 11 (na przykład Tryb 10) nie używa kompresji różnicowej, a zamiast tego jawnie przechowuje oba punkty końcowe kolorów.
Tryby 10011, 10111, 11011 i 11111 (nie pokazano) są zarezerwowane. Nie należy ich używać w koderze. Jeśli sprzęt jest przekazywany bloki z jednym z tych trybów określony, wynikowy dekompresowany blok musi zawierać wszystkie zera we wszystkich kanałach z wyjątkiem kanału alfa.
W przypadku bc6H kanał alfa musi zawsze zwracać wartość 1.0 niezależnie od trybu.
Zestaw partycji BC6H
Istnieje 32 możliwe zestawy partycji dla kafelka z dwoma regionami, które są zdefiniowane w poniższej tabeli. Każdy blok 4x4 reprezentuje jeden kształt.
W tej tabeli zestawów partycji pogrubiony i podkreślony wpis jest lokalizacją indeksu poprawki dla podzestawu 1 (który jest określony z jednym mniej bitowym). Indeks poprawki dla podzestawu 0 jest zawsze indeksem 0, ponieważ partycjonowanie jest zawsze rozmieszczone tak, aby indeks 0 był zawsze w podzestawie 0. Kolejność partycji przechodzi od lewej górnej do prawej do dołu, przechodząc od lewej do prawej, a następnie od góry do dołu.
Format skompresowanego punktu końcowego BC6H
W tej tabeli przedstawiono pola bitowe skompresowanych punktów końcowych jako funkcję formatu punktu końcowego, z każdą kolumną określającą kodowanie i każdy wiersz określający pole bitowe. Takie podejście zajmuje 82 bity dla kafelków z dwoma regionami i 65 bitów dla kafelków z jednym regionem. Na przykład pierwsze 5 bitów dla kodowania jednoregionowego [16 4] powyżej (w szczególności kolumny po prawej stronie) to bity m[4:0], następne 10 bitów to bity rw[9:0] itd. z ostatnich 6 bitów zawierających bw[10:15].
Nazwy pól w powyższej tabeli są definiowane w następujący sposób:
| Pole | Zmienna |
|---|---|
| m | tryb |
| d | indeks kształtu |
| Rw | endpt[0]. A[0] |
| Rx | endpt[0]. B[0] |
| Ry | endpt[1]. A[0] |
| rz | endpt[1]. B[0] |
| Gw | endpt[0]. A[1] |
| gx | endpt[0]. B[1] |
| Gy | endpt[1]. A[1] |
| gz | endpt[1]. B[1] |
| Bw | endpt[0]. A[2] |
| Bx | endpt[0]. B[2] |
| przez | endpt[1]. A[2] |
| Bz | endpt[1]. B[2] |
Endpt[i], gdzie i ma wartość 0 lub 1, odnosi się odpowiednio do 0 lub 1 zestawu punktów końcowych.
Podpisywanie rozszerzenia dla wartości punktu końcowego
W przypadku kafelków z dwoma regionami istnieją cztery wartości punktu końcowego, które można podpisać rozszerzone. Endpt[0]. Wartość A jest podpisana tylko wtedy, gdy format jest podpisany; inne punkty końcowe są podpisane tylko wtedy, gdy punkt końcowy został przekształcony lub format jest podpisany. Poniższy kod przedstawia algorytm rozszerzania znaku dwuregionowych wartości punktów końcowych.
static void sign_extend_two_region(Pattern &p, IntEndpts endpts[NREGIONS_TWO])
{
for (int i=0; i<NCHANNELS; ++i)
{
if (BC6H::FORMAT == SIGNED_F16)
endpts[0].A[i] = SIGN_EXTEND(endpts[0].A[i], p.chan[i].prec);
if (p.transformed || BC6H::FORMAT == SIGNED_F16)
{
endpts[0].B[i] = SIGN_EXTEND(endpts[0].B[i], p.chan[i].delta[0]);
endpts[1].A[i] = SIGN_EXTEND(endpts[1].A[i], p.chan[i].delta[1]);
endpts[1].B[i] = SIGN_EXTEND(endpts[1].B[i], p.chan[i].delta[2]);
}
}
}
W przypadku kafelków z jednym regionem zachowanie jest takie samo, tylko w przypadku usunięcia elementu endpt[1].
static void sign_extend_one_region(Pattern &p, IntEndpts endpts[NREGIONS_ONE])
{
for (int i=0; i<NCHANNELS; ++i)
{
if (BC6H::FORMAT == SIGNED_F16)
endpts[0].A[i] = SIGN_EXTEND(endpts[0].A[i], p.chan[i].prec);
if (p.transformed || BC6H::FORMAT == SIGNED_F16)
endpts[0].B[i] = SIGN_EXTEND(endpts[0].B[i], p.chan[i].delta[0]);
}
}
Przekształcanie inwersji dla wartości punktów końcowych
W przypadku kafelków dwuregionowych przekształcenie stosuje odwrotność kodowania różnicy, dodając wartość podstawową w punkcie końcowym[0]. Od trzech innych wpisów dla łącznie 9 operacji dodawania. Na poniższej ilustracji wartość podstawowa jest reprezentowana jako "A0" i ma najwyższą precyzję zmiennoprzecinkową. Wartości "A1", "B0" i "B1" to różnice obliczane na podstawie wartości kotwicy, a te wartości różnicowe są reprezentowane z niższą precyzją. (A0 odpowiada endpt[0]. A, B0 odpowiada endpt[0]. B, A1 odpowiada endpt[1]. A, a B1 odpowiada endpt[1].B.)
W przypadku kafelków z jednym regionem istnieje tylko jedno przesunięcie różnicowe i dlatego tylko 3 operacje dodawania.
Dekompresor musi zapewnić, że wyniki odwrotnej transformacji nie przepełnią precyzji elementu endpt[0].a. W przypadku przepełnienia wartości wynikające z odwrotnej transformacji muszą opakowować się w tej samej liczbie bitów. Jeśli precyzja A0 to "p" bity, algorytm przekształcania to:
B0 = (B0 + A0) & ((1 << p) - 1)
W przypadku podpisanych formatów należy również podpisać wyniki obliczeń różnicowych. Jeśli operacja rozszerzenia znaku uwzględnia rozszerzenie obu znaków, gdzie wartość 0 jest dodatnia, a 1 jest ujemna, wówczas rozszerzenie znaku 0 zajmuje się zaciskiem powyżej. Co równoważne, po powyższym zacisku należy podpisać tylko wartość 1 (ujemną).
Unquantization of Color Endpoints
Biorąc pod uwagę nieskompresowane punkty końcowe, następnym krokiem jest wykonanie początkowej niekwestionowanej ilości punktów końcowych kolorów. Obejmuje to trzy kroki:
- Unquantization palet kolorów
- Interpolacja palet
- Finalizacja unquantization
Rozdzielenie procesu niequantyzacji na dwie części (paleta kolorów niekwaplikowana przed interpolacją i ostateczną niekwestytacją po interpolacji) zmniejsza liczbę operacji mnożenia wymaganych w porównaniu z pełnym procesem niekwawansowania przed interpolacją palety.
Poniższy kod ilustruje proces pobierania oszacowań oryginalnych wartości kolorów 16-bitowych, a następnie przy użyciu podanych wartości wagi w celu dodania 6 dodatkowych wartości kolorów do palety. Ta sama operacja jest wykonywana na każdym kanale.
int aWeight3[] = {0, 9, 18, 27, 37, 46, 55, 64};
int aWeight4[] = {0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64};
// c1, c2: endpoints of a component
void generate_palette_unquantized(UINT8 uNumIndices, int c1, int c2, int prec, UINT16 palette[NINDICES])
{
int* aWeights;
if(uNumIndices == 8)
aWeights = aWeight3;
else // uNumIndices == 16
aWeights = aWeight4;
int a = unquantize(c1, prec);
int b = unquantize(c2, prec);
// interpolate
for(int i = 0; i < uNumIndices; ++i)
palette[i] = finish_unquantize((a * (64 - aWeights[i]) + b * aWeights[i] + 32) >> 6);
}
W następnym przykładzie kodu przedstawiono proces interpolacji z następującymi obserwacjami:
- Ponieważ pełny zakres wartości kolorów dla funkcji niekwestionowanych (poniżej) wynosi od -32768 do 65535, interpolator jest implementowany przy użyciu arytmetyki ze znakiem 17-bitowym.
- Po interpolacji wartości są przekazywane do funkcji finish_unquantize (opisanej w trzeciej próbie w tej sekcji), która stosuje końcowe skalowanie.
- Wszystkie dekompresory sprzętowe są wymagane do zwrócenia dokładnych wyników bitów za pomocą tych funkcji.
int unquantize(int comp, int uBitsPerComp)
{
int unq, s = 0;
switch(BC6H::FORMAT)
{
case UNSIGNED_F16:
if(uBitsPerComp >= 15)
unq = comp;
else if(comp == 0)
unq = 0;
else if(comp == ((1 << uBitsPerComp) - 1))
unq = 0xFFFF;
else
unq = ((comp << 16) + 0x8000) >> uBitsPerComp;
break;
case SIGNED_F16:
if(uBitsPerComp >= 16)
unq = comp;
else
{
if(comp < 0)
{
s = 1;
comp = -comp;
}
if(comp == 0)
unq = 0;
else if(comp >= ((1 << (uBitsPerComp - 1)) - 1))
unq = 0x7FFF;
else
unq = ((comp << 15) + 0x4000) >> (uBitsPerComp-1);
if(s)
unq = -unq;
}
break;
}
return unq;
}
finish_unquantize jest wywoływana po interpolacji palety. Funkcja niekwestionowana odroczy skalowanie przez 31/32 dla podpisanej wartości 31/64 dla niepodpisanych. To zachowanie jest wymagane, aby uzyskać końcową wartość do prawidłowego zakresu połowy(-0x7BFF ~ 0x7BFF) po zakończeniu interpolacji palety w celu zmniejszenia liczby niezbędnych mnożenia. finish_unquantize stosuje końcowe skalowanie i zwraca wartość niepodpisaną krótką, która zostanie ponownie zinterpretowana w połowie.
unsigned short finish_unquantize(int comp)
{
if(BC6H::FORMAT == UNSIGNED_F16)
{
comp = (comp * 31) >> 6; // scale the magnitude by 31/64
return (unsigned short) comp;
}
else // (BC6H::FORMAT == SIGNED_F16)
{
comp = (comp < 0) ? -(((-comp) * 31) >> 5) : (comp * 31) >> 5; // scale the magnitude by 31/32
int s = 0;
if(comp < 0)
{
s = 0x8000;
comp = -comp;
}
return (unsigned short) (s | comp);
}
}
Tematy pokrewne
-
kompresja bloków tekstury w trybie Direct3D 11