Android display架構分析(一)
http://hi.baidu.com/leowenj/blog/item/429c2dd6ac1480c851da4b95.html
高通7系列硬件架構分析
如上圖,高通7系列 Display的硬件部分主要由下面幾個(gè)部分組成:
A、MDP
高通MSM7200A內部模塊,主要負責顯示數據的轉換和部分圖像處理功能理,如YUV轉RGB,放大縮小、旋轉等。MDP內部的MDPDMA負責數據從DDR到MDDI Host的傳輸(可以完成RGB之間的轉換,如RGB565轉成RGB666,這個(gè)轉換工能載目前的code中沒(méi)有使用)。
B、MDDI
一種采用差分信號的高速的串行數據傳輸總線(xiàn),只負責數據傳輸,無(wú)其它功能;其中的MDDI Hosat提供并行數據和串行數據之間的轉換和緩沖功能。由于外面是VGA的屏幕,數據量較大,為了減少對EBI2總線(xiàn)的影響,傳輸總線(xiàn)使用MDDI,而非之前的EBI2。
C、MDDI Bridge
由于現在采用的外接LCD并不支持MDDI接口,故需要外加MDDI轉換器,即MDDIbridge,來(lái)把MDDI數據轉換成RGB接口數據。這里采用的EPSON MDDIBridge還有LCDController功能,可以完成其它一些數據處理的功能,如數據格式轉換、支持TV-OUT、PIP等;并且還可以提供一定數量的GPIO。目前我們主要用它把HOST端MDDI傳遞過(guò)來(lái)的顯示數據和控制數據(初始化配置等)轉換成并行的數據傳遞給LCD。
D、LCD module
主要是LCD Driver IC 和TFT Panel,負責把MDDI Bridge傳來(lái)的顯存中的圖像示在自己的 Panel上。
Android display架構分析(二)
http://hi.baidu.com/leowenj/blog/item/3fe59f740a6fee17b051b991.html
Android display SW架構分析
下面簡(jiǎn)單介紹一下上圖中的各個(gè)Layer:
*藍色部分-用戶(hù)空間應用程序
應用程序層,其中包括Android應用程序以及框架和系統運行庫,和底層相關(guān)的是系統運行庫,而其中和顯示相關(guān)的就是Android的Surface Manager, 它負責對顯示子系統的管理,并且為多個(gè)應用程序提 供了2D和3D圖層的無(wú)縫融合。
*黑色部分-HAL層,在2.2.1部分會(huì )有介紹
*紅色部分-Linux kernel層
Linuxkernel,其中和顯示部分相關(guān)的就是Linux的FrameBuffer,它是Linux系統中的顯示部分驅動(dòng)程序接口。Linux工作在保護模式下,User空間的應用程序無(wú)法直接調用顯卡的驅動(dòng)程序來(lái)直接畫(huà)屏,FrameBuffer機制模仿顯卡的功能,將顯卡硬件結構抽象掉,可以通過(guò)Framebuffer的讀寫(xiě)直接對顯存進(jìn)行操作。用戶(hù)可以將Framebuffer看成是顯示內存的一個(gè)映像,將其映射到進(jìn)程地址空間之后,就可以直接進(jìn)行讀寫(xiě)操作,而寫(xiě)操作可以立即反應在屏幕上。這種操作是抽象的,統一的。用戶(hù)不必關(guān)心物理顯存的位置、換頁(yè)機制等等具體細節。這些都是由Framebuffer設備驅動(dòng)來(lái)完成的。
*綠色部分-HW驅動(dòng)層
該部分可以看作高通顯卡的驅動(dòng)程序,和高通顯示部分硬件相關(guān)以及外圍LCD相關(guān)的驅動(dòng)都被定義在這邊,比如上述的顯卡的一些特性都是在這邊被初始化的,同樣MDP和MDDI相關(guān)的驅動(dòng)也都定義在這里
這里的User Space就是與應用程序相關(guān)的上層部分(參考上圖中的藍色部分),其中與Kernel空間交互的部分稱(chēng)之為HAL-HW Abstraction Layer。
HAL其實(shí)就是用戶(hù)空間的驅動(dòng)程序。如果想要將 Android 在某硬件平臺上執行,基本上完成這些驅動(dòng)程序就行了。其內定義了 Android 對各硬件裝置例如顯示芯片、聲音、數字相機、GPS、GSM 等等的需求。
HAL存在的幾個(gè)原因:
1、 并不是所有的硬件設備都有標準的linux kernel的接口。
2、 Kernel driver涉及到GPL的版權。某些設備制造商并不原因公開(kāi)硬件驅動(dòng),所以才去HAL方式繞過(guò)GPL。
3、 針對某些硬件,Android有一些特殊的需求。
在display部分,HAL的實(shí)現code在copybit.c中,應用程序直接操作這些接口即可,具體的接口如下:
struct copybit_context_t *ctx = malloc(sizeof(struct copybit_context_t));memset(ctx, 0, sizeof(*ctx));ctx->device.common.tag = HARDWARE_DEVICE_TAG;ctx->device.common.version = 0;ctx->device.common.module = module;ctx->device.common.close = close_copybit;ctx->device.set_parameter = set_parameter_copybit;//設置參數ctx->device.get = get;ctx->device.blit = blit_copybit;//傳送顯示數據ctx->device.stretch = stretch_copybit;ctx->mAlpha = MDP_ALPHA_NOP;ctx->mFlags = 0;ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);//打開(kāi)設備
這里的Kernel空間(與Display相關(guān))是Linux平臺下的FB設備(參考上圖中的紅色部分)。下面介紹一下FB設備。
Fb即FrameBuffer的簡(jiǎn)稱(chēng)。framebuffer是一種能夠提取圖形的硬件設備,是用戶(hù)進(jìn)入圖形界面很好的接口。有了framebuffer,用戶(hù)的應用程序不需要對底層驅動(dòng)有深入了解就能夠做出很好的圖形。對于用戶(hù)而言,它和/dev 下面的其他設備沒(méi)有什么區別,用戶(hù)可以把
framebuffer看成一塊內存,既可以向這塊內存中寫(xiě)入數據,也可以從這塊內存中讀取數據。它允許上層應用程序在圖形模式下直接對顯示緩沖區進(jìn)行讀寫(xiě)操作。這種操作是抽象的,統一的。用戶(hù)不必關(guān)心物理顯存的位置、換頁(yè)機制等等具體細節。這些都是由Framebuffer設備驅動(dòng)來(lái)完成的。
從用戶(hù)的角度看,幀緩沖設備和其他位于/dev下面的設備類(lèi)似,它是一個(gè)字符設備,通常主設備號是29,次設備號定義幀緩沖的個(gè)數。
在LINUX系統中,設備被當作文件來(lái)處理,所有的文件包括設備文件,Linux都提供了統一的操作函數接口。上面的結構體就是Linux為FB設備提供的操作函數接口。
1)、讀寫(xiě)(read/write)接口,即讀寫(xiě)屏幕緩沖區(應用程序不一定會(huì )調用該接口)
2)、映射(map)操作(用戶(hù)空間不能直接訪(fǎng)問(wèn)顯存物理空間,需map成虛擬地址后才可以)
由于Linux工作在保護模式,每個(gè)應用程序都有自己的虛擬地址空間,在應用程序中是不能直接訪(fǎng)問(wèn)物理緩沖區地址的。為此,Linux在文件操作file_operations結構中提供了mmap函數,可將文件的內容映射到用戶(hù)空間。對于幀緩沖設備,則可通過(guò)映射操作,可將屏幕緩沖區的物理地址映射到用戶(hù)空間的一段虛擬地址中,之后用戶(hù)就可以通過(guò)讀寫(xiě)這段虛擬地址訪(fǎng)問(wèn)屏幕緩沖區,在屏幕上繪圖了。實(shí)際上,使用幀緩沖設備的應用程序都是通過(guò)映射操作來(lái)顯示圖形的。由于映射操作都是由內核來(lái)完成,下面我們將看到,幀緩沖驅動(dòng)留給開(kāi)發(fā)人員的工作并不多
3)、I/O控制:對于幀緩沖設備,對設備文件的ioctl操作可讀取/設置顯示設備及屏幕的參數,如分辨率,顯示顏色數,屏幕大小等等。ioctl的操作是由底層的驅動(dòng)程序來(lái)完成
Note:上述部分請參考文件fbmem.c。
Android display架構分析(三)
http://hi.baidu.com/leowenj/blog/item/76411bf6237dc429bc31099f.html

如上圖所示,除了上層的圖形應用程序外,和Kernel空間有關(guān)的包括Linux FB設備層以及和具體HW相關(guān)的驅動(dòng)層,對應的源文件分別是fb_mem.c、msm_fb.c、mddi_toshiba.c。下面會(huì )一一介紹。
這個(gè)文件包含了Linux Fb設備的所有接口,主要函數接口和數據結構如下:
A、Fb設備的文件操作接口
B、3個(gè)重要的數據結構
FrameBuffer中有3個(gè)重要的結構體,fb.h中定義,如下:
1) 、frame_var_screeninfo
該結構體定義了顯卡的一些可變的特性,這些特性在程序運行期間可以由應用程序動(dòng)態(tài)改變,比較典型的如xrex和yres表示在顯示屏上顯示的真實(shí)分辨率、顯示的bit數等,該結構體user space可以訪(fǎng)問(wèn)。
2) 、frame_fix_screeninfo
該結構體定義了顯卡的一些固定的特性,這些特性在硬件初始化時(shí)就被定義了以后不可以更改。其中最重要的成員就是smem_len和smem_start,前者指示顯存的大?。壳俺绦蛑卸x的顯存大小為整屏數據RGB565大小的2倍),后者給出了顯存的物理地址。該結構體user space可以訪(fǎng)問(wèn)。
Note:smem_start是顯存的物理地址,應用程序是不可以直接訪(fǎng)問(wèn)的,必須通過(guò)fb_ops中的mmp函數映射成虛擬地址后,應用程序方可訪(fǎng)問(wèn)。
3) 、fb_info
FrameBuffer中最重要的結構體,它只能在內核空間內訪(fǎng)問(wèn)。內部定義了fb_ops結構體(包含一系列FrameBuffer的操作函數,Open/read/write、地址映射等).
C、其他
1)、一個(gè)重要的全局變量
struct fb_info *registered_fb[FB_MAX];
這變量記錄了所有fb_info 結構的實(shí)例,fb_info 結構描述顯卡的當前狀態(tài),所有設備對應的fb_info 結構都保存在這個(gè)數組中,當一個(gè)FrameBuffer設備驅動(dòng)向系統注冊自己時(shí),其對應的fb_info 結構就會(huì )添加到這個(gè)結構中,同時(shí)num_registered_fb 為自動(dòng)加1。
2)、注冊framebuffer函數
register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info);
這兩個(gè)是提供給下層FrameBuffer設備驅動(dòng)的接口,設備驅動(dòng)通過(guò)這兩函數向系統注冊或注銷(xiāo)自己。幾乎底層設備驅動(dòng)所要做的所有事情就是填充fb_info結構然后向系統注冊或注銷(xiāo)它
Android display架構分析(四)
http://hi.baidu.com/leowenj/blog/item/37e1a8521e35522842a75b99.html
該文件為高通顯卡的驅動(dòng)文件,比較重要的函數接口和數據結構如下:
A、高通msm fb設備的文件操作函數接口
static struct fb_ops msm_fb_ops = {
.owner = THIS_MODULE,
.fb_open = msm_fb_open,
.fb_release = msm_fb_release,
.fb_read = NULL,
.fb_write = NULL,
.fb_cursor = NULL,
.fb_check_var = msm_fb_check_var, /* 參數檢查 */
.fb_set_par = msm_fb_set_par, /* 設置顯示相關(guān)參數 */
.fb_setcolreg = NULL, /* set color register */
.fb_blank = NULL, /* blank display */
.fb_pan_display = msm_fb_pan_display, /* 顯示 */
.fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */
.fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */
.fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */
.fb_cursor = NULL,
.fb_rotate = NULL,
.fb_sync = NULL, /* wait for blit idle, optional */
.fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */
.fb_mmap = NULL,
};
B、高通msm fb的driver接口
static struct platform_driver msm_fb_driver = {
.probe = msm_fb_probe,//驅動(dòng)探測函數
.remove = msm_fb_remove,
#ifndef CONFIG_ANDROID_POWER
.suspend = msm_fb_suspend,
.suspend_late = NULL,
.resume_early = NULL,
.resume = msm_fb_resume,
#endif
.shutdown = NULL,
.driver = {
/* Driver name must match the device name added in platform.c. */
.name = "msm_fb",
},
};
C、msm_fb_init()
向系統注冊msm fb的driver,初始化時(shí)會(huì )調用
D、msm_fb_add_device
向系統中添加新的lcd設備,在mddi_toshiba.c中會(huì )被調用
該文件包含了所有和具體LCD(Toshiba)相關(guān)的信息和驅動(dòng),重點(diǎn)的數據結構和函數結構如下:
A、LCD設備相關(guān)信息
static struct platform_device this_device_0 = {p>
.name = "mddi_toshiba_vga",
.id = TOSHIBA_VGA_PRIM,
.dev = {
.platform_data = &toshiba_panel_data0,
}
};
其中toshiba_panel_data0包含了硬件LCD的控制函數,如開(kāi)關(guān)、初始化等等
B、LCD driver接口
static struct platform_driver this_driver = {
.probe = mddi_toshiba_lcd_probe,
.driver = {
.name = "mddi_toshiba_vga",
},
};
其中mddi_toshiba_lcd_probe中會(huì )調用msm_fb_add_device接口把具體LCD添加到系統中去。
C、mddi_toshiba_lcd_init
注冊LCD設備及driver到系統中去,同時(shí)也把LCD的固有信息(大小、格式、位率等)一并注冊到系統中去。
D、LCD相關(guān)控制函數
toshiba_common_initial_setup():初始化MDDI bridge
toshiba_prim_start():初始化LCD
本部分來(lái)看一下應用層以下,顯示數據的流程是怎樣的。
先來(lái)分析一下傳統的Linux平臺下FB設備是如果調用的,如下圖所示:
上層調用FB API(主要是fb_ioctl()),fb_ioctl()會(huì )調用具體顯卡的驅動(dòng),這里是高通的顯卡驅動(dòng),其實(shí)就是MDP DMA的驅動(dòng),通過(guò)MDP DMA把顯示數據經(jīng)MDDI接口送到外圍LCD組件。
Note:這里的MDP DMA并不對數據進(jìn)行任何處理(可以完成簡(jiǎn)單的格式轉換,如RGB565->RGB666)。
接下來(lái)再分析一下Android平臺下顯示數據是如何處理的,如下圖所示:
同樣上層也是調用FB API,不過(guò)這里其實(shí)把FB bypass了,相當于直接調用的是高通MDP PPP的驅動(dòng),然后數據經(jīng)PPP處理后再經(jīng)MDDI接口送出到外圍LCD組件。
Note:這里的MDP PPP可以完成很多顯示數據處理功能,如YUV->RGB、Scale、Rotate、Blending等。
Kernel部分display的初始化包含下面幾個(gè)步驟:
1)、在linux fb設備初始化時(shí)會(huì )向系統中注冊msm_fb_driver。Name為msm_fb。
msm_fb_init-> msm_fb_register_driver-> platform_driver_register(&msm_fb_driver)
其中的probe函數會(huì )對msm fb進(jìn)行初始化,分配顯存等(見(jiàn)msm_fb_probe函數)。
2)、在LCD模塊初始化時(shí)會(huì )先向系統中注冊驅動(dòng)(在mddi_toshiba_lcd_init函數中)
platform_driver_register(&this_driver);名字為mddi_toshiba_vga;
this_driver的probe函數為mddi_toshiba_lcd_probe,其內部會(huì )調用msm_fb_add_device向系統中添加MSM fb設備。
3)、調用platform_device_register(&this_device_0)向系統中注冊設備,名字為mddi_toshiba_vga,其中this_device_0包含了一些操作LCD的接口,如on/off。
Note:設備和driver的name需要一致才可以綁定;另外,如果某些設備不需要讓platform的總線(xiàn)來(lái)管理,那么只需要注冊驅動(dòng)即可,而無(wú)須向系統中注冊device,如msm_touch。
Android display架構分析(五)
http://hi.baidu.com/leowenj/blog/item/7a12ecb77067737f8ad4b266.html
Display接口介紹
在Android平臺下,應用程序面對的顯示部分的接口就是HAL,參考copybit.c,具體接口如下介紹:
open_copybit
初始化相關(guān)變量,并調用open("/dev/graphics/fb0", O_RDWR, 0);打開(kāi)fb設備。
set_parameter_copybit
設置各種操作參數,如rotate、alpha、dither等。
stretch_copybit
Copy一塊數據(Rectangle)到顯存,然后并命令msm_fb進(jìn)行顯示。
close_copybit
調用close(ctx->mFD);關(guān)閉fb設備。
Note:另外,應用程序在使用上面接口之前,需要調用mapFrameBuffer接口(EGLDisplaySurface.cpp),其功能如下:
1、 初始化顯示相關(guān)參數,并設置到底層。
2、 映射出顯存的虛擬地址。
Kernel部分顯示的接口全部都在fbmem.c中,這里詳細介紹一下:
fb_open
打開(kāi)Linux下fb設備。
fb_read/fb_write
讀寫(xiě)顯存中的數據
fb_ioctl
對顯示設備的命令操作。如get或set一些顯示參數、通知底層進(jìn)行刷屏等。
在典型應用中,畫(huà)屏的一般步驟如下:
1. 打開(kāi)/dev/fb設備文件。
2. 用ioctrl操作取得當前顯示屏幕的參數,如屏幕分辨率,每個(gè)像素點(diǎn)的比特數。根據屏幕參數可計算屏幕緩沖區的大小。
3. 將屏幕緩沖區映射到用戶(hù)空間。
4. 映射后就可以直接讀寫(xiě)屏幕緩沖區,進(jìn)行繪圖和圖片顯示了。
典型程序段如下:
#include
int main()
{
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
/*打開(kāi)設備文件*/
fbfd = open("/dev/fb0", O_RDWR);
/*取得屏幕相關(guān)參數*/
ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo); ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
/*計算屏幕緩沖區大小*/
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
/*映射屏幕緩沖區到用戶(hù)地址空間*/
fbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED, fbfd, 0);
/*下面可通過(guò)fbp指針讀寫(xiě)緩沖區*/
...
}
在不同應用程序中,上層的調用會(huì )有所不同,比如Andriod下會(huì )選擇應用程序跳過(guò)Linux fb操作層,直接操作顯卡驅動(dòng)層,稱(chēng)之為BLT accelerator。
下面看一下Android平臺下畫(huà)屏的操作流程。
1、 通過(guò)mapFrameBuffer直接把用戶(hù)空間的數據映射到顯存中。
2、 調用HAL中的stretch函數直接命令MSM設備提取顯存數據然后送入MDP PPP進(jìn)行處理并經(jīng)MDDI接口送到外圍LCD組件。
具體的函數調用流程如下:
copybit_open();//打開(kāi)BlitEngine,同時(shí)也打開(kāi)fb設備
mapFrameBuffer();//設置顯示參數,同時(shí)得到顯存虛擬地址
copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);//通知底層去刷屏
接下的流程是:
stretch_copybit-> msm_copybit->fb_ioctl()->msm_fb_ioctl(MSMFB_BLIT)-> msmfb_blit->mdp_blit-> mdp_ppp_blit->mdp_start_ppp->MDP&MDDI HWoperation
Android display架構分析(六)
http://hi.baidu.com/leowenj/blog/item/78c068dc443c961f48540361.html
Note:
本部分介紹的完全是用戶(hù)空間顯示部分的架構,與kernel并沒(méi)有直接的聯(lián)系,主要是JNI以下到HAL以上的部分。
Surface manager是用戶(hù)空間中framework下libraries中負責顯示相關(guān)的一個(gè)模塊。如下:
當系統同時(shí)執行多個(gè)應用程序時(shí),Surface Manager會(huì )負責管理顯示與存取操作間的互動(dòng),另外也負責將2D繪圖與3D繪圖進(jìn)行顯示上的合成。
surface manager 可以準備一塊 surface(可以看作一個(gè)layer),把 surface 的 fd (一塊內存) 傳給一個(gè) app,讓 app 可以在上面作畫(huà)。典型應用如下:
Android中的圖形系統采用Client/Server架構,如下:
Client端:應用程序相關(guān)部分。代碼分為兩部分,一部分是由Java提供的供應用使用的api,另一部分則是由c++寫(xiě)成的底層實(shí)現。
Server端:即SurfaceFlinger,負責合成并送入buffer顯示。其主要由c++代碼編寫(xiě)而成。
Client和Server之前通過(guò)Binder的IPC方式進(jìn)行通信,總體結構圖如下:
如上圖所示,Surface的client部分其實(shí)是提供給各應用程序進(jìn)行畫(huà)圖操作的一個(gè)橋梁,該橋梁通過(guò)binder通向server端的Surfaceflinger,Surfaceflinger負責合成各個(gè)surface,然后把buffer傳送到framebuffer端進(jìn)行底層顯示。其中每個(gè)surface對應2個(gè)buffer,一個(gè)front buffer, 一個(gè)back buffer,更新時(shí),數據更新在backbuffer上,需要顯示時(shí),則將back buffer和front buffer互換。
下一部分我們重點(diǎn)研究一下Surfaceflinger。
Android display架構分析(七-1)
http://hi.baidu.com/leowenj/blog/item/7abbe33a309367ff3b87ce6f.html
1、 Thread本身處理部分,包括初始化以及thread loop。
2、 Binder部分,負責接收上層應用的各個(gè)設置和命令,并反饋狀態(tài)標志給上層。
3、 與底層的交互,負責調用底層接口(HAL)。
結構圖如下:
注釋?zhuān)?/p>
a、 Binder接收到應用程序的命令(如創(chuàng )建surface、設置參數等),傳遞給flinger。
b、 Flinger完成對應命令后將相關(guān)結果狀態(tài)反饋給上層。
c、 在處理上層命令過(guò)程中,根據需要設置event(主要和顯示有關(guān)),通知Thread Loop進(jìn)行處理。
d、 Flinger根據上層命令通知底層進(jìn)行處理(主要是設置一些參數,Layer、position等)
e、 Thread Loop中進(jìn)行surface的合成并通知底層進(jìn)行顯示(Post buffer)。
f、 DisplayHardware層根據flinger命令調用HAL進(jìn)行HW的操作。
下面來(lái)具體分析一些SurfaceFlinger中重要的處理函數以及surface、Layer的屬性
1)、readToRun
SurfaceFlinger thread的初始化函數,主要任務(wù)是分配內存和設置底層接口(EGL&HAL)。
status_t SurfaceFlinger::readyToRun()
{
…
…
mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);//為IPC分配共享內存
…
mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);//為flinger分配heap,大小為8M,存放具體的顯示數據
{
// initialize the main display
GraphicPlane& plane(graphicPlane(dpy));
DisplayHardware* const hw = new DisplayHardware(this, dpy);
plane.setDisplayHardware(hw);//保存顯示接口
}
//獲取顯示相關(guān)參數
const GraphicPlane& plane(graphicPlane(dpy));
const DisplayHardware& hw = plane.displayHardware();
const uint32_t w = hw.getWidth();
const uint32_t h = hw.getHeight();
const uint32_t f = hw.getFormat();
…
…
// Initialize OpenGL|ES
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
…
…
}
2)、ThreadLoop
Surfaceflinger的loop函數,主要是等待其他接口發(fā)送的event,進(jìn)行顯示數據的合成以及顯示。
bool SurfaceFlinger::threadLoop()
{
waitForEvent();//等待其他接口的signal event
…
…
// post surfaces (if needed)
handlePageFlip();//處理翻頁(yè)機制
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw()))
{
// repaint the framebuffer (if needed)
handleRepaint();//合并所有layer并填充到buffer中去
…
…
postFramebuffer();//互換front buffer和back buffer,調用EGL接口進(jìn)行顯示
}
…
…
}
3)、createSurface
提供給應用程序的主要接口,該接口可以創(chuàng )建一個(gè)surface,底層會(huì )根據參數創(chuàng )建layer以及分配內存,surface相關(guān)參數會(huì )反饋給上層
sp SurfaceFlinger::createSurface(ClientID clientId, int pid,
ISurfaceFlingerClient::surface_data_t* params,
DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
…
…
int32_t id = c->generateId(pid);
if (uint32_t(id) >= NUM_LAYERS_MAX) //NUM_LAYERS_MAX=31
{
LOGE("createSurface() failed, generateId = %d", id);
return
}
…
layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);//創(chuàng )建layer,根據參數(寬高格式)分配內存(共2個(gè)buffer:front/back buffer)
if (layer)
{
setTransactionFlags(eTransactionNeeded);
surfaceHandle = layer->getSurface();//創(chuàng )建surface
if (surfaceHandle != 0)
surfaceHandle->getSurfaceData(params);//創(chuàng )建的surface參數反饋給應用層
}
}
待續。。。
Android display架構分析(七-2)
http://hi.baidu.com/leowenj/blog/item/ba4c5d6378a5da48eaf8f86a.html
4)、setClientState
處理上層的各個(gè)命令,并根據flag設置event通知Threadloop進(jìn)行處理
status_t SurfaceFlinger::setClientState(
ClientID cid,
int32_t count,
const layer_state_t* states)
{
Mutex::Autolock _l(mStateLock);
uint32_t flags = 0;
cid <<= 16;
for (int i=0 ; i
{
const layer_state_t& s = states[i];
LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
if (layer)
{
const uint32_t what = s.what;
// 檢測應用層是否設置各個(gè)標志,如果有則通知底層完成對應操作,并通知ThreadLoop做對應的處理
if (what & eDestroyed) //刪除該層Layer
{
if (removeLayer_l(layer) == NO_ERROR)
{
flags |= eTransactionNeeded;
continue;
}
}
if (what & ePositionChanged) //顯示位置變化
{
if (layer->setPosition(s.x, s.y))
flags |= eTraversalNeeded;
}
if (what & eLayerChanged) //Layer改變
{
if (layer->setLayer(s.z))
{
mCurrentState.layersSortedByZ.reorder(
layer, &Layer::compareCurrentStateZ);
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
if (what & eSizeChanged)
{
if (layer->setSize(s.w, s.h))//設置寬高變化
flags |= eTraversalNeeded;
}
if (what & eAlphaChanged) {//設置Alpha效果
if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
flags |= eTraversalNeeded;
}
if (what & eMatrixChanged) {//矩陣參數變化
if (layer->setMatrix(s.matrix))
flags |= eTraversalNeeded;
}
if (what & eTransparentRegionChanged) {//顯示區域變化
if (layer->setTransparentRegionHint(s.transparentRegion))
flags |= eTraversalNeeded;
}
if (what & eVisibilityChanged) {//是否顯示
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
}
}
if (flags)
{
setTransactionFlags(flags);//通過(guò)signal通知ThreadLoop
}
return NO_ERROR;
}
5)、composeSurfaces
該接口在Threadloop中被調用,負責將所有存在的surface進(jìn)行合并,OpenGl模塊負責這個(gè)部分。
6)、postFramebuffer
該接口在Threadloop中被調用,負責將合成好的數據(存于back buffer中)推入在front buffer中,然后調用HAL接口命令底層顯示。
7)、從3中可知,上層每創(chuàng )建一個(gè)surface的時(shí)候,底層都會(huì )同時(shí)創(chuàng )建一個(gè)layer,下面看一下surface及l(fā)ayer的相關(guān)屬性。
Note:code中相關(guān)結構體太大,就不全部羅列出來(lái)了
A、Surface相關(guān)屬性(詳細參考文件surface.h)
a1:SurfaceID:根據此ID把相關(guān)surface和layer對應起來(lái)
a2:SurfaceInfo
包括寬高格式等信息
a3:2個(gè)buffer指針、buffer索引等信息
B、Layer相關(guān)屬性(詳細參考文件layer.h/layerbase.h/layerbitmap.h)
包括Layer的ID、寬高、位置、layer、alpha指、前后buffer地址及索引、layer的狀態(tài)信息(如eFlipRequested、eBusy、eLocked等)
Android display架構分析(八)
http://hi.baidu.com/leowenj/blog/item/03aae36137acb8d1e6113a75.html
參考上面linux下fb設備的軟件架構,可以知道,要加入一個(gè)新的MDDI接口的LCM,Driver的工作就是要提供自己的mddi_xxxx.c(在這次porting的過(guò)程中,為了節省時(shí)間,我們直接修改了mddi_toshiba.c),并且完成和這個(gè)lcd相關(guān)的HWr的初始化。主要的工作包括:
A、初始化和LCD / LCD背光相關(guān)的IO以及電源;
B、編寫(xiě)初始化函數 。主要是初始化LCD控制器,這個(gè)一般LCD廠(chǎng)商會(huì )提供;然后分配顯存,這個(gè)高通release過(guò)來(lái)的code已經(jīng)包含這個(gè)動(dòng)作了,最后是初始化一個(gè)fb_info的結構體,在這里主要是把LCD的一些信息登記進(jìn)來(lái)。
C、把LCD的設備以及驅動(dòng)注冊到系統中去。(這里因為是替換現有的驅動(dòng),所以相關(guān)修改的部分不多。)
上述B、C部分代碼請參考kernel\drivers\video\msm\mddi_toshiba.c。
更改一些GPIO的配置以及一些電源的電平配置;然后通過(guò)實(shí)際測量,確保一下信號正常:
A、供給LCD以及MDDI Bridge的電源;
B、MDDI Bridge以及LCD reset信號;
C、控制背光IC的GPIO工作正常(背光不打開(kāi),無(wú)法調試LCD)。
LCD init的code以及外圍MDDI Bridge的初始化code,都可以之前Boston WindowsMobile系統的codebase中獲得;把這部分code移植到mddi_Toshiba.c中,并更改相應的圖像格式、分辨率等配置,編譯通過(guò)。LCD初始化部分就算基本完成。
由于硬件在之前Boston load是可以工作的,可以認為硬件連接等沒(méi)有問(wèn)題,所以只需關(guān)注軟件部分就行。
Display部分軟件調試過(guò)程如下:
A、 開(kāi)機后,量一下GPIO是否為code中配置預期的狀態(tài)(可確保code中的
GPIO接口工作正常);
B、 量一下各個(gè)電源是否都處于Code中定義的電平值。這些都OK后,背光
是會(huì )亮的(背光的控制比較簡(jiǎn)單,一個(gè)GPIO即可);
C、 這個(gè)時(shí)候如果LCD以及MDDI Bridge有被正常初始化的話(huà),屏幕上是會(huì )
看出來(lái)的。反之,如果屏幕沒(méi)有顯示,需要用JTAG跟一下mddi_Toshiba.c中的初始化函數是否在開(kāi)機的時(shí)候有被調用過(guò)。
目前版本中,是根據外圍MDDIBridge中讀到的的廠(chǎng)商號來(lái)決定加載哪個(gè)驅動(dòng)模塊的。在本次調試中,bootloader中可以正確讀到廠(chǎng)商號,所以bootloader中對于LCD的初始化是有做的,所以屏幕看到的狀態(tài)就是LCD初始化后的樣子(花屏)。但Kernel起來(lái)后,并沒(méi)有其他顯示,用JTAG跟了后發(fā)現,Kernel中MODULEINIT中讀不到正確的廠(chǎng)商號,所以說(shuō)后面的driver沒(méi)有被加載。接著(zhù)發(fā)現如果在bootloader中如果不做MDDIBridge的初始化,的話(huà)后面的MODULE INIT就可正常運行,該問(wèn)題目前還沒(méi)有澄清(現在暫時(shí)先把bootloader中的initdisable掉)。
初始化正常后,屏幕會(huì )顯示UI的相關(guān)畫(huà)面,但明顯顏色、位置都不對。
這個(gè)可能是數據類(lèi)型配置不對導致的,即MDP輸出的類(lèi)型、MDDI配置的類(lèi)型以、LCD接收的類(lèi)型不匹配導致,也有可能是RGB的順序不對導致(可配置成BGR)。經(jīng)過(guò)調試后,把MDP端輸出的格式配置成RGB565,同時(shí)外圍MDDIBridge以及LCD的input格式也配置成RGB565,這時(shí)顯示色彩正常了。
如果位置或者方向不對,比如說(shuō)上下或是左右顛倒,可以更改LCD的配置中的掃描方向即可。
后續發(fā)現一個(gè)問(wèn)題,播放video的時(shí)候顏色都是黑白的。
這個(gè)問(wèn)題很容易讓人誤解,按照正常的理解,videodecode出來(lái)的數據為YCbCr,Y為亮度信號,CbCr為色差信號,如果只有Y信號的話(huà)顏色應該就是黑白的。所以有2個(gè)懷疑點(diǎn),一個(gè)是decode出來(lái)的數據有誤,另一個(gè)是MDDIBridge誤把輸入的YcbCr信號當作RGB信號進(jìn)行出來(lái),這個(gè)也是有可能的。但很快第二個(gè)懷疑點(diǎn)被排除了(因為單更改MDDIinput格式后還是不能解決問(wèn)題)。
后來(lái)又詳細的看了顯示部分的代碼,并用JTAG追蹤video播放的時(shí)候用的顯示接口,發(fā)現目前所有的顯示接口輸出的格式都是RGB格式,也就是說(shuō)在通過(guò)MDP之前YcbCr已經(jīng)被轉化過(guò);而MDP里的轉換功能并沒(méi)有使用,MDP只是被當作一個(gè)DMA完成數據的直接傳輸,文檔中叫做Bypasse。
YcbCr到RGB的轉換是由Android的lib來(lái)完成。發(fā)了個(gè)SR給高通,高通的回復也確認了,在6.3.50中,Android上層缺少這個(gè)lib(copybit.default.so),6.3.60之后的版本經(jīng)解決了這個(gè)問(wèn)題。
高通Android平臺下關(guān)于display部分的幾個(gè)關(guān)鍵問(wèn)題
http://hi.baidu.com/leowenj/blog/item/06f8c0000763b37a3812bb03.html
顯示部分的幾個(gè)問(wèn)題這幾天通過(guò)實(shí)際測試澄清了一下,主要是下圖中各個(gè)模塊的使用狀況以及HAL層幾個(gè)模塊的調用流程。以問(wèn)題的方式描述如下:
1、 Ap是怎么進(jìn)行顯示的?
Surfaceflinger負責所有上層的顯示處理,對于A(yíng)P(2D或是3D的應用程序)而言,只要到surfaceflinger中創(chuàng )建surface,設置好參數,接下來(lái)都是統一交給surfaceflinger進(jìn)行處理
2、 Surface是怎么管理多個(gè)surface的?
不管有多少個(gè)surface,最終送到顯示部分的只能是屏幕大小數據,surfaceflinger中利用MDP或是GPU進(jìn)行多個(gè)surface的合成處理,普通的合成MDP就可完成,但如果是復雜的比如3D的應用等就必須使用GPU,最終合成的好數據會(huì )被送到framebuffer中。
3、 Framebuffer是什么?
Framebuffer是Linux中為顯示數據分配的一塊顯存(fb設備中),通常大小是一整個(gè)屏幕數據的兩倍,對于上層AP而言,只需要將要顯示的數據丟到framebuffer中就OK了,但此時(shí)顯示數據并未真正的被送到LCD上,而是暫存在framebuffer中而已。
4、 上層是通過(guò)什么方式將顯示內容送到framebuffer的?
有2個(gè)方式(二選一,不會(huì )同時(shí)在運行):
A、 普通的顯示,使用copybit(MDP)(未使用GPU)
Surfaceflinger通過(guò)copybit將要顯示的數據送到framebuffer。
Note:copybit可以看做是MDP PPP的接口,它提供了MDP的功能,如多個(gè)layer合成,scale、rotate等。
其接口在:android\hardware\msm7k\libcopybit\copybit.cpp
B、 使用GPU(即使用圖中的Graphics driver)
當進(jìn)行復雜的顯示處理時(shí),比如3D的應用,GPU把處理好的數據直接丟到framebuffer中,和MDP沒(méi)有任何關(guān)系
5、 Framebuffer中的數據是如何被送到LCD顯示的?
圖中的Gralloc完成的。
Gralloc有2個(gè)功能:
一個(gè)是和copybit相同的,里面有MDP PPP的接口(目前沒(méi)有使用)
另一個(gè)則是刷屏(整屏刷)的接口,即將framebuffer中的數據送到lcd上,調用的是MDP DMA的接口
這部分的code在android\hardware\msm7k\libgralloc-qsd8k目錄下,之前沒(méi)有留意,以為沒(méi)有使用?,F在可以看出開(kāi)機初始化后就創(chuàng )建了disp_loop thread,里面的操作就是調用系統接口
ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info)
將數據送到lcd
Note:送數據的時(shí)候是2個(gè)buffer切換的
另外,上層surfaceflinger也是通過(guò)Gralloc中的接口獲知屏幕的大小,調用接口為
ioctl(fd, FBIOGET_VSCREENINFO, &info),info中的屏幕寬高對應的就是底層driver設置的寬高值
6、 OpenGL是什么?
它是一個(gè)圖像處理引擎,當需要一些復雜的顯示(2D/3D)操作時(shí)會(huì )用到它。它分為SW方案和HW方案,軟件方案就是圖中的libagl.so,對應到目前項目中是libGLES_android.so,它可以完成簡(jiǎn)單的2D(文字,icon等)處理,通過(guò)trace看目前大部分顯示操作都是它來(lái)完成的。
Note:它是軟件方案,處理好的數據是通過(guò)copybit送到framebuffer的,而不是GPU。
其接口部分參考:android\frameworks\base\opengl\libagl
HW方案就是圖中的Graphics driver,它通過(guò)使用GPU硬件來(lái)完成圖像處理,處理后的數據直接送到framebuffer中。其接口部分參考:android\frameworks\base\opengl\libs(有幾個(gè)版本)
7、 OpenGL在項目中是如何配置的?
在android\vendor\qcom\msm7627_ffa目錄下有一個(gè)egl.cfg文件,里面指定了當前版本中的OpenGL信息,目前如下:
0 0 android
0 1 adreno200
第一行代表該codebase支持SW 方案的OpenGL,是android default的
第二行代表該codebase也支持HW方案的OpenGL,是高通的adreno引擎
如果該cfg文件為空,則只支持default的SW方案。
如果2個(gè)方案都在,上層將根據實(shí)際應用自行選擇使用其一。
該部分請參考:android\frameworks\base\opengl\libs\EGL\loader.cpp
聯(lián)系客服