DRM显示子系统:Framebuffer、GEM、DMA 与 IOMMU 的关系
1. framebuffer
前面已经说过,framebuffer 更像“显示视图”。真正存像素的,通常是 GEM buffer 或其他底层内存对象。
所以一块图像从“创建”到“显示”,通常会经过这样几层关系:
- 先分配一块可显示使用的底层缓冲区;
- 再基于它创建 framebuffer;
- 最后把 framebuffer 绑到 plane 上。
一句更直接的话:
- buffer 解决“像素放哪儿”;
- framebuffer 解决“这块像素该怎么解释和显示”。
2. GEM
GEM(Graphics Execution Manager)是 DRM 里非常重要的一层缓冲区管理抽象。它不等于 GPU 专用,也不只服务 3D,显示路径里同样大量使用 GEM buffer。
对 KMS 来说,GEM 带来的几个实际好处是:
- 缓冲区对象有统一生命周期;
- 可以被多个 DRM 子系统共享;
- 更容易和 dma-buf、IOMMU、缓存同步这些机制衔接起来。
很多简单显示设备会支持 dumb buffer。它不是另一套体系,而是 DRM 为“简单线性显示缓冲区”提供的一种便捷分配接口。用户态常常先申请 dumb buffer,再把它封装成 framebuffer。
3. DMA
这是最值得单独拎出来说的一点。
驱动里经常会看到三种不同语义的地址:
- CPU 虚拟地址:内核或用户态代码读写时使用的地址;
- CPU 物理地址:内存芯片在 CPU 视角下的物理地址;
- DMA 地址:设备在 DMA 事务里使用的地址。
这三者在某些简单系统里可能恰好接近,但概念上绝不能混。
尤其是有 IOMMU 的系统里,设备看到的 DMA 地址并不一定等于 CPU 物理地址。更准确的说法是:
DMA 地址是设备侧使用的 bus address。
设备发起读写时,走的是这套地址空间;IOMMU 存在时,会把它再翻译到真实物理内存。
4. IOMMU
对显示控制器来说,工作方式通常很简单:
“到某个地址去读像素,然后按时序往外送。”
问题在于,这个“某个地址”如果直接暴露成 CPU 物理地址,灵活性和隔离性都很差。IOMMU 的加入,就是为了让设备使用受管理的 DMA 地址空间。
它带来的价值主要有三点:
- 设备不必直接绑定到 CPU 物理地址;
- 不同设备或上下文可以拥有隔离的地址视图;
- 缓冲区搬移、共享、重映射时更灵活。
对显示驱动开发者来说,需要时刻记住:
显示硬件真正去读的是 DMA 地址,不是你在内核日志里看到的那个普通指针。
5. pitch、offset 和多平面格式
显示路径里还有三个常见概念,经常和 buffer 一起出现。
pitch / stride
每一行实际跨过多少字节。为了对齐,pitch 通常会比“width × bytes_per_pixel”更大。
offset
某个平面在底层缓冲区里的起始偏移。多平面格式尤其常见。
多平面格式(multi-planar format)
比如 NV12,亮度平面和色度平面是分开放的。此时 framebuffer 里要同时描述多个 plane 的 pitch 和 offset。
这也是 drm_framebuffer 里要用数组保存 pitches[] 和 offsets[] 的原因。

浙公网安备 33010602011771号