C语言 在浮点像素上使用SSE,只有3个颜色组件



我正在创建一个结构体来存储图像中的单个RGB像素。

struct Pixel
{
    // color values range from 0.0 to 1.0
    float r, g, b;
}__attribute__((aligned(16));

我想使用128位SSE指令来做加法,乘法等事情。这样我就可以一次对所有3个颜色通道执行操作。因此,我的SSE寄存器中的第一个打包浮动将是红色的,然后是绿色的,然后是蓝色的,但我不太确定将进入我的第四个寄存器。我真的不关心额外的32位填充中有哪些位。当我将一个像素加载到SSE寄存器中时,我会想象它包含零或垃圾值。这有问题吗?我是否应该添加第四个alpha通道,即使我真的不需要它?我认为这是一个问题的唯一方式是,如果我除以一个像素,在第四个位置上有一个零值,或者我正在对负数取根,等等。

整数操作对于未初始化的值完全没有问题,因为延迟从不依赖于数据。浮点数是不同的。一些fpu在异常、nan和无穷大(在任何一个矢量元素中)上减慢速度。

Intel Nehalem和早期版本在使用异常输入/输出和FP下流/溢出进行数学运算时减慢了很多。Sandybridge有一个不错的FPU,可以快速添加/删除任何输入(根据Agner Fog的指令表),但乘法仍然会减慢速度。

加/减/乘对于零是可以的,但潜在的问题是未初始化的垃圾可能表示NaN或其他东西。

除法时要小心,不要除以0。这甚至可能引发FPU异常,具体取决于硬件设置。

所以,保持未使用的元素为零可能是一个好主意。这取决于您最初生成内容的方式,实现起来可能相当便宜。(例如movd/pinsrd/pinsrd(或insertps)将三个32位元素放入向量中,初始movd将高位96b归零)

一个解决方法是在第4个元素中存储蓝色通道的第二个副本。(或者用最方便的方法。)你可以用movsldup (SSE3)/movlps加载矢量。在movsldup之后,您的寄存器将保存{ b b r r }movlps将重新加载较低的64位,所以你有{ b b g r }。(顺便说一句,这相当于movsd。)或者,如果shuffle端口不如load端口繁忙,则执行一次16B加载,然后进行shuffle。(movsldup在英特尔cpu上是一个运行在加载端口上的单up,即使它内置了复制。)

另一种选择是将像素打包成12字节,这样16B的加载将获得下一个像素的一个组件。根据你正在做的事情,重叠存储可能会破坏下一个像素的一个元素,也可能不会。在存储电流之前加载下一个像素可以在一些操作中解决这个问题。缓存或带宽限制是很容易的,所以节省1/4的空间,偶尔的缓存线分割加载/存储的小成本可能是值得的。

最新更新