news 2026/4/23 11:36:57

RK3568双屏异显实现:framebuffer实战案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RK3568双屏异显实现:framebuffer实战案例

RK3568双屏异显实战:从帧缓冲到工业级显示控制

你有没有遇到过这样的场景?一台工控设备,主屏要跑操作界面,副屏却得实时显示监控视频流或广告轮播——两个屏幕内容完全不同,刷新节奏也不一致。传统的桌面系统镜像模式显然不够用,而上X11或Wayland又太重,启动慢、资源占用高。

这时候,framebuffer就成了嵌入式开发者的“秘密武器”。

以瑞芯微RK3568为例,这款四核A55的国产SoC不仅性能强劲,其显示子系统更是支持HDMI、LVDS、MIPI DSI等多种接口组合。本文不讲理论套话,直接带你动手实现双屏异显,深入Linux图形栈底层,看看如何用最轻量的方式掌控两块屏幕。


为什么选 framebuffer?一个被低估的“老将”

很多人一提图形就想到Qt、Wayland甚至Android HAL,但在工业控制、自助终端这类对稳定性要求极高的场景里,越简单越可靠

framebuffer是什么?

你可以把它理解为一块“映射到内存的画布”。只要往这块内存写像素数据,屏幕就会实时更新。它没有窗口管理器、没有合成器、不需要复杂的协议交互——open → mmap → 写内存 → 刷新完成,整个过程干净利落。

更重要的是:
- 启动速度快(内核加载完就能用)
- 资源消耗低(几百KB内存搞定)
- 多屏原生支持(/dev/fb0,/dev/fb1独立存在)
- 编程模型直观(指针操作即可绘图)

别看它是“古董级”接口,在RK3568这种现代平台上,它的背后其实是DRM/KMS 驱动在支撑,硬件能力一点没打折。


双屏是怎么“分家”的?VOP架构揭秘

RK3568能实现真正的“异显”,核心在于它的双VOP设计

VOP(Video Output Processor)是Rockchip自研的显示控制器模块。RK3568有两个独立的VOP单元:VOP0 和 VOP1,每个都可以驱动一个显示通道。比如:

  • VOP0 → HDMI(1920×1080@60Hz)
  • VOP1 → LVDS(1024×600@60Hz)

这两个输出完全独立,分辨率、刷新率、色彩格式互不影响。它们通过DRM子系统创建出两个不同的CRTC(直白说就是“显示管道”),最终分别绑定到/dev/fb0/dev/fb1

这意味着什么?

你可以让fb0显示一张静态图片,fb1播放动画,两者并行不悖,毫无干扰。

这可不是简单的“复制粘贴”,而是真正意义上的多任务并行显示


实战第一步:确认你的双屏已就位

在动手编码前,先确保硬件和驱动已经正确识别了两个屏幕。

检查设备节点

ls /dev/fb* # 应该看到: # /dev/fb0 # /dev/fb1

查看各屏信息

# 查看fb0的基本参数 fbset -fb /dev/fb0 # 输出示例: # geometry 1920 1080 1920 1080-1 32 # 这表示:宽1920,高1080,虚拟宽度1920,深度32位

也可以读取sysfs信息:

cat /sys/class/graphics/fb0/name # 输出可能为:rockchipdrmfb-vop0 cat /sys/class/graphics/fb1/name # 输出可能为:rockchipdrmfb-vop1

如果名字不同且都指向rockchipdrm,则说明双通道已激活。


核心代码:如何向两个屏幕分别绘图?

下面这个例子会告诉你,如何用C语言同时控制两个屏幕,各自绘制不同图形。

#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <linux/fb.h> #include <unistd.h> #include <pthread.h> // 屏幕绘制线程函数 void* draw_screen(void *arg) { int fb_num = *(int*)arg; char dev_path[32]; sprintf(dev_path, "/dev/fb%d", fb_num); int fd = open(dev_path, O_RDWR); if (fd == -1) { perror("无法打开 framebuffer"); return NULL; } struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); ioctl(fd, FBIOGET_FSCREENINFO, &finfo); long screensize = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8); void *fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (fbp == MAP_FAILED) { perror("mmap失败"); close(fd); return NULL; } // 根据fb编号决定画什么 if (fb_num == 0) { draw_red_box(fbp, &vinfo, &finfo); // 主屏画红框 } else { draw_green_circle(fbp, &vinfo, &finfo); // 副屏画绿圈 } munmap(fbp, screensize); close(fd); return NULL; }

上面只是框架,关键在于draw_red_boxdraw_green_circle的实现。我们来看其中一个细节——怎么在一个32位ARGB缓冲中画矩形?

void draw_red_box(void *fbp, struct fb_var_screeninfo *vinfo, struct fb_fix_screeninfo *finfo) { int x, y; for (y = 100; y < 300; y++) { for (x = 100; x < 400; x++) { long location = (x + vinfo->xoffset) * (vinfo->bits_per_pixel / 8) + (y + vinfo->yoffset) * finfo->line_length; // 假设格式为XRGB8888:[B][G][R][X] *((uint32_t*)(fbp + location)) = 0x00FF0000; // 红色 } } }

注意这里的location计算方式:
-line_length是每行字节数(可能大于 xres × bpp,因为有对齐)
-xoffset/yoffset是虚拟屏幕偏移(用于滚动或双缓冲)

只要你搞清了像素布局,就能精准操控每一个点。


工程要点:这些坑我替你踩过了

1. 显存不够?系统直接卡死!

RK3568的显存是预留给GPU和显示系统的,必须在设备树里提前预留。否则双屏一开,OOM(内存溢出)直接宕机。

dts文件中添加:

reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; gpu_memory: framebuffer@0 { compatible = "shared-dma-pool"; reusable; reg = <0x0 0x70000000 0x0 0x8000000>; // 128MB @ 0x70000000 label = "gpu_mem"; }; };

并通过bootargs告诉内核使用这段内存:

rockchip_iommu_dma=1 earlycon console=ttyFIQ0 root=/dev/mmcblk0p5 rw rootwait video=HDMI-A-1:1920x1080@60 video=DSI-1:1024x600@60 mem=3G coherent_pool=1M dma-contiguous-size=128M

建议至少预留64~128MB给显存,特别是跑高清视频时。


2. 图像撕裂怎么办?加个垂直同步!

如果你发现动画闪烁、画面撕裂,那是因为CPU写显存的速度赶不上显示器扫描速度。

解决办法:启用页翻转(page flipping) + vsync同步

虽然标准framebuffer API不直接支持,但我们可以通过DRM ioctl间接操作。不过更实用的做法是:

使用双缓冲机制,在内存中维护两个缓冲区,只在vblank期间交换。

简单模拟如下:

// 分配双倍显存空间(需驱动支持) vinfo.yres_virtual = vinfo.yres * 2; // 更新完成后,通过ioctl切换当前显示缓冲 vinfo.yoffset = next_buffer ? vinfo.yres : 0; ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo);

这样就能避免边刷边读造成的撕裂现象。


3. 权限问题:普通用户打不开/dev/fbX

默认只有root才能访问帧缓冲设备。生产环境中不可能让用户都sudo运行程序。

解决方案:添加udev规则。

创建文件/etc/udev/rules.d/99-fb-permissions.rules

SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", GROUP="video", MODE="0660"

然后把应用用户加入video组:

groupadd video usermod -aG video your_app_user

重启udev服务后,非root也能安全访问fb设备。


性能优化:别让CPU累趴下

纯软件绘图很灵活,但全靠CPU处理像素,效率不高。尤其当你想在副屏播放视频时,很容易成为瓶颈。

几个实用优化技巧:

方法效果
局部刷新只更新变化区域,减少memcpy量
DMA-BUF共享与GPU/VPU共享缓冲区,避免拷贝
使用PRIMEDRM跨设备传输buffer零拷贝
结合SDL/DirectFB利用已有库做加速渲染

例如,你想在副屏播放摄像头画面,完全可以:
1. VPU解码视频到DMA-BUF
2. 将buffer映射到用户空间
3. 直接复制到/dev/fb1的显存区域

全程无需CPU参与像素转换,效率极高。


工业场景实录:某智能售货机的设计思路

我们曾为一款国产智能售货机做过类似方案:

  • 主屏(HDMI,1080P):显示商品列表 + 支付二维码
  • 副屏(LVDS,7寸触摸屏):播放广告视频 + 触控引导

最终选择:
- 主屏用 framebuffer + 自绘UI(极简,响应快)
- 副屏用 GStreamer 解码视频,输出到/dev/fb1
- 关键状态通过共享内存同步,避免进程通信延迟

整机从上电到显示第一帧不到3秒,连续运行半年无异常。客户评价:“比安卓方案稳太多了。”


结语:简单,才是最高级的复杂

尽管Wayland、Zink、Vulkan等新技术层出不穷,但在许多真实世界的应用中,我们并不需要那么“先进”

RK3568上的双屏异显,用 framebuffer 几百行代码就能搞定,稳定、高效、可控。它不像高级图形栈那样华丽,却像一把瑞士军刀——小巧、结实、关键时刻总能派上用场。

掌握 framebuffer,不只是学会一种编程接口,更是建立起对显示系统本质的理解

屏幕不过是内存的一面镜子,你写什么,它就显示什么。

下次当你面对一个多屏需求时,不妨先问问自己:
真的需要整个图形生态吗?还是,一块内存就够了?

如果你正在做RK3568项目,欢迎留言交流具体配置问题。我可以分享一份经过验证的设备树片段和启动参数模板。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 11:36:54

如何在Windows 7上快速安装PythonWin7:终极兼容性解决方案

如何在Windows 7上快速安装PythonWin7&#xff1a;终极兼容性解决方案 【免费下载链接】PythonWin7 Python 3.9 installers that support Windows 7 SP1 and Windows Server 2008 R2 项目地址: https://gitcode.com/gh_mirrors/py/PythonWin7 对于仍在使用Windows 7系统…

作者头像 李华
网站建设 2026/4/19 4:20:03

Windows虚拟显示器终极配置指南:轻松扩展你的工作空间

Windows虚拟显示器终极配置指南&#xff1a;轻松扩展你的工作空间 【免费下载链接】Virtual-Display-Driver Add virtual monitors to your windows 10/11 device! Works with VR, OBS, Sunshine, and/or any desktop sharing software. 项目地址: https://gitcode.com/gh_mi…

作者头像 李华
网站建设 2026/4/17 7:01:04

OptiScaler完整指南:多平台游戏画质优化终极方案

还在为游戏画面模糊、帧率不稳定而烦恼吗&#xff1f;OptiScaler作为一款革命性的图形优化工具&#xff0c;能够为不同硬件配置的玩家带来显著的画质提升和性能优化。通过智能整合多种超分辨率技术&#xff0c;这款工具让游戏体验达到全新高度。 【免费下载链接】OptiScaler DL…

作者头像 李华
网站建设 2026/4/19 11:36:05

基于mptools v8.0的封装仿真实战案例

用mptools v8.0搞定BGA封装仿真&#xff1a;从建模到信号完整性优化的实战全记录最近在做一款服务器CPU的封装设计&#xff0c;客户对DDR5和PCIe Gen5通道的信号质量要求极高。面对1149个I/O、10层有机基板的复杂BGA结构&#xff0c;我们团队面临一个现实问题&#xff1a;如何在…

作者头像 李华
网站建设 2026/4/18 6:44:45

OptiScaler终极指南:5分钟让任何显卡畅享DLSS级超分辨率

OptiScaler终极指南&#xff1a;5分钟让任何显卡畅享DLSS级超分辨率 【免费下载链接】OptiScaler DLSS replacement for AMD/Intel/Nvidia cards with multiple upscalers (XeSS/FSR2/DLSS) 项目地址: https://gitcode.com/GitHub_Trending/op/OptiScaler 还在为显卡不支…

作者头像 李华
网站建设 2026/4/18 17:33:02

【Open-AutoGLM模型实战指南】:手把手教你5步快速部署与调优

第一章&#xff1a;Open-AutoGLM模型怎么用Open-AutoGLM 是一个开源的自动化生成语言模型工具&#xff0c;支持快速部署、推理与微调。使用该模型前需确保环境已安装 Python 3.8 及 PyTorch 1.13&#xff0c;并从官方仓库克隆项目代码。环境配置与依赖安装 克隆项目仓库&#x…

作者头像 李华