以xorg实现xserver的xfree86代码分析为主,协助开发人员阅读启动流程代码。源代码库:xorg / xserver · GitLab。
相关知识
DRM/KMS
framebuffer:显示服务器填充像素数据,,提供了数据格式,保存在帧缓冲中,待显示的数据,通过DRM_IOCTL_MODE_ADDFB ioctls申请内存。
3种数据格式
RGB:采用RGB三种颜色元组编码像素
YUV:采用亮度和色度编码像素,Y 表示明亮度(Luminance、Luma),而 U 和 V 表示色度(Chrominance、Chroma)
C8:采用换算表将数值映射至RGB元组,用数值编码像素
YUV数据存储格式
Packed:以YUV为单元存储在一起
SemiPlanar:以Y为单元打包成一个平面,以UV为单元打包成一个平面
Planar:将Y,U,V分别打包到不同的平面
CRTC:CRT控制器,对显示buffer进行扫描,并产生时序信号的硬件模块,通常指Display Controller;可将帧缓冲数据扫描至一个或多一个显示器;更新帧缓冲,缩放尺寸等
display timing:至少提供3个信号
Pixel Clock:像素时钟,每个时钟周期发送一个像素
VSYNC:帧同步信号,发送一个VSYNC脉冲,通知显示器开始新的帧缓冲扫描
HSYNC:行同步信号,发送一个HSYNC脉冲,通知显示器开始下一行扫描
page flipping:更新缓冲帧,使用front buffer和back buffer双缓冲功能,在VBLANK间隔中实现翻页功能,交换前后缓冲
Planes:一个平面表示一个帧缓冲,由CRTC将这些平面合成一张图显示,有三种类型
DRM_PLANE_TYPE_PRIMARY:主帧缓冲,一般用于显示背景图或图形,在最底层
DRM_PLANE_TYPE_CURSOR:光标帧缓冲,在最上层,或者隐藏
DRM_PLANE_TYPE_OVERLAY:图层帧缓冲,处于中间的图层,多为动态内容的图层,如:视频,状态栏,系统栏等,现有硬件一般有多个图层硬件平面
Connector:连接物理显示设备的连接器,如HDMI、DisplayPort、DSI总线,通常和Encoder驱动绑定在一起;暴露显示器支持的显示模式;探测显示器的热插拔
Encoder:负责将CRTC输出的timing时序转换成外部设备所需要的信号的模块,如HDMI转换器或DSI Controller
The DRM/KMS subsystem from a newbie’s point of view
Linux DRM Developer's Guide (landley.net)
Kernel Mode Setting (KMS) — The Linux Kernel documentation
framebuffer坐标
framebuffer的空间要比显示区域大,多余空间为弥补显示器换行和换帧切换的耗时。CRTC按固定时钟频率向显示器发送像素,为填充显示器切换时间空挡,需发送一些无用的像素填补。换行比换帧要快。填充像素在两边的数量须相等。
pitch:字节为单位,framebuffer行(宽度)的字节数
offset:字节为单位,第一个显示像素距填充区域水平拉直的字节数。
width:可显示(或渲染)区域的宽度
height:可显示(或渲染)区域的高度
注:pitches和offsets为数组的原因:跟图形数据存储格式相关,以像素为单位存储,则只需第一个描述;以每个颜色为一个平面,RGB的framebuffer有3个平面,则需要前3个元素描述。
显卡初始化
Xorg显卡初始化与运行平台相关,此次描述的显卡初始化流程为xfree86平台,即原生linux硬件平台。实现接口为InitInput,在hw/xfree86/common/common/xf86Init.c文件中。
显卡初始化涉及RANDR、glamor、DRI3、Present等扩展
基本流程
设备扫描和探测显卡设备,xfree86支持两种方式,DDX驱动都需支持这两种方式,首选第一种方式,支持设备的热插拔。
udev系统总线:利用libudev库查找显卡设备
PCI系统总线:利用libpciaccess库遍历PCI总线检测显卡设备
xserver默认使用3中DDX显卡驱动,优先使用modesetting驱动。不同平台使用的驱动框架不同,如,xfree86采用EXA框架,xserver-xsdl使用的使用kdrive框架
modesetting:基于DRM系统的显卡驱动
fbdev:基于framebuffer的显卡驱动
mesa:通用接口标准的显卡驱动,任何显卡都能被驱动
自动生成xserver配置,根据驱动和显卡信息自动生成xorg.conf配置信息,包括显卡设备描述,驱动描述,屏幕布局等信息。
自动生成xserver配置功能由xf86BusProbe、xf86AutoConfig、autoConfigDevice三个函数实现。
显卡驱动的加载由xf86AutoConfig和xf86LoadModules实现。
探测和初始化显卡设备由xf86BusConfig和xf86PostProbe两个函数实现
初始化显卡配置
显卡配置初始化由modesetting的PreInit函数初始化,代码在hw/xfree86/drivers/modesetting/driver.c文件中
打开显卡设备(/dev/dri/card0)文件,并获得master权限
获取连接在显卡的显示器数量,显卡支持的默认颜色深度(depth)和像素位数(bpp),并根据环境设置显卡的颜色深度和像素位数
根据颜色深度设置屏幕每种颜色的位数以及掩码(xf86SetWeight)。对于24位颜色深度来说,RGB每种颜色为8位;30位颜色深度来说,RGB每种颜色为10位。
获取硬件光标的宽度和高度
使能galamor渲染功能
加载glamoregl DDX驱动,初始化modesetting中glamor的回调函数(load_glamor)
调用glamor_egl_init初始化glamor
创建gbm设备,从card0设备中创建(gbm_create_device)
初始化OpenEGL环境,获取渲染设备,平台为EGL_PLATFORM_GBM_MESA,glamor_egl_get_display、eglInitialize、eglBindAPI、eglCreateContext、eglMakeCurrent、glGetString。其依赖的扩展有
required:EGL_KHR_surfaceless_context、EGL_KHR_no_config_context、GL_OES_EGL_image
optional:EGL_EXT_image_dma_buf_import、EGL_EXT_image_dma_buf_import_modifiers
根据显卡设备能力初始化屏幕功能
pageflip:翻页,帧缓冲的更新
prime:涉及内存共享,包括:DRM_PRIME_CAP_IMPORT和DRM_PRIME_CAP_EXPORT能力,涉及缓冲的导入导出。
atomic:原子KMS
tearfree:解决撕裂问题,依赖硬件pageflip,采用damage tracking技术最小化两个buffer之间的拷贝,以及当屏幕内容不变时,省去不必要的翻页。
universal planes:统一平面,不区分framebuffer,cursor和overlay。
framebuffer modifier:帧缓冲修饰符,描述缓冲区熟悉的额外信息,可指定像素格式,内存布局,压缩格式等。(DRM_CAP_ADDFB2_MODIFIERS)
初始化CRTC和Output配置(drmmode_pre_init)
检查设备是否具备创建dump buffer的能力(DRM_CAP_DUMB_BUFFER)
初始化Output:创建xf86OutputPtr(drmmode_output_init),获取显示器信息,初始化数据和回调结构体(drmmode_output_funcs)
初始化CRTC:设置CRTC显示区域范围(xf86CrtcSetSizeRange),创建xf86CrtcPtr数据结构(drmmode_crtc_init),初始化数据和回调结构体(drmmode_crtc_funcs)
设置屏幕的gamma矫正(xf86SetGamma)功能和分辨率(xf86SetDpi)。gamma功能是根据gamma LUT将颜色转换成灰度值,也就是将颜色空间转换成灰度空间,degamma刚好相反
加载fbdev驱动
初始化显示屏幕
调用xf86ScreenInit初始化显示屏幕,直接调用ScreenInit,代码在hw/xfree86/drivers/modesetting/driver.c文件中
向显卡设备申请master权限,drmSetMaster
通过gbm设备创建dump buffer,包括:光标,前端缓冲(front buffer)
设置visual types,包括颜色深度和像素位数;以及pixmap的颜色深度
使用framebuffer扩展初始化显示屏幕的回调函数(fbScreenInit),这些函数主要用于窗口显示
调用GetPictureScreen初始化图片屏幕的回调函数,这些函数主要用于图片渲染
调用glamor_init初始化硬件加速功能
初始化glamor egl screen,使能DRI3,并使用DRI3初始化屏幕回调函数
调用glamor_egl_make_current更新EGL环境中context
required:GL_EXT_texture_format_BGRA8888、GL_OES_texture_border_clamp、GL_ARB_vertex_array_object、GL_OES_vertex_array_object
optional:GL_ARB_instanced_arrays、GL_EXT_gpu_shader4、GL_KHR_debug、GL_MESA_pack_invert、GL_EXT_framebuffer_blit、GL_ARB_map_buffer_range、GL_ARB_buffer_storage、GL_MESA_tile_raster_order、GL_NV_texture_barrier、GL_EXT_unpack_subimage、GL_NV_pack_subimage、GL_ARB_blend_func_extended、GL_EXT_blend_func_extended、GL_ARB_clear_texture、GL_ARB_texture_rg、GL_ARB_debug_output、GL_ARB_texture_swizzle
设置屏幕模式,颜色,分辨率等(glamor_setup_formats);初始化字体(glamor_font_init);初始化合成图元(glamor_composite_glyphs_init)。
使用glamor初始化屏幕图形相关回调函数
初始化vbo(vertex buffer object)、vao(vertex array object)等(glamor_init_vbo);
初始化线性梯度(linear gradient)和径向梯度(radial gradient)着色器(glamor_init_gradient_shader)
初始化同步机制(glamor_sync_init),X扩展XSHM-FENCE
初始化光标,包括软件和硬件光标(miDCInitialize、xf86_cursors_init)
使用glamor初始化屏幕pixmap操作的回调函数
初始化CRTC等提供的旋转和缩放功能(xf86CrtcScreenInit)
安装颜色映射表(drmmode_setup_colormap)
初始化显示器电源管理(xf86DPMSInit)
初始化XV扩展(xf86XVScreenInit)
初始化VBLANK、PageFlip等处理函数(ms_vblank_screen_init)
初始化DRI2扩展的直接渲染功能(ms_dri2_screen_init)
初始化Present扩展的显示操作功能(ms_present_screen_init),通过PageFlip进行翻页显示
更新桌面屏幕的位置和尺寸(update_desktop_dimensions)
亚像素处理,对于非24位深度的像素,需特殊处理(PictureSetSubpixelOrder)
RandR扩展初始化,用于处理缩放,旋转等功能(xf86EnsureRANDR)
配置输出设备结构(xf86AutoConfigOutputDevices),主要是RandR的相关操作的初始化
初始化屏幕远点坐标(xf86InitOrigins),存在多个屏幕虚拟成一个屏幕,或者一个屏幕虚拟成多个屏幕的场景
初始化屏幕回调函数
xserver的screen定义了各种类型的回调函数,支持回调函数注册多个实体函数,以链式的形式存在,先注册后调用,因此注册回调函数时须考虑扩展的注册顺序。
xserver在系统初始化后,调用msBlockHandler_oneshot处理屏幕更新,配置CRTC,然后将BlockHandler回调函数设置为msBlockHandler。
下表列出了screen回调函数注册过程,从左至右注册,从右至左调用。为紧凑表格,将一些插件功能合成一列记录。DestroyWindow、DestroyPixmap和CloseScreen调用层次深在下表后单独列出。所有功能基本都须注册CloseScreen回调函数回收资源。
callback name | framebuffer / mi | damage / RandR | curse/ xfee86 / modesetting | composite | double buffer |
---|---|---|---|---|---|
CreateWindow | fbCreateWindow | compCreateWindow | |||
PositionWindow | fbPositionWindow | compPositionWindow | miDbePositionWindow | ||
ChangeWindowAttributes | fbChangeWindowAttributes | compChangeWindowAttributes | |||
RealizeWindow | fbRealizeWindow | compRealizeWindow | |||
UnrealizeWindow | fbUnrealizeWindow | compUnrealizeWindow | |||
CopyWindow | fbCopyWindow | damageCopyWindow | miSpriteCopyWindow | compCopyWindow | |
WindowExposures | miWindowExposures | xf86XVWindowExposures | |||
MoveWindow | miMoveWindow | compResizeWindow | |||
ReparentWindow | compReparentWindow | ||||
ChangeBorderWidth | miChangeBorderWidth | compChangeBorderWidth | |||
ConfigNotify | DRI2ConfigNotify | compConfigNotify | |||
SetWindowPixmap | _fbSetWindowPixmap | damageSetWindowPixmap | |||
ModifyPixmapHeader | miModifyPixmapHeader | ||||
ReplaceScanoutPixmap | RRReplaceScanoutPixmap | ||||
SharePixmapBacking | msSharePixmapBacking | ||||
SetSharedPixmapBacking | msSetSharedPixmapBacking | PixmapStartDirtyTracking | |||
StartPixmapTracking | StopPixmapTracking | PixmapStopDirtyTracking | |||
SharedPixmapNotifyDamage | msSharedPixmapNotifyDamage | ||||
RequestSharedPixmapNotifyDamage | msRequestSharedPixmapNotifyDamage | ||||
PresentSharedPixmap | msPresentSharedPixmap | ||||
StopFlippingPixmapTracking | msStopFlippingPixmapTracking | ||||
DisplayCursor | miPointerDisplayCursor | CursorDisplayCursor | |||
RecolorCursor | miRecolorCursor | ||||
QueryBestSize | fbQueryBestSize | xf86CursorQueryBestSize | |||
ConstrainCursorHarder | RRConstrainCursorHarder | xf86RandR13ConstrainCursorHarder | |||
ClipNotify | xf86XVClipNotify | compClipNotify | |||
CreateGC | fbCreateGC | damageCreateGC | |||
CreateColormap | fbInitializeColormap | CMapCreateColormap | |||
DestroyColormap | CMapDestroyColormap | ||||
StoreColors | PictureStoreColors | miSpriteStoreColors / CMapStoreColors | |||
SourceValidate | miSourceValidate | miSpriteSourceValidate |
DestroyWindow : fbDestroyWindow -> PictureDestroyWindow -> damageDestroyWindow -> XvDestroyWindow -> xf86XVDestroyWindow -> compDestroyWindow -> DbeDestroyWindow
DestroyPixmap : fbDestroyPixmap -> glamor_egl_destroy_pixmap -> damageDestroyPixmap -> XvDestroyPixmap -> ShmDestroyPixmap
CloseScreen : fbCloseScreen -> PictureCloseScreen -> glamor_egl_close_screen -> dri3_close_screen -> miDCCloseScreen -> damageCloseScreen -> miPointerCloseScreen -> miSpriteCloseScreen -> xf86CursorCloseScreen -> CloseScreen -> RRCloseScreen -> CMapCloseScreen -> XvCloseScreen -> xf86XVCloseScreen -> xf86RandRCloseScreen -> CursorCloseScreen -> compCloseScreen -> dri3_close_screen
machine-indepent only
callback name | machine-indepent |
---|---|
ValidateTree | miValidateTree |
PaintWindow | miPaintWindow |
MarkWindow | miMarkWindow |
MarkOverlappedWindows | miMarkOverlappedWindows |
XYToWindow | miXYToWindow |
MarkUnrealizedWindow | miMarkUnrealizedWindow |
GetLayerWindow | miGetLayerWindow |
GetScreenPixmap | miGetScreenPixmap |
SetScreenPixmap | miSetScreenPixmap |
HandleExposures | miHandleValidateExposures |
ConstrainCursor | miPointerConstrainCursor |
CursorLimits | miPointerCursorLimits |
RealizeCursor | miPointerRealizeCursor |
UnrealizeCursor | miPointerUnrealizeCursor |
SetCursorPosition | miPointerSetCursorPosition |
DeviceCursorInitialize | miPointerDeviceInitialize |
DeviceCursorCleanup | miPointerDeviceCleanup |
SetShape | miSetShape |
ClearToBackground | miClearToBackground |
CreateScreenResources | miCreateScreenResources |
framebuffer only
callback name | framebuffer |
---|---|
CreatePixmap | fbCreatePixmap |
GetWindowPixmap | _fbGetWindowPixmap |
GetImage | fbGetImage |
GetSpans | fbGetSpans |
RealizeFont | fbRealizeFont |
UnrealizeFont | fbUnrealizeFont |
UninstallColormap | fbUninstallColormap |
ListInstalledColormaps | fbListInstalledColormaps |
ResolveColor | fbResolveColor |
BitmapToRegion | fbPixmapToRegion |
xfree86 only
callback name | xfree86 |
---|---|
LoadPalette | loadPalette |
SetOverscan | CMapEnterVT / xf86XVEnterVT |
LeaveVT | xf86XVLeaveVT |
SwitchMode | CMapSwitchMode |
ChangeGamma | CMapChangeGamma |
AdjustFrame | xf86XVAdjustFrame |
ModeSet | xf86XVModeSet |
EnableDisableFBAccess | xf86EnableDisableFBAccess |
SaveScreen | xf86SaveScreen |
附录
InitOutput函数调用流程
回调函数以实际调用函数代替。以xserver源码的xwayland-23版本为基础,显卡驱动为modesetting。若显卡驱动不同,如:Intel、amdgpu、nouveau,驱动相关驱动流程有差异。一般来说,modesetting驱动满足显示要求,渲染部分有OpenGL/EGL使用对应DRI驱动即可。
InitOutput (hw/xfree86/common/common/xf86Init.c) |