前段时间和大佬聊天的时候谈论到了libyuv为什么那么快?萌新emmmm几下后,表示google工程师是真牛逼....后来盲猜了一下可能是libyuv在编译的时候根据具体的abi做了特殊的优化或者对数据进行分块做多线程处理balabala......
libyuv之所以会有显著的性能提升是因为在编译的时候会根据具体的abi做指令集优化,在armv7平台上利用Neon指令集来做加速,在x86平台上使用SSE指令集来做加速,这些加速操作都是SIMD指令集的应用。
SIMD:单指令多数据流,能够复制多个操作数,并把它们打包在大型寄存器的一组指令集。以加法指令为例,单指令单数据(SISD)的CPU对加法指令译码后,执行部件先访问内存,取得第一个操作数;之后再一次访问内存,取得第二个操作数;随后才能进行求和运算。而在SIMD型的CPU中,指令译码后几个执行部件同时访问内存,一次性获得所有操作数进行运算。基于这个特性,SIMD特别适用于具有数据密集型运算的应用。
比如音视频应用中,对于视频处理,多采用OpenGL ES来利用显卡的并行计算能力来提高图像和视频的速度,而在音频方面则可以充分利用SIMD来提升信号处理(例如FFT/IFFT)的速度,从而增强用户体验。
目前市场上的Android和iOS设备多采用ARM架构的芯片,而在ARM Cortex-A和Cortex-R系列处理器的IP设计中引入了Arm Neon技术,Arm Neon技术是针对Arm处理器的高级单指令多数据(SIMD)体系结构扩展。
考虑到学习NEON成本过大,遇到需求首先考虑利用现有轮子,Arm-neon-enable-library有:
可以看到熟悉的Libyuv和Skia的身影
铺垫了半天,终于轮到文章的主角了--Ne10
Ne10是ARM官方推出的一个开源库,它提供了一系列通用的,基于ARM Neon架构并且经过深度优化的函数集合
源码地址:
https://github.com/projectNe10/Ne10
Ne10的目录结构如下:
主要模块为:文档(doc),头文件目录(inc),基础库(common),功能模块(modules)
其中功能模块包括:
编译
Ne10的编译依赖于cmake,所以要先安装它,mac上安装直接使用brew:
brew install cmake
具体平台的编译步骤可以查看doc目录下的building.md,其中编译android平台的静态或者动态库的操作步骤为:
其中有几个注意点:
1. Ne10的根目录下的CMakeLists.txt中默认编译输出的是静态库,如果需要.so则需要修改一下:
# default OFF
option(NE10_BUILD_SHARED "Build NE10 shared libraries" ON)
# default ON
option(NE10_BUILD_STATIC "Build NE10 static libraries" OFF)
2. 默认编译出来的.so文件是携带了VERSION的,类似编译早期的ffmpeg版本,也是需要手动取消VERSION
// Ne10/modules/CMakeLists.txt文件最后的if(NE10_BUILD_SHARED)分支
// 注释掉这一项 VERSION ${NE10_VERSION}
set_target_properties(NE10_shared PROPERTIES
OUTPUT_NAME "NE10"
CLEAN_DIRECT_OUTPUT 1
#VERSION ${NE10_VERSION}
LINKER_LANGUAGE C
)
3. 在GNUlinux_config.cmake文件中配置的交叉编译工具为gcc和g++,所以要注意选择合适的NDK版本或者手动修改GNUlinux_config.cmake使用clang
4. armv7下功能模块的支持是完善的,而aarch64下还未支持math和physics模块
// Ne10/CMakeLists.txt
#select functionalities to be compiled
if("${NE10_TARGET_ARCH}" STREQUAL "armv7")
# Math module has not been optimized for aarch64.
option(NE10_ENABLE_MATH "Build math functionalities to NE10" ON)
# Physics module has not been optimized for aarch64.
option(NE10_ENABLE_PHYSICS "Build physics functionalities to NE10" ON)
endif()
使用
拿到头文件(Ne10/inc目录下)和编译好的动态库,我们就可以在AS中使用了
1. 新建一个支持c++的工程,在cpp目录中导入动态库和头文件
2. CMakeLists.txt中的配置
3. 在自己的cpp中引入NE10.h就可以使用了,比如实现FFT,直接调用库的api就好
Demo 地址:
https://github.com/sifutang/Ne10Demo.git
最后
在Ne10/android目录下,官方提供了一个Demo工程来展示使用Arm Neon技术后性能有多大的提升,感兴趣的小伙伴可以自己跑一跑,关于性能提升的数据和Ne10的一些常用api和定义的基本数据结构的知识等后续文章再说。。。