BC7 格式是用于 RGB 和 RGBA 数据的高质量压缩的纹理压缩格式。
有关 BC7 格式的块模式的信息,请参阅 BC7 格式模式参考。
关于 BC7/DXGI_FORMAT_BC7
BC7 由以下DXGI_FORMAT枚举值指定:
- DXGI_FORMAT_BC7_TYPELESS。
- DXGI_FORMAT_BC7_UNORM。
- DXGI_FORMAT_BC7_UNORM_SRGB。
BC7 格式可用于 Texture2D(包括数组)、Texture3D 或 TextureCube(包括数组)纹理资源。 同样,此格式适用于与这些资源关联的任何 MIP 映射图面。
BC7 使用固定块大小 16 字节(128 位),固定磁贴大小为 4x4 纹素。 与以前的 BC 格式一样,大于支持的磁贴大小(4x4)的纹理图像使用多个块进行压缩。 此寻址标识也适用于三维图像和 MIP 地图、多维数据集地图和纹理数组。 所有图像磁贴的格式必须相同。
BC7 压缩三通道(RGB)和四通道(RGBA)固定点数据图像。 通常,源数据是每个颜色组件(通道)的 8 位,尽管该格式能够编码每个颜色分量更高的位的源数据。 所有图像磁贴的格式必须相同。
BC7 解码器在应用纹理筛选之前执行解压缩。
BC7 解压缩硬件必须准确;也就是说,硬件必须返回与本文档中所述解码器返回的结果相同的结果。
BC7 实现
BC7 实现可以指定 8 种模式之一,模式在 16 字节(128 位)块中指定的最低有效位。 模式由零位或更多位编码,值为 0,后跟 1。
BC7 块可以包含多个终结点对。 出于本文档的目的,对应于终结点对的索引集可以称为“子集”。此外,在某些块模式下,终结点表示形式采用一种形式进行编码,同样,出于本文档的目的,应称为“RGBP”,其中“P”位表示终结点颜色组件共享的最小有效位。 例如,如果格式的终结点表示形式为“RGB 5.5.5.1”,则终结点被解释为 RGB 6.6.6 值,其中 P 位的状态定义每个组件的最小有效位。 同样,对于具有 alpha 通道的源数据,如果格式的表示形式为“RGBAP 5.5.5.5.1”,则将终结点解释为 RGBA 6.6.6.6。 根据块模式,可以分别为子集的两个终结点(每个子集 2 个 P 位)指定共享最小有效位,或为每个子集共享一个子集(每个子集 1 个 P 位)。
对于不显式编码 alpha 组件的 BC7 块,BC7 块由模式位、分区位、压缩终结点、压缩索引和可选的 P 位组成。 在这些块中,终结点具有仅 RGB 表示形式,并且对于源数据中的所有纹素,alpha 组件被解码为 1.0。
对于具有组合颜色和 alpha 组件的 BC7 块,块由模式位、压缩终结点、压缩索引和可选分区位和 P 位组成。 在这些块中,终结点颜色以 RGBA 格式表示,alpha 组件值与颜色分量值一起内插。
对于具有单独的颜色和 alpha 组件的 BC7 块,块由模式位、旋转位、压缩终结点、压缩索引和可选的索引选择器位组成。 这些块具有有效的 RGB 矢量 [R, G, B] 和标量 alpha 通道 [A] 单独编码。
下表列出了每个块类型的组件。
BC7 块包含... | 模式位 | 旋转位 | 索引选择器位 | 分区位 | 压缩的终结点 | P 位 | 压缩索引 |
---|---|---|---|---|---|---|---|
仅颜色组件 | 必填 | N/A | N/A | 必填 | 必填 | 自选 | 必填 |
color + alpha combined | 必填 | N/A | N/A | 自选 | 必填 | 自选 | 必填 |
颜色和 alpha 分隔 | 必填 | 必填 | 自选 | N/A | 必填 | N/A | 必填 |
BC7 在两个终结点之间的近似线条上定义颜色调色板。 模式值确定每个块内插终结点对的数目。 BC7 为每个纹素存储一个调色板索引。
对于对应于一对终结点的每个索引子集,编码器修复了该子集的一位压缩索引数据的状态。 它通过选择一个终结点顺序来执行此作,该顺序允许指定“修复”索引的索引将其最有效位设置为 0,然后可以放弃该索引,从而为每个子集保存一位。 对于仅包含单个子集的块模式,修复索引始终为索引 0。
解码 BC7 格式
以下伪代码概述了在给定 16 字节 BC7 块的情况下解压缩像素(x,y)的步骤。
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);
}
}
以下伪代码概述了为给定 16 字节 BC7 块的每个子集完全解码终结点颜色和 alpha 组件的步骤。
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
}
}
}
若要为每个子集生成每个内插组件,请使用以下算法:让“c”成为要生成的组件;让“e0”成为子集终结点 0 的组件;让“e1”成为子集的终结点 1 的组件。
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);
}
以下伪代码说明了如何提取颜色和 alpha 组件的索引和位计数。 具有单独颜色和 alpha 的块还具有两组索引数据:一组用于矢量通道,另一组用于标量通道。 对于模式 4,这些索引的宽度不同(2 位或 3 位),并且有一个一位选择器,用于指定向量或标量数据是否使用 3 位索引。 (提取 alpha 位计数类似于提取颜色位计数,但具有基于 idxMode 位的逆行为。
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;
}
相关主题
-
在 Direct3D 11 中 纹理块压缩