5

我正在为跨平台 C 编程一个库,用于对网络摄像头图像进行各种处理。所有操作都是逐像素且高度可并行化的——例如应用位掩码、将颜色值乘以常数等。因此我认为我可以通过使用 SSE/SSE2 内在函数来获得性能。

但是,我遇到了数据格式问题。我的网络摄像头库将网络摄像头帧作为指针 (void*) 提供给包含 ABGR 或 BGR 格式的 24 位或 32 位字节像素的缓冲区。我一直将这些转换为 char* 以便 ptr++ 等行为正确。但是,所有 SSE/SSE2 操作都需要 __m128 或 __m64 数据类型中的四个整数或四个浮点数。如果我这样做(假设我已将缓冲区中的颜色值读入字符 r、g 和 b):

浮动像素[] = {(float)r, (float)g, {float)b, 0.0f};

然后加载另一个充满常量的浮点数组

浮动常量[] = {0.299, 0.587, 0.114, 0.0f};

将两个浮点指针都强制转换为 __m128,并使用 __mm_mul_ps 内在函数来执行 r * 0.299、g * 0.587 等……没有整体性能提升,因为周围的所有洗牌都占用了很多时间!

有没有人对我如何快速有效地将这些字节像素值加载到 SSE 寄存器有任何建议,以便我实际上通过对它们进行操作来获得性能提升?

4

3 回答 3

1

如果你愿意使用 MMX...

MMX 为您提供了一堆 64 位寄存器,可以将每个寄存器视为 8、8 位值。

就像您正在使用的 8 位值一样。

这里有一本很好的入门书。

于 2009-12-22T05:53:49.010 回答
1

我认为您的性能瓶颈可能来自铸造浮动,这是一个相当昂贵的操作。

如果我没记错的话,在大多数架构中,这种转换大约需要 50 个时钟周期......并且考虑到 FP 乘法可能需要的最坏情况,比方说,每个时钟大约 4 个时钟,在流水线中没有重叠,完成所有这些在 1 个周期中并行最多可以为您节省 15 个周期,仍然没有任何收益。

我肯定会一直使用相同的数字格式(在这种情况下为整数),如果像 Shmoopty 所说的那样使用 MMX 流式传输,那就更好了。

于 2009-12-22T15:52:32.523 回答
0

首先,您从中复制的数据(我猜它是由该void*指针指向的)应该是内存对齐的以获得最佳性能 - 如果不将其复制到内存对齐的缓冲区。

其次,一旦将数据移动到内存对齐的缓冲区中,您仍然可以使用 SSE2,这很容易 - 我在这里使用了代码,没有任何内在函数问题(但在程序集上有问题,详见此处)。

希望这很有用 - 我也处理图像并将它们存储unsigned char在主存储器中并将它们复制到 SSE2 寄存器(因为 R、G 或 B 在 0-255 之间变化是有意义的) - 但我使用了汇编代码,因为我觉得这更容易。

但是如果你想让它跨平台,我想使用内在函数会更干净。

祝你好运!

于 2009-12-22T15:19:29.723 回答