BC7 Format

Format BC7 adalah format kompresi tekstur yang digunakan untuk kompresi data RGB dan RGBA berkualitas tinggi.

Untuk informasi tentang mode blokir format BC7, lihat Referensi Mode Format BC7.

Tentang BC7/DXGI_FORMAT_BC7

BC7 ditentukan oleh nilai enumerasi DXGI_FORMAT berikut:

  • DXGI_FORMAT_BC7_TYPELESS.
  • DXGI_FORMAT_BC7_UNORM.
  • DXGI_FORMAT_BC7_UNORM_SRGB.

Format BC7 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.

BC7 menggunakan ukuran blok tetap 16 byte (128 bit) dan ukuran petak peta 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 dan peta MIP, peta kubus, dan array tekstur. Semua petak peta gambar harus dalam format yang sama.

BC7 memadatkan gambar data titik tetap tiga saluran (RGB) dan empat saluran (RGBA). Biasanya, data sumber adalah 8 bit per komponen warna (saluran), meskipun formatnya mampu mengodekan data sumber dengan bit yang lebih tinggi per komponen warna. Semua petak peta gambar harus dalam format yang sama.

Dekoder BC7 melakukan dekompresi sebelum pemfilteran tekstur diterapkan.

Perangkat keras dekompresi BC7 harus sedikit akurat; artinya, perangkat keras harus mengembalikan hasil yang identik dengan hasil yang dikembalikan oleh dekoder yang dijelaskan dalam dokumen ini.

Implementasi BC7

Implementasi BC7 dapat menentukan salah satu dari 8 mode, dengan mode yang ditentukan dalam bit paling tidak signifikan dari blok 16 byte (128 bit). Mode ini dikodekan oleh nol atau lebih bit dengan nilai 0 diikuti oleh 1.

Blok BC7 dapat berisi beberapa pasangan titik akhir. Untuk tujuan dokumentasi ini, sekumpulan indeks yang sesuai dengan pasangan titik akhir dapat disebut sebagai "subset." Juga, dalam beberapa mode blok, representasi titik akhir dikodekan dalam bentuk yang -- sekali lagi, untuk tujuan dokumentasi ini - harus disebut sebagai "RGBP," di mana bit "P" mewakili bit yang paling tidak signifikan bersama untuk komponen warna titik akhir. Misalnya, jika representasi titik akhir untuk format adalah "RGB 5.5.5.1," maka titik akhir ditafsirkan sebagai nilai RGB 6.6.6, di mana status P-bit menentukan bit yang paling tidak signifikan dari setiap komponen. Demikian pula, untuk data sumber dengan saluran alfa, jika representasi untuk formatnya adalah "RGBAP 5.5.5.5.1," maka titik akhir ditafsirkan sebagai RGBA 6.6.6.6. Bergantung pada mode blok, Anda dapat menentukan bit bersama yang paling tidak signifikan untuk kedua titik akhir subset satu per satu (2 P-bit per subset), atau dibagikan di antara titik akhir subset (1 P-bit per subset).

Untuk blok BC7 yang tidak secara eksplisit mengodekan komponen alfa, blok BC7 terdiri dari bit mode, bit partisi, titik akhir terkompresi, indeks terkompresi, dan P-bit opsional. Dalam blok ini, titik akhir memiliki representasi khusus RGB dan komponen alfa didekodekan sebagai 1,0 untuk semua texel dalam data sumber.

Untuk blok BC7 yang memiliki komponen gabungan warna dan alfa, blok terdiri dari bit mode, titik akhir terkompresi, indeks terkompresi, dan bit partisi opsional dan P-bit. Dalam blok ini, warna titik akhir dinyatakan dalam format RGBA, dan nilai komponen alfa diinterpolasi bersama nilai komponen warna.

Untuk blok BC7 yang memiliki komponen warna dan alfa terpisah, blok terdiri dari bit mode, bit rotasi, titik akhir terkompresi, indeks terkompresi, dan bit pemilih indeks opsional. Blok-blok ini memiliki vektor RGB yang efektif [R, G, B] dan saluran alfa skalar [A] yang dikodekan secara terpisah.

Tabel berikut mencantumkan komponen dari setiap jenis blok.

Blok BC7 berisi... bit mode bit rotasi bit pemilih indeks bit partisi titik akhir terkompresi P-bit indeks terkompresi
komponen warna saja diperlukan T/A T/A diperlukan diperlukan opsional diperlukan
warna + alfa gabungan diperlukan T/A T/A opsional diperlukan opsional diperlukan
warna dan alfa dipisahkan diperlukan diperlukan opsional T/A diperlukan T/A diperlukan

 

BC7 mendefinisikan palet warna pada garis perkiraan antara dua titik akhir. Nilai mode menentukan jumlah pasangan titik akhir interpolasi per blok. BC7 menyimpan satu indeks palet per texel.

Untuk setiap subset indeks yang sesuai dengan sepasang titik akhir, encoder memperbaiki status satu bit data indeks terkompresi untuk subset tersebut. Ini melakukannya dengan memilih urutan titik akhir yang memungkinkan indeks untuk indeks "perbaikan" yang ditunjuk untuk mengatur bit yang paling signifikan menjadi 0, dan yang kemudian dapat dibuang, menghemat satu bit per subset. Untuk mode blok hanya dengan satu subset, indeks perbaikan selalu diindeks 0.

Mendekode Format BC7

Pseudocode berikut menguraikan langkah-langkah untuk mendekompresi piksel pada (x,y) mengingat blok 16 byte BC7.

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

Pseudocode berikut menguraikan langkah-langkah untuk sepenuhnya mendekode warna titik akhir dan komponen alfa untuk setiap subset yang diberi blok BC7 16-byte.

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

Untuk menghasilkan setiap komponen terinterpolasi untuk setiap subset, gunakan algoritma berikut: biarkan "c" menjadi komponen yang akan dihasilkan; biarkan "e0" menjadi komponen titik akhir 0 dari subset; dan biarkan "e1" menjadi komponen titik akhir 1 dari subset.

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

Pseudocode berikut menggambarkan cara mengekstrak indeks dan jumlah bit untuk komponen warna dan alfa. Blok dengan warna dan alfa terpisah juga memiliki dua set data indeks: satu untuk saluran vektor, dan satu untuk saluran skalar. Untuk Mode 4, indeks ini memiliki lebar yang berbeda (2 atau 3 bit), dan ada pemilih satu bit yang menentukan apakah data vektor atau skalar menggunakan indeks 3-bit. (Mengekstrak jumlah bit alfa mirip dengan mengekstrak jumlah bit warna tetapi dengan perilaku terbalik berdasarkan bit 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;
}

Kompresi Blok Tekstur di Direct3D 11