Linux的幀緩沖設備

Linux的幀緩沖設備

幀緩沖(framebuffer)是 Linux 為顯示設備提供的一個接口,把顯存抽象后的一種設備,他允許上層應用程序在圖形模式下直接對顯示緩沖區進行讀寫操作。這種操作是抽象的,統一的。用戶不必關心物理顯存的位置、換頁機制等等具體細節。這些都是由Framebuffer 設備驅動來完成的。幀緩沖驅動的應用廣泛,在 linux 的桌面系統中,Xwindow 服務器就是利用幀緩沖進行窗口的繪制。尤其是通過幀緩沖可顯示漢字點陣,成為 Linux漢化的唯一可行方案。

幀緩沖設備對應的設備文件為/dev/fb*,如果系統有多個顯示卡,Linux 下還可支持多個幀緩沖設備,最多可達 32個,分別為/dev/fb0 到/dev/fb31,而/dev/fb 則為當前缺省的幀緩沖設備,通常指向/dev/fb0。當然在嵌入式系統中支持一個顯示設備就夠了。幀緩沖設備為標準字符設備,主設備號為29,次設備號則從0到31。分別對應/dev/fb0-/dev/fb31。

通過/dev/fb,應用程序的操作主要有這幾種:

1.讀/寫(read/write)/dev/fb:相當于讀/寫屏幕緩沖區。例如用 cp /dev/fb0 tmp 命令可將當前屏幕的內容拷貝到一個文件中,而命令 cp tmp > /dev/fb0 則將圖形文件tmp顯示在屏幕上。

2.映射(map)操作:由于 Linux 工作在保護模式,每個應用程序都有自己的虛擬地址空間,在應用程序中是不能直接訪問物理緩沖區地址的。為此,Linux 在文件操作 file_operations 結構中提供了 mmap 函數,可將文件的內容映射到用戶空間。對于幀緩沖設備,則可通過映射操作,可將屏幕緩沖區的物理地址映射到用戶空間的一段虛擬地址中,之后用戶就可以通過讀寫這段虛擬地址訪問屏幕緩沖區,在屏幕上繪圖了。

3.I/O控制:對于幀緩沖設備,對設備文件的 ioctl操作可讀取/設置顯示設備及屏幕的參數,如分辨率,顯示顏色數,屏幕大小等等。ioctl 的操作是由底層的驅動程序來完成的。


在應用程序中,操作/dev/fb的一般步驟如下:

1.打開/dev/fb設備文件。

2.用 ioctrl 操作取得當前顯示屏幕的參數,如屏幕分辨率,每個像素點的比特數。根據屏幕參數可計算屏幕緩沖

區的大小。

3.將屏幕緩沖區映射到用戶空間(mmap)。

4.映射后就可以直接讀寫屏幕緩沖區,進行繪圖和圖片顯示了。

典型程序段如下:

------------------------

#include <linux/fb.h>
int main()
{  int fbfd = 0;struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;long int screensize = 0;/*打開設備文件*/fbfd = open("/dev/fb0", O_RDWR);/*取得屏幕相關參數*/ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo);  ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);/*計算屏幕緩沖區大小*/screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;/*映射屏幕緩沖區到用戶地址空間*/fbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED, fbfd, 0);/*下面可通過 fbp指針讀寫緩沖區*/……/*釋放緩沖區,關閉設備*/munmap(fbp, screensize);close(fbfd);
}

-----------------------

ioctl操作

ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)

獲取fb_var_screeninfo結構的信息,在linux/include/linux/fb.h定義。

ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)

獲取fb_fix_screeninfon結構的信息。在linux/include/linux/fb.h定義。

fbfd為設備文件號。

-----------------------
mmap函數

功能描述:

mmap函數是unix/linux下的系統調用

mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。munmap執行相反的操作,刪除特定地址區域的對象映射。

基于文件的映射,在mmap和munmap執行過程的任何時刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情況下沒有得到更新,首次對映射區的第一個頁索引時會更新該字段的值。用PROT_WRITE 和 MAP_SHARED標志建立起來的文件映射,其st_ctime 和 st_mtime在對映射區寫入之后,但在msync()通過MS_SYNC 和 MS_ASYNC兩個標志調用之前會被更新。

用法:

#include <sys/mman.h>

void *mmap(void *start, size_t length, int prot, int flags,

int fd, off_t offset);

int munmap(void *start, size_t length);

參數:

start:映射區的開始地址。

length:映射區的長度。

prot:期望的內存保護標志,不能與文件的打開模式沖突。是以下的某個值,可以通過or運算合理地組合在一起

PROT_EXEC //頁內容可以被執行

PROT_READ //頁內容可以被讀取

PROT_WRITE //頁可以被寫入

PROT_NONE //頁不可訪問

flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體

MAP_FIXED //使用指定的映射起始地址,如果由start和len參數指定的內存區重疊于現存的映射空間,重疊部分將會被丟棄。如果指定的起始地址不可用,操作將會失敗。并且起始地址必須落在頁的邊界上。

MAP_SHARED //與其它所有映射這個對象的進程共享映射空間。對共享區的寫入,相當于輸出到文件。直到msync()或者munmap()被調用,文件實際上不會被更新。

MAP_PRIVATE //建立一個寫入時拷貝的私有映射。內存區域的寫入不會影響到原文件。這個標志和以上標志是互斥的,只能使用其中一個。

MAP_DENYWRITE //這個標志被忽略。

MAP_EXECUTABLE //同上

MAP_NORESERVE //不要為這個映射保留交換空間。當交換空間被保留,對映射區修改的可能會得到保證。當交換空間不被保留,同時內存不足,對映射區的修改會引起段違例信號。

MAP_LOCKED //鎖定映射區的頁面,從而防止頁面被交換出內存。

MAP_GROWSDOWN //用于堆棧,告訴內核VM系統,映射區可以向下擴展。

MAP_ANONYMOUS //匿名映射,映射區不與任何文件關聯。

MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用。

MAP_FILE //兼容標志,被忽略。

MAP_32BIT //將映射區放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略。當前這個標志只在x86-64平臺上得到支持。

MAP_POPULATE //為文件映射通過預讀的方式準備好頁表。隨后對映射區的訪問不會被頁違例阻塞。

MAP_NONBLOCK //僅和MAP_POPULATE一起使用時才有意義。不執行預讀,只為已存在于內存中的頁面建立頁表入口。

fd:有效的文件描述詞。如果MAP_ANONYMOUS被設定,為了兼容問題,其值應為-1。

offset:被映射對象內容的起點。

返回說明:

成功執行時,mmap()返回被映射區的指針,munmap()返回0。

失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設為以下的某個值

EACCES:訪問出錯

EAGAIN:文件已被鎖定,或者太多的內存已被鎖定

EBADF:fd不是有效的文件描述詞

EINVAL:一個或者多個參數無效

ENFILE:已達到系統對打開文件的限制

ENODEV:指定文件所在的文件系統不支持內存映射

ENOMEM:內存不足,或者進程已超出最大內存映射數量

EPERM:權能不足,操作不允許

ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志

SIGSEGV:試著向只讀區寫入

SIGBUS:試著訪問不屬于進程的內存區

------------------------

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384539.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384539.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384539.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux下沒有包含頭文件(不知是哪個)導致編譯無法通過的解決心得

最近寫程序的時候編譯出錯了&#xff0c;提示信息為&#xff1a;invalid use of undefined type fb_var_screeninfo。顯示根據英文知道是沒有定義 fb_var_screeninfo這個類型&#xff0c;明顯是缺少了某個頭文件&#xff0c;但是缺少哪個頭文件以及有什么又快又好的解決方法呢&…

gcc編譯缺少數學庫

Linux下編譯出現以下提示可以在編譯的后面加上-lm&#xff0c;例如&#xff0c;arm-none-linux-gnueabi-gcc -o example1 example1.c -lm&#xff0c;意思就是添加數學庫的意思&#xff0c;編譯就能通過了 example1.c:(.text0x3e8): undefined reference to cos example1.c:(.…

Linux編譯程序時加-I指定頭文件位置

Linux下編譯出現以下錯誤&#xff0c;錯誤的原因是在/usr/local/arm/arm-2009q3/bin/../arm-none-linux-gnueabi/libc/usr/include/freetype/config/下找不到ftheader.h&#xff0c;而我到該目錄下看&#xff0c;發現路徑是這樣的rootubuntu:/usr/local/arm/arm-2009q3/arm-non…

樹莓派遠程監控的實現

原文&#xff1a;https://blog.csdn.net/ayz123456/article/details/79252923 http://shumeipai.nxez.com/2016/09/01/raspberry-pi-motion-cameras-for-remote-monitoring.html https://blog.csdn.net/wto882dim/article/details/82195001 https://blog.csdn.net/qq_3950082…

公網訪問樹莓派

公網訪問樹莓派控制小車 上篇已經介紹了小車在局域網中的控制方法&#xff0c;比較簡單&#xff0c;既然是遠程遙控那就要能夠進行公網訪問&#xff0c;使得你的小車可以在任何有網絡的地方都能訪問到&#xff0c;并且后續還會加上攝像頭&#xff0c;進行實時監控&#xff0c;想…

關于對象的引用作為參數,可以直接訪問私有成員的問題

#include using namespace std; class CPoint { public:CPoint(int xx, int yy){x xx;y yy;}CPoint(const CPoint &p){x p.x;y p.y;} private:int x, y; };首先&#xff0c;我們來看一個例子&#xff0c;在CPoint這個類中定義了兩個構造函數&#xff0c;第一個為普通的…

僵死進程的產生以及解決辦法

本文參考自&#xff1a;https://baike.baidu.com/item/%E5%83%B5%E5%B0%B8%E8%BF%9B%E7%A8%8B/1036577?fraladdin 一個進程在調用exit命令結束自己的生命的時候&#xff0c;其實它并沒有真正的被銷毀&#xff0c;而是留下一個稱為僵尸進程&#xff08;Zombie&#xff09;的數據…

樹莓派第一次開機自動連接WIFI(不用顯示屏方法)

當我們把樹莓派系統鏡像燒錄到SD卡之后&#xff0c;我們在windows看到的TF卡變成了空間很小的名為boot的盤&#xff0c;我們在此目錄下新建一個名為wpa_supplicant.conf空白文件&#xff0c;并在其中加入以下代碼: countryGB ctrl_interfaceDIR/var/run/wpa_supplicant GROUPn…

樹莓派設置靜態IP的好處與壞處

網上后很多資源教初學者如何設置靜態IP&#xff0c;但我覺得設置靜態IP也有不好的地方&#xff1a; 首先&#xff0c;好處就是樹莓派的IP不會變&#xff0c;例如你設置了無線連接方式的靜態IP為192.168.1.110&#xff0c;那么無論你連接哪個路由器&#xff0c;或者連接同一個路…

關于源文件用不同的編碼方式編寫,會導致執行結果不一樣的現象及解決方法

如果我們編寫以下程序&#xff0c;并分別另存為ANSI和UTF-8兩種不同的編碼方式保存&#xff0c;放到Linux下編譯并運行如下圖&#xff0c;兩端相同的程序以不同的編碼方式保存編譯后的運行結果不一樣&#xff0c;./ansi采用ANSI編碼方式&#xff0c;會自動采用GBK方式來保存中文…

引入寬字符error: converting to execution character set: Invalid or incomplete multibyte or wide character

版權聲明&#xff1a;本文為博主原創文章&#xff0c;遵循 CC 4.0 by-sa 版權協議&#xff0c;轉載請附上原文出處鏈接和本聲明。 本文鏈接&#xff1a;https://blog.csdn.net/qq_26093511/article/details/60593240 交叉編譯.c文件&#xff0c;遇到如下問題 arm-linux-gcc -o…

linux交叉編譯時報錯:file not recognized: File format not recognized

版權聲明&#xff1a;本文為博主原創文章&#xff0c;遵循 CC 4.0 by-sa 版權協議&#xff0c;轉載請附上原文出處鏈接和本聲明。 本文鏈接&#xff1a;https://blog.csdn.net/u011113596/article/details/80325081 今天交叉編譯sqlite3&#xff0c;make的時候報錯&#xff1a;…

arm-linux-gcc靜態編譯和動態編譯的區別

很多教程會提到加上-static是靜態編譯&#xff0c;但對于新手來說沒有用例子來說明可能不太好理解&#xff0c;今天我就介紹一下關于這方面知識的一個例子&#xff1a; 最近在做一個關于freetype字體的東西&#xff0c;需要依賴freetype官方提供的庫&#xff0c;我已經把電腦這…

從0到1寫RT-Thread內核——線程定義及切換的實現

從0寫RT-Thread內核之線程定義及切換的實現具體可以分為以下六步來實現 一&#xff1a;分別定義線程棧、線程函數、線程控制塊&#xff1b; ALIGN(RT_ALIGN_SIZE)//設置4字節對齊 /* 定義線程棧 */ rt_uint8_t rt_flag1_thread_stack[512]; rt_uint8_t rt_flag2_thread_stack…

從0到1寫RT-Thread內核——臨界段的保護

臨界段就是一段在執行的時候不能被中斷的代碼段&#xff0c;在RT-Thread里&#xff0c;臨界段最常出現的就是對全局變量的操作&#xff08;類似Linux下的鎖&#xff09;。RT-Thread對臨界段的保護是直接把中斷全部關了&#xff0c;NMI FAULT和硬FAULT除外。下圖是3個關于中斷屏…

從0到1寫RT-Thread內核——空閑線程與阻塞延時的實現

在之前寫的另外一篇文章——<從0到1寫RT-Thread內核——線程定義及切換的實現>中線程體內的延時使用的是軟件延時&#xff0c;即還是讓CPU空等來達到延時的效果。RTOS中的延時叫阻塞延時&#xff0c;即線程需要延時的時候&#xff0c;線程會放棄CPU的使用權&#xff0c;C…

從0到1寫RT-Thread內核——支持多優先級

在本章之前&#xff0c;RT-Thread還沒有支持多優先級&#xff0c;我們手動指定了第一個運行的線程&#xff0c;并在此之后三個線程&#xff08;包括空閑線程&#xff09;互相切換&#xff0c;在本章中我們加入優先級的功能&#xff0c;第一個運行的程序是就緒列表里優先級最高的…

Linux串口阻塞與非阻塞

Linux串口編程的阻塞與否可以在open函數中設置&#xff0c;例如&#xff1a; 打開時使用&#xff1a; fd open(USAR1, O_RDWR | O_NOCTTY );//阻塞式讀寫fd open("/dev/ttyAT2",O_RDWR|O_NOCTTY|O_NDELAY); //非阻塞讀寫 除了用open函數之外還可以在open函數之…

vi中如何實現批量替換

將文件tihuan&#xff08;假設此文本中字符a&#xff09;中的所有字符a換成字符w&#xff0c;其命令為&#xff1a; 1。vi tihuan 2。按esc鍵 3。按shift&#xff1a; 4。在&#xff1a;后輸入 %s/a/w/g 其中s為&#xff1a;substitute&#xff0c;%表示所有行&#xff0c;…