ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

RK3588上编译eglinfo:Mali GPU调试与Meson构建避坑指南

RK3588上编译eglinfo:Mali GPU调试与Meson构建避坑指南 从零开始在 RK3588 板子上把 eglinfo 编译跑通整个过程远比想象中曲折。本来以为就是个普通开源工具configure 一下 make 一下就能完事结果一路从 Python 版本踩到 Meson 构建系统再折腾到 Mali GPU 驱动加载中间还穿插着 Ubuntu 20.04 的各种依赖坑。这篇博文就完整记录这次踩坑过程把能绕的路都替你们走了希望后面做 RK3588 显示栈、GPU 调试的朋友能省点时间。eglinfo 这个工具平时看起来不起眼但在 Mali 驱动调试里出场率极高。它本质上是 Mesa3D 项目里 egl demos 的一部分作用是枚举系统的 EGL 平台、显示设备、配置列表和渲染器信息。简单说跑一下 eglinfo你马上就能看清当前的 GPU 用户态驱动是否正常工作、走的是硬件 Mali 还是软件模拟渲染。对 RK3588 这种自带 Mali-G610 MP4 的芯片来说这个工具几乎是排查图形问题时的第一手诊断利器。1. 项目背景与整体设计思路1.1 为什么偏要自己编译 eglinfo很多人会问Ubuntu 仓库里不是有现成工具吗直接apt install mesa-utils不就行了。确实装完 mesa-utils 后会带一个 glxinfo在桌面环境跑一下能看 OpenGL 信息。但问题在于Rockchip 的 BSPBoard Support PackageUbuntu 系统和标准 Ubuntu 有差异官方 apt 源里的 Mesa 工具链通常是为标准桌面设计不一定能完整覆盖 Rockchip 的 libmali 用户态驱动。我在板子上试过直接apt install mesa-utils然后跑 glxinfo结果看到的是llvmpipe软件渲染。这就说明系统默认加载的 Mesa 开源驱动和 Rockchip 的 mali blobs 没有正确衔接上。而 eglinfo 比 glxinfo 更底层它直接询问 EGL 层能够绕过一些 X11/Wayland 的封装把 EGL 平台和 GPU 用户态驱动的真实状态暴露出来。另一个关键原因是Rockchip 提供的官方 libmali 库带有厂商特定扩展和配置比如 EGL_PLATFORM、gralloc 分配器、AFBCArm Frame Buffer Compression支持等。这些扩展在标准 Mesa 工具的检查逻辑里不一定能看到但 eglinfo 因为设计简洁会原样展示 EGL 扩展字符串所以更有利于判断厂商 blob 的实际能力。1.2 编译路线选型为什么走 Mesoneglinfo 的源码在 Mesa3D 的mesa/demos仓库里维护而这个仓库的构建系统选的是Meson Ninja。这就直接决定了整个工具链的选择你没法绕开 Python 和 Meson。这里有个背景知识值得说一下早期版本的 mesa-demos 用的是 autotools也就是 ./configure make 那套后来项目整体迁移到了 Meson。Meson 相比 autotools配置语法更清晰、构建速度快但代价是它对 Python 版本和依赖包的匹配要求比较敏感。Ubuntu 20.04 默认装的是 Python 3.8而新版本的 Meson比如 1.0 以上通常要求 Python 3.7看起来满足但实际跑起来会碰到一些 futex 相关的报错后面详细讲。所以我在编译前就确定了一个原则用 Ubuntu 20.04 自带的库尽量不折腾能少升级就少升级尤其是系统级的 Python 环境不要动。这个原则在后来的实践中证明帮了大忙因为很多 RK3588 的 BSP 应用和 SDK 脚本都依赖系统自带的 Python 环境一旦贸然升级 Python 或者 pip很容易把 SDK 工具链整体破坏。1.3 整体方案三阶段递进这次编译我分了三步走第一步搭建干净的构建环境解决 Python、Meson、依赖库的匹配问题第二步编译 eglinfo 本体在 RK3588 的 aarch64 环境中直接本地编译第三步运行调试重点盯着 Mali 驱动的加载状态和 EGL 平台信息。我把整个过程中用到的关键命令和环境配置都整理在下面方便你直接照着操作。先说个总的原则尽量用 Debian/Ubuntu 的 apt 包来装依赖不要手动从源码编译大而全的依赖库否则一旦出现 ABI 不兼容排查成本成倍上升。2. 编译前环境准备Python、Meson 与依赖库的坑2.1 Ubuntu 20.04 自带 Python 3.8 的“够用”与“不够用”编译 meson 项目首先要保证 Python 版本能够被 Meson 接受。Ubuntu 20.04 自带的 Python 是 3.8.10单看版本号并没有过期对于 Meson 0.63 及以下版本来说完全够用。但问题往往不出在 Python 本身而出在Python 的安装方式上。我在这块踩过一个典型坑有些人为了方便会用apt install python3-pip以后直接用pip3 install meson结果 pip 会把 meson 装到一个独立路径通常是~/.local/bin同时因为依赖关系pip 可能把python3-jsonschema、python3-packaging等一堆 Python 包都拉一遍而且版本和系统自带的不一致最终导致 meson 运行时出现莫名其妙的 module 缺失报错。这里推荐的做法是优先用 apt 安装 meson。Ubuntu 20.04 官方源里带的 meson 版本是 0.53.2虽然不算最新但对于编译 mesa-demos 这种小型项目足够用了。为什么我强烈推荐 apt 版本因为 apt 会同时处理好所有 Python 系统依赖和 Python 3.8 的兼容性经过官方测试不会出现版本错乱的问题。sudo apt update sudo apt install python3 python3-pip python3-setuptools python3-wheel sudo apt install meson装完后执行meson --version系统输出 0.53.2确认无误。假如你因为某些原因一定要用 pip 安装新版 meson比如要编译的新项目要求 meson 1.0 以上那建议用虚拟环境隔离别污染系统 Pythonsudo apt install python3-venv mkdir ~/meson-env cd ~/meson-env python3 -m venv venv source venv/bin/activate pip install meson ninja但这次的 eglinfo 编译apt 的 0.53.2 就够了没必要折腾。2.2 编译工具链与系统依赖除了 meson还需要确保板子上有完整的编译工具链。检查方式很简单gcc --version g --version make --version ninja --version如果 GCC 没装或版本太老先装基础包sudo apt install build-essential ninja-build pkg-config接下来是 EGL 开发头文件。eglinfo 编译时需要找 EGL/egl.h、EGL/eglext.h 这些头文件它们由libegl1-mesa-dev或libegl-dev提供。注意这里的头文件只是编译时需要运行时它不会去链接 Mesa 的 libEGL而是想办法找到 Rockchip 的 libmali。所以即使系统里 Mesa 的 EGL 驱动是 llvmpipe也不影响编译过程。sudo apt install libegl1-mesa-dev libgles2-mesa-dev libgl-dev这些包装上后/usr/include/EGL/目录下就会有完整的头文件。如果缺EGL/eglext.h通常是因为只装了老版本的 libegl1-mesa-dev升级一下或者直接装libegl-dev即可。2.3 依赖库顺序问题的“潜规则”在 Linux 下编译带图形依赖的项目有个隐蔽的坑是头文件库路径的搜索顺序。Rockchip 的 SDK 或者 BSP 里经常会把 libmali 放到/usr/lib/aarch64-linux-gnu/或/opt/libmali/而 Mesa 的库也放在/usr/lib/aarch64-linux-gnu/。两个库名字都是libEGL.so只是实现不同。pkg-config 在找 EGL 依赖时默认会找egl.pc这个 pkg-config 文件这个文件通常由libegl-dev提供指向 Mesa 的库。好在我们编译的是 eglinfo它并不会静态链接 libEGL而是通过dlopen的方式在运行时动态加载。这就意味着编译阶段头文件对了就行运行阶段它才会去系统库里找libEGL.so.1。因此编译环境和运行环境的库策略可以不相同这也是 eglinfo 这类 EGL 探针工具的通用模式。3. 编译核心过程从拉取源码到安装二进制3.1 获取 mesa-demos 源码mesa-demos 仓库一直比较活跃主分支跟着 Mesa 主分支走。为了稳定起见建议直接拉取官方仓库的 release 标签而不是用最新的 main 分支。我这里选的是 8.5.1 release 标签这是一个比较成熟的版本对 Meson 的版本要求也不高。git clone https://github.com/mesa3d/mesa-demos.git cd mesa-demos git checkout mesa-demos-8.5.1如果你网络不好拉不动 GitHub可以在国内镜像站点找找 cache 版本但尽量保证源码完整性否则后面编译报错容易混淆是源码问题还是环境问题。3.2 配置构建目录mesa-demos 采用 Meson 构建操作上我习惯建一个build子目录来隔离构建产物不污染源码目录meson setup build -Dprefix/usr/local这里简单解释一下-Dprefix/usr/local安装路径默认就是 /usr/local看个人习惯如果用默认值可以省略。不过建议显式指定因为后边回溯的时候能更清楚二进制装到哪里去了。跑完配置后如果报依赖缺失Meson 会明确提示你缺的是哪个包直接按提示补装即可。我在板子上配置时遇到过提示说x11依赖缺失这是因为 mesa-demos 会默认尝试开启所有 demo 的构建包括基于 X11 的 glx 示例。我们的目标只是 eglinfo不需要编译所有 demo可以用 Meson 的选项把不需要的部分关掉meson setup build \ -Dprefix/usr/local \ -Dwith-egltrue \ -Dwith-glxfalse \ -Dwith-gles1false \ -Dwith-gles2true \ -Dwith-waylandfalse \ -Dwith-x11false \ -Dwith-osmesafalse这样配置会明显缩小构建范围只保留 EGL 和 GLES2 相关的 demoeglinfo 就在其中。3.3 编译与安装配置完成后执行编译ninja -C build因为只编译部分 demo整个过程比较快大约一两分钟就能完成。如果板子的 CPU 核心多可以ninja -C build -j4指定并行度但要注意别把 CPU 全占满毕竟 RK3588 板子通常还要跑其他服务。编译完成后确认 eglinfo 二进制生成ls -l build/src/egl/eglinfo然后安装到系统路径sudo ninja -C build install安装后which eglinfo能看到/usr/local/bin/eglinfo说明安装成功。4. Mali 驱动调试当 eglinfo 碰到 RK3588 的 libmali4.1 先搞清楚 RK3588 的 GPU 驱动结构RK3588 的 GPU 是 Mali-G610 MP4属于 Arm Valhall 架构。在 Linux 下Mali GPU 驱动分两部分内核态模块Kernel Driver和用户态库User-Space Blob即 libmali。内核态部分 Rockchip 一般以模块方式编译进内核用户态库则是一个闭源二进制通常以libmali.so或libmali-bifrost.so的形式提供。在 Ubuntu 20.04 的 Rockchip BSP 系统里用户态库通常放在/usr/lib/aarch64-linux-gnu/或 SDK 的libmali目录同时会被符号链接成libEGL.so.1、libGLESv2.so.2、libgbm.so.1等名字。这样应用程序调用标准 EGL/GLES 接口时实际加载的是 Rockchip 的 Mali 实现而不是 Mesa 的软件实现。4.2 运行 eglinfo 的第一步设置 EGL_PLATFORM在运行 eglinfo 之前一个重要的环境变量是EGL_PLATFORM。eglinfo 会通过这个变量决定自己使用哪个 EGL 平台export EGL_PLATFORMsurfaceless eglinfo或者针对 DRM/KMS 平台export EGL_PLATFORMdrm eglinfo这两种平台在 RK3588 板子上表现不一样。surfaceless 模式只做 EGL 上下文和配置的枚举不涉及显示输出drm 模式则会直接打开 DRM 设备比如 /dev/dri/card0来枚举显示模式。对于纯 GPU 驱动诊断用 surfaceless 就足够了。如果没有显式设定 EGL_PLATFORMeglinfo 会去猜但猜来猜去的结果经常是落到 X11 或 Wayland 上而这两个平台在无桌面环境或者桌面环境异常时直接就退出了。所以我建议跑 eglinfo 时一定要显式设定 EGL_PLATFORM。4.3 解读 eglinfo 的输出硬件 Mali 和 llvmpipe 的分水岭我把一次成功运行的输出贴出来逐行解读EGL API version: 1.5 EGL vendor string: ARM EGL version string: 1.5 EGL client APIs: OpenGL_ES OpenGL OpenGL ES 2.x: GL_RENDERER: Mali-G610 GL_VERSION: OpenGL ES 3.2 v1.g6p0-01eac0d GL_EXTENSIONS: ... OpenGL ES 3.x: GL_RENDERER: Mali-G610 GL_VERSION: OpenGL ES 3.2 v1.g6p0-01eac0d看到EGL vendor string: ARM和GL_RENDERER: Mali-G610说明用户态驱动加载正确GPU 硬件加速已经就绪。这也是我们编译 eglinfo 最想看到的结果。如果渲染器显示的是llvmpipe说明 EGL 实际加载的是 Mesa 的软件实现。这时候即使你跑clinfo或其他 GPU 应用看到的都是 CPU 模拟渲染性能完全不对。排查方向通常是libmali 是否安装、/usr/lib/aarch64-linux-gnu/libEGL.so.1是否真的指向 Mali、内核模块 mali 是否加载成功。如果 eglinfo 直接报错could not find libEGL.so.1多半是系统里没有 libEGL.so.1 这个软链接或者动态库缓存没更新。修一下sudo ldconfig或者手动确认软链接ls -l /usr/lib/aarch64-linux-gnu/libEGL*4.4 内核模块与设备节点确认运行 eglinfo 之后如果渲染器正确显示 Mali-G610基本就可以确认用户态没问题。但调试驱动时内核态也不能忽略。几个常用检查点# 查看内核模块加载状态 dmesg | grep mali # 查看设备节点 ls -l /dev/mali0 # 查看 DRM 设备 ls -l /dev/dri/正常的 dmesg 输出应该能看到mali: Mali device driver和mali: Mali-G610之类的日志。如果 dmesg 里完全没有 mali 输出说明内核驱动模块根本没加载这时候需要检查内核配置或手动modprobe mali。如果/dev/mali0不存在但/dev/dri/card0存在说明系统走的是 DRM 显示框架libmali 可能通过 DRM 而不是 mali0 节点和内核通信这在新版 Rockchip SDK 里也常见。不用慌继续看 eglinfo 输出就行。4.5 平台差异surfaceless 与 drm 模式下 eglinfo 的区别surfaceless 模式下eglinfo 只使用 EGL 的 surfaceless 扩展不碰显示器所以输出会少一些显示相关的配置信息。而 drm 模式下eglinfo 会打开kms设备枚举显示分辨率并打印出每个 display plane 的信息。在 RK3588 上如果你关心画面是否成功输出到 HDMI 或 MIPI DSI用export EGL_PLATFORMdrm eglinfo这时输出里会多出 EGL_KHR_platform_gbm 的扩展信息和 DRM 设备的 mode 列表。如果看到 mode 列表是空的说明 DRM 设备没有正确初始化多半是面板时序或者 connector 驱动问题和 GPU 本身关系不大。5. 常见问题与排查技巧实录5.1 编译阶段报错速查表我把这次编译过程中遇到过的报错和解决方法整理成了表后续有人遇到同样问题可以直接对照。报错信息原因解决方案meson: command not foundmeson 未安装或 PATH 不正确apt install meson或检查~/.local/bin是否在 PATH 中ERROR: Python3 now requires TLS/SSL to functionPython 的 ssl 模块有问题pip 无法工作安装libssl-dev并重编 Python或直接用 apt 装 mesonUnable to detect linker编译工具链没装全apt install build-essentialmeson.build:1:0: ERROR: Unknown options: with-x11版本不同选项名不匹配meson setup build先看提示去掉不存在的选项fatal error: EGL/egl.h: No such file or directory缺少 EGL 开发头文件apt install libegl1-mesa-dev libegl-devMesa: EGL_GLEXT_PROTOTYPES warningsEglConvenience... undefined版本变异导致的源码兼容问题少见更新源码到较新版本或切换 release 标签5.2 运行阶段eglinfo 闪退或无法输出编译成功后运行阶段最常见的坑是闪退。我遇到过一次情况是执行eglinfo后进程直接退出没有任何报错。用dmesg | tail看到是段错误segfault。排查后发现问题出在LD_LIBRARY_PATH上。当时系统里同时存在/opt/libmali和/usr/lib/aarch64-linux-gnu两套 libmali而LD_LIBRARY_PATH指到了老版本库老库和新内核模块版本不匹配导致 segfault。解决办法是把LD_LIBRARY_PATH清空或者改成正确的路径unset LD_LIBRARY_PATH然后确认/etc/ld.so.conf.d/里没有重复的 libmali 路径。另一次闪退是因为 EGL_PLATFORM 没设置eglinfo 尝试初始化 x11 平台失败直接崩溃。设成surfaceless后一切正常。5.3 分辨率列表为空怎么查在 drm 模式下如果 eglinfo 输出的显示 mode 列表为空可以从两个方向排查一是modetest如果装了 libdrm-tests看看 DRM 层是否能枚举 mode二是检查设备树里 HDMI/MIPI 相关的 status 是否为 disabled。sudo apt install libdrm-tests sudo modetest -M rockchip如果 modetest 有输出说明 DRM 层正常eglinfo 这边可能只是没读到合适的 mode 配置设置EGL_PLATFORMdrm后重试。如果 modetest 也看不到任何 encoder/connector那问题在显示链路得从设备树、面板驱动、HDMI phy 这些更底层的地方查起。5.4 独家避坑技巧多版本 libmali 的管理RK3588 调试中经常接触多套 SDK很多 SDK 会自带 libmali如果直接拷贝到/usr/lib很容易把系统库搞乱。我个人的做法是给每一套 SDK 的 libmali 建独立目录用ld.so.conf.d里的配置文件控制加载优先级# /etc/ld.so.conf.d/libmali-sdk.conf /opt/xxx-sdk/libmali然后用ldconfig刷新缓存再用LD_DEBUGlibs eglinfo 21 | grep libEGL验证实际加载的库路径。这个方法能非常精确地看到 eglinfo 运行时到底加载了哪个 libEGL对排查多库冲突特别有效。6. 一个值得注意的扩展Python 环境在 RK3588 调试中的放大器效应6.1 为什么没有动 Python 环境整个编译过程我始终没有升级系统 Python。有些人习惯一上来就把 Python 升到 3.10 或者装最新 pip在 RK3588 的 BSP 系统里这非常危险。Rockchip 的很多工具脚本比如upgrade_tool、flash_tool、部分 AI SDK都依赖系统自带的 Python 3.8 和 system site-packages。一旦动到 Python 主版本自带库这些脚本可能全部失效。eglinfo 编译中用到的 meson用 apt 老版本完全够用。这也说明一个道理在嵌入式板子上做工具链选型时“够用”往往比“最新”更重要。真需要用新 Python 特性用virtualenv或者conda隔离而不是替换系统 Python。6.2 Python 相关调试的另一个常见入口很多人在 RK3588 上还要调试自己写的 Python 图形应用。如果应用报告 EGL 初始化失败可以先通过 eglinfo 验证系统 EGL 是否正常。如果系统 EGL 正常而 Python 应用失败那么问题多半在 Python 绑定的包版本和系统 EGL 不匹配比如 pyglet、OpenGL 的 EGL 支持库版本问题。这里我的习惯是先用系统级 eglinfo 做“金标准”验证确认底层没问题再去查 Python 包的封装。一层一层隔离排查效率会高很多。6.3 关于“Ubuntu 20.04 双系统”等热词的提醒借这次编译我还想多说一句题外话。网上很多 RK3588 的 Ubuntu 20.04 相关搜索词都带“双系统”“安装教程”之类词汇但真正做嵌入式开发时RK3588 板子一般用 SD 卡启动或者 eMMC 烧录和 PC 上的双系统完全不是一回事。在板子上编译显卡相关工具时不用关心双系统的问题但要特别注意板子使用的内核版本和设备树是否与你要干的事儿匹配。内核里 Mali 驱动模块版本和设备树里 GPU 频率设置都会影响驱动能否正常工作。比如有些 RK3588 镜像使用的是老内核4.19 或 5.10 版本对应的 Mali 内核模块和用户态库版本必须配套。这种情况通过uname -a确认内核版本再对照 SDK 发布说明里的版本号就清楚了。7. 实操心得这次排错最大的体会是工具链尽量用系统自带的。在 RK3588 这种嵌入式板子上追求“到处最新”不是一个好策略系统的稳定性和一致性比什么都重要。Python 3.8 Meson 0.53 Ninja 这个组合虽然老但足够稳定地完成 eglinfo 编译这比费大力气升级完 Python 之后引发一堆 SDK 问题要划算得多。还有个小技巧编译完成后保留好 build 目录。后面如果更新了源码直接ninja -C build增量编译就行不用每次重新配置。以后在板子上做图形开发eglinfo 会是你反复用到的工具放着熟悉的一套构建环境能省不少事。
返回列表