在上一小节《Linux GUI加速(1)_GUI系统概述》中,我们从应用层到kernel层大致分析了linux中的图形界面的构成,并在最后给出了kernel中DRM+KMS的软件显示框架以及accelerate logic+framebuffer+displayport的硬件结构。在这一子篇会将这两块内容详细展开。
本篇主要以Xilinx的xc7z010 的SOPC(zybo的开发板)为硬件平台,在以下几方面介绍:
在各类SOC上,CRTC+Endode+Connector一般是集成在一个外设模块挂在系统总线上,以ARM为例,CRTC/Endoder等需要配置的外设模块,配置接口挂在APB总线,数据接口直接在AHB总线上,实现和Framebuffer的高速通信。
我们按照connector-->encoder-->crtc-->framebuffer的顺序倒过来介绍吧。
Connector其实就是和显示器连接的物理接口,常见的有VGA/HDMI/DVI/DP等。以HDMI为例,HDMI的接口信号主要由以下几组信号组成:
(注:EDID全称是Extended Display Identification Data(扩展显示标识数据),目的是让视频信号输出设备输出前获取到存储在显示器内部的相关参数,如支持的分辨率、帧率、图像格式:RGB等,因此,整个输出的控制参数是由以下几个部分综合决定的:
HDMI类型的connector的任务就是输出显示器解码芯片所需的信号时序(主要是TMDS clock以及TMDS data)。
Encoder比较好理解,在此处其实就是将一定格式的图像信号(如RGB、YUV等)编码成connector需要输出的信号。以HDMI为例,帧/行同步/显示内容都是通过TMDS data的串行总线输出的,那么并行的时序按照HDMI的标准编码为串行顺序则是Encoder的任务;
在本片中的XC7Z010 SOPC中Encoder+Connector如下:
CRTC的任务是从Framebuffer中读出待显示的图像,并按照相应的格式输出给Encoder(本处的CRTC功能受限,相关格式配置只能通过配置硬件IP参数来改变,而不能通过内核)。在本例中,CRTC的硬件构成如下:
如下图:
Plane其实就是图层,实际输出的图像往往由多个图层叠加而成(想象一下photoshop的过程),比如主图层,显示光标的图层,其中有些图层由硬件加速模块生成,本例中不涉及,因此所有plane的相关操作都由软件实现,不涉及到任何硬件结构。
Framebuffer对应着存储空间中的图像数据,此处对应硬件为DDR。
麻雀虽小,五脏俱全,次例程中的显示框架非常简单,但也包含了Framebuffer、CRTC、Planes、Encoder、Connector5个组件,片内硬件结构如下:
(PS:Dynamic Clock Generator生成显示子系统中各组件所需的驱动时钟,由Linux中的common clock framework统一管理)
按照DRI中几个组件分别介绍。
我们知道Framebuffer是存储待显示图像信息的空间,因此,Framebuffer相关驱动中也就是对内存的操作,也就涉及到下面两个部分:
对于第一点,GEM主要完成的事情是:
在Linux Kernel下的默认实现方式是CMA(Contiguous Memory Allocator)实现的,内核中对应代码是:
drivers/gpu/drm/drm_fb_cma_helper.c
这里稍微提一下CMA,CMA是个好东西,不仅在显存管理中有应用,在所有软硬件协 同处理中同样起这重要的作用。在一般的硬件(片内硬件加速模块)加速方案中,一般 实现方式如下:
struct drm_framebuffer{
[...]
const struct drm_format_info *format;
[...]
}
framebuffer中在不同格式下所需要处理的图层的数量不一,具体的显存处理、格式解析主要在下列源码表中:
(显存管理)
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_framebuffer_helper.c
drivers/gpu/drm/drm_fb_fourcc.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_cma_helper.c
(显存更新驱动接口)
drivers/gpu/drm/ati_pcigart.c
drivers/gpu/drm/ati_agpsupport.c
CRTC虽然字面上意思为阴极射线显像管控制器,但CRT在普通显示设备中早已被淘汰,DRI中CRTC主要承担的作用:
上述功能的主要通过struct drm_crtc_funcs和struct drm_crtc_helper_funcs这两个描述符实现:
drm_crtc_funcs中的两个重要句柄set_config和page_flip,其中,
set_config主要任务是:
page_flip解决的问题很简单:
当page_flip完成后,会通过event通知用户层准备好下一帧的数据;
不涉及到GPU的话,planes没有那么复杂,主要是负责:
的创建、更新、销毁,其中图层的更新(多个图层的叠加),通过struct中的drm_plane_funcs来实现。
比较形象的例子如下:
由于Connector和Encoder是SOC与外设直接打交道的地方,因此对应着不同SOC也是驱动适配修改最频繁的地方。DRI中这两块通过适配struct drm_connector_helper_funcs和struct drm_encoder_helper_funcs来实现。
Linux Kernel中的DRM+KMS中涉及到的点太多,由于能力和时间问题,没能遍历一遍,只能根据自己认为的重点讨论一边,但有些点我认为比较重要的,但没能深入了解,比如:
等,如果大家能够交流一下自己的理解,那再好不过了。