BC7-format

BC7-formatet är ett texturkomprimeringsformat som används för högkvalitativ komprimering av RGB- och RGBA-data.

Information om blocklägena för BC7-formatet finns i BC7 Format Mode Reference.

Om BC7/DXGI_FORMAT_BC7

BC7 anges av följande DXGI_FORMAT uppräkningsvärden:

  • DXGI_FORMAT_BC7_TYPELESS.
  • DXGI_FORMAT_BC7_UNORM.
  • DXGI_FORMAT_BC7_UNORM_SRGB.

BC7-formatet kan användas för Texture2D- (inklusive matriser), Texture3D- eller TextureCube-strukturresurser (inklusive matriser). På samma sätt gäller det här formatet för alla MIP-kartytor som är associerade med dessa resurser.

BC7 använder en fast blockstorlek på 16 byte (128 bitar) och en fast panelstorlek på 4x4 texels. Precis som med tidigare BC-format komprimeras strukturbilder som är större än den panelstorlek som stöds (4x4) med hjälp av flera block. Den här adresseringsidentiteten gäller även för tredimensionella bilder och MIP-kartor, kubkartor och strukturmatriser. Alla bildpaneler måste ha samma format.

BC7 komprimerar både RGB-databilder (tre kanaler) och fyra kanaler (RGBA). Vanligtvis är källdata 8 bitar per färgkomponent (kanal), även om formatet kan koda källdata med högre bitar per färgkomponent. Alla bildpaneler måste ha samma format.

BC7-avkodaren utför dekomprimering innan texturfiltrering tillämpas.

BC7-dekomprimeringsmaskinvara måste vara bit exakt; Maskinvaran måste alltså returnera resultat som är identiska med de resultat som returneras av avkodaren som beskrivs i det här dokumentet.

BC7-implementering

En BC7-implementering kan ange ett av 8 lägen, med det läge som anges i den minst betydande biten av blocket 16 byte (128 bitar). Läget kodas av noll eller fler bitar med värdet 0 följt av en 1.

Ett BC7-block kan innehålla flera slutpunktspar. I den här dokumentationen kan den uppsättning index som motsvarar ett slutpunktspar kallas för en "delmängd". I vissa blocklägen kodas även slutpunktsrepresentationen i ett formulär som – återigen i den här dokumentationen – ska kallas "RGBP", där "P"-biten representerar en delad minst betydande bit för slutpunktens färgkomponenter. Om slutpunktsrepresentationen för formatet till exempel är "RGB 5.5.5.1" tolkas slutpunkten som ett RGB 6.6.6-värde, där P-bitens tillstånd definierar den minst betydande biten av varje komponent. Om representationen för formatet är "RGBAP 5.5.5.5.5.1" för källdata med en alfakanal tolkas slutpunkten som RGBA 6.6.6.6.6. Beroende på blockeringsläget kan du ange den delade minst betydande biten för antingen båda slutpunkterna i en delmängd individuellt (2 P-bitar per delmängd) eller delas mellan slutpunkter i en delmängd (1 P-bitar per delmängd).

För BC7-block som inte uttryckligen kodar alfakomponenten består ett BC7-block av lägesbitar, partitionsbitar, komprimerade slutpunkter, komprimerade index och en valfri P-bit. I dessa block har slutpunkterna en RGB-representation och alfakomponenten avkodas som 1.0 för alla texels i källdata.

För BC7-block som har kombinerade färg- och alfakomponenter består ett block av lägesbitar, komprimerade slutpunkter, komprimerade index och valfria partitionsbitar och en P-bit. I dessa block uttrycks slutpunktsfärgerna i RGBA-format och alfakomponentvärden interpoleras tillsammans med färgkomponentvärdena.

För BC7-block som har separata färg- och alfakomponenter består ett block av lägesbitar, rotationsbitar, komprimerade slutpunkter, komprimerade index och en valfri indexväljare. Dessa block har en effektiv RGB-vektor [R, G, B] och en skalär alfakanal [A] separat kodad.

I följande tabell visas komponenterna för varje blocktyp.

BC7-blocket innehåller... läge bitar rotationsbitar indexväljaren bit partitionsbitar komprimerade slutpunkter P-bit komprimerade index
endast färgkomponenter krävs Ej tillämpligt Ej tillämpligt krävs krävs valfri krävs
färg + alfa kombinerad krävs Ej tillämpligt Ej tillämpligt valfri krävs valfri krävs
färg och alfaavgränsad krävs krävs valfri Ej tillämpligt krävs Ej tillämpligt krävs

 

BC7 definierar en palett med färger på en ungefärlig linje mellan två slutpunkter. Lägesvärdet avgör antalet interpolerande slutpunktspar per block. BC7 lagrar ett palettindex per texel.

För varje delmängd av index som motsvarar ett par slutpunkter korrigerar kodaren tillståndet för en bit av komprimerade indexdata för den delmängden. Det gör det genom att välja en slutpunktsordning som gör att indexet för det avsedda "korrigeringsindexet" kan ange sin viktigaste bit till 0, och som sedan kan tas bort, vilket sparar en bit per delmängd. För blocklägen med endast en enda delmängd är korrigeringsindexet alltid index 0.

Avkodning av BC7-format

Följande pseudokod beskriver stegen för att dekomprimera pixeln vid (x,y) med tanke på 16 byte BC7-blocket.

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

Följande pseudokod beskriver stegen för att helt avkoda slutpunktsfärg och alfakomponenter för varje delmängd givet ett BC7-block på 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
        }
    }
}

Om du vill generera varje interpolerad komponent för varje delmängd använder du följande algoritm: låt "c" vara komponenten som ska genereras. låt "e0" vara komponenten i slutpunkt 0 i delmängden. och låt "e1" vara komponenten i slutpunkt 1 i delmängden.

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

Följande pseudokod visar hur du extraherar index och bitantal för färg- och alfakomponenter. Block med separat färg och alfa har också två uppsättningar indexdata: en för vektorkanalen och en för den skalära kanalen. För läge 4 har dessa index olika bredder (2 eller 3 bitar) och det finns en enbitsväljare som anger om vektor- eller skalärdata använder 3-bitarsindex. (Att extrahera alfabitsantalet liknar att extrahera antal färgbitar, men med inverterat beteende baserat på idxMode bit.)

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

komprimering av texturblock i Direct3D 11