Share via


Formato BC6H

Il formato BC6H è un formato di compressione trama progettato per supportare spazi di colore HDR (High Dynamic Range) nei dati di origine.

Informazioni su BC6H/DXGI_FORMAT_BC6H

Il formato BC6H offre una compressione di alta qualità per le immagini che usano tre canali di colore HDR, con un valore a 16 bit per ogni canale colore del valore (16:16:16). Non è disponibile alcun supporto per un canale alfa.

BC6H viene specificato dai valori di enumerazione DXGI_FORMAT seguenti:

  • DXGI_FORMAT_BC6H_TYPELESS.
  • DXGI_FORMAT_BC6H_UF16. Questo formato BC6H non usa un segno nei valori del canale a virgola mobile a 16 bit.
  • DXGI_FORMAT_BC6H_SF16. Questo formato BC6H usa un segno nei valori del canale a virgola mobile a 16 bit.

Nota

Il formato a virgola mobile a 16 bit per i canali di colore viene spesso definito formato a virgola mobile "metà". Questo formato ha il layout di bit seguente:

Formattazione Layout di bit
UF16 (float senza segno) 5 bit esponenti + 11 bit di mantissa
SF16 (float con segno) 1 bit segno + 5 bit esponenti + 10 bit mantissa

 

 

Il formato BC6H può essere usato per le risorse trama Texture2D (incluse matrici), Texture3D o TextureCube (incluse le matrici). Analogamente, questo formato si applica a qualsiasi superficie della mappa MIP associata a queste risorse.

BC6H usa una dimensione di blocco fissa di 16 byte (128 bit) e una dimensione di riquadro fissa di 4x4 texel. Come con i formati BC precedenti, le immagini di trama maggiori delle dimensioni del riquadro supportate (4x4) vengono compresse usando più blocchi. Questa identità di indirizzamento si applica anche a immagini tridimensionali, mappe MIP, mappe cubi e matrici di trame. Tutti i riquadri immagine devono essere dello stesso formato.

Alcune note importanti sul formato BC6H:

  • BC6H supporta la denormalizzazione a virgola mobile, ma non supporta INF (infinito) e NaN (non un numero). L'eccezione è la modalità con segno di BC6H (DXGI_FORMAT_BC6H_SF16), che supporta -INF (infinito negativo). Si noti che questo supporto per -INF è semplicemente un artefatto del formato stesso e non è supportato in modo specifico dai codificatori per questo formato. In generale, quando i codificatori rilevano dati di input INF (positivi o negativi) o NaN, devono \ convertire tali dati nel valore massimo consentito di rappresentazione non INF e mappare NaN a 0 prima della compressione.
  • BC6H non supporta un canale alfa.
  • Il decodificatore BC6H esegue la decompressione prima di eseguire il filtro delle trame.
  • La decompressione BC6H deve essere accurata; ovvero, l'hardware deve restituire risultati identici al decodificatore descritto in questa documentazione.

Implementazione BC6H

Un blocco BC6H è costituito da bit in modalità, endpoint compressi, indici compressi e un indice di partizione facoltativo. Questo formato specifica 14 modalità diverse.

Un colore endpoint viene archiviato come tripletta RGB. BC6H definisce una tavolozza di colori su una linea approssimativa su una serie di endpoint colore definiti. Inoltre, a seconda della modalità, un riquadro può essere diviso in due aree o considerato come una singola area, in cui un riquadro a due aree ha un set separato di endpoint colore per ogni area. BC6H archivia un indice della tavolozza per texel.

Nel caso in due aree sono presenti 32 partizioni possibili.

Decodifica del formato BC6H

Lo pseudocodice seguente mostra i passaggi per decomprimere il pixel in corrispondenza (x,y) in base al blocco BC6H a 16 byte.

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);
}

La tabella seguente contiene il numero di bit e i valori per ognuno dei 14 formati possibili per i blocchi BC6H.

Mode Indici di partizione Partizione Endpoint colore Bit modalità
1 46 bit 5 bit 75 bit (10,555, 10,555, 10,555) 2 bit (00)
2 46 bit 5 bit 75 bit (7666, 7666, 7666) 2 bit (01)
3 46 bit 5 bit 72 bit (11,555, 11,444, 11,444) 5 bit (00010)
4 46 bit 5 bit 72 bit (11,444, 11,555, 11,444) 5 bit (00110)
5 46 bit 5 bit 72 bit (11,444, 11,444, 11,555) 5 bit (01010)
6 46 bit 5 bit 72 bit (9555, 9555, 9555) 5 bit (01110)
7 46 bit 5 bit 72 bit (8666, 8555, 8555) 5 bit (10010)
8 46 bit 5 bit 72 bit (8555, 8666, 8555) 5 bit (10110)
9 46 bit 5 bit 72 bit (8555, 8555, 8666) 5 bit (11010)
10 46 bit 5 bit 72 bit (6666, 6666, 6666) 5 bit (11110)
11 63 bit 0 bit 60 bit (10.10, 10.10, 10.10) 5 bit (00011)
12 63 bit 0 bit 60 bit (11,9, 11,9, 11,9) 5 bit (00111)
13 63 bit 0 bit 60 bit (12,8, 12,8, 12,8) 5 bit (01011)
14 63 bit 0 bit 60 bit (16.4, 16.4, 16.4) 5 bit (01111)

 

Ogni formato in questa tabella può essere identificato in modo univoco dai bit della modalità. Le prime dieci modalità vengono usate per i riquadri a due aree e il campo di bit della modalità può essere lungo due o cinque bit. Questi blocchi hanno anche campi per gli endpoint colore compressi (72 o 75 bit), la partizione (5 bit) e gli indici di partizione (46 bit).

Per gli endpoint di colore compressi, i valori nella tabella precedente annotare la precisione degli endpoint RGB archiviati e il numero di bit usati per ogni valore di colore. Ad esempio, la modalità 3 specifica un livello di precisione dell'endpoint colore pari a 11 e il numero di bit usati per archiviare i valori differenziali degli endpoint trasformati per i colori rosso, blu e verde (rispettivamente 5, 4 e 4). La modalità 10 non usa la compressione differenziale e archivia in modo esplicito tutti e quattro gli endpoint colore.

Le ultime quattro modalità di blocco vengono usate per i riquadri di un'area, in cui il campo della modalità è a 5 bit. Questi blocchi hanno campi per gli endpoint (60 bit) e gli indici compressi (63 bit). La modalità 11 (ad esempio la modalità 10) non usa la compressione differenziale e archivia invece entrambi gli endpoint colore in modo esplicito.

Le modalità 10011, 10111, 11011 e 11111 (non visualizzate) sono riservate. Non usarli nel codificatore. Se l'hardware viene passato a blocchi con una di queste modalità specificate, il blocco decompresso risultante deve contenere tutti gli zeri in tutti i canali ad eccezione del canale alfa.

Per BC6H, il canale alfa deve restituire sempre 1.0 indipendentemente dalla modalità .

Set di partizioni BC6H

Esistono 32 possibili set di partizioni per un riquadro a due aree e definiti nella tabella seguente. Ogni blocco 4x4 rappresenta una singola forma.

table of bc6h partition sets

In questa tabella di set di partizioni, la voce grassetto e sottolineata è la posizione dell'indice di correzione per subset 1 (specificato con un bit minore). L'indice di correzione per il subset 0 è sempre indice 0, perché il partizionamento viene sempre disposto in modo che l'indice 0 sia sempre nel subset 0. L'ordine di partizione passa dall'alto a sinistra verso il basso a destra, spostandosi da sinistra a destra e quindi dall'alto verso il basso.

Formato endpoint compresso BC6H

bit fields for bc6h compressed endpoint formats

Questa tabella mostra i campi di bit per gli endpoint compressi come funzione del formato dell'endpoint, con ogni colonna che specifica una codifica e ogni riga che specifica un campo di bit. Questo approccio richiede 82 bit per i riquadri a due aree e 65 bit per i riquadri a un'area. Ad esempio, i primi 5 bit per la codifica un'area [16 4] sopra (in particolare la colonna più a destra) sono bit m[4:0], i 10 bit successivi sono bit rw[9:0]e così via con gli ultimi 6 bit contenenti bw[10:15].

I nomi dei campi nella tabella precedente sono definiti come segue:

Campo Variabile
m mode
g indice 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]
by endpt[1]. A[2]
Bz endpt[1]. B[2]

 

Endpt[i], dove i è 0 o 1, si riferisce rispettivamente al set di endpoint 0 o 1.

Firmare l'estensione per i valori degli endpoint

Per i riquadri a due aree sono disponibili quattro valori di endpoint che possono essere firmati estesi. Endpt[0]. Un oggetto è firmato solo se il formato è un formato firmato; gli altri endpoint vengono firmati solo se l'endpoint è stato trasformato o se il formato è firmato. Il codice seguente illustra l'algoritmo per estendere il segno dei valori dell'endpoint a due aree.

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]);
      }
    }
}

Per i riquadri di un'area, il comportamento è identico, solo con endpt[1] rimosso.

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]);
    }
}

Trasformare l'inversione per i valori dell'endpoint

Per i riquadri a due aree, la trasformazione applica l'inverso della codifica delle differenze, aggiungendo il valore di base alla finept[0]. Oggetto alle tre altre voci per un totale di 9 operazioni di aggiunta. Nell'immagine seguente il valore di base è rappresentato come "A0" e ha la precisione a virgola mobile più alta. "A1", "B0" e "B1" sono tutti delta calcolati dal valore di ancoraggio e questi valori delta sono rappresentati con precisione inferiore. (A0 corrisponde a endpt[0]. A, B0 corrisponde a endpt[0]. B, A1 corrisponde a endpt[1]. A e B1 corrisponde a endpt[1].B.)

calculation of transform inversion endpoint values

Per i riquadri di una sola area è presente un solo offset differenziale e quindi solo 3 operazioni di aggiunta.

Il decompressore deve garantire che i risultati della trasformazione inversa non esondano la precisione di endpt[0].a. Nel caso di un overflow, i valori risultanti dalla trasformazione inversa devono eseguire il wrapping all'interno dello stesso numero di bit. Se la precisione di A0 è "p", l'algoritmo di trasformazione è:

B0 = (B0 + A0) & ((1 << p) - 1)

Per i formati firmati, anche i risultati del calcolo differenziale devono essere firmati estesi. Se l'operazione di estensione del segno considera l'estensione di entrambi i segni, dove 0 è positivo e 1 è negativo, l'estensione del segno 0 si occupa del blocco precedente. Analogamente, dopo il blocco precedente, deve essere esteso solo un valore pari a 1 (negativo).

Unquantization of Color Endpoints

Dato gli endpoint non compressi, il passaggio successivo consiste nell'eseguire una squantizzazione iniziale degli endpoint colore. Questa operazione comporta tre passaggi:

  • Un'inquantizzazione delle tavolozze dei colori
  • Interpolazione delle tavolozze
  • Finalizzazione di unquantization

La separazione del processo di squantizzazione in due parti (annullamento della tavolozza dei colori prima dell'interpolazione e dell'annullamento finale dopo l'interpolazione) riduce il numero di operazioni di moltiplicazione necessarie rispetto a un processo di squantizzazione completo prima dell'interpolazione della tavolozza.

Il codice seguente illustra il processo di recupero delle stime dei valori di colore a 16 bit originali e quindi usa i valori di peso forniti per aggiungere 6 valori di colore aggiuntivi alla tavolozza. La stessa operazione viene eseguita su ogni canale.

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);
}

L'esempio di codice successivo illustra il processo di interpolazione, con le osservazioni seguenti:

  • Poiché l'intervallo completo di valori di colore per la funzione non quantificata (sotto) è compreso tra -32768 e 65535, l'interpolatore viene implementato usando l'aritmetica con segno a 17 bit.
  • Dopo l'interpolazione, i valori vengono passati alla funzione finish_unquantize (descritta nel terzo esempio in questa sezione), che applica il ridimensionamento finale.
  • Tutti i decompressori hardware sono necessari per restituire risultati accurati a bit con queste funzioni.
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 viene chiamato dopo l'interpolazione della tavolozza. La funzione di quantize posticipa il ridimensionamento di 31/32 per signed, 31/64 per unsigned. Questo comportamento è necessario per ottenere il valore finale in un intervallo di metà valido (-0x7BFF ~ 0x7BFF) dopo il completamento dell'interpolazione della tavolozza per ridurre il numero di moltiplicazioni necessarie. finish_unquantize applica il ridimensionamento finale e restituisce un valore breve senza segno che viene reinterpretato in metà.

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);
    }
}

Compressione del blocco trama in Direct3D 11