Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
La compresión de bloques es una técnica de compresión de texturas con pérdida para reducir el tamaño de las texturas y el espacio de memoria, lo que proporciona un aumento del rendimiento. Una textura comprimida por bloques puede ser menor que una textura con 32 bits por color.
La compresión en bloques es una técnica de compresión de texturas para reducir el tamaño de la textura. En comparación con una textura con 32 bits por color, una textura comprimida por bloque puede ser hasta un 75 % más pequeña. Las aplicaciones suelen recibir un aumento del rendimiento al usar la compresión en bloques debido a una superficie de memoria más pequeña.
Aunque es con pérdidas, la compresión de bloques funciona bien y se recomienda para todas las texturas que se transforman y filtran por el proceso. Las texturas que se asignan directamente a la pantalla (elementos de la interfaz de usuario como iconos y texto) no son buenas opciones para la compresión, ya que los artefactos se hacen más evidentes.
Una textura comprimida por bloques debe crearse como un múltiplo 4 de tamaño en todas las dimensiones y no se puede usar como resultado final de la canalización.
Funcionamiento de la compresión de bloques
La compresión en bloques es una técnica que sirve para reducir la cantidad de memoria necesaria para almacenar datos de color. Al almacenar algunos colores en su tamaño original y otros colores mediante un esquema de codificación, puede reducir considerablemente el volumen de memoria necesario para almacenar la imagen. Dado que el hardware descodifica automáticamente los datos comprimidos, no hay ninguna merma en el rendimiento para usar texturas comprimidas.
Para ver cómo funciona la compresión, vea los dos ejemplos siguientes. En el primer ejemplo se presenta la cantidad de memoria utilizada al almacenar datos sin comprimir; en el segundo ejemplo se presenta la cantidad de memoria usada al almacenar datos comprimidos.
Almacenamiento de datos sin comprimir
La siguiente ilustración representa una textura 4×4 sin comprimir. Supongamos que cada color contiene un único componente de color (rojo, por ejemplo) y se almacena en un byte de memoria.
Los datos sin comprimir se distribuyen en memoria en forma secuencial y requieren 16 bytes, tal como se muestra en la ilustración siguiente.
Almacenamiento de datos comprimidos
Ahora que ha visto cuánta memoria usa una imagen sin comprimir, fíjese en la cantidad de memoria que guarda una imagen comprimida. El formato de compresión BC4 almacena 2 colores (1 byte cada uno) y 16 índices de 3 bits (48 bits o 6 bytes), que se utilizan para interpolar los colores originales en la textura, como se muestra en la ilustración siguiente.
El espacio total necesario para almacenar los datos comprimidos es de 8 bytes, lo que supone un 50 por ciento menos de memoria que en el ejemplo sin comprimir. Esta reducción es aún mayor cuando se usa más de un componente de color.
El menor volumen de memoria utilizado por la compresión en bloques puede hacer que aumente el rendimiento. Este rendimiento afecta a la calidad de la imagen (debido a la interpolación del color); sin embargo, ese merma de la calidad es a menudo imperceptible.
En la sección siguiente se muestra cómo Direct3D habilita el uso de la compresión de bloques en una aplicación.
Uso de la compresión de bloques
Cree una textura comprimida en bloques igual que una textura sin comprimir, con la diferencia de que especifique un formato comprimido en bloques.
A continuación, cree una vista para enlazar la textura a la canalización, ya que una textura comprimida por bloques solo se puede usar como entrada para una etapa del sombreador, por lo que quiere crear una vista de recursos del sombreador.
Use una textura comprimida en bloques de la misma manera que usaría una textura sin comprimir. Si la aplicación obtendrá un puntero de memoria para bloquear los datos comprimidos, debe tener en cuenta el relleno de memoria en un mapa mip que hace que el tamaño declarado sea diferente del tamaño real.
Tamaño virtual frente al tamaño físico
Si el código de la aplicación usa un puntero de memoria para recorrer la memoria de una textura comprimida en bloques, hay algo importante para lo que se necesitaría modificar el código de la aplicación. Una textura comprimida por bloques debe ser un múltiplo de 4 en todas las dimensiones, ya que los algoritmos de compresión de bloques funcionan en bloques de texeles 4x4. Este será un problema para un mapa mip cuyas dimensiones iniciales son divisibles por 4, pero sus niveles subdivididos no lo son. En el diagrama siguiente se ve la diferencia en el área entre el tamaño virtual (declarado) y el tamaño físico (real) de cada nivel de mapa MIP.
El lado izquierdo del diagrama muestra los tamaños de los niveles de mipmap que se generan para una textura de 60×40 sin comprimir. El tamaño de nivel superior se captura de la llamada de la API que genera la textura; cada nivel siguiente es la mitad del tamaño del nivel anterior. En el caso de una textura sin comprimir, no hay ninguna diferencia entre el tamaño virtual (declarado) y el tamaño físico (real).
Los tamaños de nivel de mapa mip que se generan para la misma textura de 60×40 con compresión se muestran en el lado derecho del diagrama. Tenga en cuenta que tanto el segundo como el tercer nivel tienen relleno de memoria para que los tamaños sean múltiplos de 4 en cada nivel. Esto es necesario para que los algoritmos puedan funcionar en bloques de texel 4×4. Esto es especialmente evidente si consideramos niveles mipmap inferiores a 4×4; el tamaño de estos niveles mipmap muy pequeños se redondeará al múltiplo más cercano de 4 cuando se asigne memoria de textura.
El hardware de muestreo usa el tamaño virtual; cuando se muestrea la textura, se ignora el relleno de memoria. En el caso de los niveles mipmap que son menores que 4×4, solo se usarán los cuatro primeros texeles para un mapa de 2×2, y solo el primer texel será usado por un bloque de mapa 1×1. Sin embargo, no hay ninguna estructura de API que exponga el tamaño físico (incluido el relleno de memoria).
En resumen, tenga cuidado a la hora de usar bloques de memoria alineados al copiar regiones que contenga datos comprimidos en bloques. Para hacerlo en una aplicación que obtiene un puntero de memoria, asegúrese de que el puntero usa el tono de superficie para tener en cuenta el tamaño de memoria física.
Algoritmos de compresión
Las técnicas de compresión en bloques en Direct3D dividen los datos de las texturas sin comprimir en bloques de 4×4, comprimen cada bloque y después almacenan los datos. Por este motivo, se espera que las texturas que deban ser comprimidas tengan dimensiones que sean múltiplos de 4.
Compresión de bloques
En el diagrama anterior se muestra una textura dividida en bloques de texeles. El primer bloque muestra la disposición de los 16 texels etiquetados de la a a la p, pero cada bloque tiene la misma organización de datos.
Direct3D implementa varios esquemas de compresión, cada uno implementa una compensación diferente entre el número de componentes almacenados, el número de bits por componente y la cantidad de memoria consumida. Use esta tabla para elegir el formato que mejor funcione con el tipo de datos y la resolución de datos que mejor se adapte a la aplicación.
Datos de origen | Resolución de compresión de datos (en bits) | Elija este formato de compresión |
---|---|---|
Color de tres componentes y alfa | Color (5:6:5), alfa (1) o ningún alfa | BC1 |
Color de tres componentes y alfa | Color (5:6:5), alfa (4) | BC2 |
Color de tres componentes y alfa | Color (5:6:5), alfa (8) | BC3 |
Color de un componente | Un componente (8) | BC4 |
Color de dos componentes | Dos componentes (8:8) | BC5 |
BC1
Use el primer formato de compresión en bloques (BC1) (ya sea DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM o DXGI_BC1_UNORM_SRGB) para almacenar los datos de color de tres componentes mediante un color 5:6:5 (5 bits rojo, 6 bits verde, 5 bits azul). Esto es cierto incluso si los datos incluyen también alfa de 1 bits. Suponiendo que se usa una textura de 4×4 con el formato de datos más grande posible, el formato BC1 reduce la memoria requerida de 48 bytes (16 colores × 3 componentes/color × 1 byte/componente) a 8 bytes de memoria.
El algoritmo funciona en bloques de texeles de 4×4. En lugar de almacenar 16 colores, el algoritmo guarda dos colores de referencia (color_0 y color_1) y 16 índices de color de 2 bits (bloques a-p), tal como se muestra en el diagrama siguiente.
Los índices de color (a-p) se usan para buscar los colores originales en una tabla de colores. La tabla de colores contiene 4 colores. Los dos primeros colores, color_0 y color_1, son los valores de color mínimos y máximos. Los otros dos colores, color_2 y color_3, son colores intermedios calculados con interpolación lineal.
color_2 = 2/3*color_0 + 1/3*color_1
color_3 = 1/3*color_0 + 2/3*color_1
A los cuatro colores se les asignan valores de índice de 2 bits que se guardarán en los bloques a-p.
color_0 = 00
color_1 = 01
color_2 = 10
color_3 = 11
Por último, cada uno de los colores de los bloques a-p se compara con los cuatro colores de la tabla de colores y el índice del color más cercano se almacena en los bloques de 2 bits.
Este algoritmo también se presta a datos que contienen alfa de 1 bit. La única diferencia es que color_3 tiene el valor 0 (que representa un color transparente) y color_2 es una combinación lineal de color_0 y color_1.
color_2 = 1/2*color_0 + 1/2*color_1;
color_3 = 0;
BC2
Use el formato BC2 (ya sea DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM o DXGI_BC2_UNORM_SRGB) para almacenar datos que contengan datos de color y alfa de baja coherencia (use BC3 para datos alfa que sean altamente coherentes). El formato BC2 almacena datos RGB como un color 5:6:5 (5 bits rojo, 6 bits verde, 5 bits azul) y alfa como un valor independiente de 4 bits. Suponiendo que se use una textura de 4×4 con el formato de datos más grande posible, esta técnica de compresión reduce la memoria necesaria de 64 bytes (16 colores × 4 componentes/color × 1 byte/componente) a 16 bytes.
El formato BC2 almacena colores con el mismo número de bits y distribución de datos que el formato BC1; sin embargo, BC2 necesita más de 64 bits de memoria para almacenar los datos de alfa, tal como se muestra en el diagrama siguiente.
BC3
Use el formato BC3 (ya sea DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM o DXGI_BC3_UNORM_SRGB) para almacenar datos de color altamente coherentes (use BC2 con datos de alfa menos coherentes). El formato BC3 almacena datos de color mediante el color 5:6:5 (5 bits rojo, 6 bits verde, 5 bits azul) y datos de alfa con un byte. Suponiendo que se use una textura de 4×4 con el formato de datos más grande posible, esta técnica de compresión reduce la memoria necesaria de 64 bytes (16 colores × 4 componentes/color × 1 byte/componente) a 16 bytes.
El formato BC3 almacena colores con el mismo número de bits y distribución de datos que el formato BC1; sin embargo, BC3 necesita más de 64 bits de memoria para almacenar los datos de alfa. El formato BC3 almacena dos valores de referencia y los interpolan entre ellos para controlar alfa (de forma similar a cómo BC1 almacena el color RGB).
El algoritmo funciona en bloques de texeles de 4×4. En lugar de almacenar 16 valores alfa, el algoritmo almacena 2 alfas de referencia (alpha_0 y alpha_1) y 16 índices de color de 3 bits (alfa de la "a" a la "p"), tal como se muestra en el diagrama siguiente.
El formato BC3 usa los índices alfa (a–p) para buscar los colores originales en una tabla de búsqueda que contiene 8 valores. Los dos primeros valores (alpha_0 y alpha_1) son los valores mínimo y máximo; los otros seis valores intermedios se calculan mediante interpolación lineal.
El algoritmo determina el número de valores alfa interpolados examinando los dos valores alfa de referencia. Si alpha_0 es mayor que alpha_1, BC3 interpola 6 valores alfa; si no, interpola 4. Cuando BC3 interpola solo 4 valores alfa, se crean dos valores alfa adicionales (0 para totalmente transparente y 255 para totalmente opaco). BC3 comprime los valores alfa en el área de texeles 4×4 al almacenar el código de bits correspondiente a los valores alfa interpolados que más se aproximan al alfa original de un texel determinado.
if( alpha_0 > alpha_1 )
{
// 6 interpolated alpha values.
alpha_2 = 6/7*alpha_0 + 1/7*alpha_1; // bit code 010
alpha_3 = 5/7*alpha_0 + 2/7*alpha_1; // bit code 011
alpha_4 = 4/7*alpha_0 + 3/7*alpha_1; // bit code 100
alpha_5 = 3/7*alpha_0 + 4/7*alpha_1; // bit code 101
alpha_6 = 2/7*alpha_0 + 5/7*alpha_1; // bit code 110
alpha_7 = 1/7*alpha_0 + 6/7*alpha_1; // bit code 111
}
else
{
// 4 interpolated alpha values.
alpha_2 = 4/5*alpha_0 + 1/5*alpha_1; // bit code 010
alpha_3 = 3/5*alpha_0 + 2/5*alpha_1; // bit code 011
alpha_4 = 2/5*alpha_0 + 3/5*alpha_1; // bit code 100
alpha_5 = 1/5*alpha_0 + 4/5*alpha_1; // bit code 101
alpha_6 = 0; // bit code 110
alpha_7 = 255; // bit code 111
}
BC4
Use el formato BC4 para almacenar datos de color de un componente con 8 bits para cada color. Como resultado del aumento de la definición (en comparación con BC1), BC4 es ideal para almacenar datos de punto flotante en el intervalo de [0 a 1] con el formato DXGI_FORMAT_BC4_UNORM y de [-1 a +1] con el formato DXGI_FORMAT_BC4_SNORM. Suponiendo que se emplea una textura de 4×4 utilizando el formato de datos más grande posible, esta técnica de compresión reduce la memoria necesaria de 16 bytes (16 colores × 1 componente/color × 1 byte/componente) a 8 bytes.
El algoritmo funciona en bloques de texeles de 4×4. En lugar de almacenar 16 colores, el algoritmo almacena 2 colores de referencia (red_0 y red_1) e 6 índices de color de 3 bits (de "a" rojo a "p" rojo), tal como se muestra en el diagrama siguiente.
El algoritmo usa los índices de 3 bits para buscar colores de una tabla de colores que contiene 8 colores. Los dos primeros colores, red_0 y red_1, son los valores de color mínimos y máximos. El algoritmo calcula los colores restantes mediante la interpolación lineal.
El algoritmo determina el número de valores de color interpolados examinando los dos valores de referencia. Si red_0 es mayor que red_1, BC4 interpola 6 valores de color; si no, interpola 4. Cuando BC4 interpola solo 4 valores de color, se crean dos valores de color adicionales (0.0f para totalmente transparente y 1.0f para totalmente opaco). BC4 comprime los valores alfa en el área de texeles 4×4 almacenando el código de bits que corresponde a los valores alfa interpolados que más se asemejan a los valores alfa originales de un texel dado.
BC4_UNORM
La interpolación de los datos de un solo componente se realiza como en el ejemplo de código siguiente.
unsigned word red_0, red_1;
if( red_0 > red_1 )
{
// 6 interpolated color values
red_2 = (6*red_0 + 1*red_1)/7.0f; // bit code 010
red_3 = (5*red_0 + 2*red_1)/7.0f; // bit code 011
red_4 = (4*red_0 + 3*red_1)/7.0f; // bit code 100
red_5 = (3*red_0 + 4*red_1)/7.0f; // bit code 101
red_6 = (2*red_0 + 5*red_1)/7.0f; // bit code 110
red_7 = (1*red_0 + 6*red_1)/7.0f; // bit code 111
}
else
{
// 4 interpolated color values
red_2 = (4*red_0 + 1*red_1)/5.0f; // bit code 010
red_3 = (3*red_0 + 2*red_1)/5.0f; // bit code 011
red_4 = (2*red_0 + 3*red_1)/5.0f; // bit code 100
red_5 = (1*red_0 + 4*red_1)/5.0f; // bit code 101
red_6 = 0.0f; // bit code 110
red_7 = 1.0f; // bit code 111
}
A los colores de referencia se les asignan índices de 3 bits (000–111, ya que hay 8 valores), que se guardarán en bloques rojo a a rojo p durante la compresión.
BC4_SNORM
El DXGI_FORMAT_BC4_SNORM es exactamente el mismo, excepto que los datos se codifican en el intervalo SNORM y cuando se interpolan 4 valores de color. La interpolación de los datos de un solo componente se realiza como en el ejemplo de código siguiente.
signed word red_0, red_1;
if( red_0 > red_1 )
{
// 6 interpolated color values
red_2 = (6*red_0 + 1*red_1)/7.0f; // bit code 010
red_3 = (5*red_0 + 2*red_1)/7.0f; // bit code 011
red_4 = (4*red_0 + 3*red_1)/7.0f; // bit code 100
red_5 = (3*red_0 + 4*red_1)/7.0f; // bit code 101
red_6 = (2*red_0 + 5*red_1)/7.0f; // bit code 110
red_7 = (1*red_0 + 6*red_1)/7.0f; // bit code 111
}
else
{
// 4 interpolated color values
red_2 = (4*red_0 + 1*red_1)/5.0f; // bit code 010
red_3 = (3*red_0 + 2*red_1)/5.0f; // bit code 011
red_4 = (2*red_0 + 3*red_1)/5.0f; // bit code 100
red_5 = (1*red_0 + 4*red_1)/5.0f; // bit code 101
red_6 = -1.0f; // bit code 110
red_7 = 1.0f; // bit code 111
}
A los colores de referencia se les asignan índices de 3 bits (000–111, ya que hay 8 valores), que se guardarán en bloques rojo a a rojo p durante la compresión.
BC5
Use el formato BC5 para almacenar datos de color de dos componentes con 8 bits para cada color. Como resultado del aumento de la definición (en comparación con BC1), BC5 es ideal para almacenar datos de punto flotante en el intervalo de [0 a 1] con el formato DXGI_FORMAT_BC5_UNORM y de [-1 a +1] con el formato DXGI_FORMAT_BC5_SNORM. Suponiendo que una textura de 4×4 usando el formato de datos más grande posible, esta técnica de compresión reduce la memoria necesaria de 32 bytes (16 colores × 2 componente/color × 1 byte/componente) a 16 bytes de memoria.
El algoritmo funciona en bloques de texeles de 4×4. En lugar de almacenar 16 colores para ambos componentes, el algoritmo almacena 2 colores de referencia para cada componente (red_0, red_1, green_0 y green_1) y 16 índices de color de 3 bits para cada componente (rojo desde a hasta p y verde desde a hasta p), como se muestra en el diagrama siguiente.
El algoritmo usa los índices de 3 bits para buscar colores de una tabla de colores que contiene 8 colores. Los dos primeros colores (red_0 y red_1 (o green_0 y green_1) son los valores de color mínimos y máximos. El algoritmo calcula los colores restantes mediante la interpolación lineal.
El algoritmo determina el número de valores de color interpolados examinando los dos valores de referencia. Si red_0 es mayor que red_1, BC5 interpola 6 valores de color; si no, interpola 4. Cuando BC5 interpola solo 4 valores de color, se crean los dos valores de color restantes en 0.0f y 1.0f.
BC5_UNORM
La interpolación de los datos de un solo componente se realiza como en el ejemplo de código siguiente. Los cálculos de los componentes verdes son similares.
unsigned word red_0, red_1;
if( red_0 > red_1 )
{
// 6 interpolated color values
red_2 = (6*red_0 + 1*red_1)/7.0f; // bit code 010
red_3 = (5*red_0 + 2*red_1)/7.0f; // bit code 011
red_4 = (4*red_0 + 3*red_1)/7.0f; // bit code 100
red_5 = (3*red_0 + 4*red_1)/7.0f; // bit code 101
red_6 = (2*red_0 + 5*red_1)/7.0f; // bit code 110
red_7 = (1*red_0 + 6*red_1)/7.0f; // bit code 111
}
else
{
// 4 interpolated color values
red_2 = (4*red_0 + 1*red_1)/5.0f; // bit code 010
red_3 = (3*red_0 + 2*red_1)/5.0f; // bit code 011
red_4 = (2*red_0 + 3*red_1)/5.0f; // bit code 100
red_5 = (1*red_0 + 4*red_1)/5.0f; // bit code 101
red_6 = 0.0f; // bit code 110
red_7 = 1.0f; // bit code 111
}
A los colores de referencia se les asignan índices de 3 bits (000–111, ya que hay 8 valores), que se guardarán en bloques rojo a a rojo p durante la compresión.
BC5_SNORM
El DXGI_FORMAT_BC5_SNORM es exactamente el mismo, excepto que los datos se codifican en el intervalo de SNORM y cuando se interpolan 4 valores de datos, los dos valores adicionales son -1.0f y 1.0f. La interpolación de los datos de un solo componente se realiza como en el ejemplo de código siguiente. Los cálculos de los componentes verdes son similares.
signed word red_0, red_1;
if( red_0 > red_1 )
{
// 6 interpolated color values
red_2 = (6*red_0 + 1*red_1)/7.0f; // bit code 010
red_3 = (5*red_0 + 2*red_1)/7.0f; // bit code 011
red_4 = (4*red_0 + 3*red_1)/7.0f; // bit code 100
red_5 = (3*red_0 + 4*red_1)/7.0f; // bit code 101
red_6 = (2*red_0 + 5*red_1)/7.0f; // bit code 110
red_7 = (1*red_0 + 6*red_1)/7.0f; // bit code 111
}
else
{
// 4 interpolated color values
red_2 = (4*red_0 + 1*red_1)/5.0f; // bit code 010
red_3 = (3*red_0 + 2*red_1)/5.0f; // bit code 011
red_4 = (2*red_0 + 3*red_1)/5.0f; // bit code 100
red_5 = (1*red_0 + 4*red_1)/5.0f; // bit code 101
red_6 = -1.0f; // bit code 110
red_7 = 1.0f; // bit code 111
}
A los colores de referencia se les asignan índices de 3 bits (000–111, ya que hay 8 valores), que se guardarán en bloques rojo a a rojo p durante la compresión.
Conversión de formato de
Direct3D permite copias entre texturas preestructuradas y texturas comprimidas por bloques de los mismos anchos de bits.
Puede copiar recursos entre algunos tipos de formato. Este tipo de operación de copia realiza un tipo de conversión de formato que reinterpreta los datos de los recursos como un tipo de formato diferente. Consulte este ejemplo donde se ve la diferencia entre la reinterpretación de los datos y la forma en que funciona un tipo de conversión más normal:
FLOAT32 f = 1.0f;
UINT32 u;
Para reinterpretar 'f' como el tipo de 'u', use memcpy:
memcpy( &u, &f, sizeof( f ) ); // 'u' becomes equal to 0x3F800000.
En la reinterpretación anterior, el valor subyacente de los datos no cambia; memcpy reinterpreta el decimal como un entero sin signo.
Para realizar el tipo de conversión más típico, use la asignación:
u = f; // 'u' becomes 1.
En la conversión anterior, el valor subyacente de los datos cambia.
En la tabla siguiente figuran los formatos de origen y destino permitidos que puede usar en este tipo de reinterpretación de conversión de formato. Debe codificar los valores correctamente para que la reinterpretación funcione según lo previsto.
Ancho de bits | Recurso sin comprimir | Block-Compressed Recurso |
---|---|---|
32 | DXGI_FORMAT_R32_UINT DXGI_FORMAT_R32_SINT |
DXGI_FORMAT_R9G9B9E5_SHAREDEXP |
64 | DXGI_FORMAT_R16G16B16A16_UINT DXGI_FORMAT_R16G16B16A16_SINT DXGI_FORMAT_R32G32_UINT DXGI_FORMAT_R32G32_SINT |
DXGI_FORMAT_BC1_UNORM[_SRGB] DXGI_FORMAT_BC4_UNORM DXGI_FORMAT_BC4_SNORM |
128 | DXGI_FORMAT_R32G32B32A32_UINT DXGI_FORMAT_R32G32B32A32_SINT |
DXGI_FORMAT_BC2_UNORM[_SRGB] DXGI_FORMAT_BC3_UNORM[_SRGB] DXGI_FORMAT_BC5_UNORM DXGI_FORMAT_BC5_SNORM |