ASTC压缩纹理图像格式khronos官网翻译


翻译自:https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html#ASTC

ASTC压缩纹理图像格式

这个描述来源于Khronos OES_texture_compression_astc OpenGL扩展。

1. 什么是ASTC

ASTC代表自适应可伸缩纹理压缩(Adaptive Scalable Texture Compression.)。ASTC格式形成了一系列相关的压缩纹理图像格式,它们都来自一组共同的定义。

ASTC纹理可以是2D或3D。

ASTC纹理可以使用高动态范围(HDR)或低动态范围(LDR)进行编码。可以选择性地使用RGB通道的sRGB传递函数指定低动态范围图像。

可以实现两个子配置文件(“LDR配置文件”和“HDR配置文件”),分别只支持低动态范围或高动态范围的2D图像。

ASTC纹理可以编码为1,2,3或4个组件,但它们都解码为RGBA。ASTC的块大小是可变的。

2. 设计目标

该格式的设计目标如下:

  • 随机存取。这对于任何纹理压缩格式都是必须的。
  • 位精确解码。这是一致性测试和再现性的必要条件。
  • 适合移动使用。该格式应该同时适用于桌面和移动GPU环境。它应该是低带宽和低面积。
  • 灵活选择比特率。目前的格式(2012年前的压缩格式)只提供少量比特率,使得内容开发人员只能粗略地控制大小/质量的权衡。
  • 可扩展且经久耐用。该格式应该支持现有的R、RG、RGB和RGBA图像类型,并且还具有很高的“空间”,允许持续使用数年,并且能够在编码器上进行创新。其中一部分是选择包含HDR和3D。
  • 正交性的特性。格式的各种特性的选择都是相互正交的。这有三个效果:首先,它允许一个大的灵活的配置空间;其次,它使空间更容易理解;第三,它使验证更容易。
  • 在给定的比特率下是同类中最好的。在所有比特率下,它的峰值信噪比(PSNR)应该超过或匹配当前同类中最好的。
  • 快速的解码。缓存纹理的纹素吞吐量应该是每个时钟周期每个解码器解码一个纹素。从同一块中并行解码多个纹素也是可以的,但代价是递增的。
  • 低带宽。编码方案应确保内存访问保持在最低限度,缓存重用高,格式的内存带宽低。

3. 基本概念

ASTC是一种基于块的有损压缩格式。压缩后的图像被分成许多大小一致的块,这使得快速确定给定纹素所在的块成为可能。

每个块有128位的固定内存占用,但这128位可以表示不同数量的纹素。

内存块的大小不限于2的幂(POT),也不限于平方。它们可能是2D的,在这种情况下,块维度从4到12个纹素,或者是3D的,在这种情况下,块维度从3到6个纹素。

解码一个文本只需要来自单个块的数据。这简化了缓存设计,减少了带宽,提高了编码器吞吐量。

4. 区块编码

要理解块是如何存储和解码的,从一个简单的例子开始,然后介绍其他特征。

最简单的块编码从定义两种颜色的“端点”开始。端点定义了两种颜色,通过在这两种颜色之间进行插值生成许多额外的颜色。我们可以使用1、2、3或4个组件(通常对应于R、RG、RGB和RGBA纹理)来定义这些颜色,并使用低动态范围或高动态范围。

然后,我们为图像中的每个纹素存储一个颜色插值权重,它指定了如何计算要使用的颜色。由此,使用两个端点颜色的加权平均值来生成中间颜色,这是该纹素的返回颜色。

有几种不同的方法可以指定端点颜色和权重,但是一旦定义了端点颜色,就会对所有端点颜色进行相同的计算。每个块都可以自由选择最能代表其颜色端点的编码方案,但要限制所有数据都适合128位块。

对于具有大量texel的块(例如12×12块),没有足够的空间来显式存储每个纹素的权重。在这种情况下,存储具有较少权重的稀疏网格,并使用插值来确定每个纹素位置要使用的有效权重。这允许在可接受的质量下使用非常低的比特率。这也可以用于更有效地编码低细节或具有强垂直或水平特征的块。

对于混合了不同颜色的块,颜色空间中的单线不能很好地适应原始图像中像素的颜色。因此,可以将texels划分为多个集合,每个集合中的像素包含同一通道的颜色。对于每个“分区(partitions)”,我们指定单独的端点对(endpoint pairs),并通过分区索引来从分区模式表中查找来选择对特定纹素使用哪个端点。在ASTC中,这个分区表实际上是作为一个函数实现的。

每个分区的端点编码是独立的。

对于具有不相关通道的块-例如带有透明蒙版的图像,或用作法线贴图的图像-可能需要为每个纹素指定两个权重。然后,端点颜色分量之间的插值可以针对图像的每个“平面”独立进行。将通道分配给平面是可选择的。

由于上述每个选项都是独立的,因此可以指定通道,端点颜色编码,权重编码,插值,多个分区和单平面或双平面的任何组合。

因为这些值是按块指定的,所以一定要使用尽可能少的比特位表示。因此,这些值以一种难以阅读的方式打包在一起,但却非常适合硬件解码。

所有用作权重和颜色端点值的值都可以用可变位数指定。使用的编码方案允许使用“整数序列编码”在权重位和颜色端点位之间进行细粒度的权衡。这可以将相邻的值组合在一起,允许我们使用每个值的小数位数。

最后,一个块可能只有一种颜色。这就是所谓的“空区块”,它具有特殊的编码,也允许它识别附近的单色区域。这可能会缩短相同块的获取,从而进一步减少内存带宽。

5. LDR和HDR模式

如果事先知道需要sRGB输出,则可以简化LDR内容的解码过程。因此,此选择将作为全局配置的一部分包含。

这两种模式有很多不同之处,如表139所示。
在这里插入图片描述
解码过程返回值的类型由解码模式决定,如表140所示。
在这里插入图片描述
在HDR模式下使用decode_unorm8解码模式会产生未定义的结果。

对于sRGB,解码模式被忽略,并且解码总是返回一个8位无符号规范化值的向量。

错误颜色为不透明的完全饱和的洋红色(R,G,B,A) = (0xFF, 0x00, 0xFF, 0xFF)。之所以选择这种颜色,是因为它比黑色或白色更明显,而且在有效图像中出现的频率要低得多。

对于线性RGB解码,错误颜色可以是不透明的全饱和品红(R,G,B,A) =(1.0, 0.0, 1.0, 1.0)或四个NaN (R,G,B,A) = (NaN, NaN, NaN, NaN)的向量。对于后一种情况,建议返回的NaN值为0xFFFF。

当在HDR模式下使用decode_rgb9e5解码模式时,错误结果将返回错误颜色,因为NaN无法表示。

错误颜色作为对无效条件(包括无效块编码或使用保留端点模式)的信息响应返回。

未来,对ASTC的向前兼容扩展可能会定义这些条件的有效解释,这些条件将解码为其他颜色。因此,编码器和应用程序不能依赖无效编码作为生成错误颜色的方式。

6. 待办事宜

该格式的全局配置数据如下:

  • 块尺寸(2D或3D)
  • 块占用大小
  • sRGB输出是否启用

每个块指定的数据如下:

  • Texel权重网格大小
  • Texel权重范围
  • Texel权重值
  • 分区数(Number of partitions)
  • 分区模式索引
  • 颜色端点模式(包括LDR或HDR选择)
  • 颜色端点数据
  • 平面数(Number of planes)
  • 平面到通道的分配

7. 解码程序

(Optimization: If within known void-extent, immediately return single color)

Find block containing texel
Read block mode
If void-extent block, store void extent and immediately return single color

For each plane in image
  If block mode requires infill
    Find and decode stored weights adjacent to texel, unquantize and interpolate
  Else
    Find and decode weight for texel, and unquantize

Read number of partitions
If number of partitions > 1
  Read partition table pattern index
  Look up partition number from pattern

Read color endpoint mode and endpoint data for selected partition
Unquantize color endpoints
Interpolate color endpoints using weight (or weights in dual-plane mode)
Return interpolated color
(Optimization: 如果在已知的空范围内,立即返回单色)

查找包含texel的块
读取块模式
If 空范围块: 存储空范围 and 立即返回单色

For each plane in image
  If block mode requires infill
    找到 and 解码 纹素附近的存储权值, 去量化(unquantize) and 插值
  Else
    Find and decode 纹素权值, and 去量化

读取分区(partitions)数字
If number of partitions > 1
  读取分区表模式索引
  从模式中查找分区号

读取所选分区的颜色端点模式和端点数据
去量化颜色端点
使用权值(或双平面模式下的权值)插值颜色端点
Return 内插的颜色

8. 块确定和比特率

块占用是任何给定纹理的全局设置,因此不会在单个块中编码。

对于2D纹理,块空间的宽度和高度可以从许多预定义的大小中选择,即4,5,6,8,10和12像素。

对于正方形和接近正方形的块,它在表141中给出了比特率。
在这里插入图片描述
“增量”列表示比特率与下一个较低可用速率的比率。这一列中的一致值表示比特率的分布均匀。

对于3D纹理,块大小的宽度,高度和深度可以从许多预定义的大小中选择,即3,4,5和6像素。

对于立方和近立方块,它给出了表142中的比特率。
在这里插入图片描述
完整的配置文件只支持表141和表142中列出的那些块占用。不支持其他块大小。

对于不是块大小的整数倍的图像,额外的纹理被添加到最大X和Y的边缘(3D纹理和Z)。这些纹理可以是任何颜色,因为它们不会被访问。

虽然这些并不都是2的幂,但对于合法的图像大小,可以计算块地址和块内像素地址,而不会过于复杂。

给定图像的像素大小为W × H × D,块大小为w × h × d,则图像的块大小为:
在这里插入图片描述
【符号表示向上取整】

对于由2D切片构建的3D图像,每个2D切片为单个体素厚,因此对于大小为W × H × D像素的图像,块大小为w × h,则块中图像的大小为:
在这里插入图片描述

9. 块布局

图像中的每个块都作为一个128位的块存储在内存中。这些块按栅格顺序排列,从(0,0,0)开始,然后按X, Y顺序排列,最后按Z(如果存在)。它们对齐到内存中的128位边界。

块中的位按小端顺序标记-最低地址的字节包含位0…7。Bit 0是字节中最低有效位。

每个块都有相同的基本布局,如表143所示。
在这里插入图片描述
由于“纹素权重数据(Texel weight data)”字段的大小是可变的,因此“更多配置数据(More config data)”字段和“颜色端点数据(Color endpoint data)”字段显示的位置仅具有代表性,而不是固定的。

“块模式(Block mode)”字段指定如何对Texel权重数据进行编码。

“Part”字段指定了分区数(number of partitions),减1。当启用双平面模式时,分区数不能超过3个。如果指定了4个分区,则对块中的所有texel返回错误值。

额外配置数据(Extra configuration data)的大小和布局取决于分区数和图像中的平面数量,如表144所示(仅显示底部的32位)。
在这里插入图片描述
CEM是颜色端点模式字段,它决定如何对颜色端点数据进行编码。

如果启用双平面模式,颜色分量选择器位会直接出现在权重位的下方,如表145所示。
在这里插入图片描述
分区索引字段(Partition Index field)指定使用哪个分区布局。CEM是各种分区的颜色端点模式信息的前6位。对于需要超过6位CEM数据的模式,额外的位直接出现在纹素权重数据下面的可变位置。

如果双平面模式是激活的,那么颜色组件选择位就会直接出现在额外的CEM位的下面。

最后一种特殊情况是if bits [8…0]的值为" 111111100 ",则该块是一个空区块,具有23节描述的单独编码。

10. 块模式(Block mode)

block mode字段指定权重网格的宽度、高度和深度,它们使用什么范围的值,以及是否使用双权重平面。因为有些权重不能用2的幂表示(例如,权重宽度有12种),而且不允许所有的组合,所以这不是简单的位打包。但是,它可以在硬件中快速解包。

权重范围使用3位范围值ρ进行编码,并与低精度/高精度的位P一起解释,如表146所示。每个权重值都使用指定数量的Trits、Quints和Bits进行编码。这种编码的细节可以在12节中找到。

Trits表示3进制位,Quints表示5进制位,Bits为2进制位

在这里插入图片描述
对于2D块,块模式字段的布局如表147所示。
在这里插入图片描述
注意,由于ρ字段的编码,如前一页所述,位ρ2和ρ1不能都为零,这使表的前五行与其他行消除了歧义。

在确定一个块是空区块还是保留块时,会忽略值为x的位,但可能已经为特定的空区块定义了编码。

表147的倒数第二行只有在位[5…2]不都是1,在这种情况下,它编码一个空白范围块(如前一行所示)。

对于3D块,块模式字段布局如表148所示。
在这里插入图片描述
DP位设置为双平面模式。在此模式下,允许的最大分区数为3。

表148的倒数第二行只有在位[4…2]不都是1,在这种情况下,它编码一个空白范围块(如前一行所示)。

每个维度中的权重网格的大小必须小于或等于块占用空间的相应维度。如果网格大小大于任何轴上的占用空间尺寸,那么这是一个非法的块编码,所有的纹理将解码为错误的颜色。

11. 颜色端点模式

在这里插入图片描述

在单分区模式下,颜色端点模式(Color Endpoint mode, CEM)字段存储16个可能值中的一个。其中每个都指定了有多少原始数据值被编码,以及如何将这些原始值转换为两个RGBA颜色端点。它们可以总结如表149所示。
在这里插入图片描述
在多分区模式下,CEM字段的宽度是可变的,从6位到14位不等。CEM字段的最低2位指定如何计算每个分区的端点模式,如表150所示。
在这里插入图片描述

多分区模式下…[省略]

颜色端点解码过程的细节可以在13节中找到。

12. 整数序列编码

权重数据和端点颜色数据都是可变宽度的,并使用整数值序列指定。序列中每个值的范围(例如颜色权重)是受限的。

通常情况下,这些值的最有效范围不是2的幂,因此每个值序列都使用一种称为“整数序列编码”的技术进行编码。这使得高效的、硬件友好的打包和解包具有非二次幂范围的值成为可能。

在序列中,每个值都有唯一(identical)的范围。范围在表153和表154所示的其中一种形式中指定。
在这里插入图片描述
因为 3 5 3^5 35等于243,所以可以将5个trit打包到8位(有256个可能的值)中,因此一个trit可以有效地编码为1.6位。类似地,因为 5 3 5^3 53等于125,所以可以将3个五元组打包成7位(有128个可能的值),因此一个五元组可以被编码为2.33位。

该编码方案将trits或quits进行打包,然后在满足任意长度流要求的位置上交叉插入额外的n位。这使得正确指定长度不是3或5值的整数倍的值列表成为可能。它还可以轻松地在流中随机选择一个值。

如果流中没有足够的比特来填充最后的块,那么在解码时假定未使用的(高阶)比特为0。

要解码值i在位序列b中的位,都从0开始索引,请执行以下操作:
如果将范围编码为每个值n位,则该值为 b i × n + n − 1... i × n b^{i × n + n−1...i \times n} bi×n+n1...i×n位。一个简单的多路复用操作。

…太复杂了【省略】

这两个过程都能确保对所有128个可能的值进行有效解码(即使其中一些值是重复的)。它们也可以使用小的表在软件中有效地实现。这里没有指定编码方法,尽管基于表的机制可以很好地工作。

13. 端点去量化

每个颜色端点被指定为给定范围内的整数序列。这些值使用整数序列编码打包,作为从配置数据上方存储的位流,并向上增长。

一旦解包,必须将值从其存储范围中去量化,将其返回到0…255的标准范围。

对于仅位(bit-only)表示,这是从值的最高有效位进行简单的位复制。

对于基于三位数或五位数的表示,这涉及到一组位操作和调整,以避免全宽度乘法器的开销。此过程确保了正确的缩放,但会打乱已解码值相对于已编码值的顺序。这必须通过在编码器中使用表来补偿。

该过程的初始输入分别表示为A(9位)、B(9位)、C(9位)和D(3位),并使用表158中描述的范围进行解码。
在这里插入图片描述
然后按以下步骤处理:

unq = D * C + B;
unq = unq ^ A;
unq = (A & 0x80) | (unq >> 2);

注意,第一行中的乘法几乎是微不足道的,因为它只需要乘以0、1、2、3或4。

14. LDR端点解码

所使用的解码方法取决于颜色端点模式(Color Endpoint Mode, CEM)字段,该字段指定使用多少个值来表示端点。

CEM字段还指定了如何将n个未量化的颜色端点值v0到vn-1转换为两个RGBA颜色端点e0和e1。

HDR模式更复杂,不适合这个部分。它们将在下一节中进行记录。

这些方法可以总结如表159所示。
在这里插入图片描述
模式14的特殊之处在于alpha值是线性插值的,但颜色分量是对数插值的。这是唯一具有混合模式操作的端点格式,如果在LDR模式中遇到,将返回错误值。

将不同的LDR端点模式解码如下:
详见:https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html#_ldr_and_hdr_modes

15. HDR端点解码

16. 权重解码

权重信息以比特流的形式存储,从数据块中的最高位开始向下增长。因此,流中的第n位就是数据块中的第127-n位。

对于权重网格中的每个位置,一个值(在指定范围内)被打包到流中。它们以栅格模式排序,从位置(0,0,0)开始,X维度增长最快,Z维度增长最慢。如果选择双平面模式,则对每个位置同时发射两个权重,先平面0,再平面1。

17. 权重去量化

每个权重平面被指定为给定范围内的整数序列。这些值使用整数序列编码打包。

一旦解包,这些值必须从它们的存储范围中去量化,返回到0…64的标准范围。这样做的过程类似于颜色端点去量化。

首先,我们将实际存储的权重值去量化到0…63的范围。

对于仅位表示,这是从值的最高有效位进行简单的位复制。
对于基于三位数或五位数的表示,这涉及到一组位操作和调整,以避免全宽度乘法器的开销。
对于没有附加位的表示,结果如表167所示。
在这里插入图片描述
对于其他值,我们计算位操作过程的初始输入。它们分别表示为A(7位)、B(7位)、C(7位)和D(3位),使用表168所示的范围进行解码。
在这里插入图片描述
These are then processed as follows:

unq = D * C + B;
unq = unq ^ A;
unq = (A & 0x20) | (unq >> 2);

18. 权重加密

去量化后的权重进行权重选择和填充。填充方法用于根据存储的权重网格数组(可能是不同的大小)中的权重计算纹素位置的权重。下面的过程必须严格遵循,以确保位精确的结果。

19. 权重的应用程序

一旦计算出texel的有效权重i,颜色端点就会被插值和扩展。
对于LDR端点模式,每个颜色分量C由对应的8位端点分量C0和C1计算
。。。

20. 双平面解码

如果禁用双平面模式,则使用相同的权重值插值所有端点组件。
如果启用双平面模式,则每个texel存储两个权重。然后选择一个分量来使用第二个权重进行插值,而不是第一个权重。然后将第一个权重用于所有其他组件。

要特别处理的组件使用2位颜色组件选择器(CCS)字段表示,如表170所示。
在这里插入图片描述
CCS位直接存储在一个可变位置,在权重位和任何额外的CEM位之下。

21. 分区模式生成

当多个分区处于活动状态时,为每个纹素位置分配一个分区索引。这个分区索引是使用种子(分区模式索引)、纹素在块中的x、y、z位置以及分区的数量来计算的。如果块中的texel数量小于31,则设置一个额外的参数small_block为1,否则设置为0。

为了支持3D纹理,这个函数被指定为x, y和z。对于2D纹理和纹理切片,z将始终为0。

全分区选择算法如下:

int select_partition(int seed, int x, int y, int z,
                     int partitioncount, int small_block)
{
    if( small_block ){ x <<= 1; y <<= 1; z <<= 1; }
    seed += (partitioncount-1) * 1024;
    uint32_t rnum = hash52(seed);
    uint8_t seed1  =  rnum        & 0xF;
    uint8_t seed2  = (rnum >>  4) & 0xF;
    uint8_t seed3  = (rnum >>  8) & 0xF;
    uint8_t seed4  = (rnum >> 12) & 0xF;
    uint8_t seed5  = (rnum >> 16) & 0xF;
    uint8_t seed6  = (rnum >> 20) & 0xF;
    uint8_t seed7  = (rnum >> 24) & 0xF;
    uint8_t seed8  = (rnum >> 28) & 0xF;
    uint8_t seed9  = (rnum >> 18) & 0xF;
    uint8_t seed10 = (rnum >> 22) & 0xF;
    uint8_t seed11 = (rnum >> 26) & 0xF;
    uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;

    seed1  *= seed1;    seed2  *= seed2;
    seed3  *= seed3;    seed4  *= seed4;
    seed5  *= seed5;    seed6  *= seed6;
    seed7  *= seed7;    seed8  *= seed8;
    seed9  *= seed9;    seed10 *= seed10;
    seed11 *= seed11;   seed12 *= seed12;

    int sh1, sh2, sh3;
    if( seed & 1 )
        { sh1 = (seed&2 ? 4:5); sh2 = (partitioncount==3 ? 6:5); }
    else
        { sh1 = (partitioncount==3 ? 6:5); sh2 = (seed&2 ? 4:5); }
    sh3 = (seed & 0x10) ? sh1 : sh2:

    seed1 >>= sh1; seed2  >>= sh2; seed3  >>= sh1; seed4  >>= sh2;
    seed5 >>= sh1; seed6  >>= sh2; seed7  >>= sh1; seed8  >>= sh2;
    seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3;

    int a = seed1*x + seed2*y + seed11*z + (rnum >> 14);
    int b = seed3*x + seed4*y + seed12*z + (rnum >> 10);
    int c = seed5*x + seed6*y + seed9 *z + (rnum >>  6);
    int d = seed7*x + seed8*y + seed10*z + (rnum >>  2);

    a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F;

    if( partitioncount < 4 ) d = 0;
    if( partitioncount < 3 ) c = 0;

    if( a >= b && a >= c && a >= d ) return 0;
    else if( b >= c && b >= d ) return 1;
    else if( c >= d ) return 2;
    else return 3;
}

正如前面所观察到的,比特选择在硬件中比在C中更容易表达。
种子使用哈希函数hash52()展开,其定义如下:

uint32_t hash52( uint32_t p )
{
    p ^= p >> 15;  p -= p << 17;  p += p << 7; p += p <<  4;
    p ^= p >>  5;  p += p << 16;  p ^= p >> 7; p ^= p >> 3;
    p ^= p <<  6;  p ^= p >> 17;
    return p;
}

这假定所有操作都作用于32位值

22. 数据大小确定

没有显式指定用于表示颜色端点的数据的大小。相反,它由块模式和分区数量决定,如下所示:
。。。

23. Void-Extent块

空白范围块是用单一颜色编码的块。它还指定了关于超出该块的单色区域范围的一些附加信息,解码器可以选择性地使用这些信息来减少或防止冗余块获取。

在HDR的情况下,如果解码模式是decode_rgb9e5,那么在转换为共享指数格式之前,任何负颜色分量值都被设置为0(如第23.19节所述)。

2D Void-Extent块的布局如表171所示。

在这里插入图片描述

24. 非法编码

25. LDR配置文件支持

为了简化验证和加速采用,完整的ASTC规范已经提供了一个仅限ldr的子集。
LDR配置文件的实现必须满足以下要求:

26. HDR配置文件支持

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值