【问题标题】:Processing byte pixels with SSE/SSE2 intrinsics in C在 C 中使用 SSE/SSE2 内在函数处理字节像素
【发布时间】:2010-12-28 22:46:25
【问题描述】:

我正在为跨平台 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 寄存器中,以便我真正通过对它们进行操作获得性能提升,是否有人有任何建议?

【问题讨论】:

  • 是否需要进行浮点运算?还有 MMX,它适用于整数类型。
  • 确实如此。如果您正在处理整数类型,则应使用整数 SIMD 指令,而不是浮点指令。
  • 我不需要做任何浮点运算,所以你是对的,MMX 整数指令就足够了。
  • 但是,如何有效地将原始字节像素缓冲区转换为整数以便我可以一次 SIMD 四个的问题仍然存在。
  • 请记住为您的 __m128 和 __m64 数据类型使用对齐的缓冲区。至少在某些平台上,它们的对齐要求比 C 编译器所能保证的更严格。

标签: c optimization image-processing webcam


【解决方案1】:

如果你愿意使用 MMX...

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

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

有一本很好的入门书here

【讨论】:

  • 这实际上并不是最好的建议,因为 MMX 已经过时,而 SSE2 的执行速度几乎是 MMX 的两倍
【解决方案2】:

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

其次,一旦你将数据移动到内存对齐的缓冲区中,你仍然可以使用 SSE2,这很容易 - 我使用 code here 没有任何内在函数问题(但在程序集方面有问题,详细 @987654322 @)。

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

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

祝你好运!

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2013-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 2015-11-23
      • 2010-10-14
      • 2011-08-06
      • 1970-01-01
      相关资源
      最近更新 更多