DRM显示子系统:Framebuffer、GEM、DMA 与 IOMMU 的关系

1. framebuffer

前面已经说过,framebuffer 更像“显示视图”。真正存像素的,通常是 GEM buffer 或其他底层内存对象。

所以一块图像从“创建”到“显示”,通常会经过这样几层关系:

  1. 先分配一块可显示使用的底层缓冲区;
  2. 再基于它创建 framebuffer;
  3. 最后把 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. pitchoffset 和多平面格式

显示路径里还有三个常见概念,经常和 buffer 一起出现。

pitch / stride
每一行实际跨过多少字节。为了对齐,pitch 通常会比“width × bytes_per_pixel”更大。

offset
某个平面在底层缓冲区里的起始偏移。多平面格式尤其常见。

多平面格式(multi-planar format)
比如 NV12,亮度平面和色度平面是分开放的。此时 framebuffer 里要同时描述多个 plane 的 pitch 和 offset。

这也是 drm_framebuffer 里要用数组保存 pitches[]offsets[] 的原因。

posted @ 2026-07-22 18:41  G777  阅读(2)  评论(0)    收藏  举报