BC7 Format
Le format BC7 est un format de compression de texture utilisé pour la compression de haute qualité des données RVB et RVBA.
- À propos de BC7/DXGI_FORMAT_BC7
- d’implémentation BC7
- décodage du format BC7
- rubriques connexes
Pour plus d’informations sur les modes de bloc du format BC7, consultez référence du mode de format BC7.
À propos de BC7/DXGI_FORMAT_BC7
BC7 est spécifié par les valeurs d’énumération DXGI_FORMAT suivantes :
- DXGI_FORMAT_BC7_TYPELESS.
- DXGI_FORMAT_BC7_UNORM.
- DXGI_FORMAT_BC7_UNORM_SRGB.
Le format BC7 peut être utilisé pour Texture2D (y compris les tableaux), Texture3D ou TextureCube (y compris les tableaux). De même, ce format s’applique aux surfaces MIP-map associées à ces ressources.
BC7 utilise une taille de bloc fixe de 16 octets (128 bits) et une taille de vignette fixe de 4 x 4 texels. Comme pour les formats BC précédents, les images de texture supérieures à la taille de vignette prise en charge (4x4) sont compressées à l’aide de plusieurs blocs. Cette identité d’adressage s’applique également aux images tridimensionnelles et aux cartes MIP, aux cubemaps et aux tableaux de texture. Toutes les vignettes d’image doivent être du même format.
BC7 compresse à la fois les images de données à trois canaux (RVB) et à quatre canaux (RVBA). En règle générale, les données sources sont de 8 bits par composant de couleur (canal), bien que le format soit capable d’encodage des données sources avec des bits plus élevés par composant de couleur. Toutes les vignettes d’image doivent être du même format.
Le décodeur BC7 effectue la décompression avant l’application du filtrage de texture.
Le matériel de décompression BC7 doit être un peu précis ; autrement dit, le matériel doit retourner des résultats identiques aux résultats retournés par le décodeur décrit dans ce document.
Implémentation BC7
Une implémentation BC7 peut spécifier l’un des 8 modes, avec le mode spécifié dans le bit le moins significatif du bloc 16 octets (128 bits). Le mode est encodé par zéro ou plusieurs bits avec une valeur de 0 suivie d’un 1.
Un bloc BC7 peut contenir plusieurs paires de points de terminaison. Dans le cadre de cette documentation, l’ensemble d’index qui correspondent à une paire de points de terminaison peut être appelé « sous-ensemble ». En outre, dans certains modes de bloc, la représentation de point de terminaison est encodée dans une forme qui, à nouveau, à des fins de cette documentation, doit être appelée « RVBP », où le bit « P » représente un bit partagé le moins significatif pour les composants de couleur du point de terminaison. Par exemple, si la représentation de point de terminaison pour le format est « RVB 5.5.5.1 », le point de terminaison est interprété comme une valeur RVB 6.6.6, où l’état du bit P définit le bit le moins significatif de chaque composant. De même, pour les données sources avec un canal alpha, si la représentation du format est « RGBAP 5.5.5.5.1 », le point de terminaison est interprété comme RVBA 6.6.6.6.6. Selon le mode bloc, vous pouvez spécifier le bit le moins significatif partagé pour les deux points de terminaison d’un sous-ensemble individuellement (2 bits P par sous-ensemble) ou partagés entre les points de terminaison d’un sous-ensemble (1 bit P par sous-ensemble).
Pour les blocs BC7 qui n’encodent pas explicitement le composant alpha, un bloc BC7 se compose de bits de mode, de bits de partition, de points de terminaison compressés, d’index compressés et d’un bit P facultatif. Dans ces blocs, les points de terminaison ont une représentation RVB uniquement et le composant alpha est décodé en tant que 1.0 pour tous les texels dans les données sources.
Pour les blocs BC7 qui ont combiné des composants de couleur et d’alpha, un bloc se compose de bits de mode, de points de terminaison compressés, d’index compressés et de bits de partition facultatifs et d’un bit P. Dans ces blocs, les couleurs de point de terminaison sont exprimées au format RVBA et les valeurs des composants alpha sont interpolées en même temps que les valeurs des composants de couleur.
Pour les blocs BC7 qui ont des composants de couleur et d’alpha distincts, un bloc se compose de bits de mode, de bits de rotation, de points de terminaison compressés, d’index compressés et d’un bit de sélecteur d’index facultatif. Ces blocs ont un vecteur RVB efficace [R, G, B] et un canal alpha scalaire [A] encodé séparément.
Le tableau suivant répertorie les composants de chaque type de bloc.
Le bloc BC7 contient... | bits en mode | bits de rotation | bit du sélecteur d’index | bits de partition | Points de terminaison compressés | P-bit | Index compressés |
---|---|---|---|---|---|---|---|
composants de couleur uniquement | Obligatoire | N/A | N/A | Obligatoire | Obligatoire | optionnel | Obligatoire |
couleur + alpha combinée | Obligatoire | N/A | N/A | optionnel | Obligatoire | optionnel | Obligatoire |
couleur et alpha séparées | Obligatoire | Obligatoire | optionnel | N/A | Obligatoire | N/A | Obligatoire |
BC7 définit une palette de couleurs sur une ligne approximative entre deux points de terminaison. La valeur du mode détermine le nombre de paires de points de terminaison interpolantes par bloc. BC7 stocke un index de palette par texel.
Pour chaque sous-ensemble d’index qui correspond à une paire de points de terminaison, l’encodeur corrige l’état d’un bit des données d’index compressées pour ce sous-ensemble. Il le fait en choisissant un ordre de point de terminaison qui permet à l’index pour l’index désigné de définir son bit le plus significatif sur 0, et qui peut ensuite être ignoré, en enregistrant un bit par sous-ensemble. Pour les modes de bloc avec un seul sous-ensemble, l’index de correction est toujours index 0.
Décodage du format BC7
Le pseudocode suivant décrit les étapes permettant de décompresser le pixel à (x,y) en fonction du bloc BC7 de 16 octets.
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);
}
}
Le pseudocode suivant décrit les étapes permettant de décoder entièrement la couleur du point de terminaison et les composants alpha pour chaque sous-ensemble en fonction d’un bloc BC7 de 16 octets.
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
}
}
}
Pour générer chaque composant interpolé pour chaque sous-ensemble, utilisez l’algorithme suivant : laissez « c » être le composant à générer ; laissez « e0 » être ce composant du point de terminaison 0 du sous-ensemble ; et laissez « e1 » être ce composant du point de terminaison 1 du sous-ensemble.
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);
}
Le pseudocode suivant illustre comment extraire des index et des nombres de bits pour les composants de couleur et alpha. Les blocs de couleur et alpha distincts ont également deux jeux de données d’index : un pour le canal vectoriel et un pour le canal scalaire. Pour le mode 4, ces index sont de largeurs différentes (2 ou 3 bits) et il existe un sélecteur un bits qui spécifie si les données vectorielles ou scalaires utilisent les index 3 bits. (L’extraction du nombre de bits alpha est similaire à l’extraction du nombre de bits de couleur, mais avec un comportement inverse basé sur le 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;
}
Rubriques connexes
-
compression de bloc de texture dans direct3D 11