ARM霓虹内在函数的深度变换

我试图绕过NEON内在函数,并认为我可以从一个例子开始并提出一些问题。

在这个实验中,我想将32位RGB转换为16位BGR。 将以下代码转换为使用NEON内在函数会有什么好的开始? 我在这里遇到的问题是16bit与我能看到的任何内在都不匹配。 有16×4 16×8等等。但我只是运气不好,围绕着我需要如何解决这个问题。 有小费吗?

这是我试图转换的代码。

typedef struct { uint16_t b:5, g:6, r:5; } _color16; static int depth_transform_32_to_16_c (VisVideo *dest, VisVideo *src) { int x, y; int w; int h; _color16 *dbuf = visual_video_get_pixels (dest); uint8_t *sbuf = visual_video_get_pixels (src); uint16x8 int ddiff; int sdiff; depth_transform_get_smallest (dest, src, &w, &h); ddiff = (dest->pitch / dest->bpp) - w; sdiff = src->pitch - (w * src->bpp); for (y = 0; y < h; y++) { for (x = 0; x b = *(sbuf++) >> 3; dbuf->g = *(sbuf++) >> 2; dbuf->r = *(sbuf++) >> 3; dbuf++; sbuf++; } dbuf += ddiff; sbuf += sdiff; } return VISUAL_OK; } 

编辑:哦,由于某种原因我考虑16×3位,但我们正在考虑5,6,5 = 16位。 我意识到我需要轮class。 嗯。

NEON使用128位宽的寄存器,因此从概念上讲,您想要做的是读取4位32位RGB像素,对它们使用按位运算,最终写出16位像素。 一个观察结果是,为了获得最佳性能,您可能需要组合两个128位输入(8个32位像素)并生成一个128输出。 这将使您的内存访问更有效。

考虑这一点的另一种方法是你正在采用你的内循环内容并且并行执行四个像素。 使用原始代码有点困难的原因是因为你使用了位字段而隐藏了一些“魔法”。 如果您将C代码重写为32位到16位并使用shift /和/或代码将更自然地转换为SIMD,您可以直观地了解如何使用该上下文中的多个数据。

如果你只看每个32位组件 – > 16位转换:

 00000000RRRRRRRRGGGGGGGGBBBBBBBB 0000000000000000BBBBBGGGGGGRRRRR 

这可以帮助您可视化四个像素并行执行的操作。 转移,提取和组合。 您可以将其视为4个32位通道,但对于某些位操作,寄存器宽度无关紧要(例如,4个32位寄存器或8个16位寄存器是相同的)。

粗伪伪代码:

  • 读(向量加载 )128位寄存器= 4个32位像素。
  • 绿色(所有四个组件)移至右位位置。
  • 将绿色(使用AND掩码)屏蔽到另一个寄存器中。 (概念上仍然是4×32位“模式”)
  • 红色(所有四个组件)移至右位位置。
  • 掩盖红色到另一个寄存器。
  • 蓝色移至右位位置。
  • 掩盖蓝色到另一个寄存器。
  • 红色和蓝色移到右位位置。
  • 使用按位OR组合。
  • 现在,您将拥有4个16位值,32位对齐。 (到目前为止,所有概念仍为4×32位)
  • 重复另一组4像素。
  • 将这两组与NEON解压缩( VUZP )组合以产生一个128位/ 8像素寄存器。
  • 写(向量存储 )那些像素。