版权声明:涉猎过的知识都像是不断汇入大海的涓涓细流,你怎么知道是哪条汇入的溪流让海洋成为海洋呢【转载请注明出处】 https://blog.csdn.net/panda1234lee/article/details/85179775
参考原文:
目前市面上主流的旗舰android手机搭载的Soc都是64位的CPU,常见的armv7指令集的公版架构如Cortex-A8,Cortex-A9,Cortex-A15,常见的armv8指令集的公版架构如Cortex-A53,Cortex-A57,Cortex-A72,Cortex-A73。arm架构的CPU从armv7a开始已经支持neon(可选项),从而实现并行计算功能。armv8a还具备32个128neon寄存器,并且支持双精度浮点数。
下面为我添加的代码注释 :
void method_argb2gray_neon(AndroidBitmapInfo info, void *pixels) {
// Gray = (R*38 + G*75 + B*15) >> 7
TickMeter tm3;
tm3.start();
unsigned short *dst = (unsigned short *) pixels;
unsigned char *src = (unsigned char *) pixels;
uint8x8_t r = vdup_n_u8(38); // 将一个标量扩展城向量 8 bit * 8
uint8x8_t g = vdup_n_u8(75);
uint8x8_t b = vdup_n_u8(15);
uint16x8_t alp = vdupq_n_u16(255 << 8);
uint16x8_t temp;
uint8x8_t gray;
uint8x8x4_t argb;
uint16x8_t high;
uint16x8_t low;
uint16x8x2_t res;
int i, size = info.height * info.width / 8;
// 暂不考虑不能被 8 整除的情况
for (i = 0; i < size; ++i) {
// 获取r、g、b值,计算灰度值
argb = vld4_u8(src); // 从内存中加载数据(以 AOS 存储)到 4 个向量(8 bit * 8)中(SOA)
temp = vmull_u8(argb.val[1], r); // vmul 指令
temp = vmlal_u8(temp, argb.val[2], g); // vmla 指令
temp = vmlal_u8(temp, argb.val[3], b);
gray = vshrn_n_u16(temp, 7); // vshrn_n_u16 会在做右移 7 位的同时将2字节无符号型转成1字节无符号型
src += 8 * 4; // src 移到下个位置
// 赋值 4 通道argb
// 先用 vmovl_u8 (长指令)符号扩展或零扩展双字向量中的每个元素到其原始长度的两倍
// vqmovn_* 为窄指令
high = vorrq_u16(alp, vmovl_u8(gray)); // 再用 vorrq_u16 按位或运算
low = vorrq_u16(vshlq_n_u16(vmovl_u8(gray), 8), vmovl_u8(gray)); // 注意这里是左移
res = vzipq_u16(low, high); // 两个向量的元素交错打包成一个新向量
vst1q_u16(dst, res.val[0]); // 存储一个向量(res 的前半部分)到内存(16bit*8)
dst += 8;
vst1q_u16(dst, res.val[1]);
dst += 8;
}
tm3.stop();
LOGI("method_argb2gray_neon time: %lf", tm3.getTimeMilli());
LOGI(" \n");
}
值得注意的是:Android 的 Bitmap 默认是按 ARGB 顺序存储的。 vzipq_u16 函数执行的结果如下:
可以看出 res[0] 和 res[1] 两个向量分别由 low, hight 两个向量一前一后交错打包而成。
程序运行效果如下:
最后记得将 Build Variants 设置为 release(默认为 debug)