ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

RK3568开源GPU驱动实践:从内核到Mesa的Panfrost适配指南

2026/9/17 6:55:44 拓冰建站 浏览量
RK3568开源GPU驱动实践:从内核到Mesa的Panfrost适配指南 算起来我从拿到RK3568开发板到彻底放弃原厂闭源GPU栈中间只隔了一个星期。原因很简单在某次把内核从5.10切到6.1做外设适配时闭源libmali用户态库和内核模块版本对不上GLES直接起不来而厂商社区那边的回复基本等于“你等我们下一版 release”。也就是那时候我决定把主线内核自带的Panfrost驱动当作主力方案来推。今天这篇就是完整记录写给那些想在rk3568平台上用开源GPU驱动panfrost干活的人说说我从内核配置、设备树、用户态Mesa一路踩到性能调优和崩溃排查的全过程。RK3568这颗芯片在很多板子上都能看到四核A55GPU部分是Mali-G52 2EE不算强但做工业HMI、边缘盒子、轻量图形界面完全够用。Panfrost是Linux主线内核里的开源Mali GPU驱动配合Mesa社区的Gallium驱动能在没有厂商闭源组件的情况下把GLES、Vulkan这些跑起来。这篇文章适合的对象是已经能编译内核、会用设备树、手上有一块RK3568开发板的人。如果你只是刚接触嵌入式Linux我会尽量把背景和原理也讲明白但建议先熟悉一下基础编译流程再上手。1. 为什么要在RK3568上折腾Panfrost不仅是情怀1.1 Mali-G52 2EE是什么来头要理解Panfrost先得知道RK3568的GPU具体是哪一代架构。Mali-G52属于Arm Bifrost架构相比更老的Midgard架构Bifrost在调度和执行模型上有明显变化编译器、指令缓冲、作业提交方式都是另一套逻辑。RK3568用的这个G52 2EE版本相当于双执行引擎配置定位是中低端GPU但支持Vulkan、GLES 3.2这些现代图形接口的硬件特性。很多人会把Mali-G52和Mali-G52 2EE搞混。区别在于EE(Execution Engine)数量2EE意味着同一时刻能并行的执行引擎少一些在着色器密集型任务里性能跟高配版G52有差距。这块GPU通常运行在800MHz左右的频率不过具体频率由芯片的OPP表决定不同板子默认不一样。了解这一点对适配Panfrost很重要。因为Panfrost对Bifrost架构的支持是分代推进的早期只支持Midgard后来才把Bifrost的支持合入主线。G52在Bifrost里面算是比较早被覆盖的型号社区测试也多所以相对好适配。如果你想在RK3568上跑Wayland合成器、做Qt界面、播放视频叠加特效Panfrost完全能接得住。1.2 不用闭源mali驱动到底损失了什么又换回了什么原厂方案通常包含两个部分一个是内核态的mali驱动类似kbase一个是用户态的libmali里面打包了OpenGL ES、OpenCL、Vulkan的接口实现。这玩意儿的毛病在于“版本耦合太死”。不同内核版本、不同GPU频率、不同安卓或Linux BSP版本都需要对应版本的libmali。你一旦自己改了内核配置、换了编译器版本或者升级了DRM子系统闭源库可能就直接罢工。我遇到过的最典型情况是把内核从Rockchip的5.10分支换成主线6.1之后原厂libmali根本没有适配主线内核的版本因为厂商的闭源内核模块通常跟着自己内核分支走。这时候你能选择的路线只有三条一是继续停留在厂商内核放弃新内核带来的新特性二是自己尝试移植闭源mali内核模块到主线内核难度极大且没有源码可查三是切到Panfrost内核态用主线自带的开源驱动用户态用Mesa彻底绕开厂商锁定。换回什么好处最直接的好处是“可升级”。内核可以跟着主线走Mesa可以跟着麒麟/Ubuntu/Debian的软件源走出了问题能自己读代码、查bug报告。社区里有人遇到问题会报告给Panfrost的issue tracker修复后会合入主线这种透明度是闭源方案做不到的。另外Panfrost不需要厂商额外提供固件文件驱动自己处理Mali的作业调度少了“固件版本不匹配”这一层坑。代价也有。首先在OpenCL上Panfrost至今没有完整的计算方案如果你依赖GPU计算那得继续用闭源或者另想办法。其次Vulkan方面panvk驱动虽然能用但成熟度不如GLES。所以这个选择适合的是做显示、合成、2D界面、轻量3D的人而不是重度计算用户。1.3 开源路线的支持边界Panfrost的官方支持范围大致是Mali 400/450Lima驱动负责、Mali T860这类Midgard、以及Mali G31/G52/G57这种Bifrost。RK3568的G52刚好落在Bifrost支持区间内。主线内核里drivers/gpu/drm/panfrost/目录就是它的实现从内核5.4之后开始合入到6.x版本已经相当稳定。用户态方面Mesa中的Panfrost Gallium驱动支持GLES 2.0/3.0/3.1甚至部分3.2配合KMS/DRM的GBM接口可以跑weston、GNOME/ KDE这类现代合成器。Mesa中还有panvk这个Vulkan驱动基本功能可跑但扩展覆盖不全复杂场景容易崩。我的经验是做常规GUI和媒体播放走EGL/GLES没问题不要指望它去打游戏跑benchmark。2. 内核侧适配从Kconfig到设备树节点2.1 开启Panfrost必需的Kconfig主线内核默认不会把Panfrost编进去需要手动打开Kconfig。注意这里指的是CONFIG_DRM_PANFROST不是Rockchip BSP里常见的CONFIG_MALI或者CONFIG_GPU_ARMBIFROST。打开方式很简单在menuconfig里搜索Panfrost路径是Device Drivers - Graphics support - Panfrost (EXPERIMENTAL) GPU driver它依赖DRM框架和ARM64架构。建议同时打开这些项CONFIG_DRMy CONFIG_DRM_PANFROSTy CONFIG_DRM_SCHEDy CONFIG_IOMMU_SUPPORTy CONFIG_ROCKCHIP_IOMMUy CONFIG_CMAyPanfrost用DRM的调度器管理GPU作业所以CONFIG_DRM_SCHED必须开着。CONFIG_ROCKCHIP_IOMMU这个跟RK3568的GPU内存管理强相关后面会讲。CMA默认一般开着但大小建议在cmdline里显式指定否则默认值可能偏小。如果你用的内核版本比较老比如5.10或者更早的官方BSP内核Panfrost的代码可能没有完全包含G52的支持或者缺少后面修复的bug。我的建议是直接用主线6.1 LTS或更新的内核不要在旧内核上强行backport省得踩一些已经修掉的坑。2.2 设备树中的GPU节点到底在描述什么设备树是RK3568适配Panfrost最容易出问题的地方。RK3568原厂设备树里通常已经有一个mali节点但如果你的板子是从某个BSP拷贝出来的这个节点的内容不一定符合主线Panfrost驱动的解析规则。一个典型的GPU节点长这样gpu { status okay; interrupts GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH; interrupt-names job, mmu, gpu; power-domains power RK3568_PD_GPU; clocks cru CLK_GPU, cru CLK_GPU_PVTM; clock-names gpu, pvtm; operating-points-v2 gpu_opp_table; };这里的interrupt-names顺序很关键。Panfrost驱动要求三个中断按job、mmu、gpu的顺序对应Mali的Job中断、MMU中断和GPU中断。如果原厂设备树里顺序不对或者只用了一个中断号启动时驱动可能初始化失败。热词里有人搜“rk3568设备树”这个节点正是重点。power-domains指向GPU电源域RK3568的PD_GPU编号是由电源管理框架定义好的。如果这个属性缺失GPU可能根本不会被上电驱动初始化会卡在等待电源稳定。另外operating-points-v2指向GPU动态调频的OPP表没有这张表的话Panfrost只能按默认频率跑性能可能发挥不出来。2.3 频率表与devfreq让GPU真正跑起来GPU频率通常由devfreq框架控制。OPP表一般在rk3568.dtsi里维护大家常见的档位类似gpu_opp_table: opp-table { compatible operating-points-v2; opp-200000000 { opp-hz /bits/ 64 200000000; opp-microvolt 900000; }; opp-400000000 { opp-hz /bits/ 64 400000000; opp-microvolt 950000; }; opp-800000000 { opp-hz /bits/ 64 800000000; opp-microvolt 1000000; }; };具体电压要根据你的板子电源设计来贸然抄别的板子的微电压值有风险。确认方法是在某个固定频率下跑一轮glmark2观察是否出现GPU hang或者系统重启。如果频率能稳定跑就说明电压够用。在系统运行时可以通过devfreq接口查看当前GPU频率ls /sys/class/devfreq/ cat /sys/class/devfreq/fdab0000.gpu/cur_freq cat /sys/class/devfreq/fdab0000.gpu/load设备名不一定是fdab0000.gpu以实际设备树基地址为准用ls看一下再拼路径。load文件显示的是GPU负载百分比能用来判断调频策略是否合理。2.4 编译、烧录与内核参数的坑编译Panfrost没有特殊要求正常交叉编译内核即可make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- menuconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- Image dtbs烧录方式取决于你的bootloader实现。RK3568一般用rkdeveloptool烧写boot分区或者直接用SD卡启动。这里提醒一个容易踩的坑设备树一定要和内核配套编译别用厂商BSP编译的dtb去配主线内核很多莫名其妙的问题都出在“核树分离”。cmdline里建议加cma512M。Panfrost在分配GPU内存、纹理缓冲区时IOMMU可以把分散物理页映射给GPU但是有些驱动路径仍然需要连续内存。512M对于1080p合成和常见3D应用足够如果你的板子内存只有2G可以缩到256M。观察内存是否够用的方法是cat /proc/meminfo | grep CmaCmaFree太小的话渲染大纹理时会出现分配失败。3. 用户态渲染栈让Mesa替GPU干活3.1 Mesa交叉编译需要注意的依赖内核态的Panfrost只是提供作业提交和内存管理的通道真正把GLES/Vulkan API翻译成Mali指令的是用户态驱动也就是Mesa里的Panfrost Gallium驱动和panvk Vulkan驱动。这里我推荐用Mesa 23.x以上的版本对Bifrost的支持已经比较完整。交叉编译Mesa最常见的痛苦是依赖链长。Mesa本身就依赖libdrm、libexpat、zlib、libxml2如果还要编GLX就得拉X11那一堆。在嵌入式目标机上跑的通常没有X11所以可以显式声明平台meson setup build \ -Dplatformsdrm,gbm,wayland,surfaceless \ -Dgallium-driverspanfrost \ -Dvulkan-driverspanfrost \ -Dglxdisabled \ -Dbuildtyperelease \ -Dprefix/usr ninja -C build DESTDIR$ROOTFS ninja -C build install-Dplatformsdrm,gbm,wayland,surfaceless的意思是让Mesa支持KMS/DRM直接输出、GBM缓冲区管理、Wayland和surfaceless上下文正好覆盖嵌入式Linux最常见的场景。-Dglxdisabled可以省掉X11依赖大幅降低编译复杂度。还有一个容易忽略的点libdrm的版本要尽量新。Panfrost的GBM接口对libdrm版本有要求如果libdrm太老Mesa编译时可能提示找不到某个头文件。我习惯先交叉编译一份libdrm装到roofs再编Mesa。3.2 与libmali共存还是替换很多RK3568板子的出厂rootfs里已经装好了官方libmali路径通常在/usr/lib/aarch64-linux-gnu/libmali.so或者/usr/lib/libmali.so。如果你不处理它直接用Mesa装出来的libEGL、libGLESv2、libgbm动态链接器会优先找到系统已有的libmali。结果是你以为用的Panfrost实际还是在走闭源库。最简单的做法是做一次干净的切换先备份原有libmali然后卸载或者移走它确认ldconfig之后系统里只剩Mesa的库mv /usr/lib/aarch64-linux-gnu/libmali.so /usr/lib/aarch64-linux-gnu/libmali.so.bak ldconfig这里要特别提醒不要同时让两个库抢占同一个so文件名。Mesa安装后libEGL.so.1、libGLESv2.so.2、libgbm.so.1这些名字和libmali是冲突的强行共存会遇到“symbol lookup error”或者EGL初始化失败。如果你的应用使用了OpenCL那Panfrost这边暂时无解闭源libmali得留着。这种情况下可以通过LD_LIBRARY_PATH或者修改链接脚本的方式让GLES相关调用走MesaOpenCL继续走libmali。但操作起来非常麻烦我试过几次后认为除非你有硬性需求否则直接二选一更省心。3.3 用kmscube做无桌面验证安装完Mesa之后最怕的就是“看起来装好了但不知道跑没跑起来”。我建议跳过桌面直接上kmscube这种极简测试程序验证。EGL_PLATFORMgbm kmscubekmscube会无视显示服务器直接用KMS/DRM创建全屏窗口渲染一个旋转立方体。如果屏幕上能看到立方体在转说明从Panfrost内核驱动到Mesa用户态已经打通了。如果报错先看dmesg | grep -i panfrost后续在调试章节细说。比kmscube更进一步的是glmark2-es2glmark2-es2 --fullscreen这个能测出大致的GLES性能指标包括纹理填充率、光照、阴影等场景。我一般拿它作为基础回归测试每次改设备树或Mesa版本后先跑一轮确保性能没倒退。对于Wayland场景可以启动weston然后把一个带GPU渲染的客户端窗口跑起来。weston自带的weston-simple-egl就能验证合成器是否真正调用了GPU。}3.4 Vulkan的坑panvk的成熟度很多人看到Panfrost支持Vulkan就想在RK3568上跑vkcube。确实Mesa的panvk可以跑起来但我的体会是“能用但别指望太多”。在我的测试里vkcube能正常出现几个基础测试用例也能通过但一旦涉及复杂的descriptor set、compute shader、多队列并发就可能触发驱动里的bug或者直接VK_ERROR_DEVICE_LOST。所以项目上如果只是做界面优先走GLES。Vulkan先当作“可以尝试”的辅助能力不要作为交付依赖。如果非要使用Vulkan关注Mesa的更新日志panvk几乎每个版本都在修bug过三个月再回来看可能就稳很多。4. 性能摸底与调优GPU到底跑没跑起来4.1 devfreq从频率和负载看GPU工作状态“GPU卡顿”不一定真的是图形能力不够很多时候是驱动压根没让GPU跑上去。我在RK3568上遇过一种情况跑glmark2时画面一顿一顿CPU和内存占用都不高怎么看怎么像软件渲染。最后查了GPU频率发现它一直锁在200MHz。原因就是devfreq的governor没有正常工作或者OPP表里的频率档位和电源管理策略不匹配。排查方法用两个文件就够了watch -n 1 cat /sys/class/devfreq/$(ls /sys/class/devfreq | grep gpu)/load watch -n 1 cat /sys/class/devfreq/$(ls /sys/class/devfreq | grep gpu)/cur_freqload显示的是负载百分比如果在跑图形应用时这个值一直不高那说明GPU没有被充分利用卡顿来自别处比如纹理上传带宽不够、CPU提交过慢。如果load高但频率低那就是调频策略问题可以手动切到performance或者userspace验证echo performance /sys/class/devfreq/$(ls /sys/class/devfreq | grep gpu)/governor切到performance后卡顿消失基本可以确定是动态调频响应慢。长期方案是修OPP表和电源域配置或者换一个更激进的governor比如把simple_ondemand的上限阈值调低。4.2 CMA与IOMMU分配内存的第一道坎Panfrost处理GPU内存有两种路径一是通过IOMMU映射分散页二是依赖CMA分配连续内存。RK3568的设备树里GPU节点通常会关联一个rockchip,iommu节点例如gpu_mmu。如果IOMMU正常工作大部分缓冲区都能通过IOMMU映射。但总有些路径绕不开CMA。比如某些显示合成、显存导入操作或者Mesa里没有走DMA-BUF堆的代码路径会调用连续内存分配。CMA太小的话dmesg会看到类似cma_alloc: failed的错误。这时候加大cmdline里的cma参数是最快的解决方法cma512M另外需要注意不要把设备树里的GPU节点标记为dma-coherent。Mali GPU需要软件维护CPU与GPU之间的缓存一致性Panfrost驱动有自己的一套cache操作逻辑。如果你从某些板卡文档里抄了dma-coherent进去反而可能因为缓存一致性问题导致贴图花屏、随机崩溃。我见过有人排查了半天渲染错乱最后发现就是多加了这一个属性。4.3 性能对比表开源驱动与闭源方案的差距我把同一块RK3568板子上跑glmark2的数据整理过一份对比闭源libmali在部分场景下确实更强但差距没有想象中那么大。下面是我当时记录的参考数据不构成严谨benchmark只做大致量级参考测试项闭源libmaliPanfrost Mesa备注glmark2 default综合分210左右180左右相差15%上下纹理填充场景fill-rate偏高略低与内存带宽分配有关复杂光照/着色器场景稳定偶见shader编译卡顿首次编译着色器时会卡一下Wayland合成流畅流畅打开GBM后无明显区别Vulkan基础可用可用但受限panvk仍不够成熟这个对比基于Mesa 23.1和同版本内核。换个Mesa版本结果可能会变化Panfrost的性能优化一直在推进新版本通常只会更快更稳。如果你觉得开源驱动性能不够可以从两个方向优化一个是增大GPU频率档位并确保供电稳定另一个是检查DDR频率。GPU性能不只取决于GPU核心频率显存带宽一样是瓶颈。RK3568的DMC频率可以动态调整但有些板子默认把DDR频率调得比较保守导致GPU频率再高也喂不饱数据。可以用/sys/class/devfreq/dmc/cur_freq查一下。5. 踩坑实录三次典型故障的完整排查链路5.1 中断顺序不对启动过程GPU模块直接卡死第一次把主线内核跑在RK3568上时我没仔细看设备树直接沿用了某个板卡SDK里的GPU节点。启动日志里能加载Panfrost驱动但跑到初始化某个阶段时整个系统直接hang住串口无响应只能按复位键。当时的第一反应是电源域没配好。查了power-domains发现指向的是RK3568_PD_GPU看起来没问题。于是在内核启动参数里打开更多调试输出才发现GPU的中断处理有问题。回头翻设备树发现那个SDK里的interrupt-names写的是gpu, mmu, job和Panfrost驱动要求的job, mmu, gpu顺序不一致。驱动按顺序申请中断但实际上申请到的第一个中断是GPU中断而不是Job中断之后提交GPU作业时中断也触发不了整个调度器就卡死了。修复方法很简单把interrupt-names和interrupts的顺序改成job、mmu、gpu同时核对三个中断号对应关系。改完重新编译dtbGPU正常初始化。这个坑给的经验是在RK3568上适配Panfrost拿到设备树后第一件事就是检查GPU节点的interrupt-names不要想当然认为SDK给的就是对的。5.2 IOMMU Page Fault渲染命令遇上了非法地址跑通kmscube之后我又去试了一个分辨率较高的合成场景结果画面频繁花屏然后进程崩溃。查看内核日志看到反复刷类似这样的错误rockchip-iommu fdab9000.iommu: Page fault at 0x00000000xxxxxxxxIOMMU page fault的意思是GPU访问的某个虚拟地址没有被映射到物理页。一类常见原因是用户态Mesa和内核态Panfrost版本不匹配比如Mesa提交的job使用的是新的内存属性但内核还是老版本导致映射缺失。另一类常见原因是DMA-BUF导入链路出问题比如显示层和GPU共用缓冲区时某个缓冲区的fd没有被正确映射。排查思路是先升级Mesa到与内核时间接近的版本再看/sys/kernel/debug/dri/0/state里的内存信息确认每个buffer的状态。如果仍然复现尝试在cmdline里关掉GPU的IOMMU改用纯CMA方式看是否还是page fault。如果关掉IOMMU后不崩了基本就是IOMMU映射问题如果还崩那就是用户态渲染指令本身有问题。我最后定位到是Mesa版本太旧Mesa 21.x对G52的某些渲染路径存在地址计算bug升级到Mesa 23之后page fault再没出现过。5.3 CPU/内存都不高但画面卡顿总线与缓存一致性背锅还有一个常见问题特别符合热词里有人搜的“gpu cpu 内存占用都不高但卡”。我遇到过一种情况跑一个视频叠加UI的demoCPU占用20%内存占用才几百兆GPU负载看起来也不高但画面就是在定期抽风。这类卡顿不能只看部件占用率要看“某个部件在等待另一个部件”。我最先怀疑的是GPU调频太慢于是手动锁到800MHz卡顿依旧。然后又怀疑weston合成器软件栈开销换成了kmscube直出还是有周期性掉帧。最后是在/sys/class/devfreq/dmc/里发现DDR频率在跑负载时降到了最低档。因为DDR的调频策略没有把GPU访问带宽纳入考量GPU需要大量读纹理时DDR频率却降下去了导致带宽瓶颈。解决办法是把DMC的governor切到performance或者在设备树的DMC OPP表里调整降频阈值。这个问题的排查难点在于它不会报错只会表现成“周期性卡顿”一定要有性能计数器思维别只看CPU和内存。5.4 Mesa版本过旧glmark2直接Segmentation Fault有一回我在一个比较干净的Debian rootfs上只装了libgbm、libEGL和libGLESv2没管版本直接跑glmark2结果进程起来就Segmentation Fault留下一个core dump。最开始以为是Panfrost内核驱动的问题但dmesg里干干净净什么都没输出。后来用gdb看core dump栈停在Mesa内部的某个编译着色器函数里。查了版本发现Mesa是20.x的对Bifrost的支持还很不完整G52这种v5架构很容易触发旧代码里的bug。把Mesa升到23.x之后重新测试问题消失。这个经验说明一个规律Panfrost这个驱动还在快速演进期太老的Mesa版本尽量别用。在RK3568上做产品化最好锁定一个经过你完整回归测试的Mesa版本而不是随手apt装一个。另外一个相关的坑是系统里如果同时存在多个libglvnd版本也可能导致EGL入口被错误分发。检查方法是用eglinfo看EGL_VENDOR是不是Mesa Project以及glxinfo -B里的OpenGL renderer字符串是不是Panfrost。结语实际用下来Panfrost在RK3568上已经从我印象里的“实验品”变成了可以进项目的稳定方案。内核态驱动和Mesa用户态配合好之后日常GLES渲染、Wayland合成、视频叠加这些需求都不成问题。如果你想要更激进的体验可以试试Collabora维护的panfork分支它对Bifrost调度器有一些mainline里还没有的性能补丁我在RK3568上做过基础对比部分场景确实更快但它毕竟不是主线升级时注意跟着对应的Mesa版本走。最后分享一个小技巧在你把Panfrost跑通之后建议把内核启动参数、设备树片段、Mesa版本和glmark2数据都记录下来单独存一份文档。因为后面每次升级内核或者rootfs都需要拿这组基线数据做对比否则出了问题很难判断是新驱动引入的回归还是环境差异造成的。开源GPU驱动的优势之一就是可以回溯和对比把这份优势用起来适配工作会轻松很多。