使用ARM NEON内部函数添加alpha和permute
我正在开发一个iOS应用程序,需要相当快地从RGB->BGRA转换图像。如果可能的话,我想用霓虹灯。有没有比简单地分配组件更快的方法使用ARM NEON内部函数添加alpha和permute,arm,neon,intrinsics,cortex-a8,Arm,Neon,Intrinsics,Cortex A8,我正在开发一个iOS应用程序,需要相当快地从RGB->BGRA转换图像。如果可能的话,我想用霓虹灯。有没有比简单地分配组件更快的方法 void neonPermuteRGBtoBGRA(unsigned char* src, unsigned char* dst, int numPix) { numPix /= 8; //process 8 pixels at a time uint8x8_t alpha = vdup_n_u8 (0xff); for (int i=
void neonPermuteRGBtoBGRA(unsigned char* src, unsigned char* dst, int numPix)
{
numPix /= 8; //process 8 pixels at a time
uint8x8_t alpha = vdup_n_u8 (0xff);
for (int i=0; i<numPix; i++)
{
uint8x8x3_t rgb = vld3_u8 (src);
uint8x8x4_t bgra;
bgra.val[0] = rgb.val[2]; //these lines are slow
bgra.val[1] = rgb.val[1]; //these lines are slow
bgra.val[2] = rgb.val[0]; //these lines are slow
bgra.val[3] = alpha;
vst4_u8(dst, bgra);
src += 8*3;
dst += 8*4;
}
}
void neonPermuteRGBtoBGRA(无符号字符*src,无符号字符*dst,int numPix)
{
numPix/=8;//一次处理8个像素
uint8x8_t alpha=vdup_n_u8(0xff);
对于(int i=0;i这取决于编译器。例如,当我使用armcc(5.01)编译上面的代码并将其反汇编时,我得到的结果是这样的(我只是将循环放入,并将alpha赋值移到循环之外)
我在gcc中也得到了相同的执行时间
最后,我建议您要么反汇编二进制文件并检查编译器是否生成所需的内容,要么使用汇编
顺便说一句,如果你想进一步提高这个函数的执行时间,我建议你研究一下
arm的PLD(预加载数据)指令
利用循环中所有可能的霓虹灯指令,如循环展开(您会注意到,实际上带宽是从内存加载数据的时间)
ARMCC拆解也没有那么快:
- 它没有使用最合适的指令
- 它将VFP指令与霓虹灯指令混合在一起,每次都会引起巨大的打嗝
试试这个:
mov r2, r2, lsr #3
vmov.u8, d3, #0xff
loop:
vld3.8 {d0-d2}, [r0]!
subs r2, r2, #1
vswp d0, d2
vst4.8 {d0-d3}, [r1]!
bgt loop
bx lr
我建议的代码也没有完全优化,但进一步的“真正的”优化会严重损害可读性。所以我就到此为止。像你这样的用户是我如此喜欢堆栈溢出的原因。我甚至从未想过尝试ARM C编译器(这是我第一次如此精细地优化代码)。谢谢!无法将其转换为llvm内联程序集。必须将vmov.u8,d3,#0xff
更改为vmov.u8 d3,#0xff
。在使用上述函数包装时仍会导致崩溃。有什么想法吗?无效neonPermuteRGBtoBGRA_gas(unsigned char*src,unsigned char*dst,int numPix){(“movr2,r2,lsr#3\n”“vmov.u8 d3,#0xff\n”“循环:\n”“vld3.8{d0-d2},[r0]!\n”“subs r2,r2,#1\n”“vswp d0,d2\n”“vst4.8{d0-d3},[r1]!\n”“bgt循环\n”“bx lr\n”)}#endif
我并没有说armcc应该是最理想的。我想说的是,如果你使用NEON内部函数,你就掌握在编译器的手中。NEON和VFP寄存器库不是一样的吗?(1),所以在它们内部如何移动都不重要(2)@NickLee,如果你对最快的循环感兴趣,你应该做一些计时并停止使用内部函数。如果你这样做,我们可以讨论展开、预加载等。
40: f967 040f vld3.8 {d16-d18}, [r7]
44: 46d6 mov lr, sl
46: ecca 0b06 vstmia sl, {d16-d18}
4a: 9d02 ldr r5, [sp, #8]
4c: ed8d 8b1a vstr d8, [sp, #104]
50: 3718 adds r7, #24
52: e8be 000f ldmia.w lr!, {r0, r1, r2, r3}
56: f108 0801 add.w r8, r8, #1 ; 0x1
5a: c50f stmia r5!, {r0, r1, r2, r3}
5c: eddd 0b24 vldr d16, [sp, #144]
60: e89e 0003 ldmia.w lr, {r0, r1}
64: edcd 0b16 vstr d16, [sp, #88]
68: eddd 0b22 vldr d16, [sp, #136]
6c: edcd 0b18 vstr d16, [sp, #96]
70: e885 0003 stmia.w r5, {r0, r1}
74: ed9d 0b26 vldr d0, [sp, #152]
78: 9d03 ldr r5, [sp, #12]
7a: ed8d 0b14 vstr d0, [sp, #80]
7e: cd0f ldmia r5!, {r0, r1, r2, r3}
80: 46ae mov lr, r5
82: 465d mov r5, fp
84: c50f stmia r5!, {r0, r1, r2, r3}
86: e89e 000f ldmia.w lr, {r0, r1, r2, r3}
8a: e885 000f stmia.w r5, {r0, r1, r2, r3}
8e: 9501 str r5, [sp, #4]
90: 465d mov r5, fp
92: 2100 movs r1, #0
94: 2220 movs r2, #32
96: 4620 mov r0, r4
98: f7ff fffe bl 0 <memset>
9c: cd0f ldmia r5!, {r0, r1, r2, r3}
9e: 4625 mov r5, r4
a0: c50f stmia r5!, {r0, r1, r2, r3}
a2: f8dd c004 ldr.w ip, [sp, #4]
a6: e89c 000f ldmia.w ip, {r0, r1, r2, r3}
aa: e885 000f stmia.w r5, {r0, r1, r2, r3}
ae: ecd4 0b08 vldmia r4, {d16-d19}
b2: f946 000f vst4.8 {d16-d19}, [r6]
b6: 3620 adds r6, #32
b8: 45c8 cmp r8, r9
ba: dbc1 blt.n 40 <memset+0x40>
void neonPermuteRGBtoBGRA_gas(unsigned char* src, unsigned char* dst,
int numPix) {
asm(
" ASR r3,r2,#31\n"
" VMOV.I8 d1,#0xff\n"
" ADD r2,r2,r3,LSR #29\n"
" ASR r3,r2,#3\n"
" MOV r2,#0\n"
" CMP r3,#0\n"
" BLE end\n"
"loop:\n"
" VLD3.8 {d4,d5,d6},[r0]!\n"
" ADD r2,r2,#1\n"
" CMP r3,r2\n"
" VMOV.F64 d3,d5\n"
" VMOV.F64 d2,d6\n"
" VMOV.F64 d5,d1\n"
" VMOV.F64 d0,d4\n"
" VST4.8 {d2,d3,d4,d5},[r1]!\n"
" BGT loop\n"
"end:\n"
);
}
mov r2, r2, lsr #3
vmov.u8, d3, #0xff
loop:
vld3.8 {d0-d2}, [r0]!
subs r2, r2, #1
vswp d0, d2
vst4.8 {d0-d3}, [r1]!
bgt loop
bx lr