Формат BC6H
Формат BC6H — это формат сжатия текстур, предназначенный для поддержки цветовых пространств с высоким динамическим диапазоном (HDR) в исходных данных.
- Сведения о BC6H/DXGI_FORMAT_BC6H
- Реализация BC6H
- Декодирование формата BC6H
- Формат сжатой конечной точки BC6H
- Расширение подписи для значений конечных точек
- Преобразование инверсии для значений конечных точек
- Некванизация цветных конечных точек
- Связанные статьи
Сведения о BC6H/DXGI_FORMAT_BC6H
Формат BC6H обеспечивает высокое качество сжатия изображений, использующих три канала цветов HDR, с 16-разрядным значением для каждого цветового канала значения (16:16:16). Нет поддержки альфа-канала.
BC6H указывается следующими значениями перечисления DXGI_FORMAT:
- DXGI_FORMAT_BC6H_TYPELESS.
- DXGI_FORMAT_BC6H_UF16. Этот формат BC6H не использует бит знака в 16-разрядных значениях цветового канала с плавающей запятой.
- DXGI_FORMAT_BC6H_SF16. В этом формате BC6H используется бит знака в 16-разрядных значениях цветового канала с плавающей запятой.
Примечание.
16-разрядный формат с плавающей запятой для цветового канала часто называется "половина" плавающей запятой. Этот формат имеет следующий битовый макет:
Форматировать | Макет бита |
---|---|
UF16 (без знака float) | 5 экспонентных бит + 11 мантисса бит |
SF16 (подписанный с плавающей запятой) | 1 знак бит + 5 экспонентных бит + 10 мантисса бит |
Формат BC6H можно использовать для текстур Текстур2D (включая массивы), Текстур3D или текстуры (включая массивы). Аналогичным образом этот формат применяется к любым поверхностям карты MIP, связанным с этими ресурсами.
BC6H использует фиксированный размер блока 16 байт (128 бит) и фиксированный размер плитки 4x4 texels. Как и в предыдущих форматах BC, изображения текстур больше поддерживаемого размера плитки (4x4) сжимаются с помощью нескольких блоков. Это удостоверение адресации применяется также к трехмерным изображениям, картам MIP, кубам и массивам текстур. Все плитки изображения должны иметь одинаковый формат.
Некоторые важные заметки о формате BC6H:
- BC6H поддерживает денормализацию с плавающей запятой, но не поддерживает INF (бесконечность) и NaN (не число). Исключением является подписанный режим BC6H (DXGI_FORMAT_BC6H_SF16), который поддерживает -INF (отрицательное бесконечность). Обратите внимание, что эта поддержка -INF является лишь артефактом самого формата и не поддерживается кодировщиками этого формата. Как правило, если кодировщики сталкиваются с INF (положительными или отрицательными) или входными данными NaN, они должны \ преобразовывать эти данные в максимально допустимое значение представления, отличное от INF, и сопоставлять NaN с 0 до сжатия.
- BC6H не поддерживает альфа-канал.
- Декодатор BC6H выполняет декомпрессию перед выполнением фильтрации текстур.
- Декомпрессия BC6H должна быть точной; То есть оборудование должно возвращать результаты, идентичные декодатору, описанному в этой документации.
Реализация BC6H
Блок BC6H состоит из битов режима, сжатых конечных точек, сжатых индексов и необязательного индекса секции. Этот формат задает 14 различных режимов.
Цвет конечной точки хранится в виде триплета RGB. BC6H определяет палитру цветов на приблизительной линии в ряде определенных конечных точек цвета. Кроме того, в зависимости от режима плитку можно разделить на два региона или рассматриваться как один регион, где плитка с двумя регионами имеет отдельный набор цветовых конечных точек для каждого региона. BC6H хранит один индекс палитры на тексель.
В двух регионе существует 32 возможных секций.
Декодирование формата BC6H
В приведенном ниже псевдокоде показаны шаги для распаковки пикселя (x,y), заданного блоком BC6H 16 байтов.
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);
}
В следующей таблице содержатся число битов и значения для каждого из 14 возможных форматов для блоков BC6H.
Режим | Индексы секций | Секция | Цветные конечные точки | Биты режима |
---|---|---|---|---|
1 | 46 бит | 5 битов | 75 бит (10.555, 10.555, 10.555) | 2 бита (00) |
2 | 46 бит | 5 битов | 75 бит (7666, 7666, 7666) | 2 бита (01) |
3 | 46 бит | 5 битов | 72 бита (11.555, 11.444, 11.444) | 5 бит (00010) |
4 | 46 бит | 5 битов | 72 бита (11.444, 11.555, 11.444) | 5 бит (00110) |
5 | 46 бит | 5 битов | 72 бита (11.444, 11.444, 11.555) | 5 бит (01010) |
6 | 46 бит | 5 битов | 72 бита (9555, 9555, 9555) | 5 бит (01110) |
7 | 46 бит | 5 битов | 72 бита (8666, 8555, 8555) | 5 бит (10010) |
8 | 46 бит | 5 битов | 72 бита (8555, 8666, 8555) | 5 бит (10110) |
9 | 46 бит | 5 битов | 72 бита (8555, 8555, 8666) | 5 бит (11010) |
10 | 46 бит | 5 битов | 72 бита (6666, 6666, 6666) | 5 бит (11110) |
11 | 63 бита | 0 битов | 60 бит (10.10, 10.10, 10.10) | 5 бит (00011) |
12 | 63 бита | 0 битов | 60 бит (11.9, 11.9, 11.9) | 5 бит (00111) |
13 | 63 бита | 0 битов | 60 бит (12.8, 12.8, 12.8) | 5 бит (01011) |
14 | 63 бита | 0 битов | 60 бит (16.4, 16.4, 16.4) | 5 бит (01111) |
Каждый формат в этой таблице можно однозначно определить по битам режима. Первые десять режимов используются для двухрегионных плиток, а битовое поле режима может иметь длину двух или пяти битов. Эти блоки также имеют поля для сжатых конечных точек цвета (72 или 75 битов), секции (5 битов) и индексов секций (46 бит).
Для сжатых конечных точек цвета значения в предыдущей таблице отмечают точность сохраненных конечных точек RGB и количество битов, используемых для каждого значения цвета. Например, в режиме 3 указывается уровень точности цветовой конечной точки 11 и количество битов, используемых для хранения разностных значений преобразованных конечных точек для красных, голубых и зеленых цветов (5, 4 и 4 соответственно). Режим 10 не использует разностное сжатие и вместо этого сохраняет все четыре цветные конечные точки явным образом.
Последние четыре режима блока используются для плиток в одном регионе, где поле режима составляет 5 битов. Эти блоки имеют поля для конечных точек (60 бит) и сжатых индексов (63 бита). Режим 11 (например, режим 10) не использует разностное сжатие, а вместо этого сохраняет оба цвета конечных точек явным образом.
Зарезервированы режимы 10011, 1011, 11011 и 11111 (не показаны). Не используйте их в кодировщике. Если оборудование передается блоками с одним из указанных режимов, результирующий декомпрессованный блок должен содержать все нули во всех каналах, кроме альфа-канала.
Для BC6H альфа-канал должен всегда возвращать значение 1.0 независимо от режима.
Набор секций BC6H
Существует 32 возможных наборов секций для двухрегионной плитки, и которые определены в таблице ниже. Каждый блок 4x4 представляет одну фигуру.
В этой таблице наборов секций полужирная и подчеркнутая запись — это расположение индекса исправления для подмножества 1 (которое указывается с одним менее битом). Индекс исправления для подмножества 0 всегда равен индексу 0, так как секционирование всегда упорядочивается таким образом, что индекс 0 всегда находится в подмножестве 0. Порядок секций идет от верхнего левого до нижнего справа, перемещаясь слева направо, а затем сверху вниз.
Формат сжатой конечной точки BC6H
В этой таблице показаны битовые поля для сжатых конечных точек в качестве функции формата конечной точки с каждым столбцом, указывающим кодировку и каждую строку, указывающую битовое поле. Этот подход занимает 82 бита для двухрегионных плиток и 65 битов для плиток в одном регионе. Например, первые 5 битов для кодировки одного региона [16 4] выше (в частности правый столбец) являются битами m[4:0], следующие 10 битов rw[9:0], и т. д. с последними 6 битами, содержащими bw[10:15].
Имена полей в таблице выше определены следующим образом:
Поле | Переменная |
---|---|
m | mode |
дн. | Индекс фигуры |
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] |
by | endpt[1]. A[2] |
Bz | endpt[1]. B[2] |
Endpt[i], где имеет значение 0 или 1, относится к 0-му или 1-му набору конечных точек соответственно.
Расширение подписи для значений конечных точек
Для двухрегионных плиток существует четыре значения конечных точек, которые могут быть подписаны расширенными. Endpt[0]. Подпись подписывается только в том случае, если формат подписывается; Другие конечные точки подписываются только в том случае, если конечная точка была преобразована или формат подписывается. Приведенный ниже код демонстрирует алгоритм расширения знака значений двухрегионной конечной точки.
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]);
}
}
}
Для плиток в одном регионе поведение совпадает только с удалением 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]);
}
}
Преобразование инверсии для значений конечных точек
Для двухрегиональных плиток преобразование применяет обратное кодировку разницы, добавив базовое значение в концеpt[0]. А до трех других записей для общей сложности 9 операций добавления. На рисунке ниже базовое значение представлено как "A0" и имеет самую высокую точность с плавающей запятой. "A1", "B0" и "B1" являются всеми разностями, вычисляемыми из значения привязки, и эти разностные значения представлены с меньшей точностью. (A0 соответствует endpt[0]. A, B0 соответствует endpt[0]. B, A1 соответствует endpt[1]. A и B1 соответствуют endpt[1].B.)
Для плиток в одном регионе существует только одно разностное смещение, поэтому только 3 операции добавления.
Декомпрессор должен гарантировать, что результаты обратного преобразования не будут переполнены точностью endpt[0].a. В случае переполнения значения, полученные из обратного преобразования, должны быть упаковываются в одно и то же количество битов. Если точность A0 равна "p" битам, то алгоритм преобразования:
B0 = (B0 + A0) & ((1 << p) - 1)
Для подписанных форматов результаты вычисления разностного значения также должны быть подписаны. Если операция расширения знака рассматривает расширение обоих признаков, где 0 является положительным и 1 отрицательным, то расширение знака 0 заботится о зажатой выше. Аналогично, после приведенного выше зажима только значение 1 (отрицательное) должно быть продлено.
Некванизация цветных конечных точек
Учитывая несжатые конечные точки, следующим шагом является выполнение первоначальной некванизации конечных точек цвета. Этот процесс состоит из трех этапов.
- Некванизация цветовой палитры
- Интерполяция палитр
- Отмена финализации
Разделение процесса unquantization на две части (цветовая палитра неquantization до интерполяции и окончательной неквалантизации после интерполяции) уменьшает количество операций умножения, необходимых при сравнении с полным процессом некванизации перед интерполяцией палитры.
Приведенный ниже код иллюстрирует процесс получения оценок исходных 16-разрядных значений цвета, а затем с помощью предоставленных значений веса для добавления в палитру 6 дополнительных значений цвета. Одна и та же операция выполняется на каждом канале.
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);
}
Следующий пример кода демонстрирует процесс интерполяции со следующими наблюдениями:
- Так как полный диапазон значений цвета для неквантизируемой функции (ниже) составляет от -32768 до 65535, интерполятор реализуется с помощью 17-разрядной арифметики со знаком.
- После интерполяции значения передаются в функцию finish_unquantize (описанную в третьем примере в этом разделе), которая применяет окончательное масштабирование.
- Все аппаратные декомпрессоры должны возвращать точные результаты с этими функциями.
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 вызывается после интерполяции палитры. Функция без знака откладывает масштабирование на 31/32 для подписи, 31/64. Это поведение необходимо для получения окончательного значения в допустимый диапазон половины (-0x7BFF ~ 0x7BFF) после завершения интерполяции палитры, чтобы уменьшить количество необходимых умножений. finish_unquantize применяет окончательное масштабирование и возвращает без знака короткое значение, которое повторно интерпретируется на половину.
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);
}
}
См. также