xorg-xserver相关完全解析_xorg启动流程-程序员宅基地

技术标签: linux OS 笔记  xorg-xserver相关完全解析  

本文主要是从以下几个方面介绍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   kdmxdm等)
c)窗口管理器 (Window Manager) 例如(metacity ,fluxbox等)
d)DM 和 WM之上的一些图形应用程序 
在使用中一般都是b,c,d三者集合起来构成一个完整的集成工作环境,例如KDE ,GNOME等
,这就是我们平时所说的广义上的xclient

a)xserver 主要提供基本的显示接口共xclient使用,并将用户的操作等也反映给xclient,
是xclient与硬件的一个中间层。xserver相关的两个主要部分是
(1)     xorg.conf
      xorg.conf是X Server的主要配置文件,它包含一个当前系统的硬件资源列表。XServer就是根据这些硬件资源“组织”出基本的图形能力。xorg.conf文件在/etc/X11/xorg.conf,主要包含几个字段:
      Files:            X系统使用的字体存放目录(字体的具体使用由FontConfig工具主持)
      InputDevice:     输入设备,如键盘鼠标的信息
      Monitor:         显示器的设置,如分辨率,刷新率等
      Device:            显示卡信息
      Screen:            由Monitor和Device组装成一个Screen,表示由它们向这个Screen提供输出能力
      ServerLayout:     将一个Screen和InputDevice组装成一个ServerLayout
在具有多个显示设备的系统中,可能有多个Screen和多个ServerLayout,用以实现不同的硬件搭配。
      在最近的xorg版本中,XServer已经开始自动侦测硬件,现在的xorg.conf已经都成了默认名称。具体细节还待查,但基本原理还是不变的。
(2) X session(X会话)
      Xsession是指X server启动后直到X server关闭之间的这段时间。这期间一切跟X相关的动作都属于Xsession的内容。管理X session的程序称为DisplayManager,常听说的gdm或kdm就是gnome/kde所分别对应的Display Manager。
      开启一个Xsession,也就是开始了图形界面的使用。在开启的过程中,DisplayManager会对用户进行认证(也就是用户名密码的输入),运行事先设置好的程序(比如scim输入法就是这个时候启动的)等等。
      这个开启过程要执行的一系列操作都可以在/etc/X11/Xseesion以及/etc/X11/Xsession.d/目录下看到,其他还有一些配置文件如Xsession.options,Xresource等,都是执行的X session的初始化过程。仔细阅读这些脚本或配置文件,可以帮助你更好地理解X

b), Display Manager
      上面说过,Display Manager(后简称DM)是管理Xsession的程序,常见的有gdm, kdm,xdm等。对于默认进入X界面的Linux系统,必须将DM程序在开机时执行,即:/etc/rc2.d/S13gdm。下面我们从手工启动X的过程,看一下DM为我们做了哪些工作。
      如果没有设置DM在开机时运行的话,手动启动X使用startx命令。
      manstartx
可以知道,startx的作用可以看作是DisplayManager的一种隐性实现。它使用xinit命令,分别根据/etc/X11/xinit/xinitrc和/etc/X11/xinit/xserverrc中所指定的设置唤起X。
      其中,xserverrc执行Xserver的运行任务;xinitrc则运行Xsession命令。从/etc/X11/Xsession脚本的内容可以看出,它也就是进入/etc/X11/Xsession.d/目录轮询地执行所有脚本。很明显,这些也就是前面所说的Xsession初始化工作。
      综合起来说,Display Manager完成三个任务:1, X Server的启动; 2, Xsession的初始化; 3, X session的管理。

c), Window Manager
      XServer提供了基本的图形显示能力。然而具体怎么绘制应用程序的界面,却是要有应用程序自己解决的。而WindowManager(桌面管理器,后简称WM)就是用来提供统一的GUI组件的(窗口、外框、菜单、按钮等)。否则,应用程序们各自为政,既增加了程序开发的负担,不统一的桌面风格对视觉也是不小的挑战。
      WM的启动由DM控制,在gdm的登录窗口,我们可以进行选择。常见的WM有:Metacity(Gnome默认的WM),fluxbox, fvwm, E17等。

d), X Clients
      最后,就是XClient了。X客户端程序,顾名思义,就是使用X服务的程序。firefox,gedit等等都属于X Client程序。XClient部分值得考虑一下的就是DISPLAY环境变量。它主要用于远程XClient的使用。该变量表示输出目的地的位置,由三个要素组成:
      [host]:display[.screen]
      host指网络上远程主机的名称,可以是主机名、IP地址等。默认的host是本地系统,你可以在自己系统上echo$DISPLAY看一下。
      display和screen分别代表输出画面的编号和屏幕的编号。具体细节由于硬件的缺乏,还有待进一步研究。

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 文件的内容如下所示:
 
      #!/bin/bash   # 注意 : 该脚本用的是 bashshell 解析的
 
      #$Xorg: xinitrc.cpp,v 1.3 2000/08/17 19:54:30 cpqbld Exp $
 
      #/etc/X11/xinit/xinitrc
      #
      #global xinitrc file, used by all X sessions started by xinit(startx)
 
      #invoke global X session script
      ./etc/X11/Xsession   # 在当前这个 shell 环境中执行 Xsession脚本
 
因此, gnome 的启动应该在 Xsession 里。
 
而 X Server 的启动则是通过系统文件 /etc/X11/xinit/xserverrc 来指定的 ,这个文件的内容为 :
 
      #!/bin/sh # 注意:该脚本用的是 Bourne shell 解析的
 
      # $Id:xserverrc 189 2005-06-11 00:04:27Z branden $
 
      exec/usr/bin/X11/X -nolisten tcp


综上所述, 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(DirectRendering 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的工作
      InitRegions();
      pixman_disable_out_of_bounds_workaround();
      CheckUserParameters(argc, argv, envp);
      CheckUserAuthorization();
      InitConnectionLimits();
      ProcessCommandLine(argc, argv);

随后main函数进入了一个死循环。每次循环均包含了
a)xserver初始化
b)xserver循环处理client消息
c)xserver退出
三个阶段
这是xserver的main函数最外层的循环,一般启动xserver只会执行一次循环:用户在图形界面操作时,实际上xserver是处在b)阶段。
这个循环就保证了xserver出现一般的异常时会自动恢复,比如在运行x时替换了其显卡驱动,xserver会触发异常结束第一次循环
并在第二次循环中重新加载替换后的显卡驱动。

以下分别对这三个阶段做解析
a)xserver初始化
xserver初始化函数非常多,以下仅粗略介绍几个比较熟悉的:

(1)
初始化中有如下代码:
      if(serverGeneration == 1)
      {
          CreateWellKnownSockets();
          InitProcVectors();
          for (i=1;i<MAXCLIENTS; i++)
          clients[i] =NullClient; 
          serverClient =xalloc(sizeof(ClientRec));
          if (!serverClient)
          FatalError("couldn't createserver client");
          InitClient(serverClient, 0,(pointer)NULL);
      }
      else
          ResetWellKnownSockets();
当第一次循环时serverGeneration=1,执行的是第一个分支代码。
CreateWellKnownSockets() 初始化一系列sockets监听是否有clients申请连接。
InitProcVectors() 初始化ProcVector,SwappedProcVector结构
for循环是生成并初始化clients数组
之后便是serverClient变量的生成即初始化,serverClient是clients数组中索引为0的项,因为他是拥有rootwindow的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中有SectionInputDevice配置,会按照
其配置扫描加载设备



b)xserver循环处理client消息
在初始化结束之后xserver便进入了循环处理阶段即
Dispatch()函数

该函数的流程主要是一个循环结构
while (!dispatchException)
即当不出现异常时循环会不断进行下去
每一次循环可以分为如下部分
(1)接受用户的输入,并发送给client
          if (*icheck[0] !=*icheck[1])
      {
          ProcessInputEvents();
          FlushIfCriticalOutputPen ding();
      }

(2)等待clients发送事件过来
      nready= WaitForSomething(clientReady);

(3)遍历每个发送信息的client,做如下处理
      1)接受用户输入并发送
          if (*icheck[0] !=*icheck[1])
          ProcessInputEvents();
          FlushIfCriticalOutputPen ding();
      2)获得client的请求号
          result =ReadRequestFromClient(client);
      3)根据请求号调用队列中相应的处理函数
          if (result >(maxBigRequestSize << 2))
              result = BadLength;
          else {
              result = XaceHookDispatch(client, MAJOROP);
              if (result == Success)
              result = (*client->requestVector[MAJOROP])(client);
              XaceHookAuditEnd(client, result);
          }
      4)若处理函数返回异常则做异常处理
          if (result != Success)
          {
              if (client->noClientException !=Success)
                          CloseDownClient(client);
                      else
                  SendErrorToClient(client, MAJOROP,
                        MinorOpcodeOfRequest(client),
                        client->errorValue, result);
              break;
              }
          }
      5)提交处理结果
        FlushAllOutput();

由此Dispatch函数解析结束



c)xserver退出
      包含了一系列释放内存,关闭clients等操作,这里就不多做解析。





5.xserver,xclient协议简介
由上文对Dispatch函数的分析可以看出,xserver对client的处理主要是三步:
(1)获得事件信息
  nready =WaitForSomething(clientReady);
(2)获得操作号
  result =ReadRequestFromClient(client);
(3)根据操作号处理
  result = (*client->requestVector[MAJOROP])(client);

因此其操作号和操作的对应是xserver与client的协议的一部分,类似操作
系统的系统调用号和系统调用之间的关系。

在上面介绍InitClients()中有对requestVector初始化
client->requestVector = InitialVector;

InitVector如下:
int (* InitialVector[3]) (
      ClientPtr
      ) =     
{        
      0,
      ProcInitialConnection,
      ProcEstablishConnection
}; 

其只有两个函数,一个是初始化Connection,一个是确立Connection
在ProcEstablishConnection中调用SendConnSetup寒酸,
SendConnSetup函数有:
client->requestVector =client->swapped ? SwappedProcVector :ProcVector;
即初始化requestVector为SwappedProcVector或ProcVector
ProcVector如下:
_X_EXPORT int (* ProcVector[256]) (
      ClientPtr
      )=
{
      ProcBadRequest,
      ProcCreateWindow,
      ProcChangeWindowAttribut es,
      ProcGetWindowAttributes,
      ProcDestroyWindow,
      ProcDestroySubwindows,      
      ProcChangeSaveSet,
      ProcReparentWindow,
      ProcMapWindow,
      ProcMapSubwindows,
      ProcUnmapWindow,            
。。。。。。。。。。。。。
      ProcGetModifierMapping,
      0,                 
      0,
      0,
      0,
      0,
      0,                 
      0,
      ProcNoOperation    
};
SwappedProcVector类似。

也就是说Client与server交互时,先按照固定的协议初始化Connector,并且告诉xserver其适合的协议。
然后server按照该协议解析client发送过来的操作号。






6.一个基于Xlib的简单例子了解Client流程
Xlib是对X协议的的一个简单的封装,可以让程序员不用了解细节而编写图形相关程序。实际上程序员直接调用Xlib的很少,更多使用的是
GTK+ ,QT等图形库。这些又是基于Xlib的图形库。
一个简单的Xlib例子如下
 
  #include<X11/Xlib.h>
  #include<stdio.h>
  #include<stdlib.h>
  #include<string.h>
 
  int main(void) {
    Display *d;
    Window w;
    XEvent e;
    char *msg = "Hello,World!";
    int s;
 
     
    d =XOpenDisplay(NULL);
    if (d == NULL) {
      fprintf(stderr, "Cannot open display\n");
      exit(1);
    }
 
    s =DefaultScreen(d);
 
   
    w =XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
                            BlackPixel(d, s),WhitePixel(d, s));
 
     
    XSelectInput(d, w,ExposureMask | KeyPressMask);
 
   
    XMapWindow(d, w);
 
   
    while (1) {
     
      XNextEvent(d, &e);

     
      if(e.type == Expose) {
        XFillRectangle(d, w, DefaultGC(d, s), 20, 20,10, 10);
        XDrawString(d, w, DefaultGC(d, s), 50, 50, msg,strlen(msg));
      }
     
      if(e.type == KeyPress)
        break;
    }
 
   
    XCloseDisplay(d);
 
    return 0;
  }
这个程序就可以看作一个简单的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(
      DriverPtr           pDriver,
      int                entity_num,
      structpci_device *device,
      intptr_t           match_data
)
{
      returnradeon_get_scrninfo(entity_num, (void *)device);
}

在radeon_get_scrninfo函数中有:主要是对pScrn和pENT的初始化。
在pScrn的初始化中给出了将要调用的PreInit 和ScreenInit函数
#ifdef XF86DRM_MODE
      if (kms== 1) {
        pScrn->PreInit       = RADEONPreInit_KMS;
        pScrn->ScreenInit    = RADEONScreenInit_KMS;
        pScrn->SwitchMode    = RADEONSwitchMode_KMS;
        pScrn->AdjustFrame  = RADEONAdjustFrame_KMS;
        pScrn->EnterVT       = RADEONEnterVT_KMS;
        pScrn->LeaveVT       = RADEONLeaveVT_KMS;
        pScrn->FreeScreen    = RADEONFreeScreen_KMS;
        pScrn->ValidMode    = RADEONValidMode;
      }else
#endif
      {
        pScrn->PreInit       = RADEONPreInit;
        pScrn->ScreenInit    = RADEONScreenInit;
        pScrn->SwitchMode    = RADEONSwitchMode;
        pScrn->AdjustFrame  = RADEONAdjustFrame;
        pScrn->EnterVT       = RADEONEnterVT;
        pScrn->LeaveVT       = RADEONLeaveVT;
        pScrn->FreeScreen    = RADEONFreeScreen;
        pScrn->ValidMode    = RADEONValidMode;
      }
不妨已RADEONPreInit_KMS ,RADEONScreenInit_KMS为例介绍驱动PreInit和ScreenInit过程

(2)PreInit
RADEONPreInit_KMS在结构上大体可以分为三个部分(虽然不严格),
a)pScrn->driverPrivate的初始化
例如:
  info               = RADEONPTR(pScrn);
  info->pEnt         =xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities- 1]);
  f (!radeon_alloc_dri(pScrn))
      returnFALSE;
 
其实对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
例如:
      if(pScrn->bitsPerPixel > 8) {
          VisualPtr  visual;

          visual =pScreen->visuals +pScreen->numVisuals;
          while (--visual>= pScreen->visuals) {
              if ((visual->class | DynamicClass)== DirectColor) {
                  visual->offsetRed  = pScrn->offset.red;
                  visual->offsetGreen =pScrn->offset.green;
                  visual->offsetBlue  = pScrn->offset.blue;
                  visual->redMask     = pScrn->mask.red;
                  visual->greenMask  = pScrn->mask.green;
                  visual->blueMask    =pScrn->mask.blue;
              }
          }
      }

     
      fbPictureInit (pScreen, 0, 0);

#ifdef RENDER
      if ((s= xf86GetOptValString(info->Options,OPTION_SUBPIXEL_ORDER))) {
          if (strcmp(s, "RGB") == 0)subPixelOrder = SubPixelHorizontalRGB;
          else if (strcmp(s, "BGR") ==0) subPixelOrder = SubPixelHorizontalBGR;
          else if (strcmp(s, "NONE") ==0) subPixelOrder = SubPixelNone;
          PictureSetSubpixelOrder(pScreen, subPixelOrder);
      }
#endif
这部分是fbPictureInit和对像素RGB顺序的初始化


d)BackStore相关的初始化
例如:
      xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO, RADEON_LOGLEVEL_DEBUG,
                    "Initializing backing store\n");
      miInitializeBackingStore (pScreen);
      xf86SetBackingStore(pScreen);


e)加速函数相关的初始化
例如:
      if(info->r600_shadow_fb) {
          xf86DrvMsg(scrnIndex, X_INFO,"Acceleration disabled\n");
          info->accelOn =FALSE;
      } else{
          xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO, RADEON_LOGLEVEL_DEBUG,
                        "Initializing Acceleration\n");
          if (RADEONAccelInit(pScreen)){
              xf86DrvMsg(scrnIndex, X_INFO, "Accelerationenabled\n");
              info->accelOn = TRUE;
          } else {
              xf86DrvMsg(scrnIndex, X_ERROR,
                        "Acceleration initialization failed\n");
              xf86DrvMsg(scrnIndex, X_INFO, "Accelerationdisabled\n");
              info->accelOn = FALSE;
          }
      }
中的RADEONAccelInit(pScreen)函数
下面会对RADEONAccelInit(pScreen)函数做仔细的分析


f)光标显示相关的初始化
例如:
     
      xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO, RADEON_LOGLEVEL_DEBUG,
                    "Initializing DPMS\n");
      xf86DPMSInit(pScreen, xf86DPMSSet, 0);

      xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO, RADEON_LOGLEVEL_DEBUG,
                    "Initializing Cursor\n");

     
      xf86SetSilkenMouse(pScreen);

     
      miDCInitialize(pScreen,xf86GetPointerScreenFunc s());

      if(!xf86ReturnOptValBool(info->Options,OPTION_SW_CURSOR, FALSE)) {
          if(RADEONCursorInit_KMS(pScreen)) {
          }
      }

其中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相关的函数
      info->accel_state->exa->PrepareSolid= R600PrepareSolid;
      info->accel_state->exa->Solid= R600Solid;
      info->accel_state->exa->DoneSolid= R600DoneSolid;
Solid即是向某一区域填充色的操作


b)Copy相关的函数
      info->accel_state->exa->PrepareCopy= R600PrepareCopy;
      info->accel_state->exa->Copy= R600Copy;
      info->accel_state->exa->DoneCopy= R600DoneCopy;
Copy是不同区域直接拷贝的函数


c)Composite函数
      info->accel_state->exa->CheckComposite= R600CheckComposite;
      info->accel_state->exa->PrepareComposite= R600PrepareComposite;
      info->accel_state->exa->Composite= R600Composite;
      info->accel_state->exa->DoneComposite= R600DoneComposite;
Composite是不同窗口组合在一起的操作

d)UploadToScreen函数
      info->accel_state->exa->UploadToScreen= R600UploadToScreenCS;
UploadToScreen是向framebuffer拷贝矩形域数据的函数

e)DownloadFromScreen函数
      info->accel_state->exa->DownloadFromScreen= R600DownloadFromScreenCS ;
DownloadFromScreen是从framebuffer拷贝出矩形域数据的函数

至此radeon驱动初始化相关的内容做了一次简单的浏览。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangna20151015/article/details/51283367

智能推荐

python xml xpath定位_python之Xpath语法-程序员宅基地

文章浏览阅读942次。python视频教程栏目介绍python的Xpath语法。一、XMl简介(一)什么是 XMLXML 指可扩展标记语言(EXtensible)XML 是一种标记语言,很类似 HTML。XML 的设计宗旨是传输数据,而非显示数据。XML 的标签需要我们自行定义。XML 被设计为具有自我描述性。XML 是 W3C 的推荐标准。W3School 官方文档:http://www.w3school.com.c..._python xml xpath

使用navicat创建postgres如何设置自增序列_navacit pgsql 自动递增-程序员宅基地

文章浏览阅读1.6k次。1、打开查询:运行指令 CREATE SEQUENCE upms_log_id_seq START 1;2、将upms_log_id_seq 与设计表 id选项下的默认关联成如图所示nextval('upms_log_id_seq'::regclass)![image.png](https://upload-images.jianshu.io/upload_images/14535918-4146bd22595c6fbc.png?imageMogr2/auto-orient/strip%7.._navacit pgsql 自动递增

中国区块链教育及人才发展报告(2020)_中国区块链产业人才-程序员宅基地

文章浏览阅读656次。报告摘要:1、据零壹智库不完全统计,截至2020年11月底,已有32所国内高校开展区块链教学研究。其中,16所高校开展/预开展20门学分课程;27所高校设立了33个实验室。2、与2019年10月相比,企业对人才学历的要求有所下降。2020年11月,企业要求区块链人才本科率(注:仅为本科,不含硕博)为51.74%,与之前相比下降了10.84%。本科平均工资为2.47万元/月,与之前相比减少了1000元左右。3、根据样本数据,技术类管理人才受到“热捧”,招聘的5个人中至少有一个是管理人员_中国区块链产业人才

细说深度学习之TensorFlow_tensorflow的可用性神经网络-程序员宅基地

文章浏览阅读1k次,点赞2次,收藏10次。DNN(深度神经网络算法)现在是AI社区的流行词。最近,DNN 在许多数据科学竞赛/Kaggle 竞赛中获得了多次冠军。自从 1962 年 Rosenblat 提出感知机(Perceptron)以来,DNN 的概念就已经出现了,而自 Rumelhart、Hinton 和 Williams 在 1986 年发现了梯度下降算法后,DNN 的概念就变得可行了。直到最近 DNN 才成为全世界 AI/ML..._tensorflow的可用性神经网络

程序员面试题整理分享合集_程序员面试分享-程序员宅基地

文章浏览阅读190次。又到了程序员跳槽的黄金时期,大家是否都在网上搜寻各类面试题,希望扩充自己的技术知识面,为自己接下来的面试提高信心。大家可以关注我的个人公众号,回复“面试”即可获取我个人整理的大量面试资料,包含Android、C、java等等国内各个大厂的面试和笔试题,希望可以对大家有所帮助,预祝大家可以找一个心仪的工作。..._程序员面试分享

《构建高可用Linux服务器》互动网首发-程序员宅基地

文章浏览阅读136次。书名:构建高可用Linux服务器ISBN:9787111359423 作者:余洪春定价:79.00元出版时间:2011年10月出版社:机械工业出版社 订书页面编辑推荐:基于实际生产环境,从Linux虚拟化、集群、服务器故障诊断与排除、系统安全性等多角度阐述构建高可用Linux服务器的最佳实践资深Linux/Unix系统管理专家兼架构师多年一线工作经验结晶,5..._赵克衡

随便推点

python绘图时将输入的乱序横坐标进行重新排序_python 按照横坐标排序-程序员宅基地

文章浏览阅读2.7k次。最近用tkinter制作exe程序时,要实现程序绘图可视化功能,绘制的折线图是展示每年的各个指标,输入的年份可能不按照从小到大的顺序,但是要求绘制出来的图必须按照年份的顺序,不然岂不是很傻下面截取了核心代码来实现该功能。# 首先生成一个原始的list,用于获取横坐标及各折线的纵坐标,这里list1[0]是年份,1-5存放纵坐标list1=[[],[],[],[],[],[]]list1[0].append(x)list1[1].append(a1)list1[2].append(c1)l_python 按照横坐标排序

集合的二进制表示。_集合中的二进制是什么-程序员宅基地

文章浏览阅读1.9k次。一些不大的数的集合,可以用二进制的形式来表示,注意这里的集合没有重复元素。集合的存储方法是用一串二进制的数存,第i位表示i这个数是否在集合中。设集合中最大的数不超过(1集合的运算因为是二进制表示,A|B、A&B、A^B、分别对应集合的并,交和对称差。子集 元素的输出从1到n枚举,如果在s中就输出,代码:void print_element(int n,int s){_集合中的二进制是什么

中文分词工具 MiNLP-Tokenizer-程序员宅基地

文章浏览阅读1k次。MiNLP-Tokenizer1. 工具介绍MiNLP-Tokenizer是小米AI实验室NLP团队自研的中文分词工具,基于深度学习序列标注模型实现,在公开测试集上取得了SOTA效果。其具备以下特点:分词效果好:基于深度学习模型在大规模语料上进行训练,粗、细粒度在SIGHAN 2005 PKU测试集上的F1分别达到95.7%和96.3%[注1]轻量级模型:精简模型参数和结构,模型仅有..._microtokenizer自定义词典

Navicat将mysql表结构导成oracle表结构_navicat怎么把mysql表导出成oracle建表语句-程序员宅基地

文章浏览阅读2.3k次,点赞2次,收藏13次。1,选中对应的表右键逆向表到模型2.点击右上角文件转换模型为3.模型选择物理,数据库oracle,选择对应的版本4.新弹出的模型点击右上角文件,导出sql5.选择路径导出sql..._navicat怎么把mysql表导出成oracle建表语句

ROS报错Error:cannot launch node of type [map_server/map_server]_error: cannot launch node of type-程序员宅基地

文章浏览阅读2.3k次,点赞2次,收藏6次。报错:ERROR: cannot launch node of type [map_server/map_server]: Cannot locate node of type [map_server] 原因:有部分功能包没有编译。ROS使用catkin_make编译单个功能包和所有功能包。catkin_make -DCATKIN_WHITELIST_PACKAGES="需要单独编译的包名"但是如再次使用catkin_make编译所有功能包时,会出现仅仅只编译上次设置的单独功能包。如果想要再_error: cannot launch node of type

【自考】-2018年10月自考总结_2018年10月软件工程试题-程序员宅基地

文章浏览阅读510次。自考总结: 这次考试就报考了一科C ++程序设计,自学考试也就接近尾声了。加上之前考的学位英语和实践课,毕业设计。自考也就结束了。 总结一下学习C ++的着重点吧。实践 C ++程序设计三到六大题都是和程序代码相关的题目,所有得非常熟悉C ++的代码规则和原理。可以在第一、二遍的时候敲一下课本中的程序代码。自己挑一些敲,不用全部都敲了。..._2018年10月软件工程试题

推荐文章

热门文章

相关标签