Формат BC7
Формат 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 можно использовать для текстуры Текстур2D (включая массивы), Texture3D или TextureCube (включая массивы) текстур. Аналогичным образом этот формат применяется к любым поверхностям карты MIP, связанным с этими ресурсами.
BC7 использует фиксированный размер блока 16 байт (128 бит) и фиксированный размер плитки 4x4 texels. Как и в предыдущих форматах 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-бита определяет наименьший значительный бит каждого компонента. Аналогичным образом, для исходных данных с альфа-каналом, если представление формата — RGBAP 5.5.5.5.1, то конечная точка интерпретируется как RGBA 6.6.6.6.6.6. В зависимости от режима блокировки можно указать общий наименее значительный бит для обеих конечных точек подмножества по отдельности (2 P-бита на подмножество) или совместно использовать между конечными точками подмножества (1 P-бит на подмножество).
Для блоков BC7, которые не кодируют альфа-компонент, блок BC7 состоит из битов режима, битов секций, сжатых конечных точек, сжатых индексов и необязательного P-бита. В этих блоках конечные точки имеют представление только RGB, а альфа-компонент декодируется как 1.0 для всех текселей в исходных данных.
Для блоков BC7 с объединенными цветами и альфа-компонентами блок состоит из битов режима, сжатых конечных точек, сжатых индексов и необязательных битов секций и P-бита. В этих блоках цвета конечных точек выражаются в формате RGBA, а значения альфа-компонентов интерполируются вместе со значениями компонента цвета.
Для блоков BC7 с отдельными цветами и альфа-компонентами блок состоит из битов режима, битов поворота, сжатых конечных точек, сжатых индексов и дополнительного селектора индекса. Эти блоки имеют эффективный вектор RGB [R, G, B] и скалярный альфа-канал [A] отдельно закодирован.
В следующей таблице перечислены компоненты каждого типа блока.
Блок BC7 содержит... | биты режима | биты поворота | Бит селектора индекса | Биты секций | сжатые конечные точки | P-bit | сжатые индексы |
---|---|---|---|---|---|---|---|
Только компоненты цвета | Обязательно | N/A | N/A | Обязательно | Обязательно | необязательный | Обязательно |
цвет + альфа в сочетании | Обязательно | N/A | N/A | необязательный | Обязательно | необязательный | Обязательно |
цвет и альфа-разделение | Обязательно | Обязательно | необязательный | N/A | Обязательно | N/A | Обязательно |
BC7 определяет палитру цветов на приблизительной линии между двумя конечными точками. Значение режима определяет количество пар интерполяции конечных точек на блок. BC7 хранит один индекс палитры на тексель.
Для каждого подмножества индексов, которые соответствуют паре конечных точек, кодировщик исправляет состояние одного бита сжатых данных индекса для этого подмножества. Это делается путем выбора порядка конечной точки, позволяющего индексу для указанного индекса "исправление" задать его наиболее значимый бит 0, и который затем можно отменить, сохраняя один бит на подмножество. Для режимов блоков только с одним подмножеством индекс исправления всегда имеет индекс 0.
Декодирование формата BC7
В следующем псевдокоде описаны шаги по декомпрессии пикселя (x,y), заданного блоком BC7 16 байтов.
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);
}
}
В следующем псевдокоде описаны шаги по полному декодированию цвета конечной точки и альфа-компонентов для каждого подмножества, заданного блоком BC7 16-байтов.
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);
}
В следующем псевдокоде показано, как извлекать индексы и числа битов для цветов и альфа-компонентов. Блоки с отдельным цветом и альфа также имеют два набора данных индекса: один для векторного канала и один для скалярного канала. Для режима 4 эти индексы имеют разностную ширину (2 или 3 бита), а селектор одного бита определяет, использует ли вектор или скалярные данные 3-разрядные индексы. (Извлечение числа альфа-битов аналогично извлечению числа битов цвета, но с обратным поведением на основе 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