571
社区成员




本文档主要讲解在OpenHarmony中,Mesa3D的适配方法及原理说明。
环境说明:
OHOS版本: OpenHarmony 3.1-Release
内核版本: linux-5.10
硬件环境: Dayu200-rk3568
OpenHarmony对图形的渲染,支持CPU和GPU两种方式。为了支持流畅的用户体现,GPU适配是必不可少的。OpenHarmony使用GPU渲染,就必须依赖OpenGL接口。
OpenGL(Open Graphics Library) 开放图形库,是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(仅定义了接口及规范,没有实现)。OpenGL的高效性(利用了图形加速硬件)依赖于显示设备厂家的硬件及实现。
OpenGL API实现的方式又分为闭源及开源两种方式。闭源实现一般由设备厂家完成,这种方式充分保证了它的高效性,但移植起来比较麻烦。今天我们要重点介绍的是另外一种开源实现的方式:mesa3D。
Mesa3D 图形库就是OpenGL API的一种开源实现。新版本还支持OpenCL、OpenGL ES等等。Mesa3D对上提供标准的OpenGL接口,对下使用Gallium框架,屏蔽驱动差异。在RK3568中,panfrost对ARM GPU提供了非常好的开源驱动支持。
在RK3568 GPU 开源库mesa3D适配时,我们同时依赖了drm panfrost的实现。目前OpenHarmony 3.1-Release基线中,支持4.19及5.10两个Linux版本,而只有5.10才提供了对panfrost的支持。如果当前Linux版本不支持panfrost,那就需要升级内核版本,或者把panfrost移植到当前版本上。
RK3568开源GPU Mesa3D适配的方法主要分为下以三步:
以下是我们这次适配的框架示意图:
通过上图我们可以看出,一个大致的UI显示流程如下:
JS创建window->调用skia完成接口封装->调用mesa3D的OpenGL接口完成渲染->返回EglSurface数据->送到Dislay HDI的GFX合成->调用KMS完成数据转换->LCD硬件完成显示
从适配框架图可以看出,GPU适配,需要建立在Dislay HDI、DRM、LCD驱动完整的基础之上,否则Launcher没有启动,也不能确定适配是否完好。所以,在GPU适配之前,需要确保在CPU渲染的基础上,Launcher是能正常启动的。
CPU渲染修改方法:
foundation/graphic/standard/graphic_config.gni
} else if ("${product_name}" == "rk3566" || "${product_name}" == "rk3568") {
gpu_defines = [ "ACE_DISABLE_GL" ]
ace_enable_gpu = false
libgl = []
} else {
sudo apt-get install -y meson cmake llvm pkg-config
python3 -m pip install --upgrade pip
python3 -m pip install meson==0.62.0
pip install mako markupsafe
./build.sh --product-name rk3568 --build-target expat
git clone https://gitee.com/openharmony/third_party_mesa3d.git
cd third_party_mesa3d/
git checkout 68565a
python3 ohos/build_ohos.py ~/ohos/openHarmony/3.1-release rk3568 ~/ohos/openHarmony/3.1-release/third_party_mesa3d
cp build-ohos/src/egl/libEGL.so.1.0.0 ../device/hihope/hardware/gpu/
cp build-ohos/install/lib/libGLESv1_CM.so.1.1.0 ../device/hihope/hardware/gpu/
cp build-ohos/install/lib/libGLESv2.so.2.0.0 ../device/hihope/hardware/gpu/
cp build-ohos/install/lib/libgbm.so.1.0.0 ../device/hihope/hardware/gpu/
cp build-ohos/install/lib/libglapi.so.0.0.0 ../device/hihope/hardware/gpu/
cp build-ohos/src/gallium/targets/dri/libgallium_dri.so ../device/hihope/hardware/gpu/
cp build-ohos/install/lib/dri/panfrost_dri.so ../device/hihope/hardware/gpu/
内核的修改部分,主要是为了适配panfrost 开源GPU驱动部分,最简单的是在原厂家GPU的dts配置基础上修改。
out/kernel/src_tmp/linux-5.10/arch/arm64/boot/dts/rockchip/rk3568.dtsi
增加panfrost驱动名称
gpu: gpu@fde60000 {
- compatible = "arm,mali-bifrost";
+ compatible = "arm,mali-bifrost", "arm,mali-bifrost";
修改中断名称
- interrupt-names = "GPU", "MMU", "JOB";
+ interrupt-names = "gpu", "mmu", "job";
修改时钟名称
- clock-names = "clk_mali", "clk_gpu";
+ clock-names = "core", "bus";
其它ARM GPU可以参考以下配置选择相应的型号:
drivers/gpu/drm/panfrost/panfrost_drv.c
static const struct of_device_id dt_match[] = {
/* Set first to probe before the generic compatibles */
{ .compatible = "amlogic,meson-gxm-mali",
.data = &amlogic_data, },
{ .compatible = "amlogic,meson-g12a-mali",
.data = &amlogic_data, },
{ .compatible = "arm,mali-t604", .data = &default_data, },
{ .compatible = "arm,mali-t624", .data = &default_data, },
{ .compatible = "arm,mali-t628", .data = &default_data, },
{ .compatible = "arm,mali-t720", .data = &default_data, },
{ .compatible = "arm,mali-t760", .data = &default_data, },
{ .compatible = "arm,mali-t820", .data = &default_data, },
{ .compatible = "arm,mali-t830", .data = &default_data, },
{ .compatible = "arm,mali-t860", .data = &default_data, },
{ .compatible = "arm,mali-t880", .data = &default_data, },
{ .compatible = "arm,mali-bifrost", .data = &default_data, },
{}
};
out/kernel/src_tmp/linux-5.10/arch/arm64/configs/rockchip_linux_defconfig
#CONFIG_DRM_IGNORE_IOTCL_PERMIT=y 屏蔽忽略IOCTL权限(可选)
CONFIG_DRM_GEM_SHMEM_HELPER=y panfrost gem内存管理用到(必选)
CONFIG_DRM_SCHED=y GPU命令流调度接口,必须打开(必选)
CONFIG_DRM_PANFROST=y 打开panfrost功能(必选)
由于Mesa3D就是OpenGL的开源实现,所以so库的适配就是替换厂家提供的闭源GPU库。
device/hihope/hardware/gpu/BUILD.gn
# Copyright (C) 2021 HiHope Open Source Organization .
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("//build/ohos/ndk/ndk.gni")
ohos_prebuilt_shared_library("mesa_gbm") {
source = "libgbm.so.1.0.0"
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"libgbm.so.1",
"libgbm.so",
]
}
ohos_prebuilt_shared_library("mesa_egl") {
source = "libEGL.so.1.0.0"
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"libEGL.so.1",
"libEGL.so",
"libGLESv1.so",
]
}
ohos_prebuilt_shared_library("mesa_glapi") {
source = "libglapi.so.0.0.0"
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"libglapi.so.0",
"libglapi.so",
]
}
ohos_prebuilt_shared_library("mesa_glesv1") {
source = "libGLESv1_CM.so.1.1.0"
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"libGLESv1_CM.so.1",
"libGLESv1_CM.so",
]
}
ohos_prebuilt_shared_library("mesa_glesv2") {
source = "libGLESv2.so.2.0.0"
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"libGLESv2.so.2",
"libGLESv2.so",
]
}
ohos_prebuilt_shared_library("libgallium_dri") {
source = "libgallium_dri.so"
install_images = [ chipset_base_dir ]
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"libgallium_dri.so",
#"rockchip_dri.so",
]
}
ohos_prebuilt_shared_library("panfrost_dri") {
source = "panfrost_dri.so"
install_enable = true
subsystem_name = "hdf"
part_name = "display_device_driver"
symlink_target_name = [
"rockchip_dri.so",
]
}
group("mesa-gpu-libs") {
public_deps = [
":mesa_gbm",
":mesa_egl",
":mesa_glapi",
":mesa_glesv1",
":mesa_glesv2",
":panfrost_dri",
]
}
foundation/graphic/standard/graphic_config.gni
} else if ("${product_name}" == "rk3566" || "${product_name}" == "rk3568") {
gpu_defines = [ "ACE_ENABLE_GL" ]
ace_enable_gpu = true
- libgl = [ "//device/hihope/hardware/gpu:mali-bifrost-g52-g2p0-ohos" ]
+ #libgl = [ "//device/hihope/hardware/gpu:mali-bifrost-g52-g2p0-ohos" ]
+ libgl = [ "//device/hihope/hardware/gpu:mesa-gpu-libs" ]
由于surfaceimage依赖闭源GPU实现,需要关掉
foundation/graphic/standard/BUILD.gn
group("libsurface") {
public_deps = [ "frameworks/surface:surface" ]
if (ace_enable_gpu) {
- public_deps += [ "frameworks/surfaceimage:libsurfaceimage" ]
+ #public_deps += [ "frameworks/surfaceimage:libsurfaceimage" ]
}
}
device/hihope/rk3568/BUILD.gn
"build/rootfs:init_configs",
"distributedhardware:distributedhardware",
- "kernel:kernel"
+ "kernel:kernel",
+ "//device/hihope/hardware/gpu:libgallium_dri"
]
}
如果有创建card1及renderD129节点,需要给它添加读写权限。
base/startup/init_lite/ueventd/etc/ueventd.config
/dev/dri/card1 0666 0 1003
/dev/dri/renderD129 0666 0 1003
如果Display HDI gralloc模块使用的是renderD128节点,需要改成card0
device/hihope/hardware/display/src/display_gralloc/display_gralloc_gbm.c
-const char *g_drmFileNode = "/dev/dri/renderD128";
+const char *g_drmFileNode = "/dev/dri/card0";
static GrallocManager *g_grallocManager = NULL;
RK3568 在ubuntu环境中,通过以下命令下载到设备:
//编译kernel
cd out/kernel/src_tmp/linux-5.10/
./make-ohos.sh TB-RK3568X0 disable_ramdisk
//编译OpenHarmony
./build.sh --product-name rk3568
//下载img
cd out/rk3568/packages/phone/images
upgrade_tool di -p parameter.txt -uboot uboot.img -boot_linux boot_linux.img -resource resource.img -vendor vendor.img -system system.img -userdata userdata.img -updater updater.img
//重启
upgrade_tool RD
以下是panfrost启动成功后的串口日志打印:
Line 480: [ 0.780211] panfrost fde60000.gpu: clock rate = 594000000
Line 481: [ 0.780254] panfrost fde60000.gpu: bus_clock rate = 500000000
Line 482: [ 0.780476] panfrost fde60000.gpu: [drm:panfrost_devfreq_init] *ERROR* Couldn't set OPP regulators
Line 824: [ 2.008794] panfrost fde60000.gpu: clock rate = 594000000
Line 825: [ 2.008852] panfrost fde60000.gpu: bus_clock rate = 500000000
Line 826: [ 2.010067] panfrost fde60000.gpu: mali-g52 id 0x7402 major 0x1 minor 0x0 status 0x0
Line 827: [ 2.010100] panfrost fde60000.gpu: features: 00000000,13de77ff, issues: 00000000,00000400
Line 828: [ 2.010114] panfrost fde60000.gpu: Features: L2:0x07110206 Shader:0x00000002 Tiler:0x00000209 Mem:0x1 MMU:0x00002823 AS:0xff JS:0x7
Line 829: [ 2.010124] panfrost fde60000.gpu: shader_present=0x1 l2_present=0x1
Line 830: [ 2.012042] [drm] Initialized panfrost 1.1.0 20180908 for fde60000.gpu on minor 1
输入hilog并输出egl相关,能看到如下打印:
hilog -e egl
OHOS::ROSEN: RSSurfaceOhosGl:RequestFrame, eglsurface is 0x38f1ab0, width is 720, height is 48
OHOS::ROSEN: RSSurfaceOhosGl: FlushFrame, SwapBuffers eglsurface is 0x38f1ab0
OHOS::ROSEN: RSSurfaceOhosGl:RequestFrame, eglsurface is 0x39c1ba0, width is 720, height is 72
OHOS::ROSEN: RSSurfaceOhosGl: FlushFrame, SwapBuffers eglsurface is 0x39c1ba0
OHOS::ROSEN: RSSurfaceOhosGl:RequestFrame, eglsurface is 0x2df8350, width is 720, height is 1280
如果这个时候屏幕能够正常显示launcher相关内容,就恭喜你适配成功了。
从上面的适配框架可以看出,除了Mesa3D外,drm、panfrost、Display HDI也是至关重要的,下面我们简单介绍相关知识及验证方法。
drm(Direct Rendering Manager) 直接渲染管理,是Linux目前主流的图形显示框架。并且管理着GPU及Display驱动,使得软件架构更为统一,方便管理和维护。
DRM从模块上划分,可以简单分为3部分。
libdrm
为用户态提供各种IOCTL操作接口。
KMS(Kernel Mode Setting)
包换以下模块的实现:CRTC,ENCODER,CONNECTOR,PLANE,FB,VBLANK,property
GEM
显示内存的分配管理。包含:DUMB、PRIME、fence
一个新设备drm的实现就是对KMS及GEM的实现,drm提供了一个虚拟设备例子参考:drivers/gpu/drm/vkms。以下链接非常详细的介绍了drm相关知识:
在用户态,libdrm提供了modetest工具,来检测drm基础功能,是否适配成功。它可以测试基本显示功能,并列举出几大组件的参数。但一些扩展的硬件功能,modetest无法检测,比如显存压缩技术AFBC。但适配前期,modetest还是非常好用的。
panfrost的是对ARM 系列GPU驱动的开源实现,它的功能主要是完成对GPU硬件的初始化,以及以job的方式,完成对渲染数据硬件处理。在本文档中,GPU相关的配置,渲染管理等都是通过Mesa3D对panfrost ioctl来实现的。
Display HDI是OpenHarmony显示接口适配层。主要功能分三部分:
HDI 通过libdrm提供的接口来管理显示设备及送显。OpenHarmony 使用的是atomic接口,需要drm支持atomic的property操作方式。HDI操作流程基本与modetest代码一致。在使用modetest确保drm驱动基本完整的情况下,可以使用hello_composer工具来测试HDI是否适配成功。OpenHarmony默认已经编译进系统。在/system/bin目录下。
以下是适配过程中遇到的一些问题,为文档阅读者提供一些参考思路。
panfrost初始化GPU硬件时,会遇到写复位寄器超时,有如下打印:
gpu soft reset timed out
这个时候发现读写GPU寄存器都表现异常,应该考虑GPU是否上电成功。
桌面显示异常,状态和文字相关能正常显示,与图片相关的只显示一个框框,其它都是白色。并报如下错误:
[ 39.747285] panfrost 60000000.gpu: js fault, js=0, status=DATA_INVALID_FAULT, head=0x659c5c0, tail=0x659c5c0
[ 39.757132] panfrost 60000000.gpu: gpu sched timeout, js=0, config=0x3300, status=0x58, head=0x659c5c0, tail=0x659c5c0, sched_job=f77ff5d1
从错误来看,显示数据无效错误。经过定位,发现GPU是支持AFBC(显存压缩技术),但DRM没有适配。最后在Mesa3D中关闭该功能,显示正常。
--- a/src/panfrost/lib/pan_props.c
+++ b/src/panfrost/lib/pan_props.c
@@ -241,7 +241,7 @@ panfrost_open_device(void *memctx, int fd, struct panfrost_device *dev)
dev->quirks = panfrost_get_quirks(dev->gpu_id, revision);
dev->compressed_formats = panfrost_query_compressed_formats(fd);
dev->tiler_features = panfrost_query_tiler_features(fd);
- dev->has_afbc = panfrost_query_afbc(fd, dev->arch);
+ dev->has_afbc = false;//panfrost_query_afbc(fd, dev->arch);
案例参考: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7228
如果OpenHarmony无法点亮屏幕,可以用buildroot来先测试,成功后再使用OpenHarmony验证。
buildroot小巧,修改编译调试都比较方便,并且自带glmark2测试工具。
步骤一: 关闭ramdisk
# CONFIG_BLK_DEV_INITRD=y
# CONFIG_INITRAMFS_SOURCE=""
步骤二:编译buildroot。
参考:https://blog.csdn.net/u013131156/article/details/124337444
步骤三:下载
使用rootfs.ext4 替换OHOS的system.img。
步骤四:调试
1、开机必要的环境变量配置:
mkdir /tmp/xdg
export XDG_RUNTIME_DIR=/tmp/xdg
2 打开日志(可选):
export PAN_MESA_DEBUG=trace
export MESA_DEBUG=1
export EGL_LOG_LEVEL=debug
export LIBGL_DEBUG=verbose
export WAYLAND_DEBUG=1
3 启动桌面
weston --tty 1 & //GPU
或者
weston --tty=1 --use-pixman & //CPU
4 运行glmark2性能测试工具
glmark2-es2-wayland
3.2 release版本这样适配失败了,提示panfrost_mmu_reset这边异常了,请问这是啥原因了?