DRM --- direct rendering manager

以下来自维基 general description:

Linux内核已经有了一个名为fbdev的API,用于管理图形适配器的帧缓冲区,但它不能用于处理现代基于gpu的3d加速视频硬件的需求。这些设备通常需要在它们自己的内存中设置和管理一个命令队列,以便将命令分发给GPU,还需要管理该内存中的缓冲区和空闲空间。最初,用户空间程序(如X Server)直接管理这些资源,但它们通常表现得好像它们是唯一能够访问这些资源的程序。当两个或多个程序试图同时控制相同的硬件,并以自己的方式设置其资源时,大多数情况下它们会灾难性地结束

DRM能够允许多个程序共同使用视频硬件资源。DRM获得对GPU的独占访问权,并负责初始化和维护命令队列、内存和任何其他硬件资源。希望使用GPU的程序将请求发送给DRM,后者充当仲裁人并注意避免可能的冲突。

DRM的范围在过去几年里得到了扩展,涵盖了以前由用户空间程序处理的更多功能,如帧缓冲区管理和模式设置、内存共享对象和内存同步。其中一些扩展被赋予了特定的名称,如图形执行管理器(GEM)或内核模式设置(KMS),但它们实际上是整个内核DRM子系统的一部分。

目前计算机通常包含两个GPU,一个是离散的GPU,一个是集成的GPU,导致了新的问题,如GPU切换,这些问题也需要在DRM层解决。为了匹配英伟达Optimus技术,DRM提供了GPU卸载能力,称为PRIME.

软件架构:

DRM驻留在内核空间中,因此用户空间程序必须使用内核系统调用来请求它的服务。但是,DRM没有定义它自己的系统调用。相反,它遵循Unix“一切都是文件”的原则,通过文件系统名称空间公开gpu,使用/dev层次结构下的设备文件。每一个被DRM检测到的GPU都被称为DRM设备,并创建一个设备文件/dev/driver/cardx(其中X是一个连续的数字)来与它连接。希望与GPU通信的用户空间程序必须打开这个文件并使用ioctl调用与DRM通信。不同的ioctl对应于DRM API的不同功能。

为了方便用户空间程序与DRM子系统的接口,创建了一个名为libdrm的库。这个库只是一个包装器,它为DRM API的每个ioctl以及常量、结构和其他辅助元素提供了用C编写的函数。使用libdrm不仅避免了将内核接口直接暴露给应用程序,而且提供了在程序之间重用和共享代码的通常优点。

DRM由两部分组成:通用的“DRM core”和针对每种支持的硬件类型的特定的“DRM driver”。
DRM core提供了基本框架,不同的DRM驱动程序可以在其中注册,还为用户空间提供了最小的ioctl集,具有通用的、硬件独立的功能。
DRM driver实现API中与硬件相关的部分,具体到它所支持的GPU类型;并提供DRM core未覆盖的剩余ioctl的实现,也可以扩展API,提供附加的ioctl,具有仅在此类硬件上可用的额外功能。当特定的DRM driver提供了扩展API时,libdrm也通过一个额外的库libdrm-driver进行扩展

kms


以下来自开发者手册

大纲:

  1. driver 初始化
  2. 内存管理
  3. mode setting
  4. kms初始化
  5. helper function
  6. kms属性
  7. 文件操作
  8. ioctl
  9. 命令提交/隔离
  10. 暂停/恢复
  11. DMA

1 -- driver 初始化

典型的初始化包括:设置cmd buffer,初始化输出配置,初始化core service

每一个DRM driver都有drm_driver结构体,首先初始化drm_driver,然后传入drm_*_init()进行注册

drm_driver结构包括:
1. 用于描述driver的static信息
2. 一些指针,drm core通过调用这些指针实现drm api

driver info

driver_features中设置flag来体现driver的特性,在注册时就要设置这些flag

  • DRIVER_USE_AGP / DRIVER_REQUIRE_AGP
  • DRIVER_PCI_DMA   能否映射 PCI DMA buffers 至 userspace
  • DRIVER_SG 是否支持离散/聚集DMA内存映射
  • DRIVER_HAVE_DMA   是否支持DMA
  • DRIVER_HAVE_IRQ 是否含中断处理
  • DRIVER_IRQ_SHARED 是否支持共享中断
  • DRIVER_GEM 是都使用GEM进行内存管理
  • DRIVER_MODESET 是否支持KMS
  • DRIVER_PRIME 实现 DRM PRIME buffer sharing.
  • DRIVER_RENDER 是否支持渲染节点

driver versions

int major;
int minor;
int patchlevel;

driver info

char *name;
char *desc;
char *date;

driver load加载
是驱动和设备的entry 点,负责分配和初始化驱动私有数据和指定支持的性能计数器;执行资源分配和映射(例如获取时钟,映射寄存器或分配命令缓冲区);初始化内存管理器(“内存管理”part),安装IRQ处理程序(“IRQ注册”part);设置垂直空白处理(“垂直空白”的部分);模式设置(“模式设置”part)和初始输出配置(“KMS初始化和清理”part)。

int (*load) (struct drm_device *, unsigned long flags);

其中flag是通过drm_*_init()注册返回的id,只有pci设备使用这一项,usb之类的不用

driver private

driver private可以将drm_device挂起(什么意思),然后可跟踪某些信息bit,比如寄存器偏移量、cmd buffer状态、寄存器状态。加载时可设置drm_device.dev_priv,卸载时设为null

irq注册

DRM core 提供drm_irq_install进行irq注册(适用于单中断处理器)

drm_irq_install:
调用drm_dev_to_irq,去总线上检索一个irq号
调用irq_preinstall,可选的
调用request_irq,中断处理函数必须传入request_irq
调用irq_postinstall,启用中断

drm_irq_uninstall
它首先唤醒所有等待vblank中断的进程,以确保它们不会挂起,然后调用可选的irq_uninstall驱动程序操作。该操作必须禁用所有硬件中断(关中断)。最后调用free_irq释放IRQ。

多中断处理器的driver只能通过手动注册的方式(不能调用drm_irq_install)

初始化内存管理器

选择TTM/GEM进行初始化,后续有详述

其他配置

在配置过程中,PCI设备可能需要的另一个任务是映射视频BIOS。在许多设备上,VBIOS描述设备配置、LCD面板计时(如果有的话),并包含指示设备状态的标志。可以使用pci_map_rom()调用来映射BIOS,这是一个方便的函数,它负责映射实际的ROM,不管它是否已经被隐藏到内存中(通常在地址0xc0000),还是存在于ROM BAR中的PCI设备上。注意,在ROM被映射并且提取了任何必要的信息之后,它应该被解除映射;在许多设备上,ROM地址解码器与其他bar共享,因此将其映射可能导致不希望的行为,如挂起或内存损坏。

2 -- 内存管理

DRM core 包括两个内存管理器,即转换表映射(TTM)和图形执行管理器(GEM)。TTM是第一个被开发的DRM内存管理器,它试图成为一个一刀切的解决方案。它提供了一个单一的用户空间API,以适应所有硬件的需求,支持统一内存架构(UMA)设备和具有专用视频RAM的设备(即大多数离散视频卡)。这导致了一段庞大而复杂的代码很难用于驱动程序开发。

GEM最初是英特尔赞助的一个项目,以应对TTM的复杂性。GEM不是为每个与图形内存相关的问题提供解决方案,而是识别驱动程序之间的公共代码,并创建一个支持库来共享它。GEM的初始化和执行要求比TTM更简单,但没有显存管理功能,因此只能用于UMA设备。

GEM

GEM向用户空间公开了一组与内存相关的标准操作,并向驱动程序公开了一组helper func,并允许驱动程序使用自己的私有API实现特定于硬件的操作。

GEM管理抽象缓冲区对象,而不知道每个缓冲区包含什么。因此,需要了解缓冲区内容或用途(比如缓冲区分配或同步原语)的api必须使用特定于驱动程序的ioctl实现。

GEM功能包括:

  • 内存分配和释放
  • 命令执行
  • 命令执行时的光圈管理(?

特定于设备的操作,如命令执行、固定、缓冲区读写、映射和域所有权转移都留给特定于驱动程序的ioctls。

gem初始化

在drm driver进行加载load时,创建一个DRM Memory Manager对象,该对象为对象分配提供地址空间池。在KMS配置中,如果硬件需要,驱动程序需要在核心GEM初始化之后分配并初始化一个命令环缓冲区。

gem创建对象

GEM对象由结构体drm_gem_object的实例表示。驱动程序需要用私有信息扩展GEM对象,从而创建一个特定于驱动程序的GEM对象结构类型,然后嵌入drm_gem_object结构体的实例中。

创建对象时首先分配内存,然后调用drm_gem_object_init初始化上述嵌入的gem对象。该函数接受一个指向DRM设备的指针、一个指向GEM对象的指针和缓冲区对象大小(以字节为单位)

GEM使用shmem分配匿名可分页内存。Drm_gem_object_init将创建一个请求大小的SHMFS文件,并将其存储到结构drm_gem_object filp字段中。、

驱动程序通过为每个页面调用shmem_read_mapping_page_gfp来负责实际的物理页面分配。注意,他们可以在初始化GEM对象时决定分配页面,或者在需要内存时决定延迟分配(例如,当用户空间内存访问导致页面错误时,或者当驱动程序需要启动涉及内存的DMA传输时)。

驱动程序可以调用drm_gem_object_alloc函数来分配和初始化结构drm_gem_object实例。(但是私有的gem对象就不行)。在使用drm_gem_object_init初始化GEM对象之后,GEM core将调用可选的驱动程序gem_init_object操作。

int (*gem_init_object) (struct drm_gem_object *obj);

gem对象的生命周期

采用引用计数的方式,引用可以通过分别调用drm_gem_object_reference和drm_gem_object_unreference来获取和释放。调用者必须持有drm_device结构互斥锁。当最后一个引用被释放时,GEM核心调用drm_driver gem_free_object操作。

gem对象naming

用户空间和内核之间的通信引用使用本地句柄、全局名称或文件描述符。

应用程序通过驱动程序特定的ioctl获得GEM对象的句柄,并可以使用该句柄引用其他标准或驱动程序特定的ioctl中的GEM对象。

GEM名称在目的上与句柄相似,但不是DRM文件的本地名称。它们可以在进程之间传递,以全局引用GEM对象。名称不能直接用于引用DRM API中的对象,应用程序必须可使用ioctls将句柄转换为名称和名称转换为句柄。

与全局名称类似,GEM文件描述符也用于跨进程共享GEM对象。它们提供了额外的安全性。支持GEM文件描述符的驱动,也称为DRM PRIME API

helper func

通过使用辅助函数drm_gem_prime_export和drm_gem_prime_import,驱动程序可以在更简单的api中实现gem_prime_export和gem_prime_import。这些函数通过5个较低级的驱动程序回调实现了对dma-buf的支持

gem 对象映射

GEM更倾向于通过特定于驱动程序的ioctl对缓冲区进行类似于读/写的访问,而不是将缓冲区映射到用户空间。

mmap系统调用不能直接用于映射GEM对象,因此方法是在DRM文件句柄上使用mmap系统调用。

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

DRM通过通过ff_t offset假偏移来标识要映射的GEM对象。假偏移以特定于驱动程序的方式传递给应用程序,然后可以用作mmap偏移量参数。GEM核心提供了一个帮助方法drm_gem_mmap来处理对象映射。将根据偏移值查找GEM对象,并将VMA操作设置为drm_driver gem_vm_ops字段。

内存一致性

cpu与gpu之间的内存一致性大概是说一边用完了就刷新到另一边的缓存/内存中,由ioctl管理,必要时阻塞用户然后去做刷新

cmd执行

对于GPU设备来说,最重要的GEM功能可能是为客户端提供命令执行接口。客户端程序构造命令缓冲区,其中包含对以前分配的内存对象的引用,然后将它们提交给GEM。此时,GEM会小心地将所有对象绑定到GTT中,执行缓冲区,并在访问相同缓冲区的客户机之间提供必要的同步。

3 -- mode setting -- 帧缓冲区

驱动程序必须通过调用DRM设备上的drm_mode_config_init来初始化模式设置核心。包括:

int min_width, min_height;
int max_width, max_height;
struct drm_mode_config_funcs *funcs;

帧缓冲区的最小和最大宽度和高度。

创建帧缓冲区

帧缓冲区是抽象的内存对象,提供扫描到CRTC的像素源。应用程序显式地请求通过DRM_IOCTL_MODE_ADDFB(2) ioctls创建帧缓冲区,并接收一个不透明句柄,可以传递给KMS CRTC控制,平面配置和页面翻转函数。

1 driver首先验证通过mode_cmd所请求的帧缓冲区参数。(不能过大不能非法
2 然后将创建、初始化并返回结构体drm_framebuffer的实例。如果需要,可以将实例嵌入到更大的驱动程序特定结构中。驱动程序必须从通过drm_mode_fb_cmd2参数传递的值中填充它的宽度、高度、间距、偏移量、深度、bits_per_pixel和pixel_format字段。
3 drm_framebuffer_init完成实例化

对帧缓冲区的操作有:

create_handle 创建帧缓冲区底层内存对象的句柄。
destroy销毁帧缓冲区对象并释放所有相关资源。
dirty帧缓冲区的一个区域在响应DRM_IOCTL_MODE_DIRTYFB ioctl调用时发生了变化。

4 -- kms初始化

A KMS device is abstracted and exposed as a set of planes, CRTCs, encoders and connectors.

crtc

CRTC是一个抽象,表示芯片的一部分,其中包含一个指向扫描缓冲区的指针。因此,可用的crtc数量决定了在任何给定时间可以激活的独立扫描缓冲区的数量。CRTC结构包含几个字段来支持这一点:指向某些显存的指针(抽象为帧缓冲区对象)、显示模式和显存的(x, y)偏移量,以支持平移或在一块显存跨越多个CRTC时进行配置。

crtc初始化

一个kms服务必须注册一个以上的drm_crtc实例,并通过drm_crtc_init初始化

crtc操作

int (*set_config)(struct drm_mode_set *set);

应用一个新的CRTC配置到设备。该配置指定一个CRTC、要从其中扫描出的帧缓冲区、帧缓冲区中的(x,y)位置、显示模式和要使用CRTC驱动的连接器数组(如果可能的话)。

int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb,struct drm_pending_vblank_event *event);

为CRTC安排一个页面翻转到给定的帧缓冲区。是一种同步机制。

page_flip操作安排页面翻转。一旦任何以新帧缓冲区为目标的暂挂渲染完成,CRTC将被重新编程,在下一次垂直刷新后显示该帧缓冲区。操作必须立即返回,而不是等待呈现或页面翻转完成,并且必须阻塞任何新的呈现到帧缓冲区,直到页面翻转完成。

plane

平面表示可以在扫描过程中与CRTC混合或叠加在其上的图像源。平面与帧缓冲区相关联,以裁剪图像内存(源)的一部分,并可选地将其缩放到目标大小。然后将结果与CRTC混合或叠加在其上。

plane是可选的 结构是drm_plane

encoder 编码

编码器从CRTC获取像素数据,并将其转换为适合任何附加连接器的格式。

connectors

连接器是设备上像素数据的最终目的地,通常直接连接到外部显示设备,如显示器或笔记本电脑面板。一个连接器一次只能连接到一个编码器上。连接器也是保存有关附加显示器的信息的结构,包含显示数据、EDID数据、DPMS和连接状态的字段,以及有关附加显示器支持的模式的信息。

kms api

太多了随便吧。。。

5 -- helper functions

驱动程序提供的CRTC、编码器和连接器功能实现了DRM API。DRM核心和ioctl处理程序调用它们来处理设备状态更改和配置请求。由于实现这些函数通常需要不特定于驱动程序的逻辑,因此可以使用中间层帮助函数来避免重复样板代码。

DRM核心包含一个中间层实现。中间层提供了几个CRTC、编码器和连接器函数(从中间层顶部调用)的实现,这些函数对请求进行预处理,并调用驱动程序(在中间层底部)提供的较低级函数。例如,可以使用drm_crtc_helper_set_config函数填充结构drm_crtc_funcs set_config字段。当调用时,它将把set_config操作拆分为更小、更简单的操作,并调用驱动程序来处理它们。

为了使用中间层,驱动程序调用drm_crtc_helper_add, drm_encoder_helper_add和drm_connector_helper_add函数来安装它们的中间层底层操作处理程序,并用指向中间层顶层API函数的指针填充drm_crtc_funcs, drm_encoder_funcs和drm_connector_funcs结构。安装中间层底层操作处理程序最好在注册相应的KMS对象之后立即完成。

中间层没有在CRTC、编码器和连接器操作之间分割。要使用它,驱动程序必须为所有三个KMS实体提供底层函数。

常识 | drm kms 详解相关推荐

  1. android sdk 环境签名,SDK接入必备常识——keystore签名文件详解

    已经在使用u8sdk的童鞋应该知道,我们在u8sdk中增加了签名相关的配置.但是,有很多对Android不了解的童鞋,对签名文件还是了解甚少.关于u8sdk中自定义签名文件可以看之前的博客(自定义签名 ...

  2. 过拟合详解:监督学习中不准确的“常识”

    导语:本文为Mehmet Süzen撰写文章的译文,稍有删改.文章清晰地阐释和区分过度拟合及过度拟合等概念,对于本领域学习者正确理解专业术语多有帮助.正如作者在原文末所指出的:对待简单的概念,我们也应 ...

  3. linux查看空间使用情况并且清除,科技常识:Linux 查看空间使用情况的实例详解...

    今天小编跟大家讲解下有关Linux 查看空间使用情况的实例详解 ,相信小伙伴们对这个话题应该也很关注吧,小编也收集到了有关Linux 查看空间使用情况的实例详解 的相关资料,希望小伙伴会喜欢也能够帮助 ...

  4. linux get与put,科技常识:Linux ftp 命令行中下载文件get与上传文件put的命令应用详解...

    今天小编跟大家讲解下有关Linux ftp 命令行中下载文件get与上传文件put的命令应用详解 ,相信小伙伴们对这个话题应该也很关注吧,小编也收集到了有关Linux ftp 命令行中下载文件get与 ...

  5. html里position属性,科技常识:详解html中 position属性用法(四种)

    今天小编跟大家讲解下有关详解html中 position属性用法(四种) ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关详解html中 position属性用法(四种) 的相关资料,希望小 ...

  6. css画心形原理,科技常识:使用CSS画爱心的过程详解

    今天小编跟大家讲解下有关使用CSS画爱心的过程详解 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关使用CSS画爱心的过程详解 的相关资料,希望小伙伴们看了有所帮助. 今天小颖给大家分享一个 ...

  7. 并发编程专题——第二章(并发编程之Synchronized详解)

    日常中我们都会用到Synchronized关键字,但是面试就喜欢问这些,你说不重要吧,面试就不问了,你说重要吧,工作中除了高并发之外,很少能在业务代码中使用到的.所以笔者顶着风险,写下此篇对Synch ...

  8. 悟道·文澜详解:目前最大的中文多模态通用预训练模型

    近年来,BERT等预训练语言模型在多类自然语言处理任务上取得了显著的性能提升,从而极大地改写了研究范式.随着OpenAI超大规模语言模型GPT-3的发布,预训练语言模型在自然语言理解能力上再次被推至新 ...

  9. 视频直播技术详解(7)现代播放器原理

    <视频直播技术详解>系列之七:现代播放器原理 牛小七2016年9月29日发布在 视频直播技术详解 from: http://blog.qiniu.com/archives/7040 七牛云 ...

最新文章

  1. LinuX编译显示内核配置无效,配置编译内核(Linux kernel)
  2. 复选框(checkbox)、单选框(radiobox)的使用
  3. mysql gps海拔表_GPS海拔表
  4. GHOSTXPSP3系统封装网页图文教程
  5. 【数字全排列】LeetCode 60. Permutation Sequence
  6. How Google Tests Software (出书,停止更新)
  7. 【计组】计算机乘法运算
  8. 小米手机访问电脑共享文件_小米手机共享文件夹在哪里
  9. android 自启动权限,引导用户开启开机自启动权限
  10. How to learn a new technology
  11. RMAN-06817: Pluggable Database CHARLESPDB cannot be backed up in NOARCHIVELOG mode.
  12. java代码运行的三个步骤,22年最新
  13. cli模式下php会超时吗,php cli模式下调试
  14. javascript函数总结
  15. Eligible Segments (CF 1588 E)
  16. 谈谈象棋的基本功《一》残局篇
  17. layui————一个页面展示两个页签
  18. 城市记忆(4)赫连果城——(白口骝)薄骨律——刁公城
  19. Mac同时访问公司内外网
  20. #HT4928#SM5401 SOP-8移动电源SOC同口充放电 0.8A线性充电+0.8A开关放电 引脚完全兼容HT4928 功能替代TP4333

热门文章

  1. CC2530步进电机
  2. 时间序列 R 08 指数平滑 Exponential smoothing
  3. 【数据分析 R语言实战】学习笔记 第六章 参数估计与R实现(上)
  4. python用均值填充空值_python-用同一列的平均值填充pyspark DataFrame 列的空值
  5. PMP®第五章:项目范围管理
  6. Cadence LDO capless 电路,包括版图,已通过lvs ,drc检查,个人流片过,包括偏置全电路
  7. LAS语音识别框架发展简述
  8. RxJava+Retrofit+Mvp实现购物车(没有结算页面)
  9. 交换机与路由器技术:VLAN Trunk、单臂路由和三层交换及配置
  10. Java Service Wrapper将java程序设置为服务