如何在 ARM NEON 中将 uint8x8_t 加载到 float32x4 中?
Posted
技术标签:
【中文标题】如何在 ARM NEON 中将 uint8x8_t 加载到 float32x4 中?【英文标题】:How to load uint8x8_t into float32x4 in ARM NEON? 【发布时间】:2013-06-19 16:58:14 【问题描述】:我正在研究一种图像处理算法,并且正在研究使用 NEON 对其进行优化。 该算法包括将每个(RGBA,8bit)像素乘以一些权重,进行一些加法并最终转换回 uint8_t 值。 我遇到的第一个问题是如何有效地加载单个 uint8_t 像素并将其转换为 NEON 的 float32x4_t。我在参考中搜索了合适的转换,但找不到合适的,所以我求助于这个丑陋的代码:
const uint8_t* psrc = ...; // pointer to image data
float rgba[4];
for (int c = 0; c < 4; ++c)
rgba[c] = *psrc++;
float32x4_t srcpix = vld1q_f32(rgba);
任何人都可以为此建议一种“更清洁”的方法吗?
编辑: 所以想出了这个,还是觉得很麻烦:
uint8x8_t srcu8 = vld1_u8(psrc);
uint16x8_t srcu16x8 = vmovl_u8(srcu8);
uint16x4_t srcu16x4 = vget_low_u16(srcu16x8);
uint32x4_t srcu32x4 = vmovl_u16(srcu16x4);
srcpix = vcvtq_f32_u32(srcu32x4);
【问题讨论】:
【参考方案1】:所以你想将它们转换为浮点数以进行一些算术并将结果转换回整数?这与人们所说的优化正好相反。
在 NEON 真正闪耀的地方坚持使用定点算法。
我几乎无法想象在处理每个通道的大小(和精度)仅为 8 位的 ARGB 格式时转换为浮点数会有意义的任何情况。
显然,您试图让 NEON 只进行来回转换,而浮点运算由 ARM 完成,但这正是使用 NEON 的错误方式。
适当的 NEON 优化功能应让 NEON 自行处理数据加载、算术和数据存储。如果操作正确,我相信 NEON 版本的运行速度将比您当前的版本快 20 倍以上,速度接近 memcpy。 - NEON 的定点运算功能非常强大。
请透露更多信息,您正在尝试做什么。也许我可以帮忙。
【讨论】:
嘿,感谢 cmets - 我正在尝试 NEON 优化,但我确实觉得我在黑暗中刺伤。在我的 C 参考 impl 中,我将 RGBA 像素的每个通道乘以相同的浮点权重。我认为使用 NEON 指令来做到这一点(vmlaq_n_f32)可能会有所帮助。你是说浮点操作无论如何都在 ARM 上运行? 在这里我透露更多信息:):***.com/questions/17206315/…【参考方案2】:VTBX
查表指令可以在单个操作中进行无符号 8 位到 32 位扩展,但不幸的是输出是单个霓虹灯寄存器(将是 uint32x2_t
),所以要“填充”uint32x4_t
你需要调用它两次。对于uint8x8_t
源的所有八个字节,您必须这样做:
uint8x8_t bvec = vld1_u8(psrc);
uint8x8x4_t tbl =
0, -1, -1, -1, 1, -1, -1, -1 ,
2, -1, -1, -1, 3, -1, -1, -1
4, -1, -1, -1, 5, -1, -1, -1
6, -1, -1, -1, 7, -1, -1, -1
;
uint32x4_t ivec[2] =
vreinterpret_u32_u8(vtbx1_u8(tbl[0], bvec, 0)),
vreinterpret_u32_u8(vtbx1_u8(tbl[1], bvec, 0))
,
vreinterpret_u32_u8(vtbx1_u8(tbl[2], bvec, 0)),
vreinterpret_u32_u8(vtbx1_u8(tbl[3], bvec, 0))
;
float32x4_t vec[2] = vcvtq_f32_u32(ivec[0]), vcvtq_f32_u32(ivec[1]) ;
我认为它的说明并不比您找到的方法少。查找表也将来自内存,因此它可能会更慢。然后还需要vreinterpret...
...这是一个免费操作,但看起来很粗糙。
【讨论】:
【参考方案3】:据我所知,NEON
仅支持 32 位转换(使用vcvt_...()
,您可以在float32x4_t
和int32x4_t
(例如)之间进行转换)。因此,您需要将uint8x8_t
转换为uint32x4x2_t
,然后将vcvt
用于uint32x4x2_t
的两半。
编辑: 不幸的是,我无法为您提供代码,因为我没有使用它很多时间并且不记得命令。
【讨论】:
感谢您的快速回复,我想出了一个不同的版本,似乎与您的方法相似。对我来说,它看起来仍然有很多扩展和转换.. @avish 跟我说的一模一样以上是关于如何在 ARM NEON 中将 uint8x8_t 加载到 float32x4 中?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ARM NEON 内在函数将 u8 掩码转换为 u32 掩码?
ARM NEON 内部函数将 D(64 位)寄存器转换为 Q(128 位)寄存器的低半部分,而上半部分未定义
ARM NEON Intrinsics:将向量的值限制为 0-255