BC7 형식은 RGB 및 RGBA 데이터의 고품질 압축에 사용되는 텍스처 압축 형식입니다.
BC7 형식의 블록 모드에 대한 자세한 내용은 BC7 형식 모드 참조참조하세요.
BC7/DXGI_FORMAT_BC7 정보
BC7은 다음 DXGI_FORMAT 열거형 값으로 지정됩니다.
- DXGI_FORMAT_BC7_TYPELESS.
- DXGI_FORMAT_BC7_UNORM.
- DXGI_FORMAT_BC7_UNORM_SRGB.
BC7 형식은 Texture2D(배열 포함), Texture3D 또는 TextureCube(배열 포함) 텍스처 리소스에 사용할 수 있습니다. 마찬가지로 이 형식은 이러한 리소스와 연결된 모든 MIP 맵 화면에 적용됩니다.
BC7은 16바이트(128비트)의 고정 블록 크기와 4x4 텍셀의 고정 타일 크기를 사용합니다. 이전 BC 형식과 마찬가지로 지원되는 타일 크기(4x4)보다 큰 질감 이미지는 여러 블록을 사용하여 압축됩니다. 이 주소 지정 ID는 3차원 이미지 및 MIP 맵, 큐브맵 및 텍스처 배열에도 적용됩니다. 모든 이미지 타일은 동일한 형식이어야 합니다.
BC7은 3개 채널(RGB)과 RGBA(4개 채널) 고정 소수점 데이터 이미지를 모두 압축합니다. 일반적으로 원본 데이터는 색 구성 요소(채널)당 8비트이지만 형식은 색 구성 요소당 더 높은 비트로 원본 데이터를 인코딩할 수 있습니다. 모든 이미지 타일은 동일한 형식이어야 합니다.
BC7 디코더는 텍스처 필터링이 적용되기 전에 압축 해제를 수행합니다.
BC7 압축 해제 하드웨어는 비트 정확해야 합니다. 즉, 하드웨어는 이 문서에 설명된 디코더에서 반환한 결과와 동일한 결과를 반환해야 합니다.
BC7 구현
BC7 구현은 16 바이트(128비트) 블록 중 가장 중요한 비트에 지정된 모드를 사용하여 8개 모드 중 하나를 지정할 수 있습니다. 모드는 값이 0이고 그 뒤에 1이 있는 0개 이상의 비트로 인코딩됩니다.
BC7 블록에는 여러 엔드포인트 쌍이 포함될 수 있습니다. 이 설명서를 위해 엔드포인트 쌍에 해당하는 인덱스 집합을 "하위 집합"이라고 할 수 있습니다. 또한 일부 블록 모드에서 엔드포인트 표현은 이 설명서의 목적을 위해 다시 "RGBP"라고 하는 형식으로 인코딩됩니다. 여기서 "P" 비트는 엔드포인트의 색 구성 요소에 대한 공유 최소 중요 비트를 나타냅니다. 예를 들어 형식의 엔드포인트 표현이 "RGB 5.5.5.1"인 경우 엔드포인트는 RGB 6.6.6 값으로 해석됩니다. 여기서 P비트 상태는 각 구성 요소의 가장 중요한 비트를 정의합니다. 마찬가지로 알파 채널이 있는 원본 데이터의 경우 형식에 대한 표현이 "RGBAP 5.5.5.5.1"인 경우 엔드포인트는 RGBA 6.6.6.6으로 해석됩니다. 블록 모드에 따라 하위 집합의 두 엔드포인트(하위 집합당 2P비트) 또는 하위 집합의 엔드포인트 간에 공유(하위 집합당 1P비트)에 대해 공유된 최소 중요 비트를 지정할 수 있습니다.
알파 구성 요소를 명시적으로 인코딩하지 않는 BC7 블록의 경우 BC7 블록은 모드 비트, 파티션 비트, 압축된 엔드포인트, 압축된 인덱스 및 선택적 P 비트로 구성됩니다. 이러한 블록에서 엔드포인트에는 RGB 전용 표현이 있고 알파 구성 요소는 원본 데이터의 모든 텍셀에 대해 1.0으로 디코딩됩니다.
색과 알파 구성 요소가 결합된 BC7 블록의 경우 블록은 모드 비트, 압축된 엔드포인트, 압축된 인덱스, 선택적 파티션 비트 및 P비트로 구성됩니다. 이러한 블록에서 엔드포인트 색은 RGBA 형식으로 표현되고 알파 구성 요소 값은 색 구성 요소 값과 함께 보간됩니다.
별도의 색 및 알파 구성 요소가 있는 BC7 블록의 경우 블록은 모드 비트, 회전 비트, 압축된 엔드포인트, 압축된 인덱스 및 선택적 인덱스 선택기 비트로 구성됩니다. 이러한 블록에는 효과적인 RGB 벡터 [R, G, B] 및 스칼라 알파 채널 [A]가 별도로 인코딩됩니다.
다음 표에서는 각 블록 유형의 구성 요소를 나열합니다.
| BC7 블록 포함... | 모드 비트 | 회전 비트 | 인덱스 선택기 비트 | 파티션 비트 | 압축된 엔드포인트 | P비트 | 압축된 인덱스 |
|---|---|---|---|---|---|---|---|
| 색 구성 요소만 | 필수 | 해당(N/A) | 해당(N/A) | 필수 | 필수 | 선택적 | 필수 |
| 색 + 알파 결합 | 필수 | 해당(N/A) | 해당(N/A) | 선택적 | 필수 | 선택적 | 필수 |
| 색 및 알파 구분 | 필수 | 필수 | 선택적 | 해당(N/A) | 필수 | 해당(N/A) | 필수 |
BC7은 두 엔드포인트 사이의 대략적인 선에 색 팔레트를 정의합니다. 모드 값은 블록당 보간 엔드포인트 쌍 수를 결정합니다. BC7은 텍셀당 하나의 색상표 인덱스만 저장합니다.
엔드포인트 쌍에 해당하는 인덱스의 각 하위 집합에 대해 인코더는 해당 하위 집합에 대한 압축된 인덱스 데이터의 1비트 상태를 수정합니다. 이렇게 하려면 지정된 "수정" 인덱스의 인덱스가 가장 중요한 비트를 0으로 설정하고 삭제할 수 있는 엔드포인트 순서를 선택하여 하위 집합당 1비트를 저장합니다. 단일 하위 집합만 있는 블록 모드의 경우 픽스업 인덱스는 항상 인덱스 0입니다.
BC7 형식 디코딩
다음 의사 코드는 16 바이트 BC7 블록이 지정된 경우 (x,y)에서 픽셀의 압축을 푸는 단계를 간략하게 설명합니다.
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);
}
}
다음 의사 코드는 16 바이트 BC7 블록이 지정된 각 하위 집합에 대한 엔드포인트 색 및 알파 구성 요소를 완전히 디코딩하는 단계를 간략하게 설명합니다.
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
}
}
}
각 하위 집합에 대해 보간된 각 구성 요소를 생성하려면 다음 알고리즘을 사용합니다. "c"가 생성할 구성 요소가 되도록 합니다. "e0"이 하위 집합의 엔드포인트 0 구성 요소가 되도록 합니다. 및 "e1"이 하위 집합의 엔드포인트 1 구성 요소가 되도록 합니다.
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);
}
다음 의사 코드는 색 및 알파 구성 요소에 대한 인덱스 및 비트 수를 추출하는 방법을 보여 줍니다. 별도의 색과 알파가 있는 블록에는 벡터 채널과 스칼라 채널의 인덱스 데이터 집합이 있습니다. 모드 4의 경우 이러한 인덱스는 너비가 다르며(2비트 또는 3비트), 벡터 또는 스칼라 데이터가 3비트 인덱스를 사용하는지 여부를 지정하는 1비트 선택기가 있습니다. (알파 비트 수를 추출하는 것은 색 비트 수를 추출하는 것과 유사하지만 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;
}
관련 항목