目录

以xorg实现xserver的xfree86代码分析为主,协助开发人员阅读启动流程代码。源代码库:xorg / xserver · GitLab

相关知识

DRM/KMS

  1. framebuffer:显示服务器填充像素数据,,提供了数据格式,保存在帧缓冲中,待显示的数据,通过DRM_IOCTL_MODE_ADDFB ioctls申请内存。

    1. 3种数据格式 

      1. RGB:采用RGB三种颜色元组编码像素

      2. YUV:采用亮度和色度编码像素,Y 表示明亮度(Luminance、Luma),而 U 和 V 表示色度(Chrominance、Chroma)

      3. C8:采用换算表将数值映射至RGB元组,用数值编码像素

    2. YUV数据存储格式

      1. Packed:以YUV为单元存储在一起

      2. SemiPlanar:以Y为单元打包成一个平面,以UV为单元打包成一个平面

      3. Planar:将Y,U,V分别打包到不同的平面

  2. CRTC:CRT控制器,对显示buffer进行扫描,并产生时序信号的硬件模块,通常指Display Controller;可将帧缓冲数据扫描至一个或多一个显示器;更新帧缓冲,缩放尺寸等

    1. display timing:至少提供3个信号

      1. Pixel Clock:像素时钟,每个时钟周期发送一个像素

      2. VSYNC:帧同步信号,发送一个VSYNC脉冲,通知显示器开始新的帧缓冲扫描

      3. HSYNC:行同步信号,发送一个HSYNC脉冲,通知显示器开始下一行扫描

    2. page flipping:更新缓冲帧,使用front buffer和back buffer双缓冲功能,在VBLANK间隔中实现翻页功能,交换前后缓冲

  3. Planes:一个平面表示一个帧缓冲,由CRTC将这些平面合成一张图显示,有三种类型

    1. DRM_PLANE_TYPE_PRIMARY:主帧缓冲,一般用于显示背景图或图形,在最底层

    2. DRM_PLANE_TYPE_CURSOR:光标帧缓冲,在最上层,或者隐藏

    3. DRM_PLANE_TYPE_OVERLAY:图层帧缓冲,处于中间的图层,多为动态内容的图层,如:视频,状态栏,系统栏等,现有硬件一般有多个图层硬件平面

  4. Connector:连接物理显示设备的连接器,如HDMI、DisplayPort、DSI总线,通常和Encoder驱动绑定在一起;暴露显示器支持的显示模式;探测显示器的热插拔

  5. 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驱动都需支持这两种方式,首选第一种方式,支持设备的热插拔。

  1. udev系统总线:利用libudev库查找显卡设备

  2. PCI系统总线:利用libpciaccess库遍历PCI总线检测显卡设备

xserver默认使用3中DDX显卡驱动,优先使用modesetting驱动。不同平台使用的驱动框架不同,如,xfree86采用EXA框架,xserver-xsdl使用的使用kdrive框架

  1. modesetting:基于DRM系统的显卡驱动

  2. fbdev:基于framebuffer的显卡驱动

  3. mesa:通用接口标准的显卡驱动,任何显卡都能被驱动

自动生成xserver配置,根据驱动和显卡信息自动生成xorg.conf配置信息,包括显卡设备描述,驱动描述,屏幕布局等信息。

  • 自动生成xserver配置功能由xf86BusProbe、xf86AutoConfig、autoConfigDevice三个函数实现。

  • 显卡驱动的加载由xf86AutoConfig和xf86LoadModules实现。

  • 探测和初始化显卡设备由xf86BusConfig和xf86PostProbe两个函数实现

初始化显卡配置

显卡配置初始化由modesetting的PreInit函数初始化,代码在hw/xfree86/drivers/modesetting/driver.c文件中

  1. 打开显卡设备(/dev/dri/card0)文件,并获得master权限

  2. 获取连接在显卡的显示器数量,显卡支持的默认颜色深度(depth)和像素位数(bpp),并根据环境设置显卡的颜色深度和像素位数

  3. 根据颜色深度设置屏幕每种颜色的位数以及掩码(xf86SetWeight)。对于24位颜色深度来说,RGB每种颜色为8位;30位颜色深度来说,RGB每种颜色为10位。

  4. 获取硬件光标的宽度和高度

  5. 使能galamor渲染功能

    1. 加载glamoregl DDX驱动,初始化modesetting中glamor的回调函数(load_glamor)

    2. 调用glamor_egl_init初始化glamor

      1. 创建gbm设备,从card0设备中创建(gbm_create_device)

      2. 初始化OpenEGL环境,获取渲染设备,平台为EGL_PLATFORM_GBM_MESA,glamor_egl_get_display、eglInitialize、eglBindAPI、eglCreateContext、eglMakeCurrent、glGetString。其依赖的扩展有

        1. required:EGL_KHR_surfaceless_context、EGL_KHR_no_config_context、GL_OES_EGL_image

        2. optional:EGL_EXT_image_dma_buf_import、EGL_EXT_image_dma_buf_import_modifiers

  6. 根据显卡设备能力初始化屏幕功能

    1. pageflip:翻页,帧缓冲的更新

    2. prime:涉及内存共享,包括:DRM_PRIME_CAP_IMPORT和DRM_PRIME_CAP_EXPORT能力,涉及缓冲的导入导出。

    3. atomic:原子KMS

    4. tearfree:解决撕裂问题,依赖硬件pageflip,采用damage tracking技术最小化两个buffer之间的拷贝,以及当屏幕内容不变时,省去不必要的翻页。

    5. universal planes:统一平面,不区分framebuffer,cursor和overlay。

    6. framebuffer modifier:帧缓冲修饰符,描述缓冲区熟悉的额外信息,可指定像素格式,内存布局,压缩格式等。(DRM_CAP_ADDFB2_MODIFIERS)

  7. 初始化CRTC和Output配置(drmmode_pre_init)

    1. 检查设备是否具备创建dump buffer的能力(DRM_CAP_DUMB_BUFFER)

    2. 初始化Output:创建xf86OutputPtr(drmmode_output_init),获取显示器信息,初始化数据和回调结构体(drmmode_output_funcs)

    3. 初始化CRTC:设置CRTC显示区域范围(xf86CrtcSetSizeRange),创建xf86CrtcPtr数据结构(drmmode_crtc_init),初始化数据和回调结构体(drmmode_crtc_funcs)

  8. 设置屏幕的gamma矫正(xf86SetGamma)功能和分辨率(xf86SetDpi)。gamma功能是根据gamma LUT将颜色转换成灰度值,也就是将颜色空间转换成灰度空间,degamma刚好相反

  9. 加载fbdev驱动

初始化显示屏幕

调用xf86ScreenInit初始化显示屏幕,直接调用ScreenInit,代码在hw/xfree86/drivers/modesetting/driver.c文件中

  1. 向显卡设备申请master权限,drmSetMaster

  2. 通过gbm设备创建dump buffer,包括:光标,前端缓冲(front buffer)

  3. 设置visual types,包括颜色深度和像素位数;以及pixmap的颜色深度

  4. 使用framebuffer扩展初始化显示屏幕的回调函数(fbScreenInit),这些函数主要用于窗口显示

  5. 调用GetPictureScreen初始化图片屏幕的回调函数,这些函数主要用于图片渲染

  6. 调用glamor_init初始化硬件加速功能

    1. 初始化glamor egl screen,使能DRI3,并使用DRI3初始化屏幕回调函数

    2. 调用glamor_egl_make_current更新EGL环境中context

      1. required:GL_EXT_texture_format_BGRA8888、GL_OES_texture_border_clamp、GL_ARB_vertex_array_object、GL_OES_vertex_array_object

      2. 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

    3. 设置屏幕模式,颜色,分辨率等(glamor_setup_formats);初始化字体(glamor_font_init);初始化合成图元(glamor_composite_glyphs_init)。

    4. 使用glamor初始化屏幕图形相关回调函数

    5. 初始化vbo(vertex buffer object)、vao(vertex array object)等(glamor_init_vbo);

    6. 初始化线性梯度(linear gradient)和径向梯度(radial gradient)着色器(glamor_init_gradient_shader)

    7. 初始化同步机制(glamor_sync_init),X扩展XSHM-FENCE

    8. 初始化光标,包括软件和硬件光标(miDCInitialize、xf86_cursors_init)

    9. 使用glamor初始化屏幕pixmap操作的回调函数

    10. 初始化CRTC等提供的旋转和缩放功能(xf86CrtcScreenInit)

    11. 安装颜色映射表(drmmode_setup_colormap)

    12. 初始化显示器电源管理(xf86DPMSInit)

    13. 初始化XV扩展(xf86XVScreenInit)

    14. 初始化VBLANK、PageFlip等处理函数(ms_vblank_screen_init)

    15. 初始化DRI2扩展的直接渲染功能(ms_dri2_screen_init)

    16. 初始化Present扩展的显示操作功能(ms_present_screen_init),通过PageFlip进行翻页显示

  7. 更新桌面屏幕的位置和尺寸(update_desktop_dimensions)

  8. 亚像素处理,对于非24位深度的像素,需特殊处理(PictureSetSubpixelOrder)

  9. RandR扩展初始化,用于处理缩放,旋转等功能(xf86EnsureRANDR)

  10. 配置输出设备结构(xf86AutoConfigOutputDevices),主要是RandR的相关操作的初始化

  11. 初始化屏幕远点坐标(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



  1. DestroyWindow : fbDestroyWindow -> PictureDestroyWindow -> damageDestroyWindow -> XvDestroyWindow -> xf86XVDestroyWindow -> compDestroyWindow -> DbeDestroyWindow

  2. DestroyPixmap  : fbDestroyPixmap -> glamor_egl_destroy_pixmap -> damageDestroyPixmap -> XvDestroyPixmap -> ShmDestroyPixmap

  3. 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)
    -> config_pre_init
        -> config_udev_pre_init
    -> LoaderSetPath
    -> dbus_core_init
    -> systemd_logind_init
    -> xf86BusProbe (discover display card)
    -> xf86AutoConfig (load modesetting drivers)
        -> xf86allocateConfig
        -> listPossibleVideoDrivers
            -> xf86AddMatchedDriver ("modesetting")
            -> xf86AddMatchedDriver ("fbdev")
            -> xf86AddMatchedDriver ("vesa")
        -> xf86initConfigFiles
        -> xf86setBuiltinConfig
        -> xf86HandleConfigFile
    -> xf86OSPMOpen
    -> xf86ExtensionInit (not load extension)
    -> autoConfigDevice
    -> xf86LoadModules (xf86DriverlistFromConfig, modesetting)
        -> Setup (hw/xfree86/drivers/modesetting/driver.c)
            -> xf86AddDriver (modesetting)
    -> Identify (hw/xfree86/drivers/modesetting/driver.c)
    -> ms_driver_func (hw/xfree86/drivers/modesetting/driver.c)
    -> xf86OpenConsole
    -> xf86BusConfig
        -> xf86CallDriverProbe
            -> xf86platformProbeDev
                -> xf86ConfigPciEntity
                -> xf86GetDevFromEntity
                -> xf86FindOptionValue
                -> probe_hw_pci
                -> ms_setup_scrn_hooks
                -> ms_setup_entity
        -> xf86platformAddGPUDevices
        -> xf86VGAarbiterInit
    -> xf86PostProbe
    -> PreInit (hw/xfree86/drivers/modesetting/driver.c)
        -> xf86SetPrimInitDone
        -> ms_get_drm_master_fd
            -> xf86_platform_device_odev_attributes
            -> open_hw (open)
        -> check_outputs
            -> drmModeGetResources
        -> drmmode_get_default_bpp
        -> xf86SetDepthBpp
        -> xf86CollectOptions
        -> xf86ProcessOptions
        -> xf86SetWeight
        -> xf86SetDefaultVisual
        -> xf86ReturnOptValBool (OPTION_SW_CURSOR)
        -> drmGetCap (DRM_CAP_CURSOR_WIDTH / DRM_CAP_CURSOR_HEIGHT)
        -> try_enable_glamor
            -> load_glamor
                -> xf86LoadSubModule ("glamoregl")
            -> glamor_egl_init
                -> xf86ProcessOptions
                -> xf86GetOptValString (GLAMOREGLOPT_VENDOR_LIBRARY)
                -> glamor_set_glvnd_vendor
                -> xf86GetOptValString (GLAMOREGLOPT_RENDERING_API)
                -> gbm_create_device
                -> glamor_egl_get_display
                -> eglInitialize
                -> glamor_egl_try_big_gl_api
                -> glGetString (GL_RENDERER)
        -> xf86GetOptValBool (OPTION_VARIABLE_REFRESH / OPTION_ASYNC_FLIP_SECONDARIES)
        -> xf86ReturnOptValBool (OPTION_PAGEFLIP)
        -> drmGetCap (DRM_CAP_PRIME)
        -> drmSetClientCap (DRM_CLIENT_CAP_ATOMIC / DRM_CLIENT_CAP_UNIVERSAL_PLANES)
        -> drmGetCap (DRM_CAP_ADDFB2_MODIFIERS)
        -> drmmode_pre_init
            -> drmGetCap (DRM_CAP_DUMB_BUFFER)
            -> xf86CrtcConfigInit (register drmmode_xf86crtc_config_funcs)
            -> drmModeGetResources
            -> drmmode_output_init
            -> xf86CrtcSetSizeRange
            -> drmmode_crtc_init
            -> drmmode_clones_init
            -> xf86ProviderSetup
            -> xf86InitialConfiguration
        -> xf86SetGamma
        -> xf86SetDpi
        -> xf86LoadSubModule ("fb")
    -> xf86InitViewport
    -> AddScreen
        -> init_screen
        -> xf86ScreenInit
            -> ScreenInit (hw/xfree86/drivers/modesetting/driver.c)
                -> SetMaster
                -> glamor_egl_get_gbm_device
                -> drmmode_create_initial_bos
                -> miSetVisualTypes
                -> miSetPixmapDepths
                -> fbScreenInit
                    -> fbSetupScreen
                    -> fbFinishScreenInit
                -> fbPictureInit
                    -> miPictureInit
                    -> GetPictureScreen
                -> drmmode_init
                    -> glamor_init
                        -> glamor_set_screen_private
                        -> glamor_egl_screen_init
                            -> gbm_device_get_backend_name
                            -> glamor_set_glvnd_vendor
                            -> glamor_enable_dri3
                            -> drmGetDeviceNameFromFd2
                            -> dri3_screen_init
                        -> glamor_make_current
                        -> epoxy_is_desktop_gl
                        -> epoxy_gl_version
                        -> epoxy_glsl_version
                        -> glamor_check_instruction_count
                        -> glamor_setup_debug_output
                        -> glamor_setup_formats
                        -> glamor_set_debug_level
                        -> glamor_font_init
                        -> glamor_composite_glyphs_init
                        -> glamor_init_vbo
                        -> glamor_init_gradient_shader
                        -> glamor_pixmap_init
                        -> glamor_sync_init
                    -> glamor_set_drawable_modifiers_func (get_drawable_modifiers)
                -> xf86SetBlackWhitePixels
                -> xf86SetBackingStore
                -> xf86SetSilkenMouse
                -> xf86GetPointerScreenFuncs
                -> miDCInitialize
                -> xf86_cursors_init
                -> xf86CrtcScreenInit
                    -> xf86RandR12Init
                        -> RRScreenInit
                        -> xf86RandR12Init12
                            -> xf86RandR12CreateObjects12
                            -> xf86RandR12SetInfo12
                            -> xf86RandR12InitGamma
                    -> xf86RandR12SetRotations
                    -> xf86RandR12SetTransformSupport-> 
                -> drmmode_setup_colormap
                -> xf86DPMSInit
                -> xf86XVScreenInit
                    -> XvScreenInit
                    -> xf86XVInitAdaptors
                -> ms_vblank_screen_init
                -> ms_dri2_screen_init
                    -> glamor_supports_pixmap_import_export
                    -> ms_dri2_register_frame_event_resource_types
                    -> DRI2ScreenInit
                -> ms_present_screen_init
                    -> drmGetCap (DRM_CAP_ASYNC_PAGE_FLIP)
                    -> present_screen_init
                        -> present_screen_register_priv_keys
                        -> present_screen_priv_init
                        -> present_scmd_init_mode_hooks
                        -> present_fake_screen_init
        -> update_desktop_dimensions
    -> PictureSetSubpixelOrder
    -> xf86EnsureRANDR
        -> xf86RandRInit
            -> RRScreenInit
                -> RRInit
                -> SetRRScreen
                -> RRMonitorInit
            -> dixSetPrivate (xf86RandRKey)
    -> xf86AutoConfigOutputDevices
        -> RRProviderAutoConfigGpuScreen
            -> xf86RandR14ProviderSetOutputSource
            -> RRInitPrimeSyncProps
            -> RRSetChanged
            -> xf86RandR14ProviderSetOffloadSink
    -> xf86VGAarbiterWrapFunctions
    -> xf86InitOrigins