xserver相关知识汇总
本文主要是从以下几个方面介绍xorg-xserver 相关的知识 1.linux系统图形界面框架2.xserver 和x client启动过程3.图形2d,3d加速原理简介4.xserver主分支代码解析。5.xserver,xclient协议简介6.一个基于Xlib的简单例子解析7.radeon驱动初始化代码解析.1.lin
·
本文主要是从以下几个方面介绍xorg-xserver 相关的知识
1.linux系统图形界面框架
2.xserver 和x client启动过程
3.图形2d,3d加速原理简介
4.xserver主分支代码解析。
5.xserver,xclient协议简介
6.一个基于Xlib的简单例子解析
7.radeon驱动初始化代码解析.
1.linux图形界面框架
参考至:http://dzdl.ipchina.org/site/?uid-9-action-viewspace-itemid-49
linux图形界面又称x系统,其主要包含如下几个部分:
a)xserver
b)显示管理器 (Display Manager) 例如(gdm kdm xdm等)
c)窗口管理器 (Window Manager) 例如(metacity ,fluxbox等)
d)DM 和 WM之上的一些图形应用程序
在使用中一般都是b,c,d三者集合起来构成一个完整的集成工作环境,例如KDE ,GNOME等
,这就是我们平时所说的广义上的xclient
a)xserver 主要提供基本的显示接口共xclient使用,并将用户的操作等也反映给xclient,
是xclient与硬件的一个中间层。xserver相关的两个主要部分是
(1) xorg.conf
在具有多个显示设备的系统中,可能有多个Screen和多个ServerLayout,用以实现不同的硬件搭配。
(2) X session(X会话)
b), Display Manager
可以知道,startx的作用可以看作是Display Manager的一种隐性实现。它使用xinit命令,分别根据/etc/X11/xinit/xinitrc和/etc/X11/xinit/xserverrc中所指定的设置唤起X。
c), Window Manager
d), X Clients
2.xserver 和x client启动过程
参考:http://blog.csdn.net/clozxy/archive/2010/04/15/5488699.aspx
对xserver和x client的启动过程的探讨主要是对startx命令的探讨
startx脚本网上解释的很多,这里就不多做介绍,对startx介绍分以下两个部分
(1)xinit用法
startx其实是个脚本,最终调用的是xinit命令,其用法如下:
xinit 的用法为: xinit [[client] options ] [-- [server] [display] options] 。其中 client 用于指定一个基于 X 的应用程序, client 后面的 options 是传给这个应用程序的参数, server 是用于指定启动哪个 X 服务器,一般为 /usr/bin/X 或 /usr/bin/Xorg , display 用于指定 display number ,一般 为 0 ,表示第一个 display , option 为传给 server 的参数。
如果不指定 client , xinit 会查找 HOME ( 环境变量 ) 目录下的 .xinitrc 文件,如果存在这个 文件, xinit 直接调用 execvp 函数执行该文件。如果这个文件不存在,那么 client 及其 options 为: xterm -geometry +1+1 -n login -display :0 。
如果不指定 server , xinit 会查找 HOME( 环境变量 ) 目录下的 .xserverrc 文件,如果存在这个文件, xinit 直接调用 execvp 函数执行该文件。如果这个文件 不存在,那么 server 及其 display 为: X :0 。如果系统目录中不存在 X 命令,那么我们需要在系统目录下建立一个名为 X 的链接,使其指向真正的 X server 命令( Ubuntu 下为 Xorg )。
因此startx的用法跟xinit一样:startx [ [ client ] options ... ] [ -- [ server ] options ... ]
(2)startx的几种启动方式
由对 startx 脚本的分析,我们可以知道 startx 主要有三种启动方式:
a) 、一种是自己指定要启动的 client 和 server , 例如: startx /usr/bin/xclock -- /usr/bin/X :0 ;
b)、一种是通过在 $HOME 下新建 .xinitrc 文件来指定要启动的多个 client 和 .xserverrc 来指定要启动的 server;
c)、还有一种是直接输入 startx 而不指定参数,这也就是我们启动 gnome 桌面的方法。
在 c 这种启动方法中, startx 脚本会先去看系统目录( /etc/X11/xinit/ )下的 rc 文件是否存在,如果不存在就会用默认的 xterm 和 /usr/bin/X 来启动 xinit 。显然, startx 启动的不是 xterm ,而是 gnome 桌面,因此 gnome 的启动是通过系统文件 /etc/X11/xinit/xinitrc 来指定的。
而 /etc/X11/xinit/xinitrc 文件的内容如下所示:
因此, gnome 的启动应该在 Xsession 里。
而 X Server 的启动则是通过系统文件 /etc/X11/xinit/xserverrc 来指定的 , 这个文件的内容为 :
综上所述, startx 的默认启动过程为: startx 调用并将系统文件 /etc/X11/xinit/xinitrc 和 /etc/X11/xinit/xserverrc 作为参数传给 xinit , xinit 就会先执行系统文件 /etc/X11/xinit/xserverrc 以启动 X Server ,然后执行 /etc/X11/xinit/xinitrc ,而 xinitrc 则会执行脚本 /etc/X11/Xsession ,而 Xsession 则会按顺序调用执行 /etc/X11/Xsession.d 目录下的文件,从而最终调用了 gnome-session 这个用于 启动 GNOME 桌面环境的程序
3.图形2d,3d加速简介
为了是linux下图形更加流畅,必须使用加速。常用的加速方法如下
加速常见有三种方式
a)ShadowFB
ShadowFB是xserver自带的与体系结构无关的2D加速方式,它将系统framebuffer复制一份,并且在拷贝回framebuffer中实现图形旋转等操作,这样可以起到一定加速作用,但是效果不好。
b) XAA
XAA全称XFree86 Acceleration Architecture,是由 Harm Hanemaayer 在1996年写的一个显卡硬件2D加速的驱动结构,目前大多数的显卡去动均支持这种驱动模式
c) EXA
EXA是X.Org发起的用于取代XAA加速的驱动结构,修改的宗旨是是XRender更加好用。
历史上对2D 和3D加速已经做了区分,2D加速主要使用的是XAA结构,3D加速主要是通过DRM(Direct Rendering Manage) 提供.而EXA提供了比XAA更好集成XRender的结构,同时也提高了XAA的2D加速效果。
EXA采用的方法是通过实现对OpenGL的加速以实现同时对2D,3D图像的加速,这样2D图像就可以看作是3D图像的一个子集。
4.xserver 主分支代码解析
参考网站:http://xwindow.angelfire.com,
基于xorg-xserver-1.7.6版本
xserver代码是从dix/main.c中的main函数开始执行。
开始的一系列函数执行一些初始化及check的工作
随后main函数进入了一个死循环。每次循环均包含了
a)xserver初始化
b)xserver循环处理client消息
c)xserver退出
三个阶段
这是xserver的main函数最外层的循环,一般启动xserver只会执行一次循环:用户在图形界面操作时,实际上xserver是处在b)阶段。
这个循环就保证了xserver出现一般的异常时会自动恢复,比如在运行x时替换了其显卡驱动,xserver会触发异常结束第一次循环
并在第二次循环中重新加载替换后的显卡驱动。
以下分别对这三个阶段做解析
a)xserver初始化
xserver初始化函数非常多,以下仅粗略介绍几个比较熟悉的:
(1)
初始化中有如下代码:
当第一次循环时serverGeneration=1,执行的是第一个分支代码。
CreateWellKnownSockets() 初始化一系列sockets监听是否有clients申请连接。
InitProcVectors() 初始化ProcVector,SwappedProcVector结构
for循环是生成并初始化clients数组
之后便是serverClient变量的生成即初始化,serverClient是clients数组中索引为0的项,因为他是拥有root window的client。
当之后的循环时serverGeneration = 0,执行的是ResetWellKnownSockets即重置sockets工作。
(2)
InitOutput()是初始化分量较中的一环,处理过程可以分为如下部分:
1)xf86HandleConfigFile 解析xorg.con文件 ,获得xserver的配置信息。
2)xf86BusProbe 获得video的pci信息,例如framebuffer地址等。
3)DoConfigure() 根据配置文件 ,或者传进来的参数做相应的配置
4)xf86LoadModules load xorg.conf中配置的一系列模块
5)以此遍历注册的各个driver,调用其identify,probe函数, 这样就根据显卡的型号加载了相应的驱动
6)匹配screen,主要是根据xorg.conf中配置的screen,查询是否有与其匹配的device
7)遍历screen,调用其匹配device驱动的PreInit函数。这样就完成了显卡驱动的预初始化
8)遍历screen,调用AddScreen函数,分配screenInfo.screen[]的一项,并做初始化ScreenInit.这样驱动的初始化基本完成。
(3)
InitInput()是初始化输入设备,例如键盘和鼠标等。如果xorg.conf中有Section InputDevice配置,会按照
其配置扫描加载设备
b)xserver循环处理client消息
在初始化结束之后xserver便进入了循环处理阶段即
Dispatch()函数
该函数的流程主要是一个循环结构
while (!dispatchException)
即当不出现异常时循环会不断进行下去
每一次循环可以分为如下部分
(1)接受用户的输入,并发送给client
(2)等待clients发送事件过来
(3)遍历每个发送信息的client,做如下处理
由此Dispatch函数解析结束
c)xserver退出
5.xserver,xclient协议简介
由上文对Dispatch函数的分析可以看出,xserver对client的处理主要是三步:
(1)获得事件信息
(2)获得操作号
(3)根据操作号处理
因此其操作号和操作的对应是xserver与client的协议的一部分,类似操作
系统的系统调用号和系统调用之间的关系。
在上面介绍InitClients()中有对requestVector初始化
client->requestVector = InitialVector;
InitVector如下:
int (* InitialVector[3]) (
{
};
其只有两个函数,一个是初始化Connection,一个是确立Connection
在ProcEstablishConnection中调用SendConnSetup寒酸,
SendConnSetup函数有:
client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
即初始化requestVector为SwappedProcVector或ProcVector
ProcVector如下:
_X_EXPORT int (* ProcVector[256]) (
{
。。。。。。。。。。。。。
};
SwappedProcVector类似。
也就是说Client与server交互时,先按照固定的协议初始化Connector,并且告诉xserver其适合的协议。
然后server按照该协议解析client发送过来的操作号。
6.一个基于Xlib的简单例子了解Client流程
Xlib是对X协议的的一个简单的封装,可以让程序员不用了解细节而编写图形相关程序。实际上程序员直接调用Xlib的很少,更多使用的是
GTK+ ,QT等图形库。这些又是基于Xlib的图形库。
一个简单的Xlib例子如下
这个程序就可以看作一个简单的client,包含client的大体流程。
编译: gcc input.c -o output -lX11
程序执行方式有两种:
1.在图形界面下直接执行程序
2.在用户目录下新建一个.xinitrc文件,写入
exec input
之后startx,执行的不是默认的图形界面程序而是input程序
7.radeon驱动初始化代码解析.
由上面对xserver初始化的介绍,可以看到,在初始化过程中主要是显卡驱动的三个函数的调用
Probe , PreInit , ScreenInit
以下以radeon驱动为例(xorg-xserver-video-ati-6.13.1),介绍驱动对显卡的初始化过程,以及图形加速中使用的函数。
(1)Probe函数
在radeon驱动中,probe函数主要是
static Bool
radeon_pci_probe(
)
{
}
在radeon_get_scrninfo函数中有:主要是对pScrn和pENT的初始化。
在pScrn的初始化中给出了将要调用的PreInit 和ScreenInit函数
#ifdef XF86DRM_MODE
#endif
不妨已RADEONPreInit_KMS , RADEONScreenInit_KMS为例介绍驱动PreInit和ScreenInit过程
(2)PreInit
RADEONPreInit_KMS在结构上大体可以分为三个部分(虽然不严格),
a)pScrn->driverPrivate的初始化
例如:
其实对pScrn->driverPrivate的初始化贯穿了整个PreInit,但是在前面比较集中。
b)drm的初始化
radeon_open_drm_master(pScrn)
调用drmOpen打开内核drm设备
drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8)
drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo))
等做其他方面的初始化
c)一些相关模块的load
例如:
xf86LoadSubModule(pScrn, "fb")
load framebuffer相关的so
!xf86LoadSubModule(pScrn, "ramdac")
load 与光标显示相关模块
RADEONPreInitAccel_KMS(pScrn)
根据加速方式选择决定load shadowfb 还是exa模块
细节很多大体上可以分这三个部分理解
(3)ScreenInit
RADEONScreenInit_KMS要比RADEONPreInit_KMS杂乱
但也可以看作如下几个部分
a)对pScrn->driverPrivate的比较集中的初始化
例如:
info->bufmgr = radeon_bo_manager_gem_ctor(info->dri->drmFD);
info->cs = radeon_cs_create(info->csm, RADEON_BUFFER_SIZE/4);
等比较明显的
以及
radeon_setup_kernel_mem(pScreen);
初始化地址映射相关的info信息
b)fbScreenInit
初始化framebuffer信息
c) 显示图像像素相关的初始化及fbPictureInit
例如:
#ifdef RENDER
#endif
这部分是fbPictureInit和对像素RGB顺序的初始化
d)BackStore相关的初始化
例如:
e)加速函数相关的初始化
例如:
中的RADEONAccelInit(pScreen)函数
下面会对RADEONAccelInit(pScreen)函数做仔细的分析
f)光标显示相关的初始化
例如:
其中xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)的判断决定对光标显示是否使用硬件加速
g)其他的初始化
例如CloseScreen,BlockHandler 等变量赋值
Crtc初始化xf86CrtcScreenInit (pScreen)
和colormap相关的drmmode_setup_colormap(pScreen, pScrn)。
(4)RADEONAccelInit
需要重点介绍的是RADEONAccelInit函数,因为在这个函数中引入了初始化图像加速相关的函数
以笔者调试过的RS780为例:
其调用的图形加速相关的初始化是R600DrawInit(pScreen)函数,因为驱动不支持RS780的xaa加速,而软件加速shodowfb效果不好,必须使用exa加速。
R600DrawInit()函数中包含了众多加速函数的初始化其中最重要的是如下5系列函数
a)Solid相关的函数
Solid即是向某一区域填充色的操作
b)Copy相关的函数
Copy是不同区域直接拷贝的函数
c)Composite函数
Composite是不同窗口组合在一起的操作
d)UploadToScreen函数
UploadToScreen是向framebuffer拷贝矩形域数据的函数
e)DownloadFromScreen函数
DownloadFromScreen是从framebuffer拷贝出矩形域数据的函数
至此radeon驱动初始化相关的内容做了一次简单的浏览。
更多推荐
已为社区贡献1条内容
所有评论(0)