国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
【轉(zhuǎn)】Android display架構(gòu)分析

Android display架構(gòu)分析(一)

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

高通7系列硬件架構(gòu)分析

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

A、MDP

高通MSM7200A內(nèi)部模塊,主要負(fù)責(zé)顯示數(shù)據(jù)的轉(zhuǎn)換和部分圖像處理功能理,如YUV轉(zhuǎn)RGB,放大縮小、旋轉(zhuǎn)等。MDP內(nèi)部的MDPDMA負(fù)責(zé)數(shù)據(jù)從DDR到MDDI Host的傳輸(可以完成RGB之間的轉(zhuǎn)換,如RGB565轉(zhuǎn)成RGB666,這個(gè)轉(zhuǎn)換工能載目前的code中沒(méi)有使用)。

B、MDDI

一種采用差分信號(hào)的高速的串行數(shù)據(jù)傳輸總線(xiàn),只負(fù)責(zé)數(shù)據(jù)傳輸,無(wú)其它功能;其中的MDDI Hosat提供并行數(shù)據(jù)和串行數(shù)據(jù)之間的轉(zhuǎn)換和緩沖功能。由于外面是VGA的屏幕,數(shù)據(jù)量較大,為了減少對(duì)EBI2總線(xiàn)的影響,傳輸總線(xiàn)使用MDDI,而非之前的EBI2。

C、MDDI Bridge

由于現(xiàn)在采用的外接LCD并不支持MDDI接口,故需要外加MDDI轉(zhuǎn)換器,即MDDIbridge,來(lái)把MDDI數(shù)據(jù)轉(zhuǎn)換成RGB接口數(shù)據(jù)。這里采用的EPSON MDDIBridge還有LCDController功能,可以完成其它一些數(shù)據(jù)處理的功能,如數(shù)據(jù)格式轉(zhuǎn)換、支持TV-OUT、PIP等;并且還可以提供一定數(shù)量的GPIO。目前我們主要用它把HOST端MDDI傳遞過(guò)來(lái)的顯示數(shù)據(jù)和控制數(shù)據(jù)(初始化配置等)轉(zhuǎn)換成并行的數(shù)據(jù)傳遞給LCD。

D、LCD module

主要是LCD Driver IC 和TFT Panel,負(fù)責(zé)把MDDI Bridge傳來(lái)的顯存中的圖像示在自己的 Panel上。

Android display架構(gòu)分析(二)

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

Android display SW架構(gòu)分析

下面簡(jiǎn)單介紹一下上圖中的各個(gè)Layer:

*藍(lán)色部分-用戶(hù)空間應(yīng)用程序

應(yīng)用程序?qū)樱渲邪ˋndroid應(yīng)用程序以及框架和系統(tǒng)運(yùn)行庫(kù),和底層相關(guān)的是系統(tǒng)運(yùn)行庫(kù),而其中和顯示相關(guān)的就是Android的Surface Manager, 它負(fù)責(zé)對(duì)顯示子系統(tǒng)的管理,并且為多個(gè)應(yīng)用程序提 供了2D和3D圖層的無(wú)縫融合。

*黑色部分-HAL層,在2.2.1部分會(huì)有介紹

*紅色部分-Linux kernel層

Linuxkernel,其中和顯示部分相關(guān)的就是Linux的FrameBuffer,它是Linux系統(tǒng)中的顯示部分驅(qū)動(dòng)程序接口。Linux工作在保護(hù)模式下,User空間的應(yīng)用程序無(wú)法直接調(diào)用顯卡的驅(qū)動(dòng)程序來(lái)直接畫(huà)屏,F(xiàn)rameBuffer機(jī)制模仿顯卡的功能,將顯卡硬件結(jié)構(gòu)抽象掉,可以通過(guò)Framebuffer的讀寫(xiě)直接對(duì)顯存進(jìn)行操作。用戶(hù)可以將Framebuffer看成是顯示內(nèi)存的一個(gè)映像,將其映射到進(jìn)程地址空間之后,就可以直接進(jìn)行讀寫(xiě)操作,而寫(xiě)操作可以立即反應(yīng)在屏幕上。這種操作是抽象的,統(tǒng)一的。用戶(hù)不必關(guān)心物理顯存的位置、換頁(yè)機(jī)制等等具體細(xì)節(jié)。這些都是由Framebuffer設(shè)備驅(qū)動(dòng)來(lái)完成的。

*綠色部分-HW驅(qū)動(dòng)層

該部分可以看作高通顯卡的驅(qū)動(dòng)程序,和高通顯示部分硬件相關(guān)以及外圍LCD相關(guān)的驅(qū)動(dòng)都被定義在這邊,比如上述的顯卡的一些特性都是在這邊被初始化的,同樣MDP和MDDI相關(guān)的驅(qū)動(dòng)也都定義在這里

User Space Display功能介紹

這里的User Space就是與應(yīng)用程序相關(guān)的上層部分(參考上圖中的藍(lán)色部分),其中與Kernel空間交互的部分稱(chēng)之為HAL-HW Abstraction Layer。

HAL其實(shí)就是用戶(hù)空間的驅(qū)動(dòng)程序。如果想要將 Android 在某硬件平臺(tái)上執(zhí)行,基本上完成這些驅(qū)動(dòng)程序就行了。其內(nèi)定義了 Android 對(duì)各硬件裝置例如顯示芯片、聲音、數(shù)字相機(jī)、GPS、GSM 等等的需求。

HAL存在的幾個(gè)原因:

1、 并不是所有的硬件設(shè)備都有標(biāo)準(zhǔn)的linux kernel的接口。

2、 Kernel driver涉及到GPL的版權(quán)。某些設(shè)備制造商并不原因公開(kāi)硬件驅(qū)動(dòng),所以才去HAL方式繞過(guò)GPL。

3、 針對(duì)某些硬件,Android有一些特殊的需求。

在display部分,HAL的實(shí)現(xiàn)code在copybit.c中,應(yīng)用程序直接操作這些接口即可,具體的接口如下:

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;//設(shè)置參數(shù)ctx->device.get = get;ctx->device.blit = blit_copybit;//傳送顯示數(shù)據(jù)ctx->device.stretch = stretch_copybit;ctx->mAlpha = MDP_ALPHA_NOP;ctx->mFlags = 0;ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);//打開(kāi)設(shè)備

Kernel Space Display功能介紹

這里的Kernel空間(與Display相關(guān))是Linux平臺(tái)下的FB設(shè)備(參考上圖中的紅色部分)。下面介紹一下FB設(shè)備。

Fb即FrameBuffer的簡(jiǎn)稱(chēng)。framebuffer是一種能夠提取圖形的硬件設(shè)備,是用戶(hù)進(jìn)入圖形界面很好的接口。有了framebuffer,用戶(hù)的應(yīng)用程序不需要對(duì)底層驅(qū)動(dòng)有深入了解就能夠做出很好的圖形。對(duì)于用戶(hù)而言,它和/dev 下面的其他設(shè)備沒(méi)有什么區(qū)別,用戶(hù)可以把

framebuffer看成一塊內(nèi)存,既可以向這塊內(nèi)存中寫(xiě)入數(shù)據(jù),也可以從這塊內(nèi)存中讀取數(shù)據(jù)。它允許上層應(yīng)用程序在圖形模式下直接對(duì)顯示緩沖區(qū)進(jìn)行讀寫(xiě)操作。這種操作是抽象的,統(tǒng)一的。用戶(hù)不必關(guān)心物理顯存的位置、換頁(yè)機(jī)制等等具體細(xì)節(jié)。這些都是由Framebuffer設(shè)備驅(qū)動(dòng)來(lái)完成的。

從用戶(hù)的角度看,幀緩沖設(shè)備和其他位于/dev下面的設(shè)備類(lèi)似,它是一個(gè)字符設(shè)備,通常主設(shè)備號(hào)是29,次設(shè)備號(hào)定義幀緩沖的個(gè)數(shù)。

在LINUX系統(tǒng)中,設(shè)備被當(dāng)作文件來(lái)處理,所有的文件包括設(shè)備文件,Linux都提供了統(tǒng)一的操作函數(shù)接口。上面的結(jié)構(gòu)體就是Linux為FB設(shè)備提供的操作函數(shù)接口。

1)、讀寫(xiě)(read/write)接口,即讀寫(xiě)屏幕緩沖區(qū)(應(yīng)用程序不一定會(huì)調(diào)用該接口)

2)、映射(map)操作(用戶(hù)空間不能直接訪(fǎng)問(wèn)顯存物理空間,需map成虛擬地址后才可以)

由于Linux工作在保護(hù)模式,每個(gè)應(yīng)用程序都有自己的虛擬地址空間,在應(yīng)用程序中是不能直接訪(fǎng)問(wèn)物理緩沖區(qū)地址的。為此,Linux在文件操作file_operations結(jié)構(gòu)中提供了mmap函數(shù),可將文件的內(nèi)容映射到用戶(hù)空間。對(duì)于幀緩沖設(shè)備,則可通過(guò)映射操作,可將屏幕緩沖區(qū)的物理地址映射到用戶(hù)空間的一段虛擬地址中,之后用戶(hù)就可以通過(guò)讀寫(xiě)這段虛擬地址訪(fǎng)問(wèn)屏幕緩沖區(qū),在屏幕上繪圖了。實(shí)際上,使用幀緩沖設(shè)備的應(yīng)用程序都是通過(guò)映射操作來(lái)顯示圖形的。由于映射操作都是由內(nèi)核來(lái)完成,下面我們將看到,幀緩沖驅(qū)動(dòng)留給開(kāi)發(fā)人員的工作并不多

3)、I/O控制:對(duì)于幀緩沖設(shè)備,對(duì)設(shè)備文件的ioctl操作可讀取/設(shè)置顯示設(shè)備及屏幕的參數(shù),如分辨率,顯示顏色數(shù),屏幕大小等等。ioctl的操作是由底層的驅(qū)動(dòng)程序來(lái)完成

Note:上述部分請(qǐng)參考文件fbmem.c。

Android display架構(gòu)分析(三)

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

Kernel Space Display架構(gòu)介紹

如上圖所示,除了上層的圖形應(yīng)用程序外,和Kernel空間有關(guān)的包括Linux FB設(shè)備層以及和具體HW相關(guān)的驅(qū)動(dòng)層,對(duì)應(yīng)的源文件分別是fb_mem.cmsm_fb.c、mddi_toshiba.c。下面會(huì)一一介紹。

函數(shù)和數(shù)據(jù)結(jié)構(gòu)介紹

這個(gè)文件包含了Linux Fb設(shè)備的所有接口,主要函數(shù)接口和數(shù)據(jù)結(jié)構(gòu)如下:

A、Fb設(shè)備的文件操作接口

B3個(gè)重要的數(shù)據(jù)結(jié)構(gòu)

FrameBuffer中有3個(gè)重要的結(jié)構(gòu)體,fb.h中定義,如下:

1 、frame_var_screeninfo

該結(jié)構(gòu)體定義了顯卡的一些可變的特性,這些特性在程序運(yùn)行期間可以由應(yīng)用程序動(dòng)態(tài)改變,比較典型的如xrexyres表示在顯示屏上顯示的真實(shí)分辨率、顯示的bit數(shù)等,該結(jié)構(gòu)體user space可以訪(fǎng)問(wèn)。

2 、frame_fix_screeninfo

該結(jié)構(gòu)體定義了顯卡的一些固定的特性,這些特性在硬件初始化時(shí)就被定義了以后不可以更改。其中最重要的成員就是smem_lensmem_start,前者指示顯存的大?。壳俺绦蛑卸x的顯存大小為整屏數(shù)據(jù)RGB565大小的2倍),后者給出了顯存的物理地址。該結(jié)構(gòu)體user space可以訪(fǎng)問(wèn)。

Notesmem_start是顯存的物理地址,應(yīng)用程序是不可以直接訪(fǎng)問(wèn)的,必須通過(guò)fb_ops中的mmp函數(shù)映射成虛擬地址后,應(yīng)用程序方可訪(fǎng)問(wèn)。

3 、fb_info

FrameBuffer中最重要的結(jié)構(gòu)體,它只能在內(nèi)核空間內(nèi)訪(fǎng)問(wèn)。內(nèi)部定義了fb_ops結(jié)構(gòu)體(包含一系列FrameBuffer的操作函數(shù),Open/read/write、地址映射等).

C、其他

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

struct fb_info *registered_fb[FB_MAX];

這變量記錄了所有fb_info 結(jié)構(gòu)的實(shí)例,fb_info 結(jié)構(gòu)描述顯卡的當(dāng)前狀態(tài),所有設(shè)備對(duì)應(yīng)的fb_info 結(jié)構(gòu)都保存在這個(gè)數(shù)組中,當(dāng)一個(gè)FrameBuffer設(shè)備驅(qū)動(dòng)向系統(tǒng)注冊(cè)自己時(shí),其對(duì)應(yīng)的fb_info 結(jié)構(gòu)就會(huì)添加到這個(gè)結(jié)構(gòu)中,同時(shí)num_registered_fb 為自動(dòng)加1。

2)、注冊(cè)framebuffer函數(shù)

register_framebuffer(struct fb_info *fb_info);

unregister_framebuffer(struct fb_info *fb_info);

這兩個(gè)是提供給下層FrameBuffer設(shè)備驅(qū)動(dòng)的接口,設(shè)備驅(qū)動(dòng)通過(guò)這兩函數(shù)向系統(tǒng)注冊(cè)或注銷(xiāo)自己。幾乎底層設(shè)備驅(qū)動(dòng)所要做的所有事情就是填充fb_info結(jié)構(gòu)然后向系統(tǒng)注冊(cè)或注銷(xiāo)它

Android display架構(gòu)分析(四)

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

函數(shù)和數(shù)據(jù)結(jié)構(gòu)介紹

該文件為高通顯卡的驅(qū)動(dòng)文件,比較重要的函數(shù)接口和數(shù)據(jù)結(jié)構(gòu)如下:

A、高通msm fb設(shè)備的文件操作函數(shù)接口

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,     /* 參數(shù)檢查 */

.fb_set_par = msm_fb_set_par,       /* 設(shè)置顯示相關(guān)參數(shù) */

.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 fbdriver接口

static struct platform_driver msm_fb_driver = {

.probe = msm_fb_probe,//驅(qū)動(dòng)探測(cè)函數(shù)

.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()

向系統(tǒng)注冊(cè)msm fbdriver,初始化時(shí)會(huì)調(diào)用

D、msm_fb_add_device

向系統(tǒng)中添加新的lcd設(shè)備,在mddi_toshiba.c中會(huì)被調(diào)用

函數(shù)和數(shù)據(jù)結(jié)構(gòu)介紹

該文件包含了所有和具體LCDToshiba)相關(guān)的信息和驅(qū)動(dòng),重點(diǎn)的數(shù)據(jù)結(jié)構(gòu)和函數(shù)結(jié)構(gòu)如下:

A、LCD設(shè)備相關(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的控制函數(shù),如開(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ì)調(diào)用msm_fb_add_device接口把具體LCD添加到系統(tǒng)中去。

C、mddi_toshiba_lcd_init

注冊(cè)LCD設(shè)備及driver到系統(tǒng)中去,同時(shí)也把LCD的固有信息(大小、格式、位率等)一并注冊(cè)到系統(tǒng)中去。

DLCD相關(guān)控制函數(shù)

toshiba_common_initial_setup():初始化MDDI bridge

toshiba_prim_start():初始化LCD

數(shù)據(jù)流分析

本部分來(lái)看一下應(yīng)用層以下,顯示數(shù)據(jù)的流程是怎樣的。

先來(lái)分析一下傳統(tǒng)的Linux平臺(tái)下FB設(shè)備是如果調(diào)用的,如下圖所示:

上層調(diào)用FB API(主要是fb_ioctl()),fb_ioctl()會(huì)調(diào)用具體顯卡的驅(qū)動(dòng),這里是高通的顯卡驅(qū)動(dòng),其實(shí)就是MDP DMA的驅(qū)動(dòng),通過(guò)MDP DMA把顯示數(shù)據(jù)經(jīng)MDDI接口送到外圍LCD組件。

Note:這里的MDP DMA并不對(duì)數(shù)據(jù)進(jìn)行任何處理(可以完成簡(jiǎn)單的格式轉(zhuǎn)換,如RGB565->RGB666)。

接下來(lái)再分析一下Android平臺(tái)下顯示數(shù)據(jù)是如何處理的,如下圖所示:

同樣上層也是調(diào)用FB API,不過(guò)這里其實(shí)把FB bypass了,相當(dāng)于直接調(diào)用的是高通MDP PPP的驅(qū)動(dòng),然后數(shù)據(jù)經(jīng)PPP處理后再經(jīng)MDDI接口送出到外圍LCD組件。

Note:這里的MDP PPP可以完成很多顯示數(shù)據(jù)處理功能,如YUV->RGB、Scale、Rotate、Blending等。

初始化過(guò)程分析

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

1)、在linux fb設(shè)備初始化時(shí)會(huì)向系統(tǒng)中注冊(cè)msm_fb_driver。Namemsm_fb

msm_fb_init> msm_fb_register_driver-> platform_driver_register(&msm_fb_driver)

其中的probe函數(shù)會(huì)對(duì)msm fb進(jìn)行初始化,分配顯存等(見(jiàn)msm_fb_probe函數(shù))。

2)、在LCD模塊初始化時(shí)會(huì)先向系統(tǒng)中注冊(cè)驅(qū)動(dòng)(在mddi_toshiba_lcd_init函數(shù)中)

platform_driver_register(&this_driver);名字為mddi_toshiba_vga;

this_driverprobe函數(shù)為mddi_toshiba_lcd_probe,其內(nèi)部會(huì)調(diào)用msm_fb_add_device向系統(tǒng)中添加MSM fb設(shè)備。

3)、調(diào)用platform_device_register(&this_device_0)向系統(tǒng)中注冊(cè)設(shè)備,名字為mddi_toshiba_vga,其中this_device_0包含了一些操作LCD的接口,如on/off。

Note:設(shè)備和drivername需要一致才可以綁定;另外,如果某些設(shè)備不需要讓platform的總線(xiàn)來(lái)管理,那么只需要注冊(cè)驅(qū)動(dòng)即可,而無(wú)須向系統(tǒng)中注冊(cè)device,如msm_touch。

Android display架構(gòu)分析(五)

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

Display接口介紹

、User Space display接口

Android平臺(tái)下,應(yīng)用程序面對(duì)的顯示部分的接口就是HAL,參考copybit.c,具體接口如下介紹:

open_copybit

初始化相關(guān)變量,并調(diào)用open("/dev/graphics/fb0", O_RDWR, 0);打開(kāi)fb設(shè)備。

set_parameter_copybit

設(shè)置各種操作參數(shù),如rotatealpha、dither等。

stretch_copybit

Copy一塊數(shù)據(jù)(Rectangle)到顯存,然后并命令msm_fb進(jìn)行顯示。

close_copybit

調(diào)用close(ctx->mFD);關(guān)閉fb設(shè)備。

Note:另外,應(yīng)用程序在使用上面接口之前,需要調(diào)用mapFrameBuffer接口(EGLDisplaySurface.cpp),其功能如下:

1、 初始化顯示相關(guān)參數(shù),并設(shè)置到底層。

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

、Kernel display接口

Kernel部分顯示的接口全部都在fbmem.c中,這里詳細(xì)介紹一下:

fb_open

打開(kāi)Linuxfb設(shè)備。

fb_read/fb_write

讀寫(xiě)顯存中的數(shù)據(jù)

fb_ioctl

對(duì)顯示設(shè)備的命令操作。如getset一些顯示參數(shù)、通知底層進(jìn)行刷屏等。

在典型應(yīng)用中,畫(huà)屏的一般步驟如下:

1 打開(kāi)/dev/fb設(shè)備文件。

2 ioctrl操作取得當(dāng)前顯示屏幕的參數(shù),如屏幕分辨率,每個(gè)像素點(diǎn)的比特?cái)?shù)。根據(jù)屏幕參數(shù)可計(jì)算屏幕緩沖區(qū)的大小。

3 將屏幕緩沖區(qū)映射到用戶(hù)空間。

4 映射后就可以直接讀寫(xiě)屏幕緩沖區(qū),進(jìn)行繪圖和圖片顯示了。

典型程序段如下:

#include

int main()

{

int fbfd = 0;

struct fb_var_screeninfo vinfo;

struct fb_fix_screeninfo finfo;

long int screensize = 0;

/*打開(kāi)設(shè)備文件*/

fbfd = open("/dev/fb0", O_RDWR);

/*取得屏幕相關(guān)參數(shù)*/

ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo); ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);

/*計(jì)算屏幕緩沖區(qū)大小*/

screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

/*映射屏幕緩沖區(qū)到用戶(hù)地址空間*/

fbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED, fbfd, 0);

/*下面可通過(guò)fbp指針讀寫(xiě)緩沖區(qū)*/

...

}

典型應(yīng)用flow分析

在不同應(yīng)用程序中,上層的調(diào)用會(huì)有所不同,比如Andriod下會(huì)選擇應(yīng)用程序跳過(guò)Linux fb操作層,直接操作顯卡驅(qū)動(dòng)層,稱(chēng)之為BLT accelerator。

下面看一下Android平臺(tái)下畫(huà)屏的操作流程。

1、 通過(guò)mapFrameBuffer直接把用戶(hù)空間的數(shù)據(jù)映射到顯存中。

2、 調(diào)用HAL中的stretch函數(shù)直接命令MSM設(shè)備提取顯存數(shù)據(jù)然后送入MDP PPP進(jìn)行處理并經(jīng)MDDI接口送到外圍LCD組件。

具體的函數(shù)調(diào)用流程如下:

copybit_open();//打開(kāi)BlitEngine,同時(shí)也打開(kāi)fb設(shè)備

mapFrameBuffer();//設(shè)置顯示參數(shù),同時(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架構(gòu)分析(六)

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

介紹

Note:

本部分介紹的完全是用戶(hù)空間顯示部分的架構(gòu),與kernel并沒(méi)有直接的聯(lián)系,主要是JNI以下到HAL以上的部分。

、Surface manager(surface flinger)簡(jiǎn)介

Surface manager是用戶(hù)空間中framework下libraries中負(fù)責(zé)顯示相關(guān)的一個(gè)模塊。如下:

當(dāng)系統(tǒng)同時(shí)執(zhí)行多個(gè)應(yīng)用程序時(shí),Surface Manager會(huì)負(fù)責(zé)管理顯示與存取操作間的互動(dòng),另外也負(fù)責(zé)將2D繪圖與3D繪圖進(jìn)行顯示上的合成。

    surface manager 可以準(zhǔn)備一塊 surface(可以看作一個(gè)layer),把 surface 的 fd (一塊內(nèi)存) 傳給一個(gè) app,讓 app 可以在上面作畫(huà)。典型應(yīng)用如下:

 

2架構(gòu)分析

Android中的圖形系統(tǒng)采用Client/Server架構(gòu),如下:

Client:應(yīng)用程序相關(guān)部分。代碼分為兩部分,一部分是由Java提供的供應(yīng)用使用的api,另一部分則是由c++寫(xiě)成的底層實(shí)現(xiàn)。

Server:即SurfaceFlinger,負(fù)責(zé)合成并送入buffer顯示。其主要由c++代碼編寫(xiě)而成。

Client和Server之前通過(guò)Binder的IPC方式進(jìn)行通信,總體結(jié)構(gòu)圖如下:

如上圖所示,Surface的client部分其實(shí)是提供給各應(yīng)用程序進(jìn)行畫(huà)圖操作的一個(gè)橋梁,該橋梁通過(guò)binder通向server端的Surfaceflinger,Surfaceflinger負(fù)責(zé)合成各個(gè)surface,然后把buffer傳送到framebuffer端進(jìn)行底層顯示。其中每個(gè)surface對(duì)應(yīng)2個(gè)buffer,一個(gè)front buffer, 一個(gè)back buffer,更新時(shí),數(shù)據(jù)更新在backbuffer上,需要顯示時(shí),則將back buffer和front buffer互換。

下一部分我們重點(diǎn)研究一下Surfaceflinger。

Android display架構(gòu)分析(七-1

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

流程分析
根據(jù)前面的介紹,surfaceflinger作為一個(gè)server process,上層的應(yīng)用程序(作為client)通過(guò)Binder方式與其進(jìn)行通信。Surfaceflinger作為一個(gè)thread,這里把它分為3個(gè)部分,如下:

1、 Thread本身處理部分,包括初始化以及thread loop。

2、 Binder部分,負(fù)責(zé)接收上層應(yīng)用的各個(gè)設(shè)置和命令,并反饋狀態(tài)標(biāo)志給上層。

3、 與底層的交互,負(fù)責(zé)調(diào)用底層接口(HAL)。

結(jié)構(gòu)圖如下:

注釋?zhuān)?/p>

a、 Binder接收到應(yīng)用程序的命令(如創(chuàng)建surface、設(shè)置參數(shù)等),傳遞給flinger。

b、 Flinger完成對(duì)應(yīng)命令后將相關(guān)結(jié)果狀態(tài)反饋給上層。

c、 在處理上層命令過(guò)程中,根據(jù)需要設(shè)置event(主要和顯示有關(guān)),通知Thread Loop進(jìn)行處理。

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

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

f、 DisplayHardware層根據(jù)flinger命令調(diào)用HAL進(jìn)行HW的操作。

下面來(lái)具體分析一些SurfaceFlinger中重要的處理函數(shù)以及surface、Layer的屬性

1)、readToRun

SurfaceFlinger thread的初始化函數(shù),主要任務(wù)是分配內(nèi)存和設(shè)置底層接口(EGL&HAL)。

status_t SurfaceFlinger::readyToRun()

mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);//為IPC分配共享內(nèi)存

mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);//為flinger分配heap,大小為8M,存放具體的顯示數(shù)據(jù)

{

// initialize the main display

GraphicPlane& plane(graphicPlane(dpy));

DisplayHardware* const hw = new DisplayHardware(this, dpy);

plane.setDisplayHardware(hw);//保存顯示接口

}

//獲取顯示相關(guān)參數(shù)

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函數(shù),主要是等待其他接口發(fā)送的event,進(jìn)行顯示數(shù)據(jù)的合成以及顯示。

bool SurfaceFlinger::threadLoop()

{

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

// post surfaces (if needed)

handlePageFlip();//處理翻頁(yè)機(jī)制

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

if (LIKELY(hw.canDraw()))

{

// repaint the framebuffer (if needed)

handleRepaint();//合并所有l(wèi)ayer并填充到buffer中去

postFramebuffer();//互換front buffer和back buffer,調(diào)用EGL接口進(jìn)行顯示

}

}

3)、createSurface

提供給應(yīng)用程序的主要接口,該接口可以創(chuàng)建一個(gè)surface,底層會(huì)根據(jù)參數(shù)創(chuàng)建layer以及分配內(nèi)存,surface相關(guān)參數(shù)會(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,根據(jù)參數(shù)(寬高格式)分配內(nèi)存(共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參數(shù)反饋給應(yīng)用層

}

待續(xù)。。。

Android display架構(gòu)分析(七-2

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

4)、setClientState

處理上層的各個(gè)命令,并根據(jù)flag設(shè)置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;

      // 檢測(cè)應(yīng)用層是否設(shè)置各個(gè)標(biāo)志,如果有則通知底層完成對(duì)應(yīng)操作,并通知ThreadLoop做對(duì)應(yīng)的處理

   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))//設(shè)置寬高變化

flags |= eTraversalNeeded;

}

if (what & eAlphaChanged) {//設(shè)置Alpha效果

if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))

                  flags |= eTraversalNeeded;

}

if (what & eMatrixChanged) {//矩陣參數(shù)變化

if (layer->setMatrix(s.matrix))

flags |= eTraversalNeeded;

}

if (what & eTransparentRegionChanged) {//顯示區(qū)域變化

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中被調(diào)用,負(fù)責(zé)將所有存在的surface進(jìn)行合并,OpenGl模塊負(fù)責(zé)這個(gè)部分。

6)、postFramebuffer

該接口在Threadloop中被調(diào)用,負(fù)責(zé)將合成好的數(shù)據(jù)(存于back buffer中)推入在front buffer中,然后調(diào)用HAL接口命令底層顯示。

7)、從3中可知,上層每創(chuàng)建一個(gè)surface的時(shí)候,底層都會(huì)同時(shí)創(chuàng)建一個(gè)layer,下面看一下surface及l(fā)ayer的相關(guān)屬性。

Notecode中相關(guān)結(jié)構(gòu)體太大,就不全部羅列出來(lái)了

   ASurface相關(guān)屬性(詳細(xì)參考文件surface.h

       a1SurfaceID根據(jù)此ID把相關(guān)surface和layer對(duì)應(yīng)起來(lái)

      a2SurfaceInfo

包括寬高格式等信息

a32個(gè)buffer指針、buffer索引等信息

   BLayer相關(guān)屬性(詳細(xì)參考文件layer.h/layerbase.h/layerbitmap.h

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

Android display架構(gòu)分析(八)

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

開(kāi)發(fā)的經(jīng)驗(yàn)分享

1Display Driver的工作內(nèi)容

參考上面linux下fb設(shè)備的軟件架構(gòu),可以知道,要加入一個(gè)新的MDDI接口的LCM,Driver的工作就是要提供自己的mddi_xxxx.c(在這次porting的過(guò)程中,為了節(jié)省時(shí)間,我們直接修改了mddi_toshiba.c),并且完成和這個(gè)lcd相關(guān)的HWr的初始化。主要的工作包括:

A、初始化和LCD / LCD背光相關(guān)的IO以及電源;

B、編寫(xiě)初始化函數(shù) 。主要是初始化LCD控制器,這個(gè)一般LCD廠(chǎng)商會(huì)提供;然后分配顯存,這個(gè)高通release過(guò)來(lái)的code已經(jīng)包含這個(gè)動(dòng)作了,最后是初始化一個(gè)fb_info的結(jié)構(gòu)體,在這里主要是把LCD的一些信息登記進(jìn)來(lái)。

C、把LCD的設(shè)備以及驅(qū)動(dòng)注冊(cè)到系統(tǒng)中去。(這里因?yàn)槭翘鎿Q現(xiàn)有的驅(qū)動(dòng),所以相關(guān)修改的部分不多。)

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

開(kāi)發(fā)過(guò)程
1.2.1配置Power和IO

更改一些GPIO的配置以及一些電源的電平配置;然后通過(guò)實(shí)際測(cè)量,確保一下信號(hào)正常:

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

B、MDDI Bridge以及LCD reset信號(hào);

C、控制背光IC的GPIO工作正常(背光不打開(kāi),無(wú)法調(diào)試LCD)。

1.2.2Porting LCD初始化序列

LCD init的code以及外圍MDDI Bridge的初始化code,都可以之前Boston WindowsMobile系統(tǒng)的codebase中獲得;把這部分code移植到mddi_Toshiba.c中,并更改相應(yīng)的圖像格式、分辨率等配置,編譯通過(guò)。LCD初始化部分就算基本完成。

1.2.3LCD初始化過(guò)程的調(diào)試

由于硬件在之前Boston load是可以工作的,可以認(rèn)為硬件連接等沒(méi)有問(wèn)題,所以只需關(guān)注軟件部分就行。

Display部分軟件調(diào)試過(guò)程如下:

A、 開(kāi)機(jī)后,量一下GPIO是否為code中配置預(yù)期的狀態(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中的初始化函數(shù)是否在開(kāi)機(jī)的時(shí)候有被調(diào)用過(guò)。

目前版本中,是根據(jù)外圍MDDIBridge中讀到的的廠(chǎng)商號(hào)來(lái)決定加載哪個(gè)驅(qū)動(dòng)模塊的。在本次調(diào)試中,bootloader中可以正確讀到廠(chǎng)商號(hào),所以bootloader中對(duì)于LCD的初始化是有做的,所以屏幕看到的狀態(tài)就是LCD初始化后的樣子(花屏)。但Kernel起來(lái)后,并沒(méi)有其他顯示,用JTAG跟了后發(fā)現(xiàn),Kernel中MODULEINIT中讀不到正確的廠(chǎng)商號(hào),所以說(shuō)后面的driver沒(méi)有被加載。接著發(fā)現(xiàn)如果在bootloader中如果不做MDDIBridge的初始化,的話(huà)后面的MODULE INIT就可正常運(yùn)行,該問(wèn)題目前還沒(méi)有澄清(現(xiàn)在暫時(shí)先把bootloader中的initdisable掉)。

1.2.4LCD的調(diào)整

初始化正常后,屏幕會(huì)顯示UI的相關(guān)畫(huà)面,但明顯顏色、位置都不對(duì)。

這個(gè)可能是數(shù)據(jù)類(lèi)型配置不對(duì)導(dǎo)致的,即MDP輸出的類(lèi)型、MDDI配置的類(lèi)型以、LCD接收的類(lèi)型不匹配導(dǎo)致,也有可能是RGB的順序不對(duì)導(dǎo)致(可配置成BGR)。經(jīng)過(guò)調(diào)試后,把MDP端輸出的格式配置成RGB565,同時(shí)外圍MDDIBridge以及LCD的input格式也配置成RGB565,這時(shí)顯示色彩正常了。

如果位置或者方向不對(duì),比如說(shuō)上下或是左右顛倒,可以更改LCD的配置中的掃描方向即可。

1.2.5其他

后續(xù)發(fā)現(xiàn)一個(gè)問(wèn)題,播放video的時(shí)候顏色都是黑白的。

這個(gè)問(wèn)題很容易讓人誤解,按照正常的理解,videodecode出來(lái)的數(shù)據(jù)為YCbCr,Y為亮度信號(hào),CbCr為色差信號(hào),如果只有Y信號(hào)的話(huà)顏色應(yīng)該就是黑白的。所以有2個(gè)懷疑點(diǎn),一個(gè)是decode出來(lái)的數(shù)據(jù)有誤,另一個(gè)是MDDIBridge誤把輸入的YcbCr信號(hào)當(dāng)作RGB信號(hào)進(jìn)行出來(lái),這個(gè)也是有可能的。但很快第二個(gè)懷疑點(diǎn)被排除了(因?yàn)閱胃腗DDIinput格式后還是不能解決問(wèn)題)。

后來(lái)又詳細(xì)的看了顯示部分的代碼,并用JTAG追蹤video播放的時(shí)候用的顯示接口,發(fā)現(xiàn)目前所有的顯示接口輸出的格式都是RGB格式,也就是說(shuō)在通過(guò)MDP之前YcbCr已經(jīng)被轉(zhuǎn)化過(guò);而MDP里的轉(zhuǎn)換功能并沒(méi)有使用,MDP只是被當(dāng)作一個(gè)DMA完成數(shù)據(jù)的直接傳輸,文檔中叫做Bypasse。

YcbCr到RGB的轉(zhuǎn)換是由Android的lib來(lái)完成。發(fā)了個(gè)SR給高通,高通的回復(fù)也確認(rèn)了,在6.3.50中,Android上層缺少這個(gè)lib(copybit.default.so),6.3.60之后的版本經(jīng)解決了這個(gè)問(wèn)題。

高通Android平臺(tái)下關(guān)于display部分的幾個(gè)關(guān)鍵問(wèn)題

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

顯示部分的幾個(gè)問(wèn)題這幾天通過(guò)實(shí)際測(cè)試澄清了一下,主要是下圖中各個(gè)模塊的使用狀況以及HAL層幾個(gè)模塊的調(diào)用流程。以問(wèn)題的方式描述如下:

1、 Ap是怎么進(jìn)行顯示的?

Surfaceflinger負(fù)責(zé)所有上層的顯示處理,對(duì)于AP(2D或是3D的應(yīng)用程序)而言,只要到surfaceflinger中創(chuàng)建surface,設(shè)置好參數(shù),接下來(lái)都是統(tǒng)一交給surfaceflinger進(jìn)行處理

2、 Surface是怎么管理多個(gè)surface的?

不管有多少個(gè)surface,最終送到顯示部分的只能是屏幕大小數(shù)據(jù),surfaceflinger中利用MDP或是GPU進(jìn)行多個(gè)surface的合成處理,普通的合成MDP就可完成,但如果是復(fù)雜的比如3D的應(yīng)用等就必須使用GPU,最終合成的好數(shù)據(jù)會(huì)被送到framebuffer中。

3、 Framebuffer是什么?

Framebuffer是Linux中為顯示數(shù)據(jù)分配的一塊顯存(fb設(shè)備中),通常大小是一整個(gè)屏幕數(shù)據(jù)的兩倍,對(duì)于上層AP而言,只需要將要顯示的數(shù)據(jù)丟到framebuffer中就OK了,但此時(shí)顯示數(shù)據(jù)并未真正的被送到LCD上,而是暫存在framebuffer中而已。

4、 上層是通過(guò)什么方式將顯示內(nèi)容送到framebuffer的?

有2個(gè)方式(二選一,不會(huì)同時(shí)在運(yùn)行):

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

Surfaceflinger通過(guò)copybit將要顯示的數(shù)據(jù)送到framebuffer。

Note:copybit可以看做是MDP PPP的接口,它提供了MDP的功能,如多個(gè)layer合成,scale、rotate等。

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

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

當(dāng)進(jìn)行復(fù)雜的顯示處理時(shí),比如3D的應(yīng)用,GPU把處理好的數(shù)據(jù)直接丟到framebuffer中,和MDP沒(méi)有任何關(guān)系

5、 Framebuffer中的數(shù)據(jù)是如何被送到LCD顯示的?

圖中的Gralloc完成的。

Gralloc有2個(gè)功能:

一個(gè)是和copybit相同的,里面有MDP PPP的接口(目前沒(méi)有使用)

另一個(gè)則是刷屏(整屏刷)的接口,即將framebuffer中的數(shù)據(jù)送到lcd上,調(diào)用的是MDP DMA的接口

這部分的code在android\hardware\msm7k\libgralloc-qsd8k目錄下,之前沒(méi)有留意,以為沒(méi)有使用。現(xiàn)在可以看出開(kāi)機(jī)初始化后就創(chuàng)建了disp_loop thread,里面的操作就是調(diào)用系統(tǒng)接口

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

將數(shù)據(jù)送到lcd

Note:送數(shù)據(jù)的時(shí)候是2個(gè)buffer切換的

另外,上層surfaceflinger也是通過(guò)Gralloc中的接口獲知屏幕的大小,調(diào)用接口為

ioctl(fd, FBIOGET_VSCREENINFO, &info),info中的屏幕寬高對(duì)應(yīng)的就是底層driver設(shè)置的寬高值

6、 OpenGL是什么?

它是一個(gè)圖像處理引擎,當(dāng)需要一些復(fù)雜的顯示(2D/3D)操作時(shí)會(huì)用到它。它分為SW方案和HW方案,軟件方案就是圖中的libagl.so,對(duì)應(yīng)到目前項(xiàng)目中是libGLES_android.so,它可以完成簡(jiǎn)單的2D(文字,icon等)處理,通過(guò)trace看目前大部分顯示操作都是它來(lái)完成的。

Note:它是軟件方案,處理好的數(shù)據(jù)是通過(guò)copybit送到framebuffer的,而不是GPU。

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

HW方案就是圖中的Graphics driver,它通過(guò)使用GPU硬件來(lái)完成圖像處理,處理后的數(shù)據(jù)直接送到framebuffer中。其接口部分參考:android\frameworks\base\opengl\libs(有幾個(gè)版本)

7、 OpenGL在項(xiàng)目中是如何配置的?

在android\vendor\qcom\msm7627_ffa目錄下有一個(gè)egl.cfg文件,里面指定了當(dāng)前版本中的OpenGL信息,目前如下:

0 0 android

0 1 adreno200

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

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

如果該cfg文件為空,則只支持default的SW方案。

如果2個(gè)方案都在,上層將根據(jù)實(shí)際應(yīng)用自行選擇使用其一。

該部分請(qǐng)參考:android\frameworks\base\opengl\libs\EGL\loader.cpp

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Android中的FrameBuffer
LCD驅(qū)動(dòng)及Framebuffer相關(guān)
adroid WiFi/LCD/Camera 調(diào)試總結(jié)
Android上HDMI介紹(基于高通平臺(tái))
高通8x25平臺(tái)display模塊總結(jié)
Android圖形架構(gòu)實(shí)現(xiàn)分析總結(jié)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服