Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介
轉(zhuǎn):https://www.cnblogs.com/shoemaker/p/linux_graphics02.html
1. Framebuffer
Framebuffer驅(qū)動(dòng)提供基本的顯示,framebuffer驅(qū)動(dòng)操作的硬件就是一個(gè)顯示控制器和幀緩存(一片位于系統(tǒng)主存或者顯卡顯存)。Framebuffer驅(qū)動(dòng)向應(yīng)用程序提供/dev/fbx的設(shè)備接口,應(yīng)用程序通過(guò)讀寫(xiě)這個(gè)設(shè)備節(jié)點(diǎn)實(shí)現(xiàn)對(duì)顯示控制器和幀緩存。
下面這個(gè)程序顯示了應(yīng)用程序操作操作framebuffer節(jié)點(diǎn)的過(guò)程。運(yùn)行這個(gè)程序,將在屏幕上方顯示一個(gè)正方形(這里省略了錯(cuò)誤檢查代碼)。
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <sys/mman.h>
5 #include <sys/ioctl.h>
6 #include <linux/fb.h>
7
8 int main ()
9 {
10 int fd;
11 struct fb_var_screeninfo vinfo;
12 struct fb_fix_screeninfo finfo;
13 size_t screensize = 0;
14 int location;
15 char *fbp = NULL, *ptr;
16 int x, y, x0, y0;
17 int i,j;
18 int ret;
19
20 fd = open("/dev/fb0", O_RDWR);
21 if (fd < 0){
22 fprintf(stderr, "error open fb0
");
23 return -1;
24 }
25 ret= ioctl(fd, FBIOGET_FSCREENINFO, &finfo ) ;
26 if (ret < 0) {
27 fprintf(stderr, "get fixed screen info error
");
28 return -1;
29 }
30 ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
31 if (ret < 0) {
32 fprintf(stderr, "get variable screen info error
");
33 return -1;
34 }
35 ret = ioctl(fd, FBIOPAN_DISPLAY,&vinfo);
36 if (ret < 0) {
37 fprintf(stderr, "pan display failed
");
38 return -1;
39 }
40 screensize=vinfo.xres * vinfo.yres * vinfo.bits_per_pixel /8 ;
41 fbp = (char *)mmap(NULL, screensize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
42 if (fbp == MAP_FAILED) {
43 fprintf(stderr, "mapped error
");
44 return -1;
45 }
46 x0 = 200;
47 y0 = 200;
48 ptr = fbp + y0 * finfo.line_length + x0 * vinfo.bits_per_pixel / 8;
49 for( i = 0; i < 100; i++){
50 char* tmp_ptr = ptr;
51 for(j = 0; j < 100; j++){
52 *tmp_ptr++ = 0;
53 *tmp_ptr++ = 255;
54 *tmp_ptr++ = 0;
55 *tmp_ptr++ = 0;
56 }
57 ptr += finfo.line_length;
58 }
59 munmap(fbp,screensize);
60 close(fd);
61 return 0;
62 }
應(yīng)用程序?qū)ramebuffer的操作主要是通過(guò)ioctl和mmap完成的。mmap將顯存映射到用戶空間。25行和30行分別獲取當(dāng)前framebuffer驅(qū)動(dòng)的“固定參數(shù)”和“可變參數(shù)”,這兩個(gè)參數(shù)包含了當(dāng)前顯示控制其的一些信息,可變參數(shù)主要是當(dāng)前分辨率信息,固定參數(shù)主要是當(dāng)前顯存的地址。35行FBIOPAN_DISPLAY通常用于雙緩存,但是這里使用還有其它意義,在后面討論drm的framebuffer的時(shí)候還會(huì)具體討論。41行將顯存映射出來(lái),51-59行操作這片顯存,往上繪制一個(gè)左上方坐標(biāo)為(200,200),邊長(zhǎng)為100的正方形。
應(yīng)用程序能夠使用這些ioctl是因?yàn)閮?nèi)核提供了相應(yīng)的接口,Linux內(nèi)核設(shè)備驅(qū)動(dòng)相關(guān)的書(shū)籍都會(huì)討論framebuffer驅(qū)動(dòng),這里不討論如何寫(xiě)一個(gè)framebuffer驅(qū)動(dòng)。
2. DRM驅(qū)動(dòng)
前一篇博文的圖4內(nèi)核里面是drm驅(qū)動(dòng),注意到和圖3的區(qū)別,單獨(dú)的FB driver已經(jīng)沒(méi)有了,而是被集合到了drm驅(qū)動(dòng)里面。在一些只要求進(jìn)行進(jìn)本顯示的嵌入式系統(tǒng)上,依然會(huì)使用單獨(dú)的framebuffer驅(qū)動(dòng),而對(duì)于內(nèi)核中有3D加速的AMD、intel等驅(qū)動(dòng),內(nèi)核里面和顯示有關(guān)的功能已經(jīng)集合到了drm驅(qū)動(dòng)里面。在AMD/intel顯卡+Xorg+3D這樣配置的開(kāi)源Linux系統(tǒng)上,Xorg并不使用,但是系統(tǒng)中仍然有/dev/fb0這樣的設(shè)備節(jié)點(diǎn),如果我們?cè)谧烂姝h(huán)境下“cat xxx >/dev/fb0”,系統(tǒng)不會(huì)有變化。然而如果將xorg.conf的Driver修改成“fbdev”,重啟Xorg,在執(zhí)行操作,能夠看到有變化(關(guān)于Xorg.conf可以參考"man xorg.conf",或者查看這個(gè)頁(yè)面)。或者切換到控制臺(tái)終端“Ctrl+Alt+Fn”,然后運(yùn)行同樣的命令,就能夠看到屏幕上的內(nèi)容發(fā)生了變化,在這篇博文的第一節(jié)的程序有一個(gè)FBIOPAN_DISPLAY調(diào)用,這個(gè)調(diào)用會(huì)使得顯卡的Crtc指向的顯存地址發(fā)生變化而將當(dāng)前的顯示區(qū)域切換到fb0設(shè)備節(jié)點(diǎn)對(duì)應(yīng)的區(qū)域,因此上面的程序運(yùn)行即使在X桌面環(huán)境下運(yùn)行,也能夠看到屏幕發(fā)生了變化。這提示我們?cè)诤送釾驅(qū)動(dòng)正常運(yùn)行的情況下,核外X驅(qū)動(dòng)并不使用framebuffer驅(qū)動(dòng)(實(shí)際上drm驅(qū)動(dòng)注冊(cè)的frambuffer設(shè)備只是給內(nèi)核使用),在X啟動(dòng)運(yùn)行后,不使用framebuffer 管理的那片內(nèi)存的內(nèi)容作為顯示輸出,而是使用了另外一片內(nèi)存。(但是:GPU處理完成的圖像數(shù)據(jù)輸出到frambuffer。見(jiàn):https://blog.csdn.net/esc_110/article/details/73300643)
當(dāng)前的Linux系統(tǒng)上內(nèi)核的顯卡驅(qū)動(dòng)稱(chēng)為drm驅(qū)動(dòng),在通常的linux內(nèi)核發(fā)行版上,我們使用lsmod命令查看內(nèi)核模塊,能夠看到類(lèi)似下面的信息:
radeon 933054 3
ttm 45600 1 radeon
drm_kms_helper 22468 1 radeon
drm 162230 5 radeon,ttm,drm_kms_helper
i2c_algo_bit 5055 2 i2c_gpio,radeon
機(jī)器使用的是AMD的radeon顯卡,上面顯示了當(dāng)前系統(tǒng)內(nèi)核和顯卡驅(qū)動(dòng)相關(guān)的模塊,drm模塊是內(nèi)核drm驅(qū)動(dòng)的基礎(chǔ)架構(gòu),所有drm顯卡驅(qū)動(dòng)都會(huì)加載這個(gè)內(nèi)核模塊,ttm是ttm內(nèi)核管理機(jī)制,drm_kms_helper是內(nèi)核模式的基礎(chǔ)框架代碼,i2c_algo_bit是顯卡上操作i2c設(shè)備使用的模塊,顯卡上的i2c設(shè)備主要包括了connector,encoder以及pll時(shí)鐘芯片。Drm內(nèi)核驅(qū)動(dòng)的代碼在內(nèi)核源碼目錄drivers/gpu/drm下面。加載了drm驅(qū)動(dòng)后,在/dev目錄下面會(huì)生成如下設(shè)備節(jié)點(diǎn):
/dev/char/226:0 -> ../dri/card0
/dev/char/226:64 -> ../dri/controlD64
/dev/dri/card0
/dev/dri/controlD64
其中/dev/dri/card0是操作gpu的接口,發(fā)送命令等操作都是通過(guò)對(duì)這個(gè)設(shè)備節(jié)點(diǎn)進(jìn)行的。/dev/dri/controlD64是kms相關(guān)的設(shè)備節(jié)點(diǎn)。
通常核外的驅(qū)動(dòng)程序使用ioctl調(diào)用同內(nèi)核進(jìn)行交互,linux系統(tǒng)上核外對(duì)drm的ioctl進(jìn)行了一層封裝,即libdrm,應(yīng)用程序通過(guò)libdrm調(diào)用操作硬件,關(guān)于drm的調(diào)用,這里有一些比較好的示例代碼https://github.com/dvdhrm/docs,這份代碼主要調(diào)用libdrm進(jìn)行模式設(shè)置,有詳細(xì)的注釋。
Linux下的圖形驅(qū)動(dòng)的主要部分是核外部分,核外部分包括了xorg exa驅(qū)動(dòng)以及mesa 3d 驅(qū)動(dòng),exa是傳統(tǒng)的2D加速框架,mesa 3d驅(qū)動(dòng)則是針對(duì)3D驅(qū)動(dòng)的硬件加速。由于歷史原因,在Fedora 16以及更早和稍后的系統(tǒng)上,即使現(xiàn)在硬件上不包含單獨(dú)的2D部件2D功能是由3D部件實(shí)現(xiàn)的,但是2D驅(qū)動(dòng)和3D仍然是分離的。
3. EXA驅(qū)動(dòng)
早期的2D加速驅(qū)動(dòng)使用的是XAA、KAA架構(gòu),但是隨著composite擴(kuò)展的加入,新的exa框架產(chǎn)生了,EXA刪除掉了原來(lái)2D驅(qū)動(dòng)中的三角形繪制、線繪制等一些現(xiàn)在沒(méi)什么用處的功能,取而代之的是三個(gè)加速功能:矩形填充(Solid)、拷屏操作(Copy/Blt)和混合操作(Composite)。
“XFree86 server 4.x Design (DRAFT)”文詳細(xì)介紹xorg驅(qū)動(dòng)需要提供的接口,EXA驅(qū)動(dòng)通過(guò)擴(kuò)展的形式添加并編譯到xorg驅(qū)動(dòng)中。在后續(xù)的blog文章里面將介紹exa驅(qū)動(dòng)接口,并使用radeon的exa驅(qū)動(dòng)來(lái)描述顯卡驅(qū)動(dòng)編程過(guò)程。
4. 3D驅(qū)動(dòng)
在linux環(huán)境中,我們可以通過(guò)glxinfo命令插卡3D硬件圖形加速是否可用。比如在radeon顯卡上glxinfo的輸出包含以下內(nèi)容:
OpenGL renderer string: Gallium 0.4 on AMD CEDAR
這里顯示使用AMD CEDAR核心的顯卡進(jìn)行opengl 3d加速,如果硬件加速不可用,則應(yīng)當(dāng)是“vmware on llvmpipe”這類(lèi)字眼。
開(kāi)源的OpenGL實(shí)現(xiàn)是mesa,mesa向上提供OpenGL接口,下層通過(guò)硬件的mesa驅(qū)動(dòng)和硬件交互。GLX是X協(xié)議的擴(kuò)展,用于OpenGL和X的交互(GLX規(guī)范)。在mesa源碼包中包含了大量的opengl示例程序,包括OpenGL紅寶書(shū)中的示例代碼、調(diào)用GLUT或者GLX接口的代碼、調(diào)用EGL的代碼等。
圖1
圖1顯示了一個(gè)3D應(yīng)用程序運(yùn)行的過(guò)程,OpenGL繪圖程序命令被用戶空間的mesa驅(qū)動(dòng)翻譯成對(duì)應(yīng)GPU的繪圖命令放入命令緩沖區(qū)中,其他的如頂點(diǎn)信息/紋理信息/索引信息放入到相應(yīng)緩沖中,mesa驅(qū)動(dòng)為每個(gè)應(yīng)用程序保存了當(dāng)前的繪圖狀態(tài),當(dāng)發(fā)生3D程序切換,當(dāng)前狀態(tài)被保存下來(lái),當(dāng)下次調(diào)度該程序運(yùn)行的時(shí)候,先恢復(fù)該程序的繪圖狀態(tài)到硬件上,然后繼續(xù)執(zhí)行命令緩存中的命令。當(dāng)用戶空間調(diào)用發(fā)送命令到內(nèi)核的時(shí)候,內(nèi)核驅(qū)動(dòng)對(duì)硬件進(jìn)行編程從該程序的命令緩沖區(qū)中取命令開(kāi)始執(zhí)行。這個(gè)過(guò)程是在dri框架下實(shí)現(xiàn)的,這里的所有繪制過(guò)程并不請(qǐng)求X,OpenGL直接將命令發(fā)送給硬件。GLX在初始化窗口,申請(qǐng)buffer和切換buffer的時(shí)候才會(huì)和X交互。
圖1來(lái)自文獻(xiàn)“Graphic Engine Resource Management”,這篇文章描述了對(duì)早期的內(nèi)核drm驅(qū)動(dòng)做的一些改進(jìn),在這篇碩士論文“A Fair-Share Scheduler for the GraphicsProcessing Unit”對(duì)一些問(wèn)題有更清楚的描述。
其他參考資料:
DRM and KMS kernel modules描述了drm驅(qū)動(dòng)和kms的一些細(xì)節(jié)。
總結(jié)
以上是生活随笔為你收集整理的Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 转 ABAP_ALV_Function
- 下一篇: 一、CE的安装