转自:

http://manpages.ubuntu.com/manpages/utopic/man7/drm-kms.7.html

根据自己的理解来转述一下:

摘要:

DRM 是linux 下的图形渲染架构(Direct Render Manager) ,  具体的说是显卡驱动的一种架构(驱动如何玩? 把功能封装成 open/close/ioctl 等标准接口,应用程序调用这些接口来驱动设备)。

作为显卡,最基本的功能就是把用户的绘图输出到显示屏上,DRM 如何去实现呢,先看看DRM 把“这件事”给你概括的几个基本要素:

画布(FrameBuffer) ,  绘图现场(CRTC) , 输出转换器(Encoder) ,  连接器(Connector)  ,  然后就到显示屏了

1  画布( FrameBuffer )

对计算机来说,FrameBuffer 就是一块驱动和应用层都能访问的内存,当然画图之前要有一定的格式化,比方说我可以规定什么样的色彩模式(RGB24 , I420 , YUUV 等等), 分辨率是多大,还有啥参数,那就要到绘图现场去看了 :p

2  绘图现场(CRTC)

简写翻译过来是阴级摄像管上下文,在DRM 里 CRTC 就表示显示输出的上下文了,首先 CRTC 内指一个 FrameBuffer 地址, 外连一个Encoder。 它们俩之间如何沟通? 这就是显示模式(ModeSet)要做的事情,ModeSet 包括了像前面提到的色彩模式 , 还有说显示的时序(timings , ModeLines 等都代表了这个意西)等, 通常时序可以按以下来表达 

PCLK HFP HBP HSW X_RES VFP VBP VSW Y_RES

像素时钟 水平前回扫 水平后回扫 水平同步头 水平有效长度 垂直前回扫 垂直后回扫 垂直同步头 垂直有效长度

一个CRTC 可以连接多个 Encoder , 干啥用,实现复制屏幕功能。

3  输出转换器(Encoder )

想想 CRT 这种土疙瘩就够复杂了,我们的显卡很牛奔的可以连接各种不同的设备,显然输出需要不同的信号转换器,将内存的像素转换成显示器需要的信号(DVID , VGA , YPbPr , CVBS 等等……)

4 连接器 (Connector )

不是指物理线,回到DRM 这是一个抽象的数据结构 ,代表连接的显示设备,从这里我们可以得到设备的EDID , DPMS 连接状态等.

5 显示面(Planner)

咦,怎么多出来一个。我也很呐闷,以上的东东不够地干活? 其实很多创新往往源于人对现实界的不满足。你又要看文字学习,又要看电影打游戏, 还有厉害的可以一边聊天一边看电影。 这里对立出来两个概念,像文字交互这种小范围更新的Graphics 模式,和全幅更新速度奇快的 Video 模式,这两种模式将显卡的使用拉上了两个极端。

于是 Planner 的概念就发挥了很好的作用,它给视频刷新提供了一条绿色通道,偶不和图形搞在一起了,偶是一个新的图层(或overlay),可以叠加在Graphic之上或之下,偶还可以缩放…

文档上说 Planner 也在 FrameBuffer 上,这个没关系,这里我们看出来 CRTC 里要显示的东东应该是一种组合(blending)了。 

看懂了概念,下一篇来分析具体的数据结构和接口。

参考文档:

http://manpages.ubuntu.com/manpages/utopic/man7/drm-kms.7.html

http://events.linuxfoundation.org/sites/events/files/lcjpcojp13_pinchart.pdf

http://landley.net/kdocs/htmldocs/drm.html

http://events.linuxfoundation.org/sites/events/files/slides/brezillon-drm-kms.pdf

http://elinux.org/images/7/71/Elce11_dae.pdf

一 上一篇介绍了 linux 的显示驱动drm 的架构,在这里按一定顺序回顾一下:

1 我把显示器连到显卡的DVI输出口, 这个连接抽象成 Connector

2    在 DVI 的 Connector 上驱动会分配 DVI 信号的 Encoder ,  如果没分配, connector 资源上会找到 所有可用的 encoders

3    encoder 是为图像扫描现场 crtc 服务的, 驱动可能会给encoder 分配crtc , 或者从 encoder 的 possible_crtc 上能找到可用的

4    crtc 扫描现场要配置显示图像的物理内存区 fb

5    fb -> crtc -> encoder - > connector 这种关系绑定之后,绘图工作已经开始, 你可以在fb 上任意写画,然后立马得到显示!

6 然而为了避免图像撕裂,可以建立多 fb (缓冲) 通过 pageFlip 操作来刷新画图。

7 当然还有专为video 刷新用的plane , plane 也要绑定到 crtc  才能工作。

二 总结 + drm api 的使用:

api 使用参考 David Herrmann <dh.herrmann@googlemail.com> 的 drm-howto 以及 weston 还有 drm自带的 modetest 程序

drm api 核心配置就是要绑定一个 crtc 的关系 fb -> crtc -> encoder - > connector

我们来看“一”的回顾,咋是按照逆向的顺序?哈哈其实这样才顺理成章, api 如何用,往下看:

1 首先要打开drm 驱动模块,然后获取所有的资源

fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);

drmModeRes res = drmModeGetResources(fd);

res 里有啥, res 里告诉了有几个connector , 几个 encoder , 几个 crtc 等以及他们的id , 完全不成套!

2 从 connector 开始, 顺藤摸瓜

先获取 connecotr 的具体资源

drmModeConnector *  conn = drmModeGetConnector(fd, res->connectors[i]);

conn资源里重要的有两部分,一部分是通过线缆读出来显示器的 "modes " 如 1920x1080@60 等, 当然你要选一个最喜欢的

另一部分是encoder 按照一章节的2顺序开始找 encoder (看 drmModeConnector 的定义)  :p

3 给encoder 寻找合适的 crtc

按照一章节的 3 顺序找 crtc

4 为 crtc 创建fb

drm 的例子 modetest 写的很详细,  ARGB  可以直接 drmModeAddFB , 多平面的fb 可以用 drmModeAddFB2

5 绑定

核心四元组 < fb , crtc , conn ,  mode >

int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,

uint32_t x, uint32_t y, uint32_t *connectors, int count,

drmModeModeInfoPtr mode);

6 pageFlip

extern int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
                 uint32_t flags, void *user_data);

这个的玩法得好好记下,

首先 poll (drm_fd ) 可以收到 drm 的 POLLIN  消息, 消息里面无非两种一种是 VBLANK , 一种是 pageFlip complete

其次 收到 消息后必须要 调用drmHandleEvent(drm_fd , &evctx); 来处理消息 ,记得必须把你的 pageFlip 处理函数填到evctx里,

pageFlip 处理函数里干啥呢, pageFlip 一帧结束了,当然要 pageFlip 下一帧!

7 plane

plane 的玩法没搞明白,尝试了下,使用多缓冲 调 drmModeSetPlane 来换页可以实现视频的播放,但遇到两个问题:

其一是 SetPlane 的时机, 如何等待一个显示器的场同步? 看了 vblank 的code 感觉 vblank 是针对一个显卡的同步,但我有多个显示器呢?

其二是SetPlane 的运行耗时,我的 i3 cpu 执行一次用了 22 ~ 23 ms , 莫名其妙。

本想着plane 的yuv 通道可以节省资源,有这两大问题在就没法办了, pageFlip 的 fb 只能跟显示器相同颜色空间,并且通常是 ARGB !!

---------------------
作者:walletiger
来源:CSDN
原文:https://blog.csdn.net/walletiger/article/details/46596399

linux ModeSetting学习

2014年04月13日 20:35:24 Libresoft 阅读数:3725 标签: linux kernel mode setting drm

1、数据及数据结构:

Connector:代表显卡上的插口,有几个Connector表示会有几个输出。

CRTC:crt controller,负责将帧缓存中的数据传送到Connector,数据在传送到Connector之前会经过Encoder。 帧缓存 --> CRTC --> Encoder --> Connector --> 显示器。

FrameBuffer:在这里帧缓存并不是指的显存上的某一块区域,而是Linux DRM抽象出来的一个概念,用fb_id表示。

drm_mode_create_dumb:drmIoctl的参数,意思是请求内核创建缓存。 这个才是真正的内存块,可以使用mmap映射到程序虚拟内存中。Framebuffer的创建中必须指定一个缓存的id。

2、函数:

drmModeSetCrtc:最核心的函数之一,它负责将建立从帧缓存到Connector的关联。只有调用它,显示器才能显示缓存中的数据。

drmModePageFlip:直译就是翻页,笔者的理解是 drm_mode_create_dumb类型的缓存其实是双缓存,只有调用此函数之后,crtc才能将之前写入的数据传送给显示器。

3、代码:

找到处于连接状态的Connector

  1. drmModeConnector* FindConnector(int fd)

  2. {

  3. drmModeRes *resources = drmModeGetResources(fd); //drmModeRes描述了计算机所有的显卡信息:connector,encoder,crtc,modes等。

  4. if (!resources)

  5. {

  6. return NULL;

  7. }

  8. drmModeConnector* conn = NULL;

  9. int i = 0;

  10. for (i = 0; i < resources->count_connectors; i++)

  11. {

  12. conn = drmModeGetConnector(fd, resources->connectors[i]);

  13. if (conn != NULL)

  14. {

  15. //找到处于连接状态的Connector。

  16. if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0 && conn == NULL)

  17. {

  18. break;

  19. }

  20. else

  21. {

  22. drmModeFreeConnector(conn);

  23. }

  24. }

  25. }

  26. drmModeFreeResources(resources);

  27. return conn;

  28. }

查找与Connector匹配的Crtc

  1. int FindCrtc(int fd, drmModeConnector *conn)

  2. {

  3. drmModeRes *resources = drmModeGetResources(fd);

  4. if (!resources)

  5. {

  6. fprintf(stderr, "drmModeGetResources failed\n");

  7. return -1;

  8. }

  9. unsigned int i, j;

  10. for (i = 0; i < conn->count_encoders; ++i)

  11. {

  12. drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]);

  13. if (NULL != enc)

  14. {

  15. for (j = 0; j < resources->count_crtcs; ++j)

  16. {

  17. // connector下连接若干encoder,每个encoder支持若干crtc,possible_crtcs的某一位为1代表相应次序(不是id哦)的crtc可用。

  18. if ((enc->possible_crtcs & (1 << j)))

  19. {

  20. int id = resources->crtcs[j];

  21. drmModeFreeEncoder(enc);

  22. drmModeFreeResources(resources);

  23. return id;

  24. }

  25. }

  26. drmModeFreeEncoder(enc);

  27. }

  28. }

  29. drmModeFreeResources(resources);

  30. return -1;

  31. }

绘制一张全色的图:

  1. void SetColor(unsigned char *dest, int stride, int w, int h)

  2. {

  3. struct color {

  4. unsigned r, g, b;

  5. };

  6. struct color ccs[] = {

  7. { 255, 0, 0 },

  8. { 0, 255, 0 },

  9. { 0, 0, 255 },

  10. { 255, 255, 0 },

  11. { 0, 255, 255 },

  12. { 255, 0, 255 }

  13. };

  14. static int i = 0;

  15. unsigned int j, k, off;

  16. unsigned int r = 255;

  17. unsigned int g = 1;

  18. unsigned int b = 1;

  19. for (j = 0; j < h; ++j)

  20. {

  21. for (k = 0; k < w; ++k)

  22. {

  23. off = stride * j + k * 4;

  24. *(uint32_t*)&(dest[off]) = (ccs[i].r << 16) | (ccs[i].g << 8) | ccs[i].b;

  25. }

  26. }

  27. i++;

  28. printf("draw picture\n");

  29. }

主函数:

  1. #define _FILE_OFFSET_BITS 64

  2. #include <inttypes.h>

  3. #include <stdio.h>

  4. #include <stdlib.h>

  5. #include <sys/mman.h>

  6. #include <xf86drm.h>

  7. #include <xf86drmMode.h>

  8. #include <fcntl.h>

  9. #include <unistd.h>

  10. #include <string.h>

  11. int main(int argc, char *argv[])

  12. {

  13. int ret, fd;

  14. fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC | O_NONBLOCK);

  15. if (fd < 0)

  16. {

  17. /* Probably permissions error */

  18. fprintf(stderr, "couldn't open %s, skipping\n", "");

  19. return -1;

  20. }

  21. drmSetMaster(fd);

  22. drmModeConnectorPtr connector = FindConnector(fd);

  23. int width = connector->modes[0].hdisplay;

  24. int height = connector->modes[0].vdisplay;

  25. printf("display is %d*%d.\n", width, height);

  26. int crtcid = FindCrtc(fd, connector);

  27. struct drm_mode_create_dumb creq;

  28. memset(&creq, 0, sizeof(creq));

  29. creq.width = width;

  30. creq.height = height;

  31. creq.bpp = 32;

  32. creq.flags = 0;

  33. ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);

  34. if (ret)

  35. {

  36. printf("create dumb failed!\n");

  37. }

  38. uint32_t framebuffer = -1;

  39. uint32_t stride = creq.pitch;

  40. //使用缓存的handel创建一个FB,返回fb的id:framebuffer。

  41. ret = drmModeAddFB(fd, width, height, 24, 32, creq.pitch, creq.handle, &framebuffer);

  42. if (ret)

  43. {

  44. printf("failed to create fb\n");

  45. return -1;

  46. }

  47. struct drm_mode_map_dumb mreq; //请求映射缓存到内存。

  48. mreq.handle = creq.handle;

  49. ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);

  50. if (ret)

  51. {

  52. printf("map dumb failed!\n");

  53. }

  54. // 猜测:创建的缓存位于显存上,在使用之前先使用drm_mode_map_dumb将其映射到内存空间。

  55. // 但是映射后缓存位于内核内存空间,还需要一次mmap才能被程序使用。

  56. unsigned char* buf = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);

  57. if (buf == MAP_FAILED)

  58. {

  59. printf("mmap failed!\n");

  60. }

  61. memset(buf, 255, creq.size);

  62. //一切准备完毕,只差连接在一起了!

  63. ret = drmModeSetCrtc(fd, crtcid, framebuffer, 0, 0, &connector->connector_id, 1, connector->modes);

  64. if (ret)

  65. {

  66. fprintf(stderr, "failed to set mode: %m\n");

  67. return -1;

  68. }

  69. int cc = 0;

  70. while (cc < 5)

  71. {

  72. SetColor(buf, stride, width, height);

  73. drmModePageFlip(fd, crtcid, framebuffer, DRM_MODE_PAGE_FLIP_EVENT, 0);

  74. cc++;

  75. sleep(2);

  76. }

  77. printf("over\n");

  78. getchar();

  79. close(fd);

  80. exit(0);

  81. return ret;

  82. }

linux drm 架构及linux drm 架构 之代码分析相关推荐

  1. linux安全策略查询代码,Linux多安全策略和动态安全策略框架模块代码分析报告(14)...

    函数名称 函数功能 selinux_set_mapping() 计算参数map中客体类别的数量,并将map中字符形式的类别-权限映射转换为数值形式的类别权限映射 map_class() 将客体类别在策 ...

  2. Linux Alsa声卡驱动(2):代码分析

    一:初始化/注册声卡设备 (1)注册ALSA kernel\sound\core:sound.cint __init alsa_sound_init(void) {... ...if (registe ...

  3. Linux内核4.14版本——drm框架分析(1)——drm简介

    目录 1. DRM简介(Direct Rendering Manager) 1.1 DRM发展历史 1.2 DRM架构对比FB架构优势 1.3 DRM图形显示框架 1.4 DRM图形显示框架涉及元素 ...

  4. 【Linux 内核 内存管理】内存管理架构 ① ( 内存管理架构组成 | 用户空间 | 内核空间 | MMU 硬件 | Linux 内核架构层次 | Linux 系统调用接口 )

    文章目录 一.内存管理架构组成 ( 用户空间 | 内核空间 | MMU 硬件 ) 二.Linux 内核架构层次 三.Linux 系统调用接口 一.内存管理架构组成 ( 用户空间 | 内核空间 | MM ...

  5. Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化

    我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...

  6. Linux SPI总线和设备驱动架构之三:SPI控制器驱动

    通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能: 1 ...

  7. linux与安卓系统目录,android系统架构及源码目录结构

    1. android系统架构: android系统架构采用了分层架构的思想,如下图所示,从上到下共4层,分别为:应用程序层.应用程序框架层.系统库和android运行时层.linux内核层. 每层功能 ...

  8. Linux 之八 完整嵌入式 Linux 环境、(交叉)编译工具链、CPU 体系架构、嵌入式系统构建工具

      最近,工作重心要从裸机开发转移到嵌入式 Linux 系统开发,由于之前对嵌入式 Linux 环境并不是很了解,因此,第一步就是需要了解如何搭建一个完整的嵌入式 Linux 环境.现在将学习心得记录 ...

  9. linux目录结构来源6,Linux入门基础 #6 Linux系统目录架构

    Linux入门基础 #6 Linux系统目录架构 /bin 即binary,用于保存各种(二进制)可执行文件. 在CLI中输入执行的命令都保存在这里. 此目录下的所有命令都是普通权限用户也可执行的. ...

  10. linux驱动架构变化,Linux网卡驱动架构分析

    一.网卡驱动架构 由上到下层次依次为:应用程序→系统调用接口→协议无关接口→网络协议栈→设备无关接口→设备驱动. 二.重要数据结构 1.Linux内核中每一个网卡由一个net_device结构来描述. ...

最新文章

  1. mvc html的扩展,关于asp.net mvc 3:Razor无法正确呈现HtmlHelper扩展方法
  2. python简单代码演示效果-10分钟教你用python 30行代码搞定简单手写识别!
  3. [转]]将 ASP.NET MVC3 Razor 项目部署到虚拟主机中
  4. 互联网协议入门(一)
  5. linux oracle脚本编写,Linux 脚本编写基础(一)--语法
  6. 激怒开源社区,微软悄悄删除2500行功能代码后致歉:已恢复!
  7. 敏捷开发般若敏捷系列之九:敏捷开发与本能反应
  8. chrome jsp 显示不正常_selenium+java谷歌浏览器 网站打开不正常
  9. IronPython for ASP.NET 部署注意事项
  10. Topcoder SRM 656 (Div.1) 250 RandomPancakeStack - 概率+记忆化搜索
  11. Git问题解决:warning: Pulling without specifying how to reconcile divergent branches is discouraged. You
  12. Linux系统下强制删除文件
  13. BeEF-XSS详细使用教程
  14. 桃源网盘php,桃源居业主自建论坛 - Powered by PHPWind
  15. c++ IO多路复用
  16. 推荐系统学习笔记-FNN
  17. (附Matlab程序)(一)基于DCT编码的图像压缩:显示灰度图像 反余弦变换恢复图 DCT变换图 余弦变换系数图
  18. ctr 平滑_根据样本数进行点击率CTR的修正 - Wilson CTR
  19. HDU 4545 (模拟) 魔法串
  20. VMware卸载辛酸历程

热门文章

  1. PCB中过孔和通孔焊盘的区别
  2. Linux系统中的“动态库”和“静态库”
  3. tensorflow kaggle猫狗大战识别猫狗
  4. iOS新闻客户端开发教程7-新闻列表
  5. 从零开始vim搭建Java开发环境之coc.nvim 篇
  6. CSS实现隐藏滚动条但可以滚动
  7. Linux增加swap虚拟内存
  8. 美11月PPI创历史最快增速 现货黄金难有转机下跌近1%
  9. 关于win10忘记用户密码,却无法找回,反复让我输入密码
  10. JSON.stringify 方法