在硬件中高效实现 DXT1 纹理解压

Posted

技术标签:

【中文标题】在硬件中高效实现 DXT1 纹理解压【英文标题】:Efficiently implementing DXT1 texture decompression in hardware 【发布时间】:2019-06-06 09:43:31 【问题描述】:

DXT1 compression 设计用于在用于纹理采样器的硬件中快速解压缩。***文章说,在某些情况下,您可以计算出插值颜色的系数:

c2 = (2/3)*c0+(1/3)*c1

或重新排列:

c2 = (1/3)*(2*c0+c1)

但是,如果您重新排列上述等式,那么您最终总是不得不将某个值乘以 1/3(或除以 3,同样的交易更昂贵)。我觉得很奇怪,设计为在硬件中快速解压缩的纹理格式需要乘法或除法。我在其上实现 GPU 的 FPGA 只有有限的乘法资源,我想将这些资源保存到真正需要的地方。

所以我错过了什么吗?有没有一种有效的方法可以避免将颜色通道乘以 1/3?还是我应该只吃乘法的成本?

【问题讨论】:

【参考方案1】:

这可能是一种不好的想象方式,但是您可以通过使用连续一半(移位)的加法/减法来实现它吗?

由于您有 16 位,这使您能够通过连续的加法和减法获得相当准确的结果。

三分之一可以表示为

a(n+1) = a(n) +/- A>>1,其中,列表 [0, 0, 1, 0, 1, etc] 显示是否添加或减去移位结果。

我相信这叫做分数数学。

但是,在 FPGA 中,很难知道这是否真的比提供的原生 DSP 模块(例如 DSP48E1)更节能。

【讨论】:

我开始认为这是(我们的两种方式)一种很好的方式。我误读了文档,尽管您将比较作为 16 位整数进行,但您对每种颜色分别进行插值(使用 1/3 系数)。这意味着该值的最大大小为 6 位 [0-63]。因此,如果我小心的话,我可能会得到完全准确的结果,或者可能像这样获得所需结果的 +/-1。至于不使用 DSP 对我来说不是力量,只是它们的数量是有限的,我希望尽可能多地同时渲染图块,而 DSP 是我的限制因素。 (这是我正在制作的一个有趣的家庭项目 GPU,所以我可以选择忽略电源 - mikevine.net)【参考方案2】:

我能想到的最佳答案是我可以使用身份:

x/3 = sum(n=1 to infinity) (x/2^(2n))

然后取前 n 项。使用我得到的 4 个术语:

(x/4)+(x/16)+(x/64)+(x/256)

等于

x*0.33203125

这可能已经足够了。

这依赖于乘以 2 的固定幂在硬件中是免费的,然后我可以并行运行其中的 3 个加法。

感谢任何更好的答案。

** 编辑**:结合使用这个和@dyslexicgruffalo 的答案,我制作了一个简单的 c++ 程序,它迭代了各种序列并尝试了它们并记录了各种平均/最大错误。

我这样做是为了 0

最短的好序列(最大误差为 2,平均误差为 0.62)是 4 个操作:

1 + x/4 + x/16 + x/64.

最大误差为 1,平均误差为 0.32,但操作次数为 6 的最佳序列是:

x/2 - x/4 + x/8 - x/16 + x/32 - x/64.

对于 5 位值(红色和蓝色),最大值为 31*3,上述序列仍然不错,但不是最好的。它们是:

x/4 + x/8 - x/16 + x/32 [max error of 1, average 0.38]

1 + x/4 + x/16 [max error of 2, average of 0.68]

(而且,幸运的是,上述序列都没有猜到一个太大的答案,因此即使它们并不完美,也不需要钳位)

【讨论】:

道歉@Mike Vine,我想我们已经写了相同的答案!

以上是关于在硬件中高效实现 DXT1 纹理解压的主要内容,如果未能解决你的问题,请参考以下文章

GPU硬件加速

Unity ETC 压缩

高效的 OpenGL 纹理加载 gxbase

高效的串行数据驱动框架

高效的串行数据驱动框架

将矩形图像数据打包成方形纹理