一、Direct Rendering Manager(DRM)是linux内核子系统,负责与显卡交互。DRM提供一组API,用户空间程序可以使用该API将命令和数据发送到GPU或者专用图形处理硬件(如高通的MDP),并执行诸如显示器的模式设置之类的操作。用户空间程序可以使用DRM API命令GPU执行硬件加速的3D渲染、视频解码、GPU计算

二、fbdev:Linux内核已经有一个fbdev的API,用来管理图形适配器的帧缓存区,但不能用于满足基于3D加速的现代基于GPU的视频硬件需求,这些设备通常需要在自己的内存中设置和管理命令队列,以将命令分派给GPU,并且还需要管理该内存中的缓存区和可用空间。最初,用户空间程序直接管理这些资源,当多个程序试图同时控制相同的硬件,并以自己的方式设置每个资源时,就会出问题。

选择DRM在于:维护积极、功能齐全且高级;FBDEV维护不积极、功能欠缺。
在这里插入图片描述
DRM允许多个程序同时使用视频硬件资源,DRM获得对GPU的独占访问权,负责初始化和维护命令队列、内存和其他资源。希望使用GPU的程序将请求发送到DRM。
在这里插入图片描述
DRM的范围已得到扩展,已涵盖以前由用户空间程序处理的功能,例如framebuffer管理和模式设置,内存共享对象和内存同步。这些功能有特定的名称如图形执行管理器(GEM)或内核模式设置(KMS)。

DRM检测到的每个GPU都称为DRM设备,并创建了一个设备文件/dev/dri/cardX与之连接,并使用ioctl调用与DRM进行通信。

三、libdrm:一个方便用户空间程序与DRM子系统的接口库。使用libdrm不仅避免将内核接口直接暴露给应用程序,而且还提供在程序之间重用和共享代码的优点。
在这里插入图片描述
四、DRM由两部分组成:通用DRM core:提供可以注册不同DRM驱动程序的基本框架;为用户空间提供了具有通用的、独立于硬件、功能最少的ioctl集。
受支持的特定部分DRM Driver:实现API的硬件相关部分,取决于支持的GPU类型,提供其余的ioctl实现。可以扩展API,提供特定GPU附加功能的ioctl,用户空间libdrm也将通过一个额外的库libdrm-driver扩展。
在这里插入图片描述
五、DRM-Master和DRM-Auth:DRM API中有几个ioctl由于并发问题仅限用户空间单个进程使用,所以将DRM设备分为Master和Auth。

六、GEM:Graphics Execution Manger(GEM)是一种内存管理方法,也是GPU唯一用到DRM的地方

七、TTM:Translation Table Maps是在GEM之前开发的用于GPU的通用内存管理器

八、DMA-BUF:DMA缓冲区共享API是一种Linux内核内部API,旨在提供一种通用机制在多个设备之间共享DMA缓冲区。

九、KMS:Kernel Mode Setting 为了正常工作,显卡或者图形适配器必须设置一种模式(屏幕分辨率、颜色深度和刷新率的组合)。这个模式必须在其自身和所连接的显示屏支持的值的范围内。此操作称为mode-setting

在这里插入图片描述
十、Render nodes:除了主节点/dev/dri/cardX,还会创建一个设备文件/dev/dri/renderDX,称为渲染节点。

Android高通平台上的DRM

在这里插入图片描述
一、KMS由framebuffer,CRTC,Encoder,Connector等组成
CRTC:CRT controller,目前主要用于显示控制,如显示时序,分辨率,刷新率等控制,还要承担将framebuffer内容送到display,更新framebuffer等。
Encoder:负责将数据转换成合适的格式,送给connector,比如HDMI需要TMDS信息。
Connector:它是具体某种显示接口的代表,如hdmi,mipi等
Planes:一个Plane代表一个image layer,最终的image由一个或者多个Planes组成

二、在Android系统上DRM就是通过KMS一面接收userspace交付的应用画面,一面通过connector来向屏幕提交应用绘制的画面。

三、DRM使用示例
…TODO

相关大神文章链接:
何小龙:DRM

The DRM/KMS subsystem from a newbie’s point of view

四、最简单的DRM应用程序(sing-buffer)
drm-howto/modeset.c
通过代码说明了DRM API的用法,如dumb buffer、connector、crtc、framebuffer、encoders,这些都是DRM最基础的概念。

五、最简单的DRM应用程序(double-buffer)
drm-howto/modeset-double-buffered.c
单缓冲会有看到画面闪烁的问题,双缓冲机制可以解决该问题

六、最简单的DRM应用程序(page-flip)
drm-howto/modeset-vsync.c
drmModeSetCtrc()立即执行framebuffer切换动作,很可能会造成撕裂问题(tear effect)。而drmModePageFlip()则会等待vertical-blanks事件

七、最简单的DRM应用程序(plane-test)
plane-test
drmModeSetPlane()是DRM另一个重要的刷图接口。Plane,即硬件图层。使用这个接口可以在屏幕上只显示framebuffer的一部分内容,而不是全屏显示framebuffer。

八、DRM应用程序进阶(Property)
Property
之前介绍的接口,在现在的DRM架构中已经是Legacy的,目前DRM推荐使用的是Atomic接口。
Property(属性),就是把前面legacy的接口传入的参数单独抽出来,做成一个个独立的全局属性,通过设置这些属性参数,即可完成对显示参数的设置。类似于kernel中的sysfs属性节点
Property结构有3部分组成:name、id和value。其中id为该property在DRM框架中全局唯一的标识符。

九、DRM应用程序进阶(atomic-crtc)
atomic-crtc
libdrm Atomic接口,操作Property。
Atomic Commit,即本次commit操作,要么成功,要么保持原来状态不变。
drmModeObjectGetProperties
get_property_id
drmModeAtomicAlloc
drmModeAtomicAddProperty
drmModeAtomicCommit

十、DRM应用程序进阶(atomic-plane)
atomic-plane
使用atomic接口,来实现drmModeSetPlane()相同的操作。

十一、DRM驱动程序开发(开篇)
DRM驱动程序开发开始
介绍了DRM驱动程序中主要的数据结构:crtc plane encoder connector framebuffer property gem

十二、DRM驱动程序开发(VKMS)
VKMS
VKMS是“Virtual Kernel Mode Setting” 的缩写,代码位于drivers/gpu/drm/vkms目录,它是一个软件虚拟的显示设备,但看不到任何显示内容。该驱动主要是用于DRM框架的测试,在驱动流程上,它实现了modesetting该有的基本操作,很适合用来学习DRM驱动程序

十三、DRM GEM驱动程序开发(dumb)
dumb
dumb buffer:不能用于GPU硬件加速的buffer。
创建dumb buffer的目的是要拿去给CPU画图,创建之后要使用mmap映射到用户空间。dumb_create:分配dumb buffer的回调接口

十四、DRM驱动mmap和CMA Helper
mmap
CMA Helper
一次性映射:remap_pfn_range()
Page Fault:触发缺页异常,vm_insert_page()
CMA Helper是一次性映射的典型代表,是DRM驱动中一组通用的GEM API,专用于分配、访问物理连续的系统内存,对于那些不带 IOMMU 或不具有专用显存的 Display 硬件而言,极大的方便了它们的 DRM 驱动开发。

dma-buf系列

十五、dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序
最简单的dma-buf驱动程序
Android ION主要功能:
内存管理器:提供通用的内存管理接口,通过heap管理各种类型的内存。
共享内存:可提供驱动之间、用户进程之间、内核空间和用户空间之间的共享内存。

在Android多媒体底层开发中,不论是Video、Camera、display、GPU,他们的buffer都来自ION,而ION正是基于dma-buf实现。
dma-buf是内核中一个独立的子系统,可以在不同设备、不同子系统之间共享内存的机制。本质上是buffer与file的结合

dma-buf的典型应用框架:
在这里插入图片描述
编写 dma-buf 驱动的三个步骤:
(1)dma_buf_ops
(2)DEFINE_DMA_BUF_EXPORT_INFO
(3)dma_buf_export()

十六、dma-buf 由浅入深(二) —— kmap / vmap
kmap/vmap
dma-buf内核中最多的是用于DMA硬件访问(dma_buf_attach()、dma_buf_map_attachment()),但它也可以用于于CPU软件访问,因为它仍然是一块buffer。

dma-buf API:实现了CPU在内核空间对dma-buf内存的访问
dma_buf_kmap()
dma_buf_kmap_atomic()
dma_buf_vmap()
通过以上api的操作,可以把dma-buf的内存,映射到kernel空间,并转化为CPU可以连续访问的虚拟地址。

十七、dma-buf 由浅入深(三) —— map attachment
map attachment
dma-buf设计之初就是为满足那些大内存访问需求的硬件GPU/DPU设计的

dma-buf API:提供给DMA硬件访问的API
dma_buf_attach()
dma_buf_map_attachment()

sg_table:是由一块块单个物理连续的buffer所组成的链表。DMA硬件访问离散memory的唯一途径
在这里插入图片描述
IOMMU硬件就是用来解析sg_table的

dma_buf_attach():建立dma-buf与device的连接关系

dma_buf_map_attachment():1、生成sg_table 2、同步cache,通常是使用流式DMA映射接口来完成cache同步
dma_map_single()
dma_map_page()
dma_map_sg()
关于DMA一致性映射和流式映射,可以参考DMA与一致性缓存
通过DMA映射,就可以获得可供DMA硬件使用的DMA物理地址

十八、dma-buf 由浅入深(四) —— mmap
前面两篇都是介绍在kernel space对dma-buf进行访问,本篇介绍在user space访问dma-buf
dma_buf_ops提供了mmap回调接口,可以把dma-buf的物理内存直接映射到用户空间,mmap接口通过remap_pfn_range()实现

驱动程序引入了misc driver,通过misc的ioctl接口将dma-buf的fd传递给上层应用程序,应用程序直接使用这个dma-buf fd做mmap()操作;
dma_buf_fd():用于创建一个新的fd,并与该dma-buf的文件相绑定

十九、dma-buf 由浅入深(五) —— file
dma-buf与file
dma-buf与file相关的操作
在我们调用dma_buf_export()开始,file就已经open了,而且这个file还是个匿名文件,应用程序无法通过fd=open(“name”)来获取。
内核api:
dma_buf_fd() dma-buf —>new fd
dma_buf_get() fd —>dma-buf

为什么需要fd?
1.方便应用程序直接在 user space 访问该 buffer(通过 mmap);
2.方便该 buffer 在各个驱动模块之间流转,而无需拷贝;
3.降低了各驱动之间的耦合度;

二十、dma-buf 由浅入深(六) —— begin/end cpu_access
begin/end cpu_access
用于cache同步的接口,暂时没详细看

二十一、dma-buf 由浅入深(八) —— ION
ION
ion驱动代码位于driver/staging/android/ion

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐