Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O formato BC6H é um formato de compressão de textura projetado para suportar espaços de cores HDR (High Dynamic Range) em dados de origem.
- Sobre BC6H/DXGI_FORMAT_BC6H
- de implementação do BC6H
- Decodificando o formato BC6H
- Formato de ponto final comprimido BC6H
- Extensão de sinal de para valores de ponto de extremidade
- Transformar inversão para valores de ponto de extremidade
- Desquantização de pontos de extremidade de cor
- Tópicos relacionados
Sobre BC6H/DXGI_FORMAT_BC6H
O formato BC6H fornece compressão de alta qualidade para imagens que usam três canais de cores HDR, com um valor de 16 bits para cada canal de cor do valor (16:16:16). Não há suporte para um canal alfa.
BC6H é especificado pelos seguintes valores de enumeração DXGI_FORMAT:
- DXGI_FORMAT_BC6H_TYPELESS.
- DXGI_FORMAT_BC6H_UF16. Este formato BC6H não usa um bit de sinal nos valores do canal de cor de ponto flutuante de 16 bits.
- DXGI_FORMAT_BC6H_SF16. Este formato BC6H usa um bit de sinal nos valores do canal de cor de ponto flutuante de 16 bits.
Observação
O formato de ponto flutuante de 16 bits para canais de cores é muitas vezes referido como um formato de ponto flutuante "metade". Este formato tem o seguinte layout de bits:
| Formato | Layout de bits |
|---|---|
| UF16 (flutuador não assinado) | 5 bits expoentes + 11 bits mantissa |
| SF16 (flutuador assinado) | 1 bit de sinal + 5 bits expoentes + 10 bits mantissa |
O formato BC6H pode ser usado para recursos de textura Texture2D (incluindo matrizes), Texture3D ou TextureCube (incluindo matrizes). Da mesma forma, esse formato se aplica a qualquer superfície de mapa MIP associada a esses recursos.
BC6H usa um tamanho de bloco fixo de 16 bytes (128 bits) e um tamanho de bloco fixo de 4x4 texels. Tal como nos formatos BC anteriores, as imagens de textura maiores do que o tamanho de mosaico suportado (4x4) são comprimidas utilizando vários blocos. Essa identidade de endereçamento também se aplica a imagens tridimensionais, mapas MIP, cubemaps e matrizes de textura. Todos os blocos de imagem devem ter o mesmo formato.
Algumas notas importantes sobre o formato BC6H:
- BC6H suporta desnormalização de ponto flutuante, mas não suporta INF (infinito) e NaN (não um número). A exceção é o modo assinado de BC6H (DXGI_FORMAT_BC6H_SF16), que suporta -INF (infinito negativo). Observe que esse suporte para -INF é meramente um artefato do próprio formato e não é especificamente suportado por codificadores para esse formato. Em geral, quando os codificadores encontram dados de entrada INF (positivos ou negativos) ou NaN, eles devem \ converter esses dados para o valor máximo permitido de representação não-INF e mapear NaN para 0 antes da compactação.
- BC6H não suporta um canal alfa.
- O descodificador BC6H executa a descompressão antes de efetuar a filtragem de textura.
- A descompressão BC6H deve ser precisa de bits; ou seja, o hardware deve retornar resultados idênticos ao decodificador descrito nesta documentação.
Implementação BC6H
Um bloco BC6H consiste em bits de modo, pontos de extremidade compactados, índices compactados e um índice de partição opcional. Este formato especifica 14 modos diferentes.
Uma cor de ponto de extremidade é armazenada como um trio RGB. BC6H define uma paleta de cores em uma linha aproximada através de vários pontos de extremidade de cor definidos. Além disso, dependendo do modo, um bloco pode ser dividido em duas regiões ou tratado como uma única região, onde um bloco de duas regiões tem um conjunto separado de pontos de extremidade de cor para cada região. BC6H armazena um índice de paleta por texel.
No caso das duas regiões, há 32 partições possíveis.
Decodificando o formato BC6H
O pseudocódigo abaixo mostra as etapas para descompactar o pixel em (x,y) dado o bloco BC6H de 16 bytes.
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);
}
A tabela a seguir contém a contagem de bits e os valores para cada um dos 14 formatos possíveis para blocos BC6H.
| Modo | Índices de partição | Partição | Pontos finais de cor | Modo Bits |
|---|---|---|---|---|
| 1 | 46 bits | 5 bits | 75 bits (10.555, 10.555, 10.555) | 2 bits (00) |
| 2 | 46 bits | 5 bits | 75 bits (7666, 7666, 7666) | 2 bits (01) |
| 3 | 46 bits | 5 bits | 72 bits (11.555, 11.444, 11.444) | 5 bits (00010) |
| 4 | 46 bits | 5 bits | 72 bits (11.444, 11.555, 11.444) | 5 bits (00110) |
| 5 | 46 bits | 5 bits | 72 bits (11.444, 11.444, 11.555) | 5 bits (01010) |
| 6 | 46 bits | 5 bits | 72 bits (9555, 9555, 9555) | 5 bits (01110) |
| 7 | 46 bits | 5 bits | 72 bits (8666, 8555, 8555) | 5 bits (10010) |
| 8 | 46 bits | 5 bits | 72 bits (8555, 8666, 8555) | 5 bits (10110) |
| 9 | 46 bits | 5 bits | 72 bits (8555, 8555, 8666) | 5 bits (11010) |
| 10 | 46 bits | 5 bits | 72 bits (6666, 6666, 6666) | 5 bits (11110) |
| 11 | 63 bits | 0 bits | 60 bits (10.10, 10.10, 10.10) | 5 bits (00011) |
| 12 | 63 bits | 0 bits | 60 bits (11,9, 11,9, 11,9) | 5 bits (00111) |
| 13 | 63 bits | 0 bits | 60 bits (12,8, 12,8, 12,8) | 5 bits (01011) |
| 14 | 63 bits | 0 bits | 60 bits (16,4, 16,4, 16,4) | 5 bits (01111) |
Cada formato nesta tabela pode ser identificado exclusivamente pelos bits de modo. Os primeiros dez modos são usados para blocos de duas regiões, e o campo de bit do modo pode ter dois ou cinco bits de comprimento. Esses blocos também têm campos para os pontos finais de cor compactados (72 ou 75 bits), a partição (5 bits) e os índices de partição (46 bits).
Para os pontos de extremidade de cor compactados, os valores na tabela anterior observam a precisão dos pontos de extremidade RGB armazenados e o número de bits usados para cada valor de cor. Por exemplo, o modo 3 especifica um nível de precisão de ponto final de cor de 11 e o número de bits usados para armazenar os valores delta dos pontos de extremidade transformados para as cores vermelho, azul e verde (5, 4 e 4, respectivamente). O modo 10 não usa compactação delta e, em vez disso, armazena todos os quatro pontos de extremidade de cor explicitamente.
Os últimos quatro modos de bloco são usados para blocos de uma região, onde o campo de modo é de 5 bits. Estes blocos têm campos para os pontos finais (60 bits) e os índices comprimidos (63 bits). O Modo 11 (como o Modo 10) não usa compactação delta e, em vez disso, armazena ambos os pontos de extremidade de cor explicitamente.
Os modos 10011, 10111, 11011 e 11111 (não mostrados) são reservados. Não os utilize no codificador. Se o hardware é passado blocos com um desses modos especificados, o bloco descompactado resultante deve conter todos os zeros em todos os canais, exceto para o canal alfa.
Para BC6H, o canal alfa deve sempre retornar 1.0, independentemente do modo.
Conjunto de partições BC6H
Há 32 conjuntos de partições possíveis para um bloco de duas regiões e que são definidos na tabela abaixo. Cada bloco 4x4 representa uma única forma.
Nesta tabela de conjuntos de partições, a entrada em negrito e sublinhada é o local do índice de correção para o subconjunto 1 (que é especificado com um bit a menos). O índice de correção para o subconjunto 0 é sempre o índice 0, pois o particionamento é sempre organizado de tal forma que o índice 0 está sempre no subconjunto 0. A ordem da partição vai de cima para a esquerda para baixo-direita, movendo-se da esquerda para a direita e, em seguida, de cima para baixo.
Formato de ponto final comprimido BC6H
Campos de 
Esta tabela mostra os campos de bits para os pontos de extremidade compactados em função do formato do ponto final, com cada coluna especificando uma codificação e cada linha especificando um campo de bits. Essa abordagem ocupa 82 bits para blocos de duas regiões e 65 bits para blocos de uma região. Como exemplo, os primeiros 5 bits para a codificação de uma região [16 4] acima (especificamente a coluna mais à direita) são bits m[4:0], os próximos 10 bits são bits rw[9:0], e assim por diante com os últimos 6 bits contendo bw[10:15].
Os nomes dos campos na tabela acima são definidos da seguinte forma:
| Domínio | Variável |
|---|---|
| m | modo |
| d | índice de forma |
| 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] |
| por | ENDPT[1]. A[2] |
| BZ | ENDPT[1]. B[2] |
Endpt[i], onde i é 0 ou 1, refere-se ao 0º ou 1º conjunto de parâmetros, respetivamente.
Extensão de sinal para valores de ponto final
Para blocos de duas regiões, há quatro valores de ponto de extremidade que podem ser assinados estendidos. Fim[0]. A é assinado somente se o formato for um formato assinado; Os outros pontos de extremidade são assinados somente se o ponto de extremidade foi transformado ou se o formato for um formato assinado. O código abaixo demonstra o algoritmo para estender o sinal de valores de ponto de extremidade de duas regiões.
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]);
}
}
}
Para blocos de uma região, o comportamento é o mesmo, apenas com endpt[1] removido.
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]);
}
}
Transformar inversão para valores de ponto de extremidade
Para blocos de duas regiões, a transformação aplica o inverso da codificação de diferença, adicionando o valor base em endpt[0]. A às outras três entradas para um total de 9 operações de som. Na imagem abaixo, o valor base é representado como "A0" e tem a maior precisão de ponto flutuante. "A1", "B0" e "B1" são todos deltas calculados a partir do valor da âncora, e esses valores delta são representados com menor precisão. (A0 corresponde a endpt[0]. A, B0 corresponde a endpt[0]. B, A1 corresponde a endpt[1]. A, e B1 corresponde a endpt[1].B.)
Para blocos de uma região, há apenas um deslocamento delta e, portanto, apenas 3 operações de adição.
O descompressor deve assegurar que os resultados da transformação inversa não transbordam a precisão da extremidade[0].a. No caso de um estouro, os valores resultantes da transformação inversa devem ser encapsulados dentro do mesmo número de bits. Se a precisão de A0 é "p" bits, então o algoritmo de transformação é:
B0 = (B0 + A0) & ((1 << p) - 1)
Para formatos assinados, os resultados do cálculo do delta também devem ser estendidos por sinal. Se a operação de extensão do sinal considerar estender ambos os sinais, onde 0 é positivo e 1 é negativo, então a extensão do sinal de 0 cuida do grampo acima. Equivalentemente, após o grampo acima, apenas um valor de 1 (negativo) precisa ser sinal estendido.
Unquantização de pontos de extremidade de cor
Dado os pontos de extremidade não compactados, a próxima etapa é executar uma desquantização inicial dos pontos de extremidade de cor. Isto envolve três etapas:
- Uma desquantização das paletas de cores
- Interpolação das paletas
- Finalização da não quantização
Separar o processo de desquantização em duas partes (desquantização da paleta de cores antes da interpolação e desquantização final após a interpolação) reduz o número de operações de multiplicação necessárias quando comparado a um processo de desquantização completo antes da interpolação da paleta.
O código abaixo ilustra o processo para recuperar estimativas dos valores de cor originais de 16 bits e, em seguida, usar os valores de peso fornecidos para adicionar 6 valores de cor adicionais à paleta. A mesma operação é realizada em cada canal.
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);
}
O próximo exemplo de código demonstra o processo de interpolação, com as seguintes observações:
- Como a faixa completa de valores de cor para a função unquantize (abaixo) é de -32768 a 65535, o interpolador é implementado usando aritmética assinada de 17 bits.
- Após a interpolação, os valores são passados para a função finish_unquantize (descrita na terceira amostra desta seção), que aplica o dimensionamento final.
- Todos os descompressores de hardware são necessários para retornar resultados com precisão de bits com essas funções.
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 é chamado após a interpolação da paleta. O unquantize função adia o dimensionamento em 31/32 para assinado, 31/64 para não assinado. Esse comportamento é necessário para obter o valor final em metade do intervalo válido(-0x7BFF ~ 0x7BFF) após a interpolação da paleta ser concluída, a fim de reduzir o número de multiplicações necessárias. finish_unquantize aplica o dimensionamento final e retorna um valor de curto não assinado que é reinterpretado em metade.
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);
}
}
Tópicos relacionados
-
Compressão de blocos de textura no Direct3D 11