Qualcomm Android display架構分析

Android display架構分析(一)html

http://blog.csdn.net/BonderWu/archive/2010/08/12/5805961.aspx

 

http://hi.baidu.com/leowenj/blog/item/429c2dd6ac1480c851da4b95.htmllinux

高通7系列硬件架構分析android

1

如上圖,高通7系列 Display的硬件部分主要由下面幾個部分組成:c++

A、MDPapi

高通MSM7200A內部模塊,主要負責顯示數據的轉換和部分圖像處理功能理,如YUV轉RGB,放大縮小、旋轉等。MDP內部的MDP DMA負責數據從DDR到MDDI Host的傳輸(能夠完成RGB之間的轉換,如RGB565轉成RGB666,這個轉換工能載目前的code 中沒有使用)。數組

B、MDDI數據結構

一種採用差分信號的高速的串行數據傳輸總線,只負責數據傳輸,無其它功能;其中的MDDI Hosat提供並行數據和串行數據之間的轉換和緩衝功能。因爲外面是VGA的屏幕,數據量較大,爲了減小對EBI2總線的影響,傳輸總線使用MDDI,而非以前的EBI2。架構

C、MDDI Bridgeapp

因爲如今採用的外接LCD並不支持MDDI接口,故須要外加MDDI轉換器,即MDDI bridge,來把MDDI數據轉換成RGB接口數據。這裏採用的EPSON MDDIBridge還有LCD Controller功能,能夠完成其它一些數據處理的功能,如數據格式轉換、支持TV-OUT、PIP等;而且還能夠提供必定數量的GPIO。目前咱們主要用它把HOST端MDDI傳遞過來的顯示數據和控制數據(初始化配置等)轉換成並行的數據傳遞給LCD。框架

D、LCD module

主要是LCD Driver IC 和TFT Panel,負責把MDDI Bridge傳來的顯存中的圖像示在本身的 Panel上。

Android display架構分析(二)

http://hi.baidu.com/leowenj/blog/item/3fe59f740a6fee17b051b991.html

Android display SW架構分析

2

3

下面簡單介紹一下上圖中的各個Layer:

*藍色部分-用戶空間應用程序

應用程序層,其中包括Android應用程序以及框架和系統運行庫,和底層相關的是系統運行庫,而其中和顯示相關的就是Android的Surface Manager, 它負責對顯示子系統的管理,而且爲多個應用程序提 供了2D和3D圖層的無縫融合。

*黑色部分-HAL層,在2.2.1部分會有介紹

*紅色部分-Linux kernel層

Linux kernel,其中和顯示部分相關的就是Linux的FrameBuffer,它是Linux系統中的顯示部分驅動程序接口。Linux工做在保護模式下,User空間的應用程序沒法直接調用顯卡的驅動程序來直接畫屏,FrameBuffer機制模仿顯卡的功能,將顯卡硬件結構抽象掉,能夠經過 Framebuffer的讀寫直接對顯存進行操做。用戶能夠將Framebuffer當作是顯示內存的一個映像,將其映射到進程地址空間以後,就能夠直接進行讀寫操做,而寫操做能夠當即反應在屏幕上。這種操做是抽象的,統一的。用戶沒必要關心物理顯存的位置、換頁機制等等具體細節。這些都是由 Framebuffer設備驅動來完成的。

*綠色部分-HW驅動層

該部分能夠看做高通顯卡的驅動程序,和高通顯示部分硬件相關以及外圍LCD相關的驅動都被定義在這邊,好比上述的顯卡的一些特性都是在這邊被初始化的,一樣MDP和MDDI相關的驅動也都定義在這裏

 

User Space Display功能介紹

這裏的User Space就是與應用程序相關的上層部分(參考上圖中的藍色部分),其中與Kernel空間交互的部分稱之爲HAL-HW Abstraction Layer。

HAL其實就是用戶空間的驅動程序。若是想要將 Android 在某硬件平臺上執行,基本上完成這些驅動程序就好了。其內定義了 Android 對各硬件裝置例如顯示芯片、聲音、數字相機、GPS、GSM 等等的需求。

HAL存在的幾個緣由:

一、 並非全部的硬件設備都有標準的linux kernel的接口。

二、 Kernel driver涉及到GPL的版權。某些設備製造商並不緣由公開硬件驅動,因此纔去HAL方式繞過GPL。

三、 針對某些硬件,Android有一些特殊的需求。

在display部分,HAL的實現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);//打開設備

Kernel Space Display功能介紹

這裏的Kernel空間(與Display相關)是Linux平臺下的FB設備(參考上圖中的紅色部分)。下面介紹一下FB設備。

Fb即FrameBuffer的簡稱。framebuffer 是一種可以提取圖形的硬件設備,是用戶進入圖形界面很好的接口。有了framebuffer,用戶的應用程序不須要對底層驅動有深刻了解就可以作出很好的圖形。對於用戶而言,它和/dev 下面的其餘設備沒有什麼區別,用戶能夠把

framebuffer 當作一塊內存,既能夠向這塊內存中寫入數據,也能夠從這塊內存中讀取數據。它容許上層應用程序在圖形模式下直接對顯示緩衝區進行讀寫操做。這種操做是抽象的,統一的。用戶沒必要關心物理顯存的位置、換頁機制等等具體細節。這些都是由Framebuffer設備驅動來完成的。

從用戶的角度看,幀緩衝設備和其餘位於/dev下面的設備相似,它是一個字符設備,一般主設備號是29,次設備號定義幀緩衝的個數。

在LINUX系統中,設備被看成文件來處理,全部的文件包括設備文件,Linux都提供了統一的操做函數接口。上面的結構體就是Linux爲FB設備提供的操做函數接口。

1)、讀寫(read/write)接口,即讀寫屏幕緩衝區(應用程序不必定會調用該接口)

2)、映射(map)操做(用戶空間不能直接訪問顯存物理空間,需map成虛擬地址後才能夠)

因爲Linux工做在保護模式,每一個應用程序都有本身的虛擬地址空間,在應用程序中是不能直接訪問物理緩衝區地址的。爲此,Linux在文件操做 file_operations結構中提供了mmap函數,可將文件的內容映射到用戶空間。對於幀緩衝設備,則可經過映射操做,可將屏幕緩衝區的物理地址映射到用戶空間的一段虛擬地址中,以後用戶就能夠經過讀寫這段虛擬地址訪問屏幕緩衝區,在屏幕上繪圖了。實際上,使用幀緩衝設備的應用程序都是經過映射操做來顯示圖形的。因爲映射操做都是由內核來完成,下面咱們將看到,幀緩衝驅動留給開發人員的工做並很少

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

Note:上述部分請參考文件fbmem.c。

Android display架構分析(三)

http://hi.baidu.com/leowenj/blog/item/76411bf6237dc429bc31099f.html

Kernel Space Display架構介紹4

如上圖所示,除了上層的圖形應用程序外,和Kernel空間有關的包括Linux FB設備層以及和具體HW相關的驅動層,對應的源文件分別是fb_mem.c、msm_fb.c、mddi_toshiba.c。下面會一一介紹。

函數和數據結構介紹

這個文件包含了Linux Fb設備的全部接口,主要函數接口和數據結構以下:

A、Fb設備的文件操做接口

5

B、3個重要的數據結構

FrameBuffer中有3個重要的結構體,fb.h中定義,以下:

1) 、frame_var_screeninfo

該結構體定義了顯卡的一些可變的特性,這些特性在程序運行期間能夠由應用程序動態改變,比較典型的如xrex和yres表示在顯示屏上顯示的真實分辨率、顯示的bit數等,該結構體user space能夠訪問。

2) 、frame_fix_screeninfo

該結構體定義了顯卡的一些固定的特性,這些特性在硬件初始化時就被定義了之後不能夠更改。其中最重要的成員就是smem_len和smem_start,前者指示顯存的大小(目前程序中定義的顯存大小爲整屏數據RGB565大小的2倍),後者給出了顯存的物理地址。該結構體user space能夠訪問。

Note:smem_start是顯存的物理地址,應用程序是不能夠直接訪問的,必須經過fb_ops中的mmp函數映射成虛擬地址後,應用程序方可訪問。

3) 、fb_info

FrameBuffer中最重要的結構體,它只能在內核空間內訪問。內部定義了fb_ops結構體(包含一系列FrameBuffer的操做函數,Open/read/write、地址映射等).

C、其餘

1)、一個重要的全局變量

struct fb_info *registered_fb[FB_MAX];

這變量記錄了全部fb_info 結構的實例,fb_info 結構描述顯卡的當前狀態,全部設備對應的fb_info 結構都保存在這個數組中,當一個FrameBuffer設備驅動向系統註冊本身時,其對應的fb_info 結構就會添加到這個結構中,同時num_registered_fb 爲自動加1。

2)、註冊framebuffer函數

register_framebuffer(struct fb_info *fb_info);

unregister_framebuffer(struct fb_info *fb_info);

這兩個是提供給下層FrameBuffer設備驅動的接口,設備驅動經過這兩函數向系統註冊或註銷本身。幾乎底層設備驅動所要作的全部事情就是填充fb_info結構而後向系統註冊或註銷它

Android display架構分析(四)

http://hi.baidu.com/leowenj/blog/item/37e1a8521e35522842a75b99.html

函數和數據結構介紹

該文件爲高通顯卡的驅動文件,比較重要的函數接口和數據結構以下:

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,       /* 設置顯示相關參數 */

.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,//驅動探測函數

.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,初始化時會調用

D、msm_fb_add_device

向系統中添加新的lcd設備,在mddi_toshiba.c中會被調用

函數和數據結構介紹

該文件包含了全部和具體LCD(Toshiba)相關的信息和驅動,重點的數據結構和函數結構以下:

A、LCD設備相關信息

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的控制函數,如開關、初始化等等

B、LCD driver接口

static struct platform_driver this_driver = {

.probe = mddi_toshiba_lcd_probe,

.driver = {

.name   = "mddi_toshiba_vga",

},

};

其中mddi_toshiba_lcd_probe中會調用msm_fb_add_device接口把具體LCD添加到系統中去。

C、mddi_toshiba_lcd_init

註冊LCD設備及driver到系統中去,同時也把LCD的固有信息(大小、格式、位率等)一併註冊到系統中去。

D、LCD相關控制函數

toshiba_common_initial_setup():初始化MDDI bridge

toshiba_prim_start():初始化LCD

數據流分析

本部分來看一下應用層如下,顯示數據的流程是怎樣的。

先來分析一下傳統的Linux平臺下FB設備是若是調用的,以下圖所示:

上層調用FB API(主要是fb_ioctl()),fb_ioctl()會調用具體顯卡的驅動,這裏是高通的顯卡驅動,其實就是MDP DMA的驅動,經過MDP DMA把顯示數據經MDDI接口送到外圍LCD組件。

Note:這裏的MDP DMA並不對數據進行任何處理(能夠完成簡單的格式轉換,如RGB565->RGB666)。

6

接下來再分析一下Android平臺下顯示數據是如何處理的,以下圖所示:

7

一樣上層也是調用FB API,不過這裏其實把FB bypass了,至關於直接調用的是高通MDP PPP的驅動,而後數據經PPP處理後再經MDDI接口送出到外圍LCD組件。

Note:這裏的MDP PPP能夠完成不少顯示數據處理功能,如YUV->RGB、Scale、Rotate、Blending等。

初始化過程分析

   Kernel部分display的初始化包含下面幾個步驟:

1)、在linux fb設備初始化時會向系統中註冊msm_fb_driver。Name爲msm_fb。

msm_fb_init-> msm_fb_register_driver-> platform_driver_register(&msm_fb_driver)

其中的probe函數會對msm fb進行初始化,分配顯存等(見msm_fb_probe函數)。

2)、在LCD模塊初始化時會先向系統中註冊驅動(在mddi_toshiba_lcd_init函數中)

platform_driver_register(&this_driver);名字爲mddi_toshiba_vga;

this_driver的probe函數爲mddi_toshiba_lcd_probe,其內部會調用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的總線來管理,那麼只須要註冊驅動便可,而無須向系統中註冊device,如msm_touch。

Android display架構分析(五)

http://hi.baidu.com/leowenj/blog/item/7a12ecb77067737f8ad4b266.html

Display接口介紹

、User Space display接口

在Android平臺下,應用程序面對的顯示部分的接口就是HAL,參考copybit.c,具體接口以下介紹:

open_copybit

初始化相關變量,並調用open("/dev/graphics/fb0", O_RDWR, 0);打開fb設備。

set_parameter_copybit

設置各類操做參數,如rotate、alpha、dither等。

stretch_copybit

Copy一塊數據(Rectangle)到顯存,而後並命令msm_fb進行顯示。

close_copybit

調用close(ctx->mFD);關閉fb設備。

Note:另外,應用程序在使用上面接口以前,須要調用mapFrameBuffer接口(EGLDisplaySurface.cpp),其功能以下:

一、 初始化顯示相關參數,並設置到底層。

二、 映射出顯存的虛擬地址。

、Kernel display接口

Kernel部分顯示的接口所有都在fbmem.c中,這裏詳細介紹一下:

fb_open

打開Linux下fb設備。

fb_read/fb_write

讀寫顯存中的數據

fb_ioctl

對顯示設備的命令操做。如get或set一些顯示參數、通知底層進行刷屏等。

在典型應用中,畫屏的通常步驟以下:

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

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

3. 將屏幕緩衝區映射到用戶空間。

4. 映射後就能夠直接讀寫屏幕緩衝區,進行繪圖和圖片顯示了。

典型程序段以下:

#include

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指針讀寫緩衝區*/

...

}

典型應用flow分析

在不一樣應用程序中,上層的調用會有所不一樣,好比Andriod下會選擇應用程序跳過Linux fb操做層,直接操做顯卡驅動層,稱之爲BLT accelerator。

下面看一下Android平臺下畫屏的操做流程。

一、 經過mapFrameBuffer直接把用戶空間的數據映射到顯存中。

二、 調用HAL中的stretch函數直接命令MSM設備提取顯存數據而後送入MDP PPP進行處理並經MDDI接口送到外圍LCD組件。

具體的函數調用流程以下:

copybit_open();//打開BlitEngine,同時也打開fb設備

mapFrameBuffer();//設置顯示參數,同時獲得顯存虛擬地址

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 HW operation

Android display架構分析(六)

http://hi.baidu.com/leowenj/blog/item/78c068dc443c961f48540361.html

介紹

Note:

本部分介紹的徹底是用戶空間顯示部分的架構,與kernel並無直接的聯繫,主要是JNI如下到HAL以上的部分。

、Surface manager(surface flinger)簡介

Surface manager是用戶空間中framework下libraries中負責顯示相關的一個模塊。以下:

8

當系統同時執行多個應用程序時,Surface Manager會負責管理顯示與存取操做間的互動,另外也負責將2D繪圖與3D繪圖進行顯示上的合成。

    surface manager 能夠準備一塊 surface(能夠看做一個layer),把 surface 的 fd (一塊內存) 傳給一個 app,讓 app 能夠在上面做畫。典型應用以下:

9  
10

2架構分析

Android中的圖形系統採用Client/Server架構,以下:

Client端:應用程序相關部分。代碼分爲兩部分,一部分是由Java提供的供應用使用的api,另外一部分則是由c++寫成的底層實現。

Server端:即SurfaceFlinger,負責合成並送入buffer顯示。其主要由c++代碼編寫而成。

Client和Server以前經過Binder的IPC方式進行通訊,整體結構圖以下:

如上圖所示,Surface的client部分實際上是提供給各應用程序進行畫圖操做的一個橋樑,該橋樑經過binder通向server端的Surfaceflinger,Surfaceflinger負責合成各個surface,而後把buffer傳送到framebuffer端進行底層顯示。其中每一個surface對應2個buffer,一個front buffer, 一個back buffer,更新時,數據更新在back buffer上,須要顯示時,則將back buffer和front buffer互換。

下一部分咱們重點研究一下Surfaceflinger。

Android display架構分析(七-1)

http://hi.baidu.com/leowenj/blog/item/7abbe33a309367ff3b87ce6f.html

流程分析根據前面的介紹,surfaceflinger做爲一個server process,上層的應用程序(做爲client)經過Binder方式與其進行通訊。Surfaceflinger做爲一個thread,這裏把它分爲3個部分,以下:

一、 Thread自己處理部分,包括初始化以及thread loop。

二、 Binder部分,負責接收上層應用的各個設置和命令,並反饋狀態標誌給上層。

三、 與底層的交互,負責調用底層接口(HAL)。

結構圖以下:

11

註釋:

a、 Binder接收到應用程序的命令(如建立surface、設置參數等),傳遞給flinger。

b、 Flinger完成對應命令後將相關結果狀態反饋給上層。

c、 在處理上層命令過程當中,根據須要設置event(主要和顯示有關),通知Thread Loop進行處理。

d、 Flinger根據上層命令通知底層進行處理(主要是設置一些參數,Layer、position等)

e、 Thread Loop中進行surface的合成並通知底層進行顯示(Post buffer)。

f、 DisplayHardware層根據flinger命令調用HAL進行HW的操做。

下面來具體分析一些SurfaceFlinger中重要的處理函數以及surface、Layer的屬性

1)、readToRun

SurfaceFlinger thread的初始化函數,主要任務是分配內存和設置底層接口(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);//保存顯示接口

}

//獲取顯示相關參數

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

Surfaceflingerloop函數,主要是等待其餘接口發送的event,進行顯示數據的合成以及顯示。

bool SurfaceFlinger::threadLoop()

{

waitForEvent();//等待其餘接口的signal event

// post surfaces (if needed)

handlePageFlip();//處理翻頁機制

const DisplayHardware& hw(graphicPlane(0).displayHardware());

if (LIKELY(hw.canDraw()))

{

// repaint the framebuffer (if needed)

handleRepaint();//合併全部layer並填充到buffer中去

postFramebuffer();//互換front buffer和back buffer,調用EGL接口進行顯示

}

}

3)、createSurface

提供給應用程序的主要接口,該接口能夠建立一個surface,底層會根據參數建立layer以及分配內存,surface相關參數會反饋給上層

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);//建立layer,根據參數(寬高格式)分配內存(共2個buffer:front/back buffer)

if (layer)

{

setTransactionFlags(eTransactionNeeded);

surfaceHandle = layer->getSurface();//建立surface

if (surfaceHandle != 0)

surfaceHandle->getSurfaceData(params);//建立的surface參數反饋給應用層

}

待續。。。

Android display架構分析(七-2)

http://hi.baidu.com/leowenj/blog/item/ba4c5d6378a5da48eaf8f86a.html

4)、setClientState

處理上層的各個命令,並根據flag設置event通知Threadloop進行處理

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;

      // 檢測應用層是否設置各個標誌,若是有則通知底層完成對應操做,並通知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);//經過signal通知ThreadLoop

}

return NO_ERROR;

}

5)、composeSurfaces

該接口在Threadloop中被調用,負責將全部存在的surface進行合併,OpenGl模塊負責這個部分。

6)、postFramebuffer

該接口在Threadloop中被調用,負責將合成好的數據(存於back buffer中)推入在front buffer中,而後調用HAL接口命令底層顯示。

7)、從3中可知,上層每建立一個surface的時候,底層都會同時建立一個layer,下面看一下surface及layer的相關屬性。

Note:code中相關結構體太大,就不所有羅列出來了

   A、Surface相關屬性(詳細參考文件surface.h)

       a1:SurfaceID:根據此ID把相關surface和layer對應起來

      a2:SurfaceInfo

包括寬高格式等信息

a3:2個buffer指針、buffer索引等信息

   B、Layer相關屬性(詳細參考文件layer.h/layerbase.h/layerbitmap.h)

包括Layer的ID、寬高、位置、layer、alpha指、先後buffer地址及索引、layer的狀態信息(如eFlipRequested、eBusy、eLocked等)

Android display架構分析(八)

http://hi.baidu.com/leowenj/blog/item/03aae36137acb8d1e6113a75.html

開發的經驗分享1Display Driver的工做內容

參考上面linux下fb設備的軟件架構,能夠知道,要加入一個新的MDDI 接口的LCM,Driver的工做就是要提供本身的mddi_xxxx.c(在此次porting的過程當中,爲了節省時間,咱們直接修改了mddi_toshiba.c),而且完成和這個lcd相關的HWr的初始化。主要的工做包括:

A、初始化和LCD / LCD背光相關的IO以及電源;

B、編寫初始化函數 。主要是初始化LCD控制器,這個通常LCD廠商會提供;而後分配顯存,這個高通release過來的code已經包含這個動做了,最後是初始化一個fb_info的結構體,在這裏主要是把LCD的一些信息登記進來。

C、把LCD的設備以及驅動註冊到系統中去。(這裏由於是替換現有的驅動,因此相關修改的部分很少。)

上述B、C部分代碼請參考kernel\drivers\video\msm\mddi_toshiba.c。

開發過程1.2.1配置Power和IO

更改一些GPIO的配置以及一些電源的電平配置;而後經過實際測量,確保一下信號正常:

A、供給LCD以及MDDI Bridge的電源;

B、MDDI Bridge以及LCD reset信號;

C、控制背光IC的GPIO工做正常(背光不打開,沒法調試LCD)。

1.2.2Porting LCD初始化序列

LCD init的code以及外圍MDDI Bridge的初始化code,均可以以前Boston Windows Mobile系統的code base中得到;把這部分code移植到mddi_Toshiba.c中,並更改相應的圖像格式、分辨率等配置,編譯經過。LCD初始化部分就算基本完成。

1.2.3LCD初始化過程的調試

因爲硬件在以前Boston load是能夠工做的,能夠認爲硬件鏈接等沒有問題,因此只需關注軟件部分就行。

Display部分軟件調試過程以下:

A、 開機後,量一下GPIO是否爲code中配置預期的狀態(可確保code中的

GPIO接口工做正常);

B、 量一下各個電源是否都處於Code中定義的電平值。這些都OK後,背光

是會亮的(背光的控制比較簡單,一個GPIO便可);

C、 這個時候若是LCD以及MDDI Bridge有被正常初始化的話,屏幕上是會

看出來的。反之,若是屏幕沒有顯示,須要用JTAG跟一下mddi_Toshiba.c中的初始化函數是否在開機的時候有被調用過。

目前版本中,是根據外圍MDDI Bridge中讀到的的廠商號來決定加載哪一個驅動模塊的。在本次調試中,bootloader中能夠正確讀到廠商號,因此bootloader中對於LCD的初始化是有作的,因此屏幕看到的狀態就是LCD初始化後的樣子(花屏)。 但Kernel起來後,並無其餘顯示,用JTAG跟了後發現,Kernel中MODULE INIT中讀不到正確的廠商號,因此說後面的driver沒有被加載。接着發現若是在bootloader中若是不作MDDI Bridge的初始化,的話後面的MODULE INIT就可正常運行,該問題目前尚未澄清(如今暫時先把bootloader中的init disable掉)。

1.2.4LCD的調整

初始化正常後,屏幕會顯示UI的相關畫面,但明顯顏色、位置都不對。

這個多是數據類型配置不對致使的,即MDP輸出的類型、MDDI配置的類型以、LCD接收的類型不匹配致使,也有多是RGB的順序不對致使(可配置成BGR)。通過調試後,把MDP端輸出的格式配置成RGB565,同時外圍MDDI Bridge以及LCD的input格式也配置成RGB565,這時顯示色彩正常了。

若是位置或者方向不對,好比說上下或是左右顛倒,能夠更改LCD的配置中的掃描方向便可。

1.2.5其餘

後續發現一個問題,播放video的時候顏色都是黑白的。

這個問題很容易讓人誤解,按照正常的理解,video decode出來的數據爲YCbCr,Y爲亮度信號,CbCr爲色差信號,若是隻有Y信號的話顏色應該就是黑白的。因此有2個懷疑點,一個是decode出來的數據有誤,另外一個是MDDI Bridge誤把輸入的YcbCr信號看成RGB信號進行出來,這個也是有可能的。但很快第二個懷疑點被排除了(由於單更改MDDI input格式後仍是不能解決問題)。

後來又詳細的看了顯示部分的代碼,並用JTAG追蹤video播放的時候用的顯示接口,發現目前全部的顯示接口輸出的格式都是RGB格式,也就是說在經過MDP以前YcbCr已經被轉化過;而MDP裏的轉換功能並無使用,MDP只是被看成一個DMA完成數據的直接傳輸,文檔中叫作Bypasse。

YcbCr到RGB的轉換是由Android的lib來完成。發了個SR給高通,高通的回覆也確認了,在6.3.50中,Android上層缺乏這個lib(copybit.default.so),6.3.60以後的版本經解決了這個問題。

高通Android平臺下關於display部分的幾個關鍵問題

http://hi.baidu.com/leowenj/blog/item/06f8c0000763b37a3812bb03.html

顯示部分的幾個問題這幾天經過實際測試澄清了一下,主要是下圖中各個模塊的使用情況以及HAL層幾個模塊的調用流程。以問題的方式描述以下:

一、 Ap是怎麼進行顯示的?

Surfaceflinger負責全部上層的顯示處理,對於AP(2D或是3D的應用程序)而言,只要到surfaceflinger中建立surface,設置好參數,接下來都是統一交給surfaceflinger進行處理

二、 Surface是怎麼管理多個surface的?

無論有多少個surface,最終送到顯示部分的只能是屏幕大小數據,surfaceflinger中利用MDP或是GPU進行多個surface的合成處理,普通的合成MDP就可完成,但若是是複雜的好比3D的應用等就必須使用GPU,最終合成的好數據會被送到framebuffer中。

三、 Framebuffer是什麼?

Framebuffer是Linux中爲顯示數據分配的一塊顯存(fb設備中),一般大小是一整個屏幕數據的兩倍,對於上層AP而言,只須要將要顯示的數據丟到framebuffer中就OK了,但此時顯示數據並未真正的被送到LCD上,而是暫存在framebuffer中而已。

四、 上層是經過什麼方式將顯示內容送到framebuffer的?

有2個方式(二選一,不會同時在運行):

A、 普通的顯示,使用copybit(MDP)(未使用GPU)

Surfaceflinger經過copybit將要顯示的數據送到framebuffer。

Note:copybit能夠看作是MDP PPP的接口,它提供了MDP的功能,如多個layer合成,scale、rotate等。

其接口在:android\hardware\msm7k\libcopybit\copybit.cpp

B、 使用GPU(即便用圖中的Graphics driver)

當進行復雜的顯示處理時,好比3D的應用,GPU把處理好的數據直接丟到framebuffer中,和MDP沒有任何關係

五、 Framebuffer中的數據是如何被送到LCD顯示的?

圖中的Gralloc完成的。

Gralloc有2個功能:

一個是和copybit相同的,裏面有MDP PPP的接口(目前沒有使用)

另外一個則是刷屏(整屏刷)的接口,即將framebuffer中的數據送到lcd上,調用的是MDP DMA的接口

這部分的code在android\hardware\msm7k\libgralloc-qsd8k目錄下,以前沒有留意,覺得沒有使用。如今能夠看出開機初始化後就建立了disp_loop thread,裏面的操做就是調用系統接口

ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info)

將數據送到lcd

Note:送數據的時候是2個buffer切換的

另外,上層surfaceflinger也是經過Gralloc中的接口獲知屏幕的大小,調用接口爲

ioctl(fd, FBIOGET_VSCREENINFO, &info),info中的屏幕寬高對應的就是底層driver設置的寬高值

六、 OpenGL是什麼?

它是一個圖像處理引擎,當須要一些複雜的顯示(2D/3D)操做時會用到它。它分爲SW方案和HW方案,軟件方案就是圖中的libagl.so,對應到目前項目中是libGLES_android.so,它能夠完成簡單的2D(文字,icon等)處理,經過trace看目前大部分顯示操做都是它來完成的。

Note:它是軟件方案,處理好的數據是經過copybit送到framebuffer的,而不是GPU。

其接口部分參考:android\frameworks\base\opengl\libagl

HW方案就是圖中的Graphics driver,它經過使用GPU硬件來完成圖像處理,處理後的數據直接送到framebuffer中。其接口部分參考:android\frameworks\base\opengl\libs(有幾個版本)

七、 OpenGL在項目中是如何配置的?

在android\vendor\qcom\msm7627_ffa目錄下有一個egl.cfg文件,裏面指定了當前版本中的OpenGL信息,目前以下:

0 0 android

0 1 adreno200

第一行表明該codebase支持SW 方案的OpenGL,是android default的

第二行表明該codebase也支持HW方案的OpenGL,是高通的adreno引擎

若是該cfg文件爲空,則只支持default的SW方案。

若是2個方案都在,上層將根據實際應用自行選擇使用其一。

該部分請參考:android\frameworks\base\opengl\libs\EGL\loader.cpp

63468f3ba1f59dfed4622529

相關文章
相關標籤/搜索