Arm 如何使用neon创建1/255 f32矢量?
当我计算alpha混合时,我需要将8bit alpha转换为float,即alpha/255。因为霓虹灯没有除法,所以我想要alpha*1/255。那么如何在q1中生成1/255向量呢 vmov.f32 q1,#0.003921569始终报告错误 vmov.u32 q1#255Arm 如何使用neon创建1/255 f32矢量?,arm,neon,Arm,Neon,当我计算alpha混合时,我需要将8bit alpha转换为float,即alpha/255。因为霓虹灯没有除法,所以我想要alpha*1/255。那么如何在q1中生成1/255向量呢 vmov.f32 q1,#0.003921569始终报告错误 vmov.u32 q1#255 vrecpe.u32 q1,q1在f32中始终生成0。不是100%的答案,但由于到目前为止您还没有得到任何其他答案,我想我可以帮助您开始 根据我的记忆,可以使用vmov.f32加载的浮点子集非常有限,因此如果要加载任意浮
vrecpe.u32 q1,q1在f32中始终生成0。不是100%的答案,但由于到目前为止您还没有得到任何其他答案,我想我可以帮助您开始 根据我的记忆,可以使用
vmov.f32
加载的浮点子集非常有限,因此如果要加载任意浮点,需要将其存储为常量,并使用vldr
从常量池加载。像这样的事情应该可以做到
ldr r1,=floats
vldr.32 s0,[r1] @1/256
floats:
.float 0.003921569
“非100%”部分是因为我没有查看向量指令,所以我不确定您是否可以立即用此代码中的
q1
替换s0
,或者是否需要在加载后将s0
移动到q1
。不是100%答案,但既然你还没有找到其他人,我想我会帮你开始
根据我的记忆,可以使用vmov.f32
加载的浮点子集非常有限,因此如果要加载任意浮点,需要将其存储为常量,并使用vldr
从常量池加载。像这样的事情应该可以做到
ldr r1,=floats
vldr.32 s0,[r1] @1/256
floats:
.float 0.003921569
“非100%”部分是因为我没有研究向量指令,所以我不确定您是否可以立即用此代码中的
q1
替换s0
,或者是否需要在加载后将s0
移动到q1
。您很接近了。在取倒数之前,需要将255的向量转换为浮点
vmov.u32 q0, #255
vcvt.f32.u32 q0, q0
vrecpe.f32 q1, q0
请注意,
vrecpe
有少量错误,但应该足够接近alpha混合。您已经接近了。在取倒数之前,需要将255的向量转换为浮点
vmov.u32 q0, #255
vcvt.f32.u32 q0, q0
vrecpe.f32 q1, q0
请注意,vrecpe
有少量错误,但它应该足够接近alpha混合。可能是您想要的
float32x4_t x=vdupq_n_32(1.0f/255)
编译器负责计算常量,vdup指令将值广播到向量的所有四个通道
vdup指令支持霓虹灯标量和ARM寄存器作为源操作数
float32x4_t x=vdupq_n_32(1.0f/255)
编译器负责计算常量,vdup指令将值广播到向量的所有四个通道
vdup指令支持霓虹灯标量和ARM寄存器作为源操作数对于一个简单的alpha混合,您真的不必为浮点而烦恼。鉴于:
y = rint(x * a / 255.0);
对于任何8位输入,您可以使用以下方法获得相同的结果,而无需使用浮点:
t = x * a;
t += (t + 0x80) >> 8;
y = (t + 0x80) >> 8;
这有点像:
; given eight 8-bit x in d0, and eight 8-bit a in d1
vmull.u8 q2, d0, d1
vrsra.u16 q2, q2, #8
vrshrn.u16 d2, q2, #8
; result is eight 8-bit (s*a/255) in d2
通常,最后两个操作实现从16位输入到8位输出的整数除以255;但它们依赖于8乘8的有限范围。如果16位中间值不仅仅是乘法的结果,那么可能需要钳制,并且由于没有vqrsra
序列,因此序列变长:
; given eight 8-bit x in d0, and eight 8-bit a in d1
vmull.u8 q2, d0, d1
???
vrshr.u16 q3, q2, #8
vqadd.u16 q2, q2, q3
vqrshrn.u16 d2, q2, #8
; result is eight 8-bit (s*a/255) in d2
对于一个简单的alpha混合,您真的不必为浮点而烦恼。鉴于:
y = rint(x * a / 255.0);
对于任何8位输入,您可以使用以下方法获得相同的结果,而无需使用浮点:
t = x * a;
t += (t + 0x80) >> 8;
y = (t + 0x80) >> 8;
这有点像:
; given eight 8-bit x in d0, and eight 8-bit a in d1
vmull.u8 q2, d0, d1
vrsra.u16 q2, q2, #8
vrshrn.u16 d2, q2, #8
; result is eight 8-bit (s*a/255) in d2
通常,最后两个操作实现从16位输入到8位输出的整数除以255;但它们依赖于8乘8的有限范围。如果16位中间值不仅仅是乘法的结果,那么可能需要钳制,并且由于没有vqrsra
序列,因此序列变长:
; given eight 8-bit x in d0, and eight 8-bit a in d1
vmull.u8 q2, d0, d1
???
vrshr.u16 q3, q2, #8
vqadd.u16 q2, q2, q3
vqrshrn.u16 d2, q2, #8
; result is eight 8-bit (s*a/255) in d2
谢谢你的回答!是的,neon也可以加载常量。asm代码嵌入在C中,因此我也可以在C中计算浮点常量。但是neon不能像r0那样移动寄存器到Q0/S0,对吗?也许我必须将常量传递给变量,并将变量地址传递给嵌入的asm代码。@RichardZhao:当然,您可以从r0移动到s0<代码>vmov s0,r0。您还可以将预计算的常数直接加载到
s0
或q0
,这可能是您实际需要的。谢谢您的回答!是的,neon也可以加载常量。asm代码嵌入在C中,因此我也可以在C中计算浮点常量。但是neon不能像r0那样移动寄存器到Q0/S0,对吗?也许我必须将常量传递给变量,并将变量地址传递给嵌入的asm代码。@RichardZhao:当然,您可以从r0移动到s0<代码>vmov s0,r0。您还可以将预计算的常量直接加载到s0
或q0
,这可能是您实际需要的;使用16位定点算法可以获得足够的精度,这样可以在每个向量中保留更多的像素;您可以使用16位定点算法获得足够的精度,该算法允许在每个向量中保留更多像素。