BC7 Format
Format BC7 to format kompresji tekstury używany do wysokiej jakości kompresji danych RGB i RGBA.
- o BC7/DXGI_FORMAT_BC7
- implementacji BC7
- dekodowanie formatu BC7
- Tematy pokrewne
Aby uzyskać informacje o trybach bloków formatu BC7, zobacz BC7 Format Mode Reference.
Informacje o bc7/DXGI_FORMAT_BC7
BC7 jest określany przez następujące wartości wyliczenia DXGI_FORMAT:
- DXGI_FORMAT_BC7_TYPELESS.
- DXGI_FORMAT_BC7_UNORM.
- DXGI_FORMAT_BC7_UNORM_SRGB.
Format BC7 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.
BC7 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ż trójwymiarowych obrazów i map MIP, map modułów i tablic tekstur. Wszystkie kafelki obrazów muszą mieć ten sam format.
BC7 kompresuje zarówno trzykanałowe (RGB) jak i czterokanałowe (RGBA) obrazy danych punktów stałych. Zazwyczaj dane źródłowe to 8 bitów na składnik koloru (kanał), chociaż format umożliwia kodowanie danych źródłowych z wyższymi bitami na składnik koloru. Wszystkie kafelki obrazów muszą mieć ten sam format.
Dekoder BC7 wykonuje dekompresję przed zastosowaniem filtrowania tekstur.
Sprzęt dekompresacji BC7 musi być nieco dokładny; oznacza to, że sprzęt musi zwracać wyniki identyczne z wynikami zwróconymi przez dekoder opisany w tym dokumencie.
Implementacja BC7
Implementacja BC7 może określać jeden z 8 trybów z trybem określonym w najmniej znaczącym bitzie bloku 16 bajtów (128 bitów). Tryb jest kodowany przez zero lub więcej bitów z wartością 0, a następnie 1.
Blok BC7 może zawierać wiele par punktów końcowych. Na potrzeby tej dokumentacji zestaw indeksów odpowiadających parze punktów końcowych może być określany jako "podzbiór". Ponadto w niektórych trybach blokowych reprezentacja punktu końcowego jest kodowana w postaci, która — ponownie do celów tej dokumentacji — jest określana jako "RGBP", gdzie bit "P" reprezentuje najmniej znaczący bit dla składników kolorów punktu końcowego. Jeśli na przykład reprezentacja punktu końcowego dla formatu to "RGB 5.5.5.1", punkt końcowy jest interpretowany jako wartość RGB 6.6.6, gdzie stan bitu P definiuje najmniej znaczący bit każdego składnika. Podobnie w przypadku danych źródłowych z kanałem alfa, jeśli reprezentacja formatu to "RGBAP 5.5.5.5.1", punkt końcowy jest interpretowany jako RGBA 6.6.6.6.6. W zależności od trybu blokowania można określić współużytkowany najmniej znaczący bit dla obu punktów końcowych podzestawu indywidualnie (2 bity P na podzestaw) lub współużytkować między punktami końcowymi podzestawu (1 P-bit na podzestaw).
W przypadku bloków BC7, które nie kodują jawnie składnika alfa, blok BC7 składa się z bitów trybu, bitów partycji, skompresowanych punktów końcowych, skompresowanych indeksów i opcjonalnego P-bitu. W tych blokach punkty końcowe mają reprezentację tylko RGB, a składnik alfa jest zdekodowany jako 1.0 dla wszystkich texels w danych źródłowych.
W przypadku bloków BC7, które mają połączone składniki kolorów i alfa, blok składa się z bitów trybu, skompresowanych punktów końcowych, skompresowanych indeksów i opcjonalnych bitów partycji i P-bitów. W tych blokach kolory punktu końcowego są wyrażane w formacie RGBA, a wartości składników alfa są interpolowane wraz z wartościami składników kolorów.
W przypadku bloków BC7, które mają oddzielne składniki kolorów i alfa, blok składa się z bitów trybu, bitów obrotu, skompresowanych punktów końcowych, skompresowanych indeksów i opcjonalnego bitu selektora indeksów. Te bloki mają skuteczny wektor RGB [R, G, B] i skalarny kanał alfa [A] oddzielnie zakodowany.
W poniższej tabeli wymieniono składniki każdego typu bloku.
Blok BC7 zawiera... | bity trybu | bity obrotu | bit selektora indeksu | bity partycji | skompresowane punkty końcowe | P-bit | skompresowane indeksy |
---|---|---|---|---|---|---|---|
tylko składniki kolorów | Wymagane | N/A | N/A | Wymagane | Wymagane | fakultatywny | Wymagane |
kolor i alfa połączone | Wymagane | N/A | N/A | fakultatywny | Wymagane | fakultatywny | Wymagane |
kolor i alfa oddzielone | Wymagane | Wymagane | fakultatywny | N/A | Wymagane | N/A | Wymagane |
BC7 definiuje paletę kolorów na przybliżonej linii między dwoma punktami końcowymi. Wartość trybu określa liczbę par punktów końcowych interpolacji na blok. BC7 przechowuje jeden indeks palety na texel.
Dla każdego podzestawu indeksów odpowiadających parze punktów końcowych koder naprawia stan jednego bitu skompresowanych danych indeksu dla tego podzestawu. Robi to, wybierając kolejność punktów końcowych, która umożliwia indeksowi wyznaczonego indeksu "fix-up", aby ustawić jego najbardziej znaczący bit na 0, a następnie można go odrzucić, zapisując jeden bit na podzestaw. W przypadku trybów bloków z tylko jednym podzestawem indeks poprawki jest zawsze indeksowany 0.
Dekodowanie formatu BC7
Poniższy pseudokod przedstawia kroki dekompresowania piksela (x,y) na podstawie 16-bajtowego bloku BC7.
decompress_bc7(x, y, block)
{
mode = extract_mode(block);
//decode partition data from explicit partition bits
subset_index = 0;
num_subsets = 1;
if (mode.type == 0 OR == 1 OR == 2 OR == 3 OR == 7)
{
num_subsets = get_num_subsets(mode.type);
partition_set_id = extract_partition_set_id(mode, block);
subset_index = get_partition_index(num_subsets, partition_set_id, x, y);
}
//extract raw, compressed endpoint bits
UINT8 endpoint_array[2 * num_subsets][4] = extract_endpoints(mode, block);
//decode endpoint color and alpha for each subset
fully_decode_endpoints(endpoint_array, mode, block);
//endpoints are now complete.
UINT8 endpoint_start[4] = endpoint_array[2 * subset_index];
UINT8 endpoint_end[4] = endpoint_array[2 * subset_index + 1];
//Determine the palette index for this pixel
alpha_index = get_alpha_index(block, mode, x, y);
alpha_bitcount = get_alpha_bitcount(block, mode);
color_index = get_color_index(block, mode, x, y);
color_bitcount = get_color_bitcount(block, mode);
//determine output
UINT8 output[4];
output.rgb = interpolate(endpoint_start.rgb, endpoint_end.rgb, color_index, color_bitcount);
output.a = interpolate(endpoint_start.a, endpoint_end.a, alpha_index, alpha_bitcount);
if (mode.type == 4 OR == 5)
{
//Decode the 2 color rotation bits as follows:
// 00 – Block format is Scalar(A) Vector(RGB) - no swapping
// 01 – Block format is Scalar(R) Vector(AGB) - swap A and R
// 10 – Block format is Scalar(G) Vector(RAB) - swap A and G
// 11 - Block format is Scalar(B) Vector(RGA) - swap A and B
rotation = extract_rot_bits(mode, block);
output = swap_channels(output, rotation);
}
}
Poniższy pseudokod przedstawia kroki pełnego dekodowania koloru punktu końcowego i składników alfa dla każdego podzestawu przy użyciu bloku BC7 16 bajtów.
fully_decode_endpoints(endpoint_array, mode, block)
{
//first handle modes that have P-bits
if (mode.type == 0 OR == 1 OR == 3 OR == 6 OR == 7)
{
for each endpoint i
{
//component-wise left-shift
endpoint_array[i].rgba = endpoint_array[i].rgba << 1;
}
//if P-bit is shared
if (mode.type == 1)
{
pbit_zero = extract_pbit_zero(mode, block);
pbit_one = extract_pbit_one(mode, block);
//rgb component-wise insert pbits
endpoint_array[0].rgb |= pbit_zero;
endpoint_array[1].rgb |= pbit_zero;
endpoint_array[2].rgb |= pbit_one;
endpoint_array[3].rgb |= pbit_one;
}
else //unique P-bit per endpoint
{
pbit_array = extract_pbit_array(mode, block);
for each endpoint i
{
endpoint_array[i].rgba |= pbit_array[i];
}
}
}
for each endpoint i
{
// Color_component_precision & alpha_component_precision includes pbit
// left shift endpoint components so that their MSB lies in bit 7
endpoint_array[i].rgb = endpoint_array[i].rgb << (8 - color_component_precision(mode));
endpoint_array[i].a = endpoint_array[i].a << (8 - alpha_component_precision(mode));
// Replicate each component's MSB into the LSBs revealed by the left-shift operation above
endpoint_array[i].rgb = endpoint_array[i].rgb | (endpoint_array[i].rgb >> color_component_precision(mode));
endpoint_array[i].a = endpoint_array[i].a | (endpoint_array[i].a >> alpha_component_precision(mode));
}
//If this mode does not explicitly define the alpha component
//set alpha equal to 1.0
if (mode.type == 0 OR == 1 OR == 2 OR == 3)
{
for each endpoint i
{
endpoint_array[i].a = 255; //i.e. alpha = 1.0f
}
}
}
Aby wygenerować każdy składnik interpolowany dla każdego podzestawu, użyj następującego algorytmu: let "c" be the component to generate; niech wartość "e0" będzie tym składnikiem punktu końcowego 0 podzestawu; i niech wartość "e1" będzie tym składnikiem punktu końcowego 1 podzestawu.
UINT16 aWeights2[] = {0, 21, 43, 64};
UINT16 aWeights3[] = {0, 9, 18, 27, 37, 46, 55, 64};
UINT16 aWeights4[] = {0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64};
UINT8 interpolate(UINT8 e0, UINT8 e1, UINT8 index, UINT8 indexprecision)
{
if(indexprecision == 2)
return (UINT8) (((64 - aWeights2[index])*UINT16(e0) + aWeights2[index]*UINT16(e1) + 32) >> 6);
else if(indexprecision == 3)
return (UINT8) (((64 - aWeights3[index])*UINT16(e0) + aWeights3[index]*UINT16(e1) + 32) >> 6);
else // indexprecision == 4
return (UINT8) (((64 - aWeights4[index])*UINT16(e0) + aWeights4[index]*UINT16(e1) + 32) >> 6);
}
Poniższy pseudokod ilustruje sposób wyodrębniania indeksów i liczb bitów dla składników kolorów i alfa. Bloki z oddzielnym kolorem i alfa mają również dwa zestawy danych indeksu: jeden dla kanału wektorowego i jeden dla kanału skalarnego. W przypadku trybu 4 indeksy te mają różne szerokości (2 lub 3 bity) i istnieje selektor jedno bitowy, który określa, czy wektor lub skalarne dane używają indeksów 3-bitowych. (Wyodrębnianie liczby bitów alfa jest podobne do wyodrębniania liczby bitów kolorów, ale z odwrotnym zachowaniem na podstawie idxMode bit.
bitcount get_color_bitcount(block, mode)
{
if (mode.type == 0 OR == 1)
return 3;
if (mode.type == 2 OR == 3 OR == 5 OR == 7)
return 2;
if (mode.type == 6)
return 4;
//The only remaining case is Mode 4 with 1-bit index selector
idxMode = extract_idxMode(block);
if (idxMode == 0)
return 2;
else
return 3;
}
Tematy pokrewne
-
kompresja bloków tekstury w trybie Direct3D 11