【本文正在参加2023年第一期优质创作者激励计划】
在OpenHarmony的各部件适配中,GPU适配是公认的最难,首先原厂安卓的驱动是没办法用的,后来又因为OpenHarmony3.1开始启用了自研的Rosen合成框架取代了Weston合成框架,原来能直接用的开源图形驱动现在也不能直接用了,新版的OpenHarmony需要图形驱动要额外对接OpenHarmony的接口,采用闭源驱动要得到原厂的支持,这个目前走不通,所以第三方设备要启用GPU加速只能选择采用开源的Mesa3d驱动,所幸OpenHarmony提供了一份mesa3d的参考实现,也能使OpenHarmony流畅丝滑了,这篇文章我打算分享一下我移植适配GPU的相关经验,希望能帮到大家。
同时在此说明一下,这些知识基本都是我在网上自学得来,不是图形专家,没有深入学习过图形方面的知识,对某些图形的专业名词或者某些概念可能会用词不准确或者解释错误,请大家谅解。
1.OpenHarmony图形显示移植适配思路
首先借用一张OpenHarmony图形能力的视图,我们可以了解到目前OpenHarmony当前以及未来支持的能力情况。
之前我们点亮屏幕采用的是CPU合成+CPU渲染的技术路径,在【2022.3】的时候开始支持的,同时采用OpenGLES接口的GPU合成+GPU渲染也在3.2Beta4【2022.12】的时候实现了,基于这个版本才能实现完整的GPU加速,可以期待一下【2023.9】基于Vulkan接口的GPU加速。
经过上面简单介绍,可能大家对GPU图形适配还是毫无头绪,因为这是在引申图形适配的一些前置知识,在此我简单总结一下适配OH图形需要关注两个大点:合成和渲染,下面是简单的解释。
1.合成:计算处理图层叠加关系。
2.渲染:生成需要显示的色彩数据(buffer)。
以上是我的个人总结,可能不准确,大致先这样分,这样后面好进行讲解移植适配的思路。
下面进入正题,因为移植GPU比较复杂,不可能一部到位,在此我拆开进行逐步实现,以便出现问题时能快速定位问题点出现在哪一部分,拆分思路如下:
1.不启用GPU功能,在CPU合成+CPU渲染的环境下,确认GPU驱动正常工作
2.启用部分GPU功能,在CPU合成+GPU渲染的环境下,确认GPU能正确渲染
3.启用GPU合成+GPU渲染,加速OpenHarmony图形显示
2.编译开源GPU驱动Mesa3d
2.1编译mesa3d
2.1.1安装依赖
首先安装编译需要的依赖:
sudo apt-get install -y meson cmake llvm
python3 -m pip install meson==0.62.0
python -m pip install --upgrade pip
pip install mako atomic markupsafe
2.1.2版本变更失效路径修正
OpenHarmony源码中以及带有适配过的mesa3d库,但是因为长时间没有维护,部分配置需要更新:
ohos/pkgconfig_template/gbm.pc
libdir=${ohos_project_dir}/device/rockchip/hardware/gpu
includedir=${ohos_project_dir}/device/rockchip/hardware/gpu/include
Cflags: -I${ohos_project_dir}/device/rockchip/hardware/gpu/include
替换为:
libdir=${ohos_project_dir}/device/soc/qualcomm/msm8998/hardware/gpu
includedir=${ohos_project_dir}/device/soc/qualcomm/msm8998/hardware/gpu/include
Cflags: -I${ohos_project_dir}/device/soc/qualcomm/msm8998/hardware/gpu/include
ohos/pkgconfig_template/libdrm.pc
libdir=${ohos_project_dir}/out/ohos-arm-release/graphic/graphic_standard/
修正为:
libdir=${ohos_project_dir}/out/ohos-arm-release/thirdparty/libdrm/
ohos/pkgconfig_template/libhilog.pc
includedir=${ohos_project_dir}/foundation/graphic/standard/rosen/include/backstore/nativewindow
修正为:
includedir=${ohos_project_dir}/base/hiviewdfx/hilog/interfaces/native/innerkits/include
ohos/pkgconfig_template/libjpeg.pc
libdir=${ohos_project_dir}/out/ohos-arm-release/obj/third_party/libjpeg/
includedir=${ohos_project_dir}/third_party/libjpeg
Libs: -L${libdir} -ljpeg_static
修正为:
libdir=${ohos_project_dir}/out/ohos-arm-release/obj/third_party/libjpeg-turbo/
includedir=${ohos_project_dir}/third_party/libjpeg-turbo
Libs: -L${libdir} -llibturbojpeg_static
ohos/pkgconfig_template/libpng.pc
libdir=${ohos_project_dir}/out/ohos-arm-release/common/graphic_standard/
修正为:
libdir=${ohos_project_dir}/out/ohos-arm-release/thirdparty/libpng/
ohos/meson_cross_process.py
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/clang/10.0.1/lib/arm-linux-ohos',
'-Lproject_stub/prebuilts/clang/ohos/linux-x87_64/llvm/lib/arm-linux-ohos/c++',
修正为:
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/clang/current/lib/arm-linux-ohos',
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/arm-linux-ohos/c++',
以上是因为版本变迁需要进行的修改,下面讲解适配新的GPU需要做的修改。
2.1.3驱动编译脚本64位适配
因为我适配小米6采用的是64位系统,官方的mesa库里面的脚本是32位的,这里我采用的方法是复制原版32位的两个相关脚本,修改为64位编译脚本。
复制ohos/build_ohos.py为ohos/build_ohos64.py
复制ohos/meson_cross_process.py为ohos/meson_cross_process64.py
修改gpu驱动名以及驱动搜索路径
ohos/build_ohos64.py
run_cross_pross_cmd = 'python3 ' + script_dir + '/meson_cross_process.py ' + sys.argv[1] + ' ' + sys.argv[2]
...
run_build_cmd += '-Dplatforms=ohos -Degl-native-platform=ohos -Ddri-drivers= -Dgallium-drivers=panfrost \
-Dvulkan-drivers= -Dgbm=enabled -Degl=enabled -Dcpp_rtti=false -Dglx=disabled -Dtools=panfrost -Ddri-search-path=/system/lib '
修改为:
run_cross_pross_cmd = 'python3 ' + script_dir + '/meson_cross_process64.py ' + sys.argv[1] + ' ' + sys.argv[2]
...
run_build_cmd += '-Dplatforms=ohos -Degl-native-platform=ohos -Ddri-drivers= -Dgallium-drivers=freedreno \
-Dvulkan-drivers= -Dgbm=enabled -Degl=enabled -Dcpp_rtti=false -Dglx=disabled -Dtools= -Ddri-search-path=/vendor/lib/chipsetsdk '
这里简单解释编译参数需要修改的三个地方
-Dgallium-drivers=panfrost -> freedreno
这里修改的是开源GPU驱动的名字,panfrost是arm mali gpu对应的开源驱动的名字,freedreno是高通gpu对应的开源驱动的名字。
-Dtools=
这个是加入编译某些可以查看gpu负载的工具,我不需要,而且加入之后编译报错,解决比较麻烦,暂时去掉了。
-Ddri-search-path=/system/lib -> /vendor/lib/chipsetsdk
这个是驱动so库放置的路径,原配置是3.1版本还没有soc分离思想,所以统一放置到system/lib下了,3.2采用了soc分离思想,soc驱动统一放置到vendor下了。
如果需要编译32位GPU驱动,只需要参考修改gpu驱动名以及驱动搜索路径即可。
meson_cross_process64.py
模板部分
修改【arm-linux-ohosmusl】为【aarch64-linux-ohosmusl】
去掉-march,-mtune等优化参数,最后修改为:
corss_file_content='''
[properties]
needs_exe_wrapper = true
c_args = [
'--target=aarch64-linux-ohosmusl',
'--sysroot=sysroot_stub',
'-fPIC']
cpp_args = [
'--target=aarch64-linux-ohosmusl',
'--sysroot=sysroot_stub',
'-fPIC']
c_link_args = [
'--target=aarch64-linux-ohosmusl',
'-fPIC',
'--sysroot=sysroot_stub',
'-Lsysroot_stub/usr/lib/aarch64-linux-ohos',
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/clang/current/lib/aarch64-linux-ohos',
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos/c++',
'--rtlib=compiler-rt',
]
cpp_link_args = [
'--target=aarch64-linux-ohosmusl',
'--sysroot=sysroot_stub',
'-Lsysroot_stub/usr/lib/aarch64-linux-ohos',
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/clang/current/lib/aarch64-linux-ohos',
'-Lproject_stub/prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos/c++',
'-fPIC',
'-Wl,--exclude-libs=libunwind_llvm.a',
'-Wl,--exclude-libs=libc++_static.a',
'-Wl,--exclude-libs=libvpx_assembly_arm.a',
'-Wl,--warn-shared-textrel',
'--rtlib=compiler-rt',
]
[binaries]
ar = 'project_stub/prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-ar'
c = ['ccache', 'project_stub/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang']
cpp = ['ccache', 'project_stub/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang++']
c_ld= 'lld'
cpp_ld = 'lld'
strip = 'project_stub/prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-strip'
pkgconfig = '/usr/bin/pkg-config'
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'armv8'
endian = 'little'
'''
另外generate_pc_file函数中需要添加多一行,把pkgconfig_template中的【ohos-arm】替换为【ohos-arm64】
raw_content = raw_content.replace("ohos_project_directory_stub", project_dir)
raw_content = raw_content.replace("ohos-arm-release", product_name)
添加:
raw_content = raw_content.replace("ohos-arm", "ohos-arm64")
2.1.4修改build_id获取函数
因为OpenHarmony在elf文件里面的note信息添加了一个ohos特有的标识符,导致mesa3d获取build_id的函数进行地址偏移计算的时候计算失误,需要修正build_id获取函数。
src/util/build_id.c
2.1.5mesa编译
soc目录下参照rockchip新建对应的qualcomm/msm8998/hardware/gpu目录,include内的头文件可复制rockchip下的文件。
修改完毕之后参照README_zh.md,在mesa3d目录下执行py脚本进行编译
python ohos/build_ohos64.py /home/diemit/ohos_beta5 sagit /home/diemit/ohos_beta5/third_party/mesa3d/
正常完成如下显示
3.OpenHarmony编译框架适配
复制编译出的lib到对应的soc/gpu目录下
cp build-ohos/src/gallium/targets/dri/libgallium_dri.so ../../device/soc/qualcomm/msm8998/hardware/gpu/lib64
cp build-ohos/src/egl/libEGL.so.1.0.0 ../../device/soc/qualcomm/msm8998/hardware/gpu/lib64
cp build-ohos/install/lib/libGLESv1_CM.so.1.1.0 ../../device/soc/qualcomm/msm8998/hardware/gpu/lib64
cp build-ohos/install/lib/libGLESv2.so.2.0.0 ../../device/soc/qualcomm/msm8998/hardware/gpu/lib64
cp build-ohos/install/lib/libgbm.so.1.0.0 ../../device/soc/qualcomm/msm8998/hardware/gpu/lib64
cp build-ohos/install/lib/libglapi.so.0.0.0 ../../device/soc/qualcomm/msm8998/hardware/gpu/lib64
添加对应的BUILD.gn,复制对应的so文件到vendor下,并创建软连接
import("//build/ohos.gni")
import("//build/ohos/ndk/ndk.gni")
ohos_prebuilt_shared_library("mesa_egl") {
source = "lib64/libEGL.so.1.0.0"
install_enable = true
part_name = "qualcomm_products"
install_images = [ chipset_base_dir ]
relative_install_dir = "chipsetsdk"
symlink_target_name = [
"libEGL.so",
"libEGL_impl.so",
]
}
ohos_prebuilt_shared_library("mesa_gbm") {
source = "lib64/libgbm.so.1.0.0"
install_enable = true
part_name = "qualcomm_products"
install_images = [ chipset_base_dir ]
relative_install_dir = "chipsetsdk"
symlink_target_name = [
"libgbm.so.1",
"libgbm.so",
]
}
ohos_prebuilt_shared_library("mesa_glapi") {
source = "lib64/libglapi.so.0.0.0"
install_enable = true
part_name = "qualcomm_products"
install_images = [ chipset_base_dir ]
relative_install_dir = "chipsetsdk"
symlink_target_name = [
"libglapi.so.0",
"libglapi.so",
]
}
ohos_prebuilt_shared_library("mesa_glesv1") {
source = "lib64/libGLESv1_CM.so.1.1.0"
install_enable = true
part_name = "qualcomm_products"
install_images = [ chipset_base_dir ]
relative_install_dir = "chipsetsdk"
symlink_target_name = [
"libGLESv1.so",
"libGLESv1_impl.so",
]
}
ohos_prebuilt_shared_library("mesa_glesv2") {
source = "lib64/libGLESv2.so.2.0.0"
install_enable = true
part_name = "qualcomm_products"
install_images = [ chipset_base_dir ]
relative_install_dir = "chipsetsdk"
symlink_target_name = [
"libGLESv2.so",
"libGLESv2_impl.so",
"libGLESv3.so",
"libGLESv3_impl.so",
]
}
ohos_prebuilt_shared_library("libgallium_dri") {
source = "lib64/libgallium_dri.so"
install_enable = true
part_name = "qualcomm_products"
install_images = [ chipset_base_dir ]
relative_install_dir = "chipsetsdk"
symlink_target_name = [
"msm_dri.so",
]
}
group("mesa3d-lib") {
deps = [
":mesa_egl",
":mesa_gbm",
":mesa_glapi",
":mesa_glesv1",
":mesa_glesv2",
":libgallium_dri",
]
}
上层BUILD.gn中添加gpu对应的lib信息
import("//build/ohos.gni")
group("hardware_group") {
deps = [
"gpu:mesa3d-lib",
]
}
这里可能会有的小伙伴会疑惑,为啥要复制build-ohos/src/gallium/targets/dri/libgallium_dri.so而不是build-ohos/install/lib/dri/msm_dri.so,这也是我之前遇到的问题,后来我发现dri下面那一大堆都是同一个文件,都是通过脚本从libgallium_dri.so复制过来重命名的而已,所以直接复制libgallium_dri.so即可,libgallium_dri.so可以软连接成所有x_dri.so
另外为什么要软连接成x_impl.so,是因为OH的代码里面是用这个文件名进行lib的加载。
GPU适配这块我是在树莓派上首次验证成功,细节印象还比较深刻,所以打算详细讲解,篇幅会比较长,第一篇先讲解mesa编译的坑与解决办法,下篇讲解编译gpu测试程序,与gpu驱动程序的验证,敬请期待。
参考资料
Openharmony之GPU Mesa3D移植二(render 新框架)
本文作者:Diemit
想了解更多关于开源的内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com/#bkwz