BC6H Format

Format BC6H adalah format kompresi tekstur yang dirancang untuk mendukung ruang warna rentang dinamis tinggi (HDR) dalam data sumber.

Tentang BC6H/DXGI_FORMAT_BC6H

Format BC6H menyediakan kompresi berkualitas tinggi untuk gambar yang menggunakan tiga saluran warna HDR, dengan nilai 16-bit untuk setiap saluran warna nilai (16:16:16). Tidak ada dukungan untuk saluran alfa.

BC6H ditentukan oleh nilai enumerasi DXGI_FORMAT berikut:

  • DXGI_FORMAT_BC6H_TYPELESS.
  • DXGI_FORMAT_BC6H_UF16. Format BC6H ini tidak menggunakan bit tanda dalam nilai saluran warna titik mengambang 16-bit.
  • DXGI_FORMAT_BC6H_SF16. Format BC6H ini menggunakan sign bit dalam nilai saluran warna titik mengambang 16-bit.

Catatan

Format titik mengambang 16 bit untuk saluran warna sering disebut sebagai format titik mengambang "setengah". Format ini memiliki tata letak bit berikut:

Format Tata letak bit
UF16 (float tidak ditandatangani) 5 bit eksponen + 11 bit mantissa
SF16 (float bertanda tangan) 1 bit tanda + 5 bit eksponen + 10 bit mantissa

 

 

Format BC6H dapat digunakan untuk sumber daya tekstur Texture2D (termasuk array), Texture3D, atau TextureCube (termasuk array). Demikian pula, format ini berlaku untuk permukaan peta MIP apa pun yang terkait dengan sumber daya ini.

BC6H menggunakan ukuran blok tetap 16 byte (128 bit) dan ukuran petak tetap 4x4 texel. Seperti format SM sebelumnya, gambar tekstur yang lebih besar dari ukuran petak peta yang didukung (4x4) dikompresi dengan menggunakan beberapa blok. Identitas alamat ini juga berlaku untuk gambar tiga dimensi, peta MIP, peta kubus, dan array tekstur. Semua petak peta gambar harus dalam format yang sama.

Beberapa catatan penting tentang format BC6H:

  • BC6H mendukung denormalisasi floating point, tetapi tidak mendukung INF (infinity) dan NaN (bukan angka). Pengecualian adalah mode BC6H yang ditandatangani (DXGI_FORMAT_BC6H_SF16), yang mendukung -INF (tak terbatas negatif). Perhatikan bahwa dukungan untuk -INF ini hanyalah artefak dari format itu sendiri, dan tidak didukung secara khusus oleh encoder untuk format ini. Secara umum, ketika encoder menemukan inf (positif atau negatif) atau data input NaN, mereka harus \ mengonversi data tersebut ke nilai representasi non-INF maksimum yang diizinkan, dan memetakan NaN ke 0 sebelum pemadatan.
  • BC6H tidak mendukung saluran alfa.
  • Dekoder BC6H melakukan dekompresi sebelum melakukan pemfilteran tekstur.
  • Dekompresi BC6H harus sedikit akurat; artinya, perangkat keras harus mengembalikan hasil yang identik dengan dekoder yang dijelaskan dalam dokumentasi ini.

Implementasi BC6H

Blok BC6H terdiri dari bit mode, titik akhir terkompresi, indeks terkompresi, dan indeks partisi opsional. Format ini menentukan 14 mode berbeda.

Warna titik akhir disimpan sebagai triplet RGB. BC6H mendefinisikan palet warna pada garis perkiraan di sejumlah titik akhir warna yang ditentukan. Selain itu, tergantung pada mode, petak peta dapat dibagi menjadi dua wilayah atau diperlakukan sebagai satu wilayah, di mana petak peta dua wilayah memiliki sekumpulan titik akhir warna terpisah untuk setiap wilayah. BC6H menyimpan satu indeks palet per texel.

Dalam kasus dua wilayah, ada 32 partisi yang mungkin.

Mendekode Format BC6H

Pseudocode di bawah ini menunjukkan langkah-langkah untuk mendekompresi piksel pada (x,y) mengingat blok 16 byte BC6H.

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

Tabel berikut berisi jumlah bit dan nilai untuk masing-masing dari 14 format yang mungkin untuk blok BC6H.

Mode Indeks Partisi Partisi Titik Akhir Warna Bit Mode
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)

 

Setiap format dalam tabel ini dapat diidentifikasi secara unik oleh bit mode. Sepuluh mode pertama digunakan untuk petak peta dua wilayah, dan bidang bit mode dapat memiliki panjang dua atau lima bit. Blok ini juga memiliki bidang untuk titik akhir warna terkompresi (72 atau 75 bit), partisi (5 bit), dan indeks partisi (46 bit).

Untuk titik akhir warna terkompresi, nilai dalam tabel sebelumnya mencatat presisi titik akhir RGB yang disimpan, dan jumlah bit yang digunakan untuk setiap nilai warna. Misalnya, mode 3 menentukan tingkat presisi titik akhir warna 11, dan jumlah bit yang digunakan untuk menyimpan nilai delta titik akhir yang diubah untuk warna merah, biru, dan hijau (masing-masing 5, 4, dan 4). Mode 10 tidak menggunakan kompresi delta, dan sebaliknya menyimpan keempat titik akhir warna secara eksplisit.

Empat mode blok terakhir digunakan untuk petak peta satu wilayah, di mana bidang mode adalah 5 bit. Blok ini memiliki bidang untuk titik akhir (60 bit) dan indeks terkompresi (63 bit). Mode 11 (seperti Mode 10) tidak menggunakan kompresi delta, dan sebaliknya menyimpan kedua titik akhir warna secara eksplisit.

Mode 10011, 10111, 11011, dan 11111 (tidak ditampilkan) dicadangkan. Jangan gunakan ini di encoder Anda. Jika perangkat keras diteruskan memblokir dengan salah satu mode ini yang ditentukan, blok yang didekompresi yang dihasilkan harus berisi semua nol di semua saluran kecuali untuk saluran alfa.

Untuk BC6H, saluran alfa harus selalu mengembalikan 1,0 terlepas dari modenya.

Set Partisi BC6H

Ada 32 set partisi yang mungkin untuk petak peta dua wilayah, dan yang ditentukan dalam tabel di bawah ini. Setiap blok 4x4 mewakili satu bentuk.

table of bc6h partition sets

Dalam tabel set partisi ini, entri tebal dan bergaris bawah adalah lokasi indeks perbaikan untuk subset 1 (yang ditentukan dengan satu bit lebih sedikit). Indeks perbaikan untuk subset 0 selalu diindeks 0, karena partisi selalu diatur sedemikian sehingga indeks 0 selalu berada di subset 0. Urutan partisi berubah dari kiri atas ke kanan bawah, bergerak kiri ke kanan lalu atas ke bawah.

Format Titik Akhir Terkompresi BC6H

bit fields for bc6h compressed endpoint formats

Tabel ini memperlihatkan bidang bit untuk titik akhir terkompresi sebagai fungsi format titik akhir, dengan setiap kolom menentukan pengodean dan setiap baris yang menentukan bidang bit. Pendekatan ini membutuhkan 82 bit untuk petak peta dua wilayah dan 65 bit untuk petak peta satu wilayah. Sebagai contoh, 5 bit pertama untuk pengodean satu wilayah [16 4] di atas (khususnya kolom paling kanan) adalah bit m[4:0], 10 bit berikutnya adalah bit rw[9:0], dan sebagainya dengan 6 bit terakhir yang berisi bw[10:15].

Nama bidang dalam tabel di atas didefinisikan sebagai berikut:

Bidang Variabel
m mode
d indeks bentuk
Rw endpt[0]. A[0]
Rx endpt[0]. B[0]
Ry berakhir[1]. A[0]
Rz berakhir[1]. B[0]
gw endpt[0]. A[1]
Gx endpt[0]. B[1]
Gy berakhir[1]. A[1]
Gz berakhir[1]. B[1]
Bw endpt[0]. A[2]
Bx endpt[0]. B[2]
oleh berakhir[1]. A[2]
Bz berakhir[1]. B[2]

 

Endpt[i], di mana saya adalah 0 atau 1, masing-masing mengacu pada set titik akhir ke-0 atau ke-1.

Tanda tangani Ekstensi untuk Nilai Titik Akhir

Untuk petak peta dua wilayah, ada empat nilai titik akhir yang dapat ditandatangani diperluas. Berakhir[0]. ditandatangani hanya jika formatnya adalah format bertanda tangan; titik akhir lainnya ditandatangani hanya jika titik akhir diubah, atau jika formatnya adalah format yang ditandatangani. Kode di bawah ini menunjukkan algoritma untuk memperluas tanda nilai titik akhir dua wilayah.

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

Untuk petak peta satu wilayah, perilakunya sama, hanya dengan akhiran[1] dihapus.

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

Mengubah Inversi untuk Nilai Titik Akhir

Untuk petak peta dua wilayah, transformasi menerapkan inversi pengodean perbedaan, menambahkan nilai dasar pada akhir[0]. A ke tiga entri lain untuk total 9 operasi penambahan. Pada gambar di bawah ini, nilai dasar direpresentasikan sebagai "A0" dan memiliki presisi titik mengambang tertinggi. "A1," "B0," dan "B1" adalah semua delta yang dihitung dari nilai jangkar, dan nilai delta ini diwakili dengan presisi yang lebih rendah. (A0 sesuai dengan endpt[0]. A, B0 sesuai dengan endpt[0]. B, A1 sesuai dengan endpt[1]. A, dan B1 sesuai dengan endpt[1].B.)

calculation of transform inversion endpoint values

Untuk petak peta satu wilayah hanya ada satu offset delta, dan oleh karena itu hanya 3 operasi penambahan.

Dekompresor harus memastikan bahwa hasil transformasi terbalik tidak akan meluap presisi endpt[0].a. Dalam kasus luapan, nilai yang dihasilkan dari transformasi terbalik harus dibungkus dalam jumlah bit yang sama. Jika presisi A0 adalah bit "p", maka algoritma transformasi adalah:

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

Untuk format yang ditandatangani, hasil perhitungan delta juga harus diperpanjang. Jika operasi ekstensi tanda mempertimbangkan untuk memperpanjang kedua tanda, di mana 0 positif dan 1 negatif, maka ekstensi tanda 0 mengurus klem di atas. Setara, setelah klem di atas, hanya nilai 1 (negatif) yang perlu ditandatangani diperpanjang.

Ketidaksamaan Titik Akhir Warna

Mengingat titik akhir yang tidak dikompresi, langkah selanjutnya adalah melakukan unquantization awal titik akhir warna. Ini melibatkan tiga langkah:

  • Ketidaksamaan palet warna
  • Interpolasi palet
  • Finalisasi unquantization

Memisahkan proses unquantization menjadi dua bagian (unquantization palet warna sebelum interpolasi dan unquantization akhir setelah interpolasi) mengurangi jumlah operasi perkalian yang diperlukan jika dibandingkan dengan proses unquantization penuh sebelum interpolasi palet.

Kode di bawah ini menggambarkan proses untuk mengambil perkiraan nilai warna 16-bit asli, lalu menggunakan nilai bobot yang disediakan untuk menambahkan 6 nilai warna tambahan ke palet. Operasi yang sama dilakukan pada setiap saluran.

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

Sampel kode berikutnya menunjukkan proses interpolasi, dengan pengamatan berikut:

  • Karena rentang penuh nilai warna untuk fungsi unquantize (di bawah) adalah dari -32768 hingga 65535, interpolator diimplementasikan menggunakan aritmatika bertanda tangan 17-bit.
  • Setelah interpolasi, nilai diteruskan ke fungsi finish_unquantize (dijelaskan dalam sampel ketiga di bagian ini), yang menerapkan penskalaan akhir.
  • Semua dekompresor perangkat keras diperlukan untuk mengembalikan hasil bit-akurat dengan fungsi-fungsi ini.
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 dipanggil setelah interpolasi palet. Fungsi unquantize menunda penskalaan sebesar 31/32 untuk ditandatangani, 31/64 untuk tidak ditandatangani. Perilaku ini diperlukan untuk mendapatkan nilai akhir ke dalam rentang setengah yang valid(-0x7BFF ~ 0x7BFF) setelah interpolasi palet selesai untuk mengurangi jumlah perkalian yang diperlukan. finish_unquantize menerapkan penskalaan akhir dan mengembalikan nilai pendek yang tidak ditandatangani kembali menjadi setengahnya.

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

Kompresi Blok Tekstur di Direct3D 11