如何在ARM NEON中将uint8x8_t加载到float32x4中?

3

我正在开发一种图像处理算法,希望通过使用NEON进行优化。该算法包括将每个(RGBA,8位)像素乘以某个权重,进行一些加法,最后转换回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);
3个回答

1
< p > VTBX 表查找指令可以在单个操作中执行无符号8位到32位的扩展,但不幸的是输出是单个NEON寄存器(应该是uint32x2_t),因此要"填充"一个uint32x4_t,您需要调用它两次。对于uint8x8_t源的所有8个字节,您需要执行以下操作:

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...,虽然这是一个免费操作,但看起来很糟糕。

1

所以你想将它们转换为浮点数进行一些算术运算,然后将结果转换回整数?这恰恰是人们所谓的优化的相反。

坚持使用固定点算术,其中NEON真正发挥作用。

我几乎无法想象在处理每个通道仅为8位(并且精度也是如此)的ARGB格式时,将其转换为浮点数会有任何意义。

显然,您正在尝试让NEON只做来回转换,而浮点算术由ARM完成,但这恰恰是利用NEON的错误方式。

适当的NEON优化函数应该让NEON自己处理数据加载、算术和数据存储。如果做得正确,我相信NEON版本将比您当前的版本快20倍以上,接近memcpy速度。 - NEON在固定点算术方面非常强大。

请透露更多信息,您正在尝试做什么。也许我可以帮忙。


嘿,感谢您的评论 - 我正在尝试使用NEON优化,并且感觉自己像在摸索。在我的C参考实现中,我将RGBA像素的每个通道乘以相同的浮点权重。我认为使用NEON指令来完成这个操作(vmlaq_n_f32)可能会有所帮助。您是说ARM上已经运行了浮点运算? - avish
在这里,我透露更多信息 :):http://stackoverflow.com/questions/17206315/image-resizing-using-arm-neon - avish

0
据我所知,NEON仅支持32位转换(使用vcvt_...()可以在float32x4_tint32x4_t之间进行转换(例如))。因此,您需要将uint8x8_t转换为uint32x4x2_t,然后对uint32x4x2_t的两个半部分都使用vcvt编辑: 很遗憾,我无法提供代码,因为我没有花太多时间与它一起工作,也记不住命令。

谢谢您的快速回复,我想出了一个不同的版本,似乎与您的方法相似。对我来说,它仍然看起来需要很多扩展和转换。 - avish
@avish,这正是我所谈论的内容。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接