1. 程式人生 > >Linux環境下的圖形系統和AMD R600顯卡編程(1)——Linux環境下的圖形系統簡介

Linux環境下的圖形系統和AMD R600顯卡編程(1)——Linux環境下的圖形系統簡介

嵌入式 技術分享 捕獲 鏈接庫 深入 圖形系統 訪問 amd lam

轉:https://www.cnblogs.com/shoemaker/p/linux_graphics01.html

Linux/Unix環境下最早的圖形系統是Xorg圖形系統,Xorg圖形系統通過擴展的方式以適應顯卡和桌面圖形發展的需要,然而隨著軟硬件的發展,特別是嵌入式系統的發展,Xorg顯得龐大而落後。開源社區開發開發了一些新的圖形系統,比如Wayland圖形系統。

由於圖形系統、3D圖形本身的復雜以及歷史原因,Linux下的圖形系統相關的源碼龐大而且復雜,而且缺少學習的資料(所有源代碼分析或者驅動編程的書籍都很少介紹顯卡驅動)。在後續一系列文章中,筆者將從對AMD硬件編程的角度出發對部分問題做一個簡單的介紹,當然,這種介紹是很初級的,旨在希望能夠對初學著有所幫助。

內核DRM、Xorg以及Mesa三部分加起來的代碼和整個Linux內核的體量是差不多大的。而且現代的顯卡上的GPU的復雜程度在一定程度上可以和CPU相聘美,從程序員的角度看,操作系統(CPU的驅動)包含的許多功能在GPU驅動上都能夠找到。比如,GPU有自己的指令系統,著色器程序(GLSL、HLSL、Cg這類著色語言)需要經過編譯成GPU的指令集,然後才能夠在GPU上運行,符合著色語言規範的3D驅動都包含一個編譯器。3D應用程序需要使用大量內存,GPU在進行運算的時候需要訪問這些內存,GPU在訪問這些內存的時候也使用一套和CPU頁表一樣的機制。另外,在中斷系統上,GPU和CPU也有相似之處。後面的一些內容將會陸續對這些問題做一個簡單的介紹。

傳統上認為Linux是一個宏內核,設備驅動大部分都是包含在內核裏面的,因此可以看到內核代碼最龐大的部分是drivers目錄,如果從kernel.org上面下載一個內核源碼,直接編譯,編譯的時間大部分都耗在編譯設備驅動上。

微內核的操作系統,設備驅動不是內核的部分。這裏不討論微內核和宏內核的區別或者各自的優缺點。但是出於調試方便以及其他一些原因,Linux操作系統上面的一些驅動是放在核外的。一個主要的類別就是打印機、掃描儀這類設備,當前的打印機掃描儀通常都是通過USB 接口連接到計算機上的,對於這些設備的Linux驅動,除了USB核心部分在內核,這些打印機掃描儀本身的驅動都是在核外的。Linux上面的打印機使用CUPS系統,CUPS運行在核外,其驅動是按照CUPS的接口來開發的。Linux上面的掃描儀使用的是運行在核外的sane系統,其驅動是以動態鏈接庫的形式存在的。另外一類核外的驅動是圖形系統的驅動,由於圖形系統、顯卡本身比較復雜,而且由於一些歷史原因,圖形系統的驅動在核內核外都有,並且顯卡驅動最主要的部分在核外。

在wiki詞條“Free and open-source graphics device driver”的最新頁面上,對linux環境下的圖形系統演變過程有一個很好的圖解,這裏直接使用這個頁面的圖進行描述 http://en.wikipedia.org/wiki/Free_and_open-source_graphics_device_driver。

顯卡最早只有基本的顯示功能,可以成為顯示控制器(Display Controller)或者幀緩沖設備,對於這樣的顯示控制器,當前的Linux內核對其的支持表現為framebuffer驅動,Xorg部分對其的支持是一個名為fbdev的驅動。

技術分享圖片

圖1

其後顯卡上逐漸加上了2D加速部件,這種情況下面的驅動如上圖顯示。這個情況下的架構還是比較簡單的。

技術分享圖片

圖2

隨著3D圖形顯示和運算的需要,帶有圖形運算功能的顯卡出現,這個時候需要有專門的3D驅動來處理3D,於是出現了上圖的GLX driver,這裏註意到X server依然處在一個中心節點的位置,無論是X11程序還是3D OpenGL程序,都要通過X server才能到底層。同時註意到到現在為止X的2D driver和GLX driver都是直接調用到硬件,而沒有通過內核調用。在2.6版本的內核的系統上,依然能看到X 2D driver中有訪問硬件有MMIO和CP兩套代碼,MMIO就是這裏的情況,顯卡寄存器直接暴露給核外的2D driver(和GLX driver,目前已經不存在這個了)。

這種情況下的結構仍然是比較簡單的,然而這種情況有一個很大的問題,讀過X server代碼的(或者參考這篇文章“X Window System Internals”http://xwindow.angelfire.com/)應該知道,X server是單線程的(關於多線程X server,可以google到一些郵件討論記錄),main函數完成系統初始化之後就進入了一個循環,等待客戶端程序的連入,等一個客戶端程序發送完數據之後其他的客戶端才能連上來,OpenGL客戶端程序每次要請求硬件都必須先經過X server,然後由X server“代表”OpenGL程序進入硬件,對於場景稍微復雜的3D應用程序來說,這樣頻繁的和X server交互是難以保證3D渲染的實時性的。

鑒於上面的問題,引入了DRI機制,在這個機制下面,OpenGL程序對硬件的請求不再經過X server,而是自己直接和硬件交互。整個過程是這樣的:在繪圖之前,OpenGL程序向內核申請到一片渲染目標並告訴X server,然後OpenGL程序不經過X server而直接調用進內核請求硬件進行渲染操作,並將結果渲染到申請到的渲染目標中,渲染結束後,OpenGL程序通知X server該渲染目標發生了變化,對應的屏幕上的窗口區域需要進行更新,X server收到這個通知後,進行一次重新的窗口混合工作(當前代碼是EXA的Composite功能提供的。這個時候的情況如下圖示,GLX driver被DRI driver取代,和Dri driver交互的不再是X server而直接是OpenGL程序。另外DRI(原來是GLX)不直接操作硬件,而是通過內核drm驅動操作硬件,drm提供硬件訪問通道和訪問機制。在當前的系統上,2D driver以EXA 2D加速驅動的形式存在於Xorg裏面,DRI driver則在Mesa中。

技術分享圖片

圖3

然後又添加了對遠程3D client的支持AIGLX,這部分的功能和原來的Utah GLX有類似之處。AIGLX可以參考wiki頁面(http://en.wikipedia.org/wiki/AIGLX)。

技術分享圖片

圖4

X server通過不斷擴展形成了現在的樣子,顯得龐大而且復雜,有些工作是不必要的。開源社區提出了更為簡潔的wayland圖形系統,在“揭開Wayland的面紗(一)(二)”兩篇文章裏面對wayland做了說明,讀者可以點擊下面的地址:

http://www.ibentu.org/2010/11/06/introduce-to-wayland-01.html

http://www.ibentu.org/2010/11/06/introduce-to-wayland-01.html

技術分享圖片

圖5

在這兩篇文章裏面描述了這麽一個場景:在一個圖形程序上點擊某個按鈕。在X圖形系統下,X的evdev驅動捕獲到這個信息,X被告知有應用程序需要進行渲染,然後X server查詢到需要渲染的窗口,然後將“鼠標點擊”這個事件通知給需要渲染的窗口對應的X程序,X程序接收到通知後再告訴X server“如何進行渲染”,X server接收到“如何渲染”的消息後進行渲染(2D情況下X/EXA自己完成,3D情況下無需先通知X server,使用DRI完成繪制並由應用程序告知X渲染已經完成),完成通知X的“composite”擴展進行混合,X的composite擴展接到混合請求後告知X server混合已經完成,這裏面X server和X client以及X server和X composite之間都有雙向的通信,這兩部分是比較耗時的,而且由於X server通知X composite之前還需要進行窗口的重疊判斷、被覆蓋窗口的剪載計算等——然而這些是X composite不需要的,因此會有一些額外的時間消耗。

在Wayland情況下,server主要進行composite,應用程序全部使用DRI直接渲染機制,完成後通知Server(composite)進行混合,結構上非常簡單而且高效。

另外對窗口的請求也發生了變化,在X DRI下,X11和3D程序需要向X server請求窗口,那個時候X server進行的加速操作必須依賴單獨的EXA驅動(無法直接調用OpenGL加速),後來的mesa做了一些修改,在wayland環境下,Application直接通過EGL、GLES driver向內核drm請求繪圖窗口,而這裏的composite可以直接調用OpenGLES進行加速,而無需單獨有2D加速驅動。

還註意到,內核裏面有一個KMS,全稱是kernel mode setting(內核模式設置,設置顯示分辨率之類的),前面曾經提到過,早期的顯卡寄存器是直接暴漏給核外驅動的,直到現在的EXA內核代碼裏面仍然有MMIO和CP兩種操作方式,早期X進行模式設置的時候直接寫寄存器進行操作,後來內核引入了KMS(在wayland之前就已經有了),於是核外驅動可以通過調用KMS接口進行模式操作而不需要了解硬件細節。

上面提到了composite,X的composite的操作如下圖示:

技術分享圖片

圖6

過去的X11 client直接在顯示區域上,現在X11 client窗口在off-screen顯存上,compositor從這些顯存上取出內容並最終混合到顯示區域上去。X裏面和composite操作相關的擴展有damage、render、composite,這三者描述參考以下資料:

http://cgit.freedesktop.org/xorg/proto/compositeproto/plain/compositeproto.txt

http://cgit.freedesktop.org/xorg/proto/damageproto/plain/damageproto.txt

http://cgit.freedesktop.org/xorg/proto/renderproto/plain/renderproto.txt

關於X composite的引入過程讀者可以參考以下資料:

Keith Packard. Design and Implementation of the X Rendering Extension

Matthieu Herrb, Matthias Hopf. New Evolutions in the X Window System

Andy Ritger. Using the Existing XFree86/X.Org Loadable Driver Framework to Achieve a Composited X Desktop

當前的Linux環境上的圖形系統架構如下圖示:

技術分享圖片圖7

這裏的部分內容在前面描述過了,需要註意的是X server的EXA驅動部分出現了glamor,glamor直接調用到了mesa裏面,過去EXA驅動是單獨的驅動,通過drm調用操作硬件,而由於mesa的改變,X可以和wayland composite一樣直接調用Mesa的接口。

後面的描述將針對Fedora 16操作系統,Fedora 16系統和現在最新的系統(圖7)有一定的區別,後面的一些問題的討論主要使用圖4。在後續blog中,將先對Fedora的圖形系統內核、X、Mesa這個層次的部分進行一個簡單的描述,然後開始介紹驅動對AMD顯卡硬件部分模塊(功能)的編程。

其他參考資料:

Inside Linux graphics 是intel的開發人員編寫的一份介紹圖形架構的文檔。

Linux Graphics Drivers: an Introduction 是開源社區的開發人員寫的一份文檔,對Linux圖形系統的各個方面都有一些介紹。

A deeper look into GPUs and the Linux Graphics Stack 這一份ppt對圖形系統架構有比較深入的探討。

Graphics Card Interfaces 這篇博文對圖形架構的部分細節有一些探討。

精通嵌入式Linux編程:構建自己的GUI環境 這本書描述了如何在framebuffer上構建一個完整的圖形系統,其中的許多概念和原理在X圖形系統中也能夠看到。

Linux環境下的圖形系統和AMD R600顯卡編程(1)——Linux環境下的圖形系統簡介