[轉帖]xserver相關知識彙總

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  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
    xorg.conf是X Server的主要配置文件,它包含一個當前系統的硬件資源列表。X Server就是根據這些硬件資源「組織」出基本的圖形能力。xorg.conf文件在/etc/X11/xorg.conf,主要包含幾個字段:
    Files:            X系統使用的字體存放目錄(字體的具體使用由FontConfig工具主持)
    InputDevice:    輸入設備,如鍵盤鼠標的信息
    Monitor:        顯示器的設置,如分辨率,刷新率等
    Device:            顯示卡信息
    Screen:            由Monitor和Device組裝成一個Screen,表示由它們向這個Screen提供輸出能力
    ServerLayout:    將一個Screen和InputDevice組裝成一個ServerLayout
在具備多個顯示設備的系統中,可能有多個Screen和多個ServerLayout,用以實現不一樣的硬件搭配。
    在最近的xorg版本中,X Server已經開始自動偵測硬件,如今的xorg.conf已經都成了默認名稱。具體細節還待查,但基本原理仍是不變的。
(2) X session(X會話)
    X session是指X server啓動後直到X server關閉之間的這段時間。這期間一切跟X相關的動做都屬於X session的內容。管理X session的程序稱爲Display Manager,常據說的gdm或kdm就是gnome/kde所分別對應的Display Manager。
    開啓一個X session,也就是開始了圖形界面的使用。在開啓的過程當中,Display Manager會對用戶進行認證(也就是用戶名密碼的輸入),運行事先設置好的程序(好比scim輸入法就是這個時候啓動的)等等。
    這個開啓過程要執行的一系列操做均可以在/etc/X11/Xseesion以及/etc/X11/Xsession.d/目錄下看到,其餘還有一些配置文件如Xsession.options, Xresource等,都是執行的X session的初始化過程。仔細閱讀這些腳本或配置文件,能夠幫助你更好地理解X
 
b), Display Manager
    上面說過,Display Manager(後簡稱DM)是管理X session的程序,常見的有gdm, kdm, xdm等。對於默認進入X界面的Linux系統,必須將DM程序在開機時執行,即:/etc/rc2.d/S13gdm。下面咱們從手工啓動X的過程,看一下DM爲咱們作了哪些工做。
    若是沒有設置DM在開機時運行的話,手動啓動X使用startx命令。
    man startx
能夠知道,startx的做用能夠看做是Display Manager的一種隱性實現。它使用xinit命令,分別根據/etc/X11/xinit/xinitrc和/etc/X11/xinit/xserverrc中所指定的設置喚起X。
    其中,xserverrc執行X server的運行任務;xinitrc則運行Xsession命令。從/etc/X11/Xsession腳本的內容能夠看出,它也就是進入/etc /X11/Xsession.d/目錄輪詢地執行全部腳本。很明顯,這些也就是前面所說的Xsession初始化工做。
    綜合起來講,Display Manager完成三個任務:1, X Server的啓動; 2, X session的初始化; 3, X session的管理。
 
c), Window Manager
    X Server提供了基本的圖形顯示能力。然而具體怎麼繪製應用程序的界面,倒是要有應用程序本身解決的。而Window Manager(桌面管理器,後簡稱WM)就是用來提供統一的GUI組件的(窗口、外框、菜單、按鈕等)。不然,應用程序們各自爲政,既增長了程序開發的負擔,不統一的桌面風格對視覺也是不小的挑戰。
    WM的啓動由DM控制,在gdm的登陸窗口,咱們能夠進行選擇。常見的WM有:Metacity(Gnome默認的WM), fluxbox, fvwm, E17等。
 
d), X Clients
    最後,就是X Client了。X客戶端程序,顧名思義,就是使用X服務的程序。firefox,gedit等等都屬於X Client程序。X Client部分值得考慮一下的就是DISPLAY環境變量。它主要用於遠程X Client的使用。該變量表示輸出目的地的位置,由三個要素組成:
    [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  # 注意 : 該腳本用的是 bash shell 解析的
 
    #  Xorg:xinitrc.cpp,v1.32000/08/1719:54:30cpqbldExpXorg:xinitrc.cpp,v1.32000/08/1719:54:30cpqbldExp
 
    # /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:xserverrc1892005061100:04:27ZbrandenId:xserverrc1892005−06−1100:04:27Zbranden
 
    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(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的工做
    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 create server client」);
        InitClient(serverClient, 0, (pointer)NULL);
    }
    else
        ResetWellKnownSockets ();
當第一次循環時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
        if (*icheck[0] != *icheck[1])
    {
        ProcessInputEvents();
        FlushIfCriticalOutputPending();
    }
 
(2)等待clients發送事件過來
    nready = WaitForSomething(clientReady);
 
(3)遍歷每一個發送信息的client,作以下處理
    1)接受用戶輸入併發送
        if (*icheck[0] != *icheck[1])
        ProcessInputEvents();
        FlushIfCriticalOutputPending();
    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,
    ProcChangeWindowAttributes,
    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,
    struct pci_device *device,
    intptr_t           match_data
)
{
    return radeon_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))
     return FALSE;
其實對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, 「Acceleration enabled\n」);
            info->accelOn = TRUE;
        } else {
            xf86DrvMsg(scrnIndex, X_ERROR,
                       「Acceleration initialization failed\n」);
            xf86DrvMsg(scrnIndex, X_INFO, 「Acceleration disabled\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, xf86GetPointerScreenFuncs());
    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驅動初始化相關的內容作了一次簡單的瀏覽。
</div>
            </div>
            <div class="hide-article-box text-center">
        <a class="btn btn-red-hollow" id="btn-readmore" data-track-view="{&quot;mod&quot;:&quot;popu_376&quot;,&quot;con&quot;:&quot;,https://blog.csdn.net/arag2009/article/details/78465854,&quot;}" data-track-click="{&quot;mod&quot;:&quot;popu_376&quot;,&quot;con&quot;:&quot;,https://blog.csdn.net/arag2009/article/details/78465854,&quot;}">閱讀更多</a>
    </div>
        </article>
相關文章
相關標籤/搜索