介紹了Android SurfaceFlinger層次如下的圖形合成和顯示系統,主要基於高通MSM8k MDP4x平臺。前端
作爲Android Display專題。SurfaceFlinger的詳細介紹參見連接文章。node
Android GDI之SurfaceFlingerlinux
SurfaceFinger按英文翻譯過來就是Surface投遞者。SufaceFlinger的構成並非太複雜,複雜的是他的客戶端建構。SufaceFlinger主要功能是:android
1)將Layers(Surfaces)內容的刷新到屏幕上編程
2)維持Layer的Zorder序列,並對Layer最終輸出作出裁剪計算。後端
3)響應Client要求,建立Layer與客戶端的Surface創建鏈接數組
4)接收Client要求,修改Layer屬性(輸出大小,Alpha等設定)緩存
可是做爲投遞者的實際意義,咱們首先須要知道的是如何投遞,投擲物,投遞路線,投遞目的地。數據結構
1 SurfaceFlinger的基本組成框架架構
SurfaceFlinger管理對象爲:
mClientsMap:管理客戶端與服務端的鏈接。
ISurface,IsurfaceComposer:AIDL調用接口實例
mLayerMap:服務端的Surface的管理對象。
mCurrentState.layersSortedByZ:以Surface的Z-order序列排列的Layer數組。
graphicPlane緩衝區輸出管理
OpenGL ES:圖形計算,圖像合成等圖形庫。
gralloc.xxx.so這是個跟平臺相關的圖形緩衝區管理器。
pmem Device:提供共享內存,在這裏只是在gralloc.xxx.so可見,在上層被gralloc.xxx.so抽象了。
2 SurfaceFinger Client和服務端對象關係圖
Client端與SurfaceFlinger鏈接圖:
Client對象:通常的在客戶端都是經過SurfaceComposerClient來跟SurfaceFlinger打交道。
3主要對象說明
3.1 DisplayHardware &FrameBuffer
首先SurfaceFlinger須要操做到屏幕,須要創建一個屏幕硬件緩衝區管理框架。Android在設計支持時,考慮多個屏幕的狀況,引入了graphicPlane的概念。在SurfaceFlinger上有一個graphicPlane數組,每個graphicPlane對象都對應一個DisplayHardware.在當前的Android(2.1)版本的設計中,系統支持一個graphicPlane,因此也就支持一個DisplayHardware。
SurfaceFlinger,Hardware硬件緩衝區的數據結構關係圖。
3.2 Layer
method:setBuffer在SurfaceFlinger端創建顯示緩衝區。這裏的緩衝區是指的HW性質的,PMEM設備文件映射的內存。
1) layer的繪製
void Layer::onDraw(const Region& clip) const
{
int index = mFrontBufferIndex;
GLuint textureName = mTextures[index].name;
…
drawWithOpenGL(clip, mTextures[index]);
}
3.2 mCurrentState.layersSortedByZ
以Surface的Z-order序列排列的LayerBase數組,該數組是層顯示遮擋的依據。在每一個層計算本身的可見區域時,從Z-order頂層開始計算,是考慮到遮擋區域的裁減,本身以前層的可見區域就是本身的不可見區域。而繪製Layer時,則從Z-order底層開始繪製,這個考慮到透明層的疊加。
4 SurfaceFlinger的運行框架
咱們從前面的章節<Android Service>的基本原理能夠知道,SurfaceFlinger的運行框架存在於:threadLoop,他是SurfaceFlinger的主循環體。SurfaceFlinger在進入主體循環以前會首先運行:SurfaceFlinger::readyToRun()。
4.1 SurfaceFlinger::readyToRun()
(1)創建GraphicPanle
(2)創建FrameBufferHardware(肯定輸出目標)
初始化:OpenGL ES
創建兼容的mainSurface.利用eglCreateWindowSurface。
創建OpenGL ES進程上下文。
創建主Surface(OpenGL ES)。 DisplayHardware的Init()@DisplayHardware.cpp函數對OpenGL作了初始化,並建立立主Surface。爲何叫主Surface,由於全部的Layer在繪製時,都須要先繪製在這個主Surface上,最後系統纔將主Surface的內容」投擲」到真正的屏幕上。
(3)主Surface的綁定
1)在DisplayHandware初始完畢後,hw.makeCurrent()將主Surface,OpenGL ES進程上下文綁定到SurfaceFlinger的上下文中,
2)以後全部的SurfaceFlinger進程中使用EGL的全部的操做目的地都是mSurface@DisplayHardware。
這樣,在OpenGL繪製圖形時,主Surface被記錄在進程的上下文中,因此看不到顯示的主Surfce相關參數的傳遞。下面是Layer-Draw,Hardware.flip的動做示意圖:
4.2 ThreadLoop
(1)handleTransaction(…):主要計算每一個Layer有無屬性修改,若是有修改着內用須要重畫。
(2)handlePageFlip()
computeVisibleRegions:根據Z-Order序列計算每一個Layer的可見區域和被覆蓋區域。裁剪輸出範圍計算-
在生成裁剪區域的時候,根據Z_order依次,每一個Layer在計算本身在屏幕的可顯示區域時,須要經歷以下步驟:
1)以本身的W,H給出本身初始的可見區域
2)減去本身上面窗口所覆蓋的區域
在繪製時,Layer將根據本身的可將區域作相應的區域數據Copy。
(3)handleRepaint()
composeSurfaces(須要刷新區域):
根據每一個Layer的可見區域與須要刷新區域的交集區域從Z-Order序列從底部開始繪製到主Surface上。
(4)postFramebuffer()
(DisplayHardware)hw.flip(mInvalidRegion);
eglSwapBuffers(display,mSurface) :將mSruface投遞到屏幕。
5總結
如今SurfaceFlinger乾的事情利用下面的示意圖表示出來:
更詳細地,參考
Android GUI之SurfaceFlinger系列
Android display架構分析-SW架構分析(1-8)
SurfaceFlinger使用的各組件,參考
Learning about Android Graphics Subsystem by MIPS Engineer
*******************************************************************************
Copybit HAL Introduction
SurfaceFlinger layer的compositionType有三種:
HWC_FRAMEBUFFER的使用OpenGL ES來繪製;
HWC_OVERLAY的使用Overlay Engine來合成;
HWC_USE_COPYBIT的使用Copybit硬件加速繪製;
MSM8xxx平臺Jellybean代碼中沒有發現使用HWC_USE_COPYBIT的layer,該平臺下 Copybit 硬件加速主要有兩種:
PPP :vpe模塊的PPP,direct copy;
C2D :多是2D GPU OpenVG之類的。
PPP驅動實現是作爲Framebuffer設備的一個命令MSMFB_BLIT,C2D是使用c2d hal庫;
MSM7627平臺下hwcomposer仍是使用copybit的。
可能早期系統沒有Hardware Composer,又沒有GPU的時候,layer draw就要使用Copybit去一層一層一Rect一Rect的拷貝了。
Copybit的代碼在display/libcopybit下,硬件合成器使用Copybit作的封裝代碼在display/libhwcomposer/copybit和copybit_c2d中,前者對應PPP,後者對應C2D。
*******************************************************************************
主要介紹Gralloc/Framebuffer HAL設備,能夠籍此考察顯示Buffer(Ashmem、Pmem)的擁有者和傳遞。
平臺中內存有ashmen、PMEM等多種內存類型,爲了Video、Graphics、GPU內存訪問的須要,android引入Gralloc模塊實現內存的管理。Gralloc把FrameBuffer的分配也歸入了其中,而且新引入ION作爲Gralloc的非FrameBuffer內存的分配器。ION對於內核態內存在用戶進程之間的訪問和硬件平臺模塊之間數據流轉提供了高效的解決方案。
Android中 lcd 是一個幀緩衝設備,驅動程序經過處理器的 lcd控制器將物理內存的一段區域設置爲顯存,若是向這段內存區域寫入數據就會立刻在 lcd上顯示出來。Android在 HAL 中提供了gralloc模塊,封裝了用戶層對幀緩衝設備的全部操做接口,並經過 SurfaceFlinger服務嚮應用提供顯示支持。在啓動過程當中系統會加載 gralloc模塊,而後打開幀緩衝設備,獲取設備的各類參數並完成 gralloc模塊的初始化。當應用程序須要把內容顯示到 lcd上時,須要經過 gralloc模塊申請一塊圖形緩衝區,而後將這塊圖形緩衝區映射到本身的地址空間並寫入內容便可。當應用程序再也不須要這塊圖形緩衝區時須要經過 gralloc模塊釋放掉,而後解除對緩衝區的映射。
1、基礎數據結構
gralloc模塊經過 struct private_module_t來描述,該結構定義以下:
1. struct private_module_t {
2. gralloc_module_t base;
3.
4. private_handle_t* framebuffer; /* 指向圖形緩衝區的句柄 */
5. uint32_t flags; /* 用來標誌系統幀緩衝區是否支持雙緩衝 */
6. uint32_t numBuffers; /* 表示系統幀緩衝的個數 */
7. uint32_t bufferMask; /* 記錄系統幀緩衝的使用狀況 */
8. pthread_mutex_t lock; /* 保護結構體private_module_t的並行訪問 */
9. buffer_handle_t currentBuffer; /* 描述當前正在被渲染的圖形緩衝區 */
10. int pmem_master; /* pmem設備節點的描述符 */
11. void* pmem_master_base; /* pmem的起始虛擬地址 */
12.
13. struct fb_var_screeninfo info; /* lcd的可變參數 */
14. struct fb_fix_screeninfo finfo; /* lcd的固定參數 */
15. float xdpi; /* x方向上每英寸的像素數量 */
16. float ydpi; /* y方向上每英寸的像素數量 */
17. float fps; /* lcd的刷新率 */
18.
19. int orientation; /* 顯示方向 */
20.
21. enum {
22. PRIV_USAGE_LOCKED_FOR_POST = 0x80000000 /* flag to indicate we'll post this buffer */
23. };
24. };
該結構的成員記錄了 gralloc模塊的各類參數,主要爲模塊本身使用,應用程序操做的圖形緩衝區的數據結構是struct private_handle_t,定義如下:
1. >#ifdef __cplusplus
2. struct private_handle_t : public native_handle {
3. #else
4. struct private_handle_t {
5. struct native_handle nativeHandle; /* 用來描述一個本地句柄值 */
6. #endif
7.
8. enum {
9. PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
10. PRIV_FLAGS_USES_PMEM = 0x00000002,
11. PRIV_FLAGS_USES_MMEM = 0x00000004,
12. PRIV_FLAGS_NEEDS_FLUSH = 0x00000008,
13. };
14.
15. enum {
16. LOCK_STATE_WRITE = 1<<31,
17. LOCK_STATE_MAPPED = 1<<30,
18. LOCK_STATE_READ_MASK = 0x3FFFFFFF
19. };
20.
21. /* 指向一個文件描述符,這個文件描述符要麼指向幀緩衝區設備,要麼指向一塊匿名共享內存
22. * 取決於private_handle_t描述的圖形緩衝區是在幀緩衝區分配的,仍是在內存中分配的 */
23. int fd;
24. /* 指向一個魔數,它的值由靜態成員變量sMagic來指定,用來標識一個private_handle_t結構體 */
25. int magic;
26. /* 用來描述一個圖形緩衝區的標誌,它的值要麼等於0,要麼等於PRIV_FLAGS_FRAMEBUFFER
27. * 當一個圖形緩衝區的標誌值等於PRIV_FLAGS_FRAMEBUFFER的時候,就表示它是在幀緩衝區中分配的 */
28. int flags;
29. int size; /* 描述一個圖形緩衝區的大小 */
30. int offset; /* 描述一個圖形緩衝區的偏移地址 */
31.
32. int phys; /* 圖形緩衝區或幀緩衝的起始物理地址 */
33. int base; /* 圖形緩衝區或幀緩衝的起始虛擬地址 */
34. int lockState;
35. int writeOwner;
36. int pid; /* 描述一個圖形緩衝區的建立者的PID */
37.
38. #ifdef __cplusplus
39. static const int sNumInts = 9; /* 有9個整數變量 */
40. static const int sNumFds = 1; /* 有1個文件描述符 */
41. static const int sMagic = 0x3141592;
42.
43. private_handle_t(int fd, int size, int flags) :
44. fd(fd), magic(sMagic), flags(flags), size(size), offset(0),
45. phys(0), base(0), lockState(0), writeOwner(0), pid(getpid())
46. {
47. version = sizeof(native_handle);
48. numInts = sNumInts;
49. numFds = sNumFds;
50. }
51. ~private_handle_t() {
52. magic = 0;
53. }
54.
55. bool usesPhysicallyContiguousMemory() {
56. return (flags & PRIV_FLAGS_USES_PMEM) != 0;
57. }
58.
59. /* 用來驗證一個native_handle_t指針是否指向了一個private_handle_t結構體 */
60. static int validate(const native_handle* h) {
61. const private_handle_t* hnd = (const private_handle_t*)h;
62. if (!h || h->version != sizeof(native_handle) ||
63. h->numInts != sNumInts || h->numFds != sNumFds ||
64. hnd->magic != sMagic)
65. {
66. LOGE("invalid gralloc handle (at %p)", h);
67. return -EINVAL;
68. }
69. return 0;
70. }
71.
72. static private_handle_t* dynamicCast(const native_handle* in) {
73. if (validate(in) == 0) {
74. return (private_handle_t*) in;
75. }
76. return NULL;
77. }
78. #endif
79. };
圖形緩衝區的操做接口由結構struct gralloc_module_t 定義:
80. typedef struct gralloc_module_t {
81. struct hw_module_t common;
82.
83. /* 註冊一個圖形緩衝區,這個指定的圖形緩衝區使用一個buffer_handle_t句柄來描述 */
84. int (*registerBuffer)(struct gralloc_module_t const* module,
85. buffer_handle_t handle);
86.
87. /* 註銷一個圖形緩衝區 */
88. int (*unregisterBuffer)(struct gralloc_module_t const* module,
89. buffer_handle_t handle);
90.
91. /* 用來鎖定一個圖形緩衝區並將緩衝區映射到用戶進程
92. * 在鎖定一塊圖形緩衝區的時候,能夠指定要鎖定的圖形繪衝區的位置以及大小
93. * 這是經過參數l、t、w和h來指定的,其中,參數l和t指定的是要訪問的圖形緩衝區的左上角位置
94. * 而參數w和h指定的是要訪問的圖形緩衝區的寬度和長度
95. * 鎖定以後,就能夠得到由參數參數l、t、w和h所圈定的一塊緩衝區的起始地址,保存在輸出參數vaddr中
96. * 另外一方面,在訪問完成一塊圖形緩衝區以後,須要解除這塊圖形緩衝區的鎖定 */
97. int (*lock)(struct gralloc_module_t const* module,
98. buffer_handle_t handle, int usage,
99. int l, int t, int w, int h,
100. void** vaddr);
101.
102. int (*unlock)(struct gralloc_module_t const* module,
103. buffer_handle_t handle);
104.
105. int (*perform)(struct gralloc_module_t const* module,
106. int operation, ... );
107.
108. /* reserved for future use */
109. void* reserved_proc[7];
110.} gralloc_module_t;
gralloc設備則用結構 struct alloc_device_t來描述,其定義以下:
111.typedef struct alloc_device_t {
112. struct hw_device_t common;
113.
114. /* 申請圖形緩衝區的內存空間 */
115. int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);
116.
117. /* 釋放圖形緩衝區的內存空間 */
118. int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);
119.} alloc_device_t;
幀緩衝設備則採用結構 struct framebuffer_device_t描述:
120.typedef struct framebuffer_device_t {
121. struct hw_device_t common;
122.
123. const uint32_t flags; /* 用來記錄系統幀緩衝區的標誌 */
124.
125. const uint32_t width; /* lcd顯示區域的像素點數 */
126. const uint32_t height;
127.
128. const int stride; /* 描述設備顯示屏的一行有多少個像素點 */
129.
130. /* 描述系統幀緩衝區的像素格式,主要有HAL_PIXEL_FORMAT_RGBX_8888和HAL_PIXEL_FORMAT_RGB_565兩種 */
131. const int format;
132.
133. const float xdpi;
134. const float ydpi;
135. const float fps; /* lcd刷新率 */
136. const int minSwapInterval; /* 交換兩幀圖像的最小間隔時間 */
137. const int maxSwapInterval; /* 交換兩幀圖像的最大間隔時間 */
138.
139. int reserved[8];
140.
141. /* 設置幀交換間隔 */
142. int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);
143.
144. /* 設置幀緩衝區的更新區域 */
145. int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);
146.
147. /* 用來將圖形緩衝區buffer的內容渲染到幀緩衝區中去,即顯示在設備的顯示屏中去 */
148. int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
149.
150. /* 用來通知fb設備device,圖形緩衝區的組合工做已經完成 */
151. int (*compositionComplete)(struct framebuffer_device_t* dev);
152.
153. void* reserved_proc[8];
154. } framebuffer_device_t;
其中成員函數 post對應用程序來講是最重要的接口,它將完成數據寫入顯存的工做:
2、gralloc模塊
HAL中經過 hw_get_module接口加載指定 id的模塊,並得到一個 hw_module_t結構來打開設備,流程以下:
1. >#define HAL_LIBRARY_PATH1 "/system/lib/hw"
2. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
3.
4. static const char *variant_keys[] = {
5. "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */
6. "ro.product.board",
7. "ro.board.platform",
8. "ro.arch"
9. };
10.
11. static const int HAL_VARIANT_KEYS_COUNT =
12. (sizeof(variant_keys)/sizeof(variant_keys[0]));
13.
14. int hw_get_module(const char *id, const struct hw_module_t **module)
15. {
16. int status;
17. int i;
18. const struct hw_module_t *hmi = NULL;
19. char prop[PATH_MAX];
20. char path[PATH_MAX];
21.
22. /*
23. * Here we rely on the fact that calling dlopen multiple times on
24. * the same .so will simply increment a refcount (and not load
25. * a new copy of the library).
26. * We also assume that dlopen() is thread-safe.
27. */
28.
29. /* Loop through the configuration variants looking for a module */
30. for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
31. if (i < HAL_VARIANT_KEYS_COUNT) {
32. if (property_get(variant_keys[i], prop, NULL) == 0) { /* 讀取variant_keys數組指定的屬性值 */
33. continue;
34. }
35. snprintf(path, sizeof(path), "%s/%s.%s.so", /* 格式化模塊名和路徑,如:/system/lib/hw/gralloc.xxx.so */
36. HAL_LIBRARY_PATH1, id, prop);
37. if (access(path, R_OK) == 0) break;
38.
39. snprintf(path, sizeof(path), "%s/%s.%s.so",
40. HAL_LIBRARY_PATH2, id, prop);
41. if (access(path, R_OK) == 0) break;
42. } else {
43. snprintf(path, sizeof(path), "%s/%s.default.so",
44. HAL_LIBRARY_PATH1, id);
45. if (access(path, R_OK) == 0) break;
46. }
47. }
48.
49. status = -ENOENT;
50. if (i < HAL_VARIANT_KEYS_COUNT+1) {
51. /* load the module, if this fails, we're doomed, and we should not try to load a different variant. */
52. status = load(id, path, module); /* 加載模塊 */
53. }
54.
55. return status;
56. }
能夠看出,是使用id和系統平臺的名字組合出so的文件名,去設定的目錄動態加載該庫文件而後解析特定符號,找到hw_module_t object。函數會在 /system/lib/hw或者 /vendor/lib/hw目錄中去尋找gralloc.xxx.so文件,若是找到了就調用load接口完成加載。最終會調用 gralloc_device_open完成 gralloc 設備成員的初始化:
1. int gralloc_device_open(const hw_module_t* module, const char* name,
2. hw_device_t** device)
3. {
4. 98 int status = -EINVAL;
5. 99 if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
6. 100 const private_module_t* m = reinterpret_cast<const private_module_t*>(
7. 101 module);
8. 102 gpu_context_t *dev;
9. 103 IAllocController* alloc_ctrl = IAllocController::getInstance();
10.104 dev = new gpu_context_t(m, alloc_ctrl);
11.105 *device = &dev->common;
12.106 status = 0;
13. } else {
14. status = fb_device_open(module, name, device);
15. }
16.
17. return status;
18. }
能夠認爲Gralloc module中有兩個設備gpu_alloc_device和fb_device,前者用於分配GPU0使用的內存和FB內存,GPU0內存管理使用ION allocator;後者用於獲取分配Framebuffer Info並操做fb。
在android系統中,全部的圖形緩衝區都是由SurfaceFlinger服務分配的,在系統幀緩衝區中分配的圖形緩衝區只在 SurfaceFlinger服務中使用,而在內存中分配的圖形緩衝區既能夠在 SurfaceFlinger服務中使用,也能夠在其它的應用程序中使用,當應用程序請求 SurfaceFlinger服務分配圖形緩衝區時會發生兩次映射:服務所在的進程首先會將申請到的緩衝區映射至服務的地址空間,而後應用程序使用這個圖形緩衝時再將其映射至應用程序的地址空間。分配函數的實現以下:
1. static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
2. {
3. private_module_t* m = reinterpret_cast<private_module_t*>(
4. dev->common.module);
5. pthread_mutex_lock(&m->lock);
6. int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
7. pthread_mutex_unlock(&m->lock);
8. return err;
9. }
10.
11. static int gralloc_alloc_buffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
12. {
13. 127 int err = 0;
14. 128 int flags = 0;
15. 129 size = roundUpToPageSize(size);
16. 130 alloc_data data;
17. 131 data.offset = 0;
18. 132 data.fd = -1;
19. 133 data.base = 0;
20. 134 data.size = size;
21. 135 if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)
22. 136 data.align = 8192;
23. 137 else
24. 138 data.align = getpagesize();
25. 139 data.pHandle = (unsigned int) pHandle;
26. 140 err = mAllocCtrl->allocate(data, usage);
27. 141
28. 142 if (!err) {
29. 143 /* allocate memory for enhancement data */
30. 144 alloc_data eData;
31. 145 eData.fd = -1;
32. 146 eData.base = 0;
33. 147 eData.offset = 0;
34. 148 eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
35. 149 eData.pHandle = data.pHandle;
36. 150 eData.align = getpagesize();
37. 151 int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
38. 152 int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);
39. 153 ALOGE_IF(eDataErr, "gralloc failed for eData err=%s", strerror(-err));
40. 154
41. 155 if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {
42. 156 flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
43. 157 }
44. 158
45. 159 if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
46. 160 flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
47. 161 //The EXTERNAL_BLOCK flag is always an add-on
48. 162 if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {
49. 163 flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
50. 164 }
51. 165 if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {
52. 166 flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;
53. 167 }
54. 168 }
55. 169
56. 170 flags |= data.allocType;
57. 171 int eBaseAddr = int(eData.base) + eData.offset;
58. 172 private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
59. 173 bufferType, format, width, height, eData.fd, eData.offset,
60. 174 eBaseAddr);
61. 175
62. 176 hnd->offset = data.offset;
63. 177 hnd->base = int(data.base) + data.offset;
64. 178 *pHandle = hnd;
65. 179 }
66. 180
67. 181 ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
68. 182
69. 183 return err;
70. 184}
71.
72. /*****************************************************************************/
73.
74. static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format, int usage,
75. buffer_handle_t* pHandle, int* pStride)
76. {
77. if (!pHandle || !pStride)
78. return -EINVAL;
79.
80. size_t size, stride;
81.
82. int align = 4;
83. int bpp = 0;
84. switch (format) { /* 一個像素點佔用的字節數 */
85. case HAL_PIXEL_FORMAT_RGBA_8888:
86. case HAL_PIXEL_FORMAT_RGBX_8888:
87. case HAL_PIXEL_FORMAT_BGRA_8888:
88. bpp = 4;
89. break;
90. case HAL_PIXEL_FORMAT_RGB_888:
91. bpp = 3;
92. break;
93. case HAL_PIXEL_FORMAT_RGB_565:
94. case HAL_PIXEL_FORMAT_RGBA_5551:
95. case HAL_PIXEL_FORMAT_RGBA_4444:
96. bpp = 2;
97. break;
98. default:
99. return -EINVAL;
100. }
101. size_t bpr = (w*bpp + (align-1)) & ~(align-1);
102. size = bpr * h;
103. stride = bpr / bpp;
104.
105. int err;
106. if (usage & GRALLOC_USAGE_HW_FB) {
107. err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); /* 在系統幀緩衝中分配圖形緩衝區 */
108. } else {
109. err = gralloc_alloc_buffer(dev, size, usage, pHandle); /* 在內存中分配圖形緩衝區 */
110. }
111.
112. if (err < 0) {
113. return err;
114. }
115.
116. *pStride = stride;
117. return 0;
118.}
3、gpu_alloc 模塊
gpu0內存即非HW_FB內存使用ION分配器進行分配,此文不作詳述。
4、fb模塊
gralloc_device_open中會根據傳遞的參數分別初始化兩個設備,定義以下:
1. >#define GRALLOC_HARDWARE_FB0 "fb0"
2. #define GRALLOC_HARDWARE_GPU0 "gpu0"
若是參數不是 "gpu0",那麼是"fb%u"的形式,則會調用fb_device_open 初始化 fb 設備,主要流程和打開 gralloc基本一致,在函數中會經過調用 mapFrameBuffer->mapFrameBufferLocked獲取幀緩存設備的參數並將其設備節點映射到用戶空間,流程以下(大體如此,msm8960平臺代碼有所變化,msm平臺上fb設備文件名是/dev/graphics/fb%u):
1. int mapFrameBufferLocked(struct private_module_t* module)
2. {
3. if (module->framebuffer) {
4. return 0;
5. }
6.
7. char const * const device_template[] = {
8. "/dev/graphics/fb%u",
9. "/dev/fb%u",
10. 0 };
11.
12. int fd = -1;
13. int i=0;
14. char name[64];
15.
16. while ((fd==-1) && device_template[i]) {
17. snprintf(name, 64, device_template[i], 0);
18. fd = open(name, O_RDWR, 0);
19. i++;
20. }
21. if (fd < 0)
22. return -errno;
23.
24. struct fb_fix_screeninfo finfo;
25. if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) /* 獲取幀緩衝的固定參數 */
26. return -errno;
27.
28. struct fb_var_screeninfo info;
29. if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) /* 獲取幀緩衝的可變參數 */
30. return -errno;
31.
32. info.reserved[0] = 0;
33. info.reserved[1] = 0;
34. info.reserved[2] = 0;
35. info.xoffset = 0;
36. info.yoffset = 0;
37. info.activate = FB_ACTIVATE_NOW;
38.
39. info.bits_per_pixel = 32;
40. info.red.offset = 16;
41. info.red.length = 8;
42. info.green.offset = 8;
43. info.green.length = 8;
44. info.blue.offset = 0;
45. info.blue.length = 8;
46. info.transp.offset = 24;
47. info.transp.length = 8;
48.
49. /*
50. * Request NUM_BUFFERS screens (at lest 2 for page flipping)
51. */
52. info.yres_virtual = info.yres * NUM_BUFFERS; /* 幀緩衝總長度 */
53.
54.
55. uint32_t flags = PAGE_FLIP; /* 支持緩衝交換 */
56. if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
57. info.yres_virtual = info.yres;
58. flags &= ~PAGE_FLIP;
59. LOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
60. }
61.
62. if (info.yres_virtual < info.yres * 2) {
63. /* we need at least 2 for page-flipping */
64. info.yres_virtual = info.yres;
65. flags &= ~PAGE_FLIP;
66. LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
67. info.yres_virtual, info.yres*2);
68. }
69.
70. if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
71. return -errno;
72.
73. int refreshRate = 1000000000000000LLU /
74. (
75. uint64_t( info.upper_margin + info.lower_margin + info.yres )
76. * ( info.left_margin + info.right_margin + info.xres )
77. * info.pixclock
78. ); /* 計算lcd刷新率 */
79.
80. if (refreshRate == 0) {
81. /* bleagh, bad info from the driver */
82. refreshRate = 60*1000; // 60 Hz
83. }
84.
85. if (int(info.width) <= 0 || int(info.height) <= 0) {
86. /* the driver doesn't return that information, default to 160 dpi */
87. info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
88. info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
89. }
90.
91. float xdpi = (info.xres * 25.4f) / info.width;
92. float ydpi = (info.yres * 25.4f) / info.height;
93. float fps = refreshRate / 1000.0f;
94.
95. LOGI( "using (fd=%d)\n"
96. "id = %s\n"
97. "xres = %d px\n"
98. "yres = %d px\n"
99. "xres_virtual = %d px\n"
100. "yres_virtual = %d px\n"
101. "bpp = %d\n"
102. "r = %2u:%u\n"
103. "g = %2u:%u\n"
104. "b = %2u:%u\n",
105. fd,
106. finfo.id,
107. info.xres,
108. info.yres,
109. info.xres_virtual,
110. info.yres_virtual,
111. info.bits_per_pixel,
112. info.red.offset, info.red.length,
113. info.green.offset, info.green.length,
114. info.blue.offset, info.blue.length
115. );
116.
117. LOGI( "width = %d mm (%f dpi)\n"
118. "height = %d mm (%f dpi)\n"
119. "refresh rate = %.2f Hz\n",
120. info.width, xdpi,
121. info.height, ydpi,
122. fps
123. );
124.
125. if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
126. return -errno;
127.
128. if (finfo.smem_len <= 0)
129. return -errno;
130.
131. module->flags = flags;
132. module->info = info;
133. module->finfo = finfo;
134. module->xdpi = xdpi;
135. module->ydpi = ydpi;
136. module->fps = fps;
137.
138. /*
139. * map the framebuffer
140. */
141.
142. int err;
143. size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual); /* 幀緩衝大小 */
144. module->framebuffer = new private_handle_t(dup(fd), fbSize,
145. private_handle_t::PRIV_FLAGS_USES_PMEM);
146.
147. module->numBuffers = info.yres_virtual / info.yres; /* 計算系統幀緩衝的個數 */
148. module->bufferMask = 0;
149.
150. void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); /* 將fb映射到用戶空間 */
151. if (vaddr == MAP_FAILED) {
152. LOGE("Error mapping the framebuffer (%s)", strerror(errno));
153. return -errno;
154. }
155. module->framebuffer->base = intptr_t(vaddr); /* 幀緩衝的起始虛擬地址 */
156. memset(vaddr, 0, fbSize);
157. return 0;
158.}
關於fb設備的打開和HW_FB內存的分配,是在FrameBufferNativeWindow的構造代碼中,能夠看到打開fb0設備獲取Framebuffer Info,而後使用gralloc爲該FrameBufferNativeWindow分配兩個HW_FB內存即Framebuffer,即每一個Window,double buffer。代碼以下:
1. 62/*
2. 63 * This implements the (main) framebuffer management. This class is used
3. 64 * mostly by SurfaceFlinger, but also by command line GL application.
4. 65 *
5. 66 * In fact this is an implementation of ANativeWindow on top of
6. 67 * the framebuffer.
7. 68 *
8. 69 * Currently it is pretty simple, it manages only two buffers (the front and
9. 70 * back buffer).
10. 71 *
11. 72 */
12. 73
13. 74FramebufferNativeWindow::FramebufferNativeWindow()
14. 75 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
15. 76{
16. 77 hw_module_t const* module;
17. 78 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
18. 79 int stride;
19. 80 int err;
20. 81 int i;
21. 82 err = framebuffer_open(module, &fbDev);
22. 83 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
23. 84
24. 85 err = gralloc_open(module, &grDev);
25. 86 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
26. 87
27. 88 // bail out if we can't initialize the modules
28. 89 if (!fbDev || !grDev)
29. 90 return;
30. 91
31. 92 mUpdateOnDemand = (fbDev->setUpdateRect != 0);
32. 93
33. 94 // initialize the buffer FIFO
34. 95 if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
35. 96 fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
36. 97 mNumBuffers = fbDev->numFramebuffers;
37. 98 } else {
38. 99 mNumBuffers = MIN_NUM_FRAME_BUFFERS;
39. 100 }
40. 101 mNumFreeBuffers = mNumBuffers;
41. 102 mBufferHead = mNumBuffers-1;
42. 103
43. 104 /*
44. 105 * This does not actually change the framebuffer format. It merely
45. 106 * fakes this format to surfaceflinger so that when it creates
46. 107 * framebuffer surfaces it will use this format. It's really a giant
47. 108 * HACK to allow interworking with buggy gralloc+GPU driver
48. 109 * implementations. You should *NEVER* need to set this for shipping
49. 110 * devices.
50. 111 */
51. 112#ifdef FRAMEBUFFER_FORCE_FORMAT
52. 113 *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
53. 114#endif
54. 115
55. 116 for (i = 0; i < mNumBuffers; i++)
56. 117 {
57. 118 buffers[i] = new NativeBuffer(
58. 119 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
59. 120 }
60. 121
61. 122 for (i = 0; i < mNumBuffers; i++)
62. 123 {
63. 124 err = grDev->alloc(grDev,
64. 125 fbDev->width, fbDev->height, fbDev->format,
65. 126 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
66. 127
67. 128 ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
68. 129 i, fbDev->width, fbDev->height, strerror(-err));
69. 130
70. 131 if (err)
71. 132 {
72. 133 mNumBuffers = i;
73. 134 mNumFreeBuffers = i;
74. 135 mBufferHead = mNumBuffers-1;
75. 136 break;
76. 137 }
77. 138 }
78. 139
79. 140 const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
80. 141 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
81. 142 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
82. 143 const_cast<int&>(ANativeWindow::minSwapInterval) =
83. 144 fbDev->minSwapInterval;
84. 145 const_cast<int&>(ANativeWindow::maxSwapInterval) =
85. 146 fbDev->maxSwapInterval;
86. 147 } else {
87. 148 ALOGE("Couldn't get gralloc module");
88. 149 }
89. 150
90. 151 ANativeWindow::setSwapInterval = setSwapInterval;
91. 152 ANativeWindow::dequeueBuffer = dequeueBuffer;
92. 153 ANativeWindow::lockBuffer = lockBuffer;
93. 154 ANativeWindow::queueBuffer = queueBuffer;
94. 155 ANativeWindow::query = query;
95. 156 ANativeWindow::perform = perform;
96. 157 ANativeWindow::cancelBuffer = NULL;
97. 158}
建立FrameBufferNativeWindow僅發生在DisplayHardware的構造後初始化中,代碼片斷以下:
1. 150void DisplayHardware::init(uint32_t dpy)
2. 151{
3. 152 mNativeWindow = new FramebufferNativeWindow(); //******
4. 153 framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
5. 154 if (!fbDev) {
6. 155 ALOGE("Display subsystem failed to initialize. check logs. exiting...");
7. 156 exit(0);
8. 157 }
9. 158
10. 159 int format;
11. 160 ANativeWindow const * const window = mNativeWindow.get();
12. 161 window->query(window, NATIVE_WINDOW_FORMAT, &format);
13. 162 mDpiX = mNativeWindow->xdpi;
14. 163 mDpiY = mNativeWindow->ydpi;
15. 164 mRefreshRate = fbDev->fps;
16. ....
17. }
而DisplayHardware的真正構造僅在Surfacelinger啓動後readyToRun中,其他都是使用拷貝構造默認的Bitwise Copy,固然這僅僅是針對一塊屏的狀況,當前大屏主流。相關代碼片斷以下:
1. 217status_t SurfaceFlinger::readyToRun()
2. 218{
3. 219 ALOGI( "SurfaceFlinger's main thread ready to run. "
4. 220 "Initializing graphics H/W...");
5. 221
6. 222 // we only support one display currently
7. 223 int dpy = 0;
8. 224
9. 225 {
10. 226 // initialize the main display
11. 227 GraphicPlane& plane(graphicPlane(dpy));
12. 228 DisplayHardware* const hw = new DisplayHardware(this, dpy); //*******
13. 229 plane.setDisplayHardware(hw);
14. 230 }
15. 231
16. 232 // create the shared control-block
17. 233 mServerHeap = new MemoryHeapBase(4096,
18. 234 MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
19. 235 ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
20. 236
21. 237 mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
22. 238 ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
23. 239
24. 240 new(mServerCblk) surface_flinger_cblk_t;
25. 241
26. 242 // initialize primary screen
27. 243 // (other display should be initialized in the same manner, but
28. 244 // asynchronously, as they could come and go. None of this is supported
29. 245 // yet).
30. 246 const GraphicPlane& plane(graphicPlane(dpy));
31. 247 const DisplayHardware& hw = plane.displayHardware();
32. 248 const uint32_t w = hw.getWidth();
33. 249 const uint32_t h = hw.getHeight();
34. 250 const uint32_t f = hw.getFormat();
35. 251 hw.makeCurrent();
36. .....
37. }
fb模塊最重要的工做就是將應用程序指定的內容寫入顯存中,是經過函數 fb_post完成的,流程以下(msm8960代碼大體如此,不過使用的是FBIOPUT_VSCREENINFO IOCTL_CODE):
1. /* 將圖形緩衝區buffer的內容渲染到幀緩衝區中去 */
2. static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
3. {
4. unsigned int phys;
5. void* virt;
6. int pitch;
7. int format;
8.
9. /* 首先驗證參數handle指向的一塊圖形緩衝區的確是由Gralloc模塊分配的 */
10. if (private_handle_t::validate(buffer) < 0)
11. return -EINVAL;
12.
13. fb_context_t* ctx = (fb_context_t*)dev;
14.
15. private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer); /* 圖形緩衝區 */
16. private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module); /* 幀緩衝區 */
17.
18. if (m->currentBuffer) { /* 當前正在渲染的圖形緩衝區 */
19. m->base.unlock(&m->base, m->currentBuffer);
20. m->currentBuffer = 0;
21. }
22.
23. if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { /* 若是圖形緩衝區是在系統幀緩衝中分配的 */
24. m->base.lock(&m->base, buffer, /* 鎖定圖像緩衝區 */
25. private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
26. 0, 0, m->info.xres, m->info.yres, NULL);
27.
28. const size_t offset = hnd->base - m->framebuffer->base; /* 計算圖形緩衝區與幀緩衝的偏移 */
29. /* 將做爲參數的fb_var_screeninfo結構體的成員變量activate的值設置FB_ACTIVATE_VBL
30. * 表示要等到下一個垂直同步事件出現時,再將當前要渲染的圖形緩衝區的內容繪製出來
31. * 這樣作的目的是避免出現屏幕閃爍,即避免先後兩個圖形緩衝區的內容各有一部分同時出現屏幕中 */
32. m->info.activate = FB_ACTIVATE_VBL;
33. m->info.yoffset = offset / m->finfo.line_length; /* 獲得偏移的起始行 */
34.
35. if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1) { /* 刷新顯示內容 */
36. LOGE("FBIOPAN_DISPLAY failed");
37. m->base.unlock(&m->base, buffer);
38. return -errno;
39. }
40.
41. if (UNLIKELY(mDebugFps)) {
42. debugShowFPS();
43. }
44.
45. m->currentBuffer = buffer; /* 設置當前圖形緩衝區 */
46. return 0;
47. }
五、 Gralloc map/unmap、register/unregister
當GPU內存file descriptor從一個進程A傳遞到另外一個進程B後,進程B作gralloc_register_buffer就是使用allocator此時是ION將該buffer在本進程映射一下,用於訪問。這些功能作爲gralloc的mapper功能。
關於內存file descriptor、binder傳遞該內存fd的具體機制參見ION的功能。
*******************************************************************************
SurfaceFlinger Layer Clip & Draw
/*
*收到VSYNC後 REFRESH顯示
*/
413void SurfaceFlinger::onMessageReceived(int32_t what)
{
419 // if we're in a global transaction, don't do anything.
420 const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
421 uint32_t transactionFlags = peekTransactionFlags(mask);
422 if (CC_UNLIKELY(transactionFlags)) {
423 handleTransaction(transactionFlags);
424 }
425
426 // post surfaces (if needed)
427 handlePageFlip();
428
435 handleRefresh();
436
437 const DisplayHardware& hw(graphicPlane(0).displayHardware());
438
443 if (CC_UNLIKELY(mHwWorkListDirty)) {
444 // build the h/w work list
445 handleWorkList();
446 }
447
448 if (CC_LIKELY(hw.canDraw())) {
449 // repaint the framebuffer (if needed)
450 handleRepaint();
451 // inform the h/w that we're done compositing
452 hw.compositionComplete();
453 postFramebuffer();
454 } else {
455 // pretend we did the post
456 hw.compositionComplete();
457 }
}
511void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
512{
513 const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
514 const size_t count = currentLayers.size();
515
516 /*
517 * Traversal of the children
518 * (perform the transaction for each of them if needed)
519 */
520
/*
* 針對每一個Layer,提交其所作的狀態變化
*/
521 const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
522 if (layersNeedTransaction) {
523 for (size_t i=0 ; i<count ; i++) {
524 const sp<LayerBase>& layer = currentLayers[i];
525 uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
526 if (!trFlags) continue;
527
528 const uint32_t flags = layer->doTransaction(0);
529 if (flags & Layer::eVisibleRegion)
530 mVisibleRegionsDirty = true;
531 }
532 }
533
534 /*
535 * Perform our own transaction if needed
536 */
537 /*
* 處理SurfaceFlinger全局狀態變化
*/
538 if (transactionFlags & eTransactionNeeded) {
/*
*若是屏幕發生旋轉,則設置mDirtyRegion爲整個屏幕範圍,更新mServerCblk
* 客戶端能夠訪問到,通知HWC屏幕位向改變從新設置其參數。
*/
539 if (mCurrentState.orientation != mDrawingState.orientation) {
540 // the orientation has changed, recompute all visible regions
541 // and invalidate everything.
542
543 const int dpy = 0;
544 const int orientation = mCurrentState.orientation;
545 // Currently unused: const uint32_t flags = mCurrentState.orientationFlags;
546 GraphicPlane& plane(graphicPlane(dpy));
547 plane.setOrientation(orientation);
548 const Transform& planeTransform(plane.transform());
549
550 // update the shared control block
551 const DisplayHardware& hw(plane.displayHardware());
552 volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
553 dcblk->orientation = orientation;
554 dcblk->w = plane.getWidth();
555 dcblk->h = plane.getHeight();
556
557 mVisibleRegionsDirty = true;
558 mDirtyRegion.set(hw.bounds());
559
560 //set the new orientation to HWC
561 HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
562 hwc.eventControl(DisplayHardware::EVENT_ORIENTATION,
563 planeTransform.getOrientation());
564
565 }
566
/*
*若是有Layer增長,設置贓區域標誌,此時mDirtyRegion還爲空,
*每次Repaint後mDirtyRegion就清空了。
*此處的判斷條件使用Layer個數比較,須要與下面mLayersRemoved結合看。
*若是Layer有減小,即便增長的個數小於減小的個數,
*那麼mVisibleRegionsDirty必定會被設置。
*若是沒有減小,增長Layer後數目必定會增多。可讀性很差。
*/
567 if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
568 // layers have been added
569 mVisibleRegionsDirty = true;
570 }
571
/*
*有減小的Layer,那麼其下Layer可能會暴露出來,須要Invalidate該Layer
*暴露出來的區域,因此須要記錄這塊區域。
*全部移除layer暴露出來的區域累積,記錄在mDirtyRegionRemovedLayer中。
* Invalidate的效果是在lockPageFlip後,將mDirtyRegionRemovedLayer加到
* mDirtyRegion中。
*用戶繪圖後Post的贓區域在unlockPageFlip時作。
*/
572 // some layers might have been removed, so
573 // we need to update the regions they're exposing.
574 if (mLayersRemoved) {
575 mLayersRemoved = false;
576 mVisibleRegionsDirty = true;
577 const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
578 const size_t count = previousLayers.size();
579 for (size_t i=0 ; i<count ; i++) {
580 const sp<LayerBase>& layer(previousLayers[i]);
581 if (currentLayers.indexOf( layer ) < 0) {
582 // this layer is not visible anymore
583 mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
584 }
585 }
586 }
587 }
588
/*
* 複製CurrentState到DrawingState中,即提交,下面代碼處理Repaint時使用DrawingState
*/
589 commitTransaction();
590}
735void SurfaceFlinger::handlePageFlip()
736{
737 ATRACE_CALL();
738 const DisplayHardware& hw = graphicPlane(0).displayHardware();
739 const Region screenRegion(hw.bounds());
740
/*
* 更新每一個Layer的髒區域,獲取每Layer此次重繪所須要的GraphicBuffer,
* 爲每Layer生成紋理供GPU render使用。
*/
741 const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
742 const bool visibleRegions = lockPageFlip(currentLayers);
743
744 if (visibleRegions || mVisibleRegionsDirty) {
745 Region opaqueRegion;
/*
*計算更新mDirtyRegion,獲得全部Opaqued Layers的總的Region。
*/
746 computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
747
748 /*
749 * rebuild the visible layer list;重建mVisibleLayersSortedByZ
750 */
751 const size_t count = currentLayers.size();
752 mVisibleLayersSortedByZ.clear();
753 mVisibleLayersSortedByZ.setCapacity(count);
754 for (size_t i=0 ; i<count ; i++) {
755 if (!currentLayers[i]->visibleRegionScreen.isEmpty())
756 mVisibleLayersSortedByZ.add(currentLayers[i]);
757 }
758
/*
* opaqueRegion區域外的區域繪製「蟲洞」,記錄該區域
*/
759 mWormholeRegion = screenRegion.subtract(opaqueRegion);
/*
*本輪處理中mVisibleRegionsDirty標誌使用完畢,重置。
*/
760 mVisibleRegionsDirty = false;
761 invalidateHwcGeometry();
762 }
763
/*
* 主要是將每一個Layer用戶Post的區域併到贓區域上
*/
764 unlockPageFlip(currentLayers);
765
766 mDirtyRegion.orSelf(getAndClearInvalidateRegion());
767 mDirtyRegion.andSelf(screenRegion);
768}
775bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
776{
777 bool recomputeVisibleRegions = false;
778 size_t count = currentLayers.size();
779 sp<LayerBase> const* layers = currentLayers.array();
780 for (size_t i=0 ; i<count ; i++) {
781 const sp<LayerBase>& layer(layers[i]);
782 layer->lockPageFlip(recomputeVisibleRegions);
783 }
784 return recomputeVisibleRegions;
785}
527void Layer::lockPageFlip(bool& recomputeVisibleRegions)
528{
529 ATRACE_CALL();
530
/*
* 本Layer有新Queued Buffer才須要更新紋理。
*/
531 if (mQueuedFrames > 0) {
532
533 // if we've already called updateTexImage() without going through
534 // a composition step, we have to skip this layer at this point
535 // because we cannot call updateTeximage() without a corresponding
536 // compositionComplete() call.
537 // we'll trigger an update in onPreComposition().
/*
*若是上次的重繪尚未顯示,本輪又要顯示了,直接返回。
*/
538 if (mRefreshPending) {
539 mPostedDirtyRegion.clear();
540 return;
541 }
542
543 // Capture the old state of the layer for comparisons later
544 const bool oldOpacity = isOpaque();
545 sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
546
/*
*由於有mRefreshPending時致使直接return,全部須要「引起」下個Frame的顯示;
* signalLayerUpdate()便是requestNextVsync(),由於setRefreshRate(0)時,
*不接收VSYNC,因此須要顯式要求下一個VSYNC發過來,「引起」下幀顯示
*/
547 // signal another event if we have more frames pending
548 if (android_atomic_dec(&mQueuedFrames) > 1) {
549 mFlinger->signalLayerUpdate();
550 }
551
/*
*內部類用於檢驗Queued過來的Buffer是否符合該Layer的顯示要求,
*不符合則reject,不予顯示。
*如Camera或Video圖像buffer的大小,格式等要符合。
*/
552 struct Reject : public SurfaceTexture::BufferRejecter {
553 Layer::State& front;
554 Layer::State& current;
555 bool& recomputeVisibleRegions;
556 Reject(Layer::State& front, Layer::State& current,
557 bool& recomputeVisibleRegions)
558 : front(front), current(current),
559 recomputeVisibleRegions(recomputeVisibleRegions) {
560 }
561
562 virtual bool reject(const sp<GraphicBuffer>& buf,
563 const BufferQueue::BufferItem& item) {
564 if (buf == NULL) {
565 return false;
566 }
567
568 uint32_t bufWidth = buf->getWidth();
569 uint32_t bufHeight = buf->getHeight();
570
571 // check that we received a buffer of the right size
572 // (Take the buffer's orientation into account)
573 if (item.mTransform & Transform::ROT_90) {
574 swap(bufWidth, bufHeight);
575 }
576
577
578 bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
579 if (front.active != front.requested) {
580
581 if (isFixedSize ||
582 (bufWidth == front.requested.w &&
583 bufHeight == front.requested.h))
584 {
585 // Here we pretend the transaction happened by updating the
586 // current and drawing states. Drawing state is only accessed
587 // in this thread, no need to have it locked
588 front.active = front.requested;
589
590 // We also need to update the current state so that
591 // we don't end-up overwriting the drawing state with
592 // this stale current state during the next transaction
593 //
594 // NOTE: We don't need to hold the transaction lock here
595 // because State::active is only accessed from this thread.
596 current.active = front.active;
597
598 // recompute visible region
599 recomputeVisibleRegions = true;
600 }
601
622
623 if (!isFixedSize) {
624 if (front.active.w != bufWidth ||
625 front.active.h != bufHeight) {
626 // reject this buffer
627 return true;
628 }
629 }
630 return false;
631 }
632 };
633
634
635 Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
636
/*
*使用該Layer的mActiveBuffer生成SurfaceTexture,用於OpenGL/3D GPU render。
*圖像格式不符合時,Reject::reject()被回調。
*/
637 if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) {
638 // something happened!
639 recomputeVisibleRegions = true;
640 return;
641 }
/*************
*updateTexImage會釋放上輪該Layer使用的GraphicBuffer;
*也即本輪使用的GraphicBuffer持續到下次須要重繪時釋放。
*記得其申請是在lockPageFlip中記錄在mActiveBuffer。
*/
642
/*
*記錄或更新當前使用的即mActiveBuffer字段
*注意該buffer直到該Layer下輪重繪Repaint時才Release,
*期間SurfaceTexture對該Buffer是不可用的。
*/
643 // update the active buffer
644 mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
645 if (mActiveBuffer == NULL) {
646 // this can only happen if the very first buffer was rejected.
647 return;
648 }
649
/*
*設置mRefreshPending標誌了,若是本輪尚未Paint而下次又來了,直接返回。
*/
650 mRefreshPending = true;
651 mFrameLatencyNeeded = true;
652 if (oldActiveBuffer == NULL) {
653 // the first time we receive a buffer, we need to trigger a
654 // geometry invalidation.
655 mFlinger->invalidateHwcGeometry();
656 }
657
/*
*若是Crop & Transform & Scale改變,重設HWC參數
*/
658 Rect crop(mSurfaceTexture->getCurrentCrop());
659 const uint32_t transform(mSurfaceTexture->getCurrentTransform());
660 const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
661 if ((crop != mCurrentCrop) ||
662 (transform != mCurrentTransform) ||
663 (scalingMode != mCurrentScalingMode))
664 {
665 mCurrentCrop = crop;
666 mCurrentTransform = transform;
667 mCurrentScalingMode = scalingMode;
668 mFlinger->invalidateHwcGeometry();
669 }
670
/*
*比較GraphicBuffer的維度是否有改變,用於更新HWC的維度參數,
*從而使HWC知道該準備多大的buffer空間,和圖像參數用於合成。
*/
671 if (oldActiveBuffer != NULL) {
672 uint32_t bufWidth = mActiveBuffer->getWidth();
673 uint32_t bufHeight = mActiveBuffer->getHeight();
674 if (bufWidth != uint32_t(oldActiveBuffer->width) ||
675 bufHeight != uint32_t(oldActiveBuffer->height)) {
676 mFlinger->invalidateHwcGeometry();
677 }
678 }
679
680 mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
681 if (oldOpacity != isOpaque()) {
682 recomputeVisibleRegions = true;
683 }
684
/*
* FIXME?每一個layer的dirty是在後面調用的computeVisibleRegions()中計算出來的,
*能夠在彼時設置給Layer,記錄髒區域是個很好的優化。
*可是Region mPostedDirtyRegion是class Layer而不是class LayerBase的成員,
*慢慢FIX! 此dirty非computeVisibleRegions中的dirty
*/
685 // FIXME: mPostedDirtyRegion = dirty & bounds
686 const Layer::State& front(drawingState());
687 mPostedDirtyRegion.set(front.active.w, front.active.h);
688
689 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
690 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
691 }
692}
Layer Clip精髓所在----
592void SurfaceFlinger::computeVisibleRegions(
593 const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
594{
595 ATRACE_CALL();
596
597 const GraphicPlane& plane(graphicPlane(0));
598 const Transform& planeTransform(plane.transform());
599 const DisplayHardware& hw(plane.displayHardware());
600 const Region screenRegion(hw.bounds());
601
602 Region aboveOpaqueLayers;
603 Region aboveCoveredLayers;
604 Region dirty;
605
606 bool secureFrameBuffer = false;
607
608 size_t i = currentLayers.size();
/*
* Clip不就是計算遮擋嗎?z-order從頂向底,合乎邏輯。
*/
609 while (i--) {
610 const sp<LayerBase>& layer = currentLayers[i];
611 layer->validateVisibility(planeTransform);
612
613 // start with the whole surface at its current location
614 const Layer::State& s(layer->drawingState());
615
616 /*
617 * opaqueRegion: area of a surface that is fully opaque.
618 */
619 Region opaqueRegion;
620
621 /*
622 * visibleRegion: area of a surface that is visible on screen
623 * and not fully transparent. This is essentially the layer's
624 * footprint minus the opaque regions above it.
625 * Areas covered by a translucent surface are considered visible.
626 */
627 Region visibleRegion;
628
629 /*
630 * coveredRegion: area of a surface that is covered by all
631 * visible regions above it (which includes the translucent areas).
632 */
633 Region coveredRegion;
634
635
636 // handle hidden surfaces by setting the visible region to empty
637 if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
//該Layer是否半透
638 const bool translucent = !layer->isOpaque();
//該Layer可見範圍
639 const Rect bounds(layer->visibleBounds());
640 visibleRegion.set(bounds);
641 visibleRegion.andSelf(screenRegion);
642 if (!visibleRegion.isEmpty()) {
/*
*若是本layer具備全透明區域(全透明子窗口),如Video或Camera,
*本Layer該區域必定是不可見的,visibleRegion應該減去全透區域,
* translucent的判斷條件並不表示該Layer爲半透,而是有全透區域時,
*該Layer的Opaque屬性應該設置爲false,表並不是Full Opaque。
* setTransparentRegion/setTransparentRegionWindow
* => setTransparentRegionHint設置透明的。
*那半透明子窗口如何呢?由於Layer的地位至關於該應用的Parent most window,
*因此半透子窗口下的區域也必定是本Layer的子窗口,而不多是別的Layer,
*從而該半透子窗口在本Layer範圍內部就作Alpha混疊了,對於本Layer來講是
* Opaque的,因此不須要半透部分區域。半透屬性是針對整個Layer的。
*/
643 // Remove the transparent area from the visible region
644 if (translucent) {
645 visibleRegion.subtractSelf(layer->transparentRegionScreen);
646 }
647
648 // compute the opaque region
649 const int32_t layerOrientation = layer->getOrientation();
/*
*若是該Layer是Opaque的,那麼其整個可見區域必定是遮擋下面的層的。
*記錄,累積到aboveOpaqueLayers, 供計算下面層的遮擋之用。
*/
650 if (s.alpha==255 && !translucent &&
651 ((layerOrientation & Transform::ROT_INVALID) == false)) {
652 // the opaque region is the layer's footprint
653 opaqueRegion = visibleRegion;
654 }
655 }
656 }
657
/*
* coveredRegion本層被覆蓋的區域,包括被上面層半透覆蓋的區域,覆蓋並不是遮擋。
*本層可見區域總對下面層構成覆蓋,累積到aboveCoveredLayers
*/
658 // Clip the covered region to the visible region
659 coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
660
661 // Update aboveCoveredLayers for next (lower) layer
662 aboveCoveredLayers.orSelf(visibleRegion);
663
/*
*減去本層被上面層遮擋的區域
*/
664 // subtract the opaque region covered by the layers above us
665 visibleRegion.subtractSelf(aboveOpaqueLayers);
666
/*
*計算本層的髒區域,份內容是否爲髒(size是否變化)兩種情形。
*若是是用內容髒,即size變化,那麼認爲整個區域都是髒的;
*若是是移除上層的Layer暴露出本Layer區域,則計算可見的最小的髒區域;
*此時贓區域是屏幕座標系統?
*這麼有用的個dirty爲何不保存給各個Layer?
*此時的dirty還不包括用戶Posted的真正意義上的髒區域!
*爲何不直接地處理爲visbleRegion.andSelf(mDirtyRegionRemovedLayer)?
*由於mDirtyRegionRemovedLayer僅是個區域,並無記錄層的透明屬性。
*/
667 // compute this layer's dirty region
668 if (layer->contentDirty) {
669 // we need to invalidate the whole region
670 dirty = visibleRegion;
671 // as well, as the old visible region
672 dirty.orSelf(layer->visibleRegionScreen);
673 layer->contentDirty = false;
674 } else {
675 /* compute the exposed region:
676 * the exposed region consists of two components:
677 * 1) what's VISIBLE now and was COVERED before
678 * 2) what's EXPOSED now less what was EXPOSED before
679 *
680 * note that (1) is conservative, we start with the whole
681 * visible region but only keep what used to be covered by
682 * something -- which mean it may have been exposed.
683 *
684 * (2) handles areas that were not covered by anything but got
685 * exposed because of a resize.
686 */
687 const Region newExposed = visibleRegion - coveredRegion;
688 const Region oldVisibleRegion = layer->visibleRegionScreen;
689 const Region oldCoveredRegion = layer->coveredRegionScreen;
690 const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
691 dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
692 }
/*
*被遮擋區域不須要重繪,從髒區域裏除去
*/
693 dirty.subtractSelf(aboveOpaqueLayers);
694
/*
*累積總的髒區域
*/
695 // accumulate to the screen dirty region
696 dirtyRegion.orSelf(dirty);
697
/*
*累積遮擋區域
*/
698 // Update aboveOpaqueLayers for next (lower) layer
699 aboveOpaqueLayers.orSelf(opaqueRegion);
700
/*
*爲每一個Layer記錄其mVisibleRegion和mCoveredRegion
*/
701 // Store the visible region is screen space
702 layer->setVisibleRegion(visibleRegion);
703 layer->setCoveredRegion(coveredRegion);
704
705 // If a secure layer is partially visible, lock-down the screen!
706 if (layer->isSecure() && !visibleRegion.isEmpty()) {
707 secureFrameBuffer = true;
708 }
709 }
710
/*
* 把mDirtyRegionRemovedLayer併到mDirtyRegion中去。
* 有移除Layers暴露出來的區域須要其下的Layers重繪,其實這個在dirty計算時已處理
* 關鍵的是移除的Layer是最底層Layer的時候則直接露出屏底色,因此要此處要或上。
*/
711 // invalidate the areas where a layer was removed
712 dirtyRegion.orSelf(mDirtyRegionRemovedLayer);
713 mDirtyRegionRemovedLayer.clear();
714
/*
* 抓屏相關?
*/
715 mSecureFrameBuffer = secureFrameBuffer;
/*
* 傳出遮擋區域,Opaque Region爲全部Opaque Layer Area之和
*/
716 opaqueRegion = aboveOpaqueLayers;
717}
787void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
788{
789 const GraphicPlane& plane(graphicPlane(0));
790 const Transform& planeTransform(plane.transform());
791 const size_t count = currentLayers.size();
792 sp<LayerBase> const* layers = currentLayers.array();
793 for (size_t i=0 ; i<count ; i++) {
794 const sp<LayerBase>& layer(layers[i]);
795 layer->unlockPageFlip(planeTransform, mDirtyRegion);
796 }
797}
694void Layer::unlockPageFlip(
695 const Transform& planeTransform, Region& outDirtyRegion)
696{
697 ATRACE_CALL();
698
699 Region postedRegion(mPostedDirtyRegion);
700 if (!postedRegion.isEmpty()) {
701 mPostedDirtyRegion.clear();
702 if (!visibleRegionScreen.isEmpty()) {
703 // The dirty region is given in the layer's coordinate space
704 // transform the dirty region by the surface's transformation
705 // and the global transformation.
706 const Layer::State& s(drawingState());
707 const Transform tr(planeTransform * s.transform);
708 postedRegion = tr.transform(postedRegion);
709
/*
* computeVisibleRegions處理的贓區域是size變化和上層遮擋移除的狀況,須要重繪;
*而用戶修改提交的區域也須要重繪,還未加到贓區域中,此時並進來。
*/
710 // At this point, the dirty region is in screen space.
711 // Make sure it's constrained by the visible region (which
712 // is in screen space as well).
713 postedRegion.andSelf(visibleRegionScreen);
714 outDirtyRegion.orSelf(postedRegion);
715 }
716 }
717}
handleRefresh()沒什麼做用了。
handleWorkList()是爲HWComposer分配緩衝工做集,用於硬件合成,暫不考察。
DisplayHardware.canDraw()用於判斷當前是否處於draw過程當中,屏是否已經關閉等,得出須要Repaint的判斷。
835void SurfaceFlinger::handleRepaint()
836{
837 ATRACE_CALL();
838
839 // compute the invalid region
840 mSwapRegion.orSelf(mDirtyRegion);
841
842 if (CC_UNLIKELY(mDebugRegion)) {
843 debugFlashRegions();
844 }
845
846 // set the frame buffer
847 const DisplayHardware& hw(graphicPlane(0).displayHardware());
848 glMatrixMode(GL_MODELVIEW);
849 glLoadIdentity();
850
/*
* 針對DisplayHardware是支持RECT更新仍是RECTS更新,作相應處理。
*/
851 uint32_t flags = hw.getFlags();
852 if (flags & DisplayHardware::SWAP_RECTANGLE) {
853 // we can redraw only what's dirty, but since SWAP_RECTANGLE only
854 // takes a rectangle, we must make sure to update that whole
855 // rectangle in that case
856 mDirtyRegion.set(mSwapRegion.bounds());
857 } else {
858 if (flags & DisplayHardware::PARTIAL_UPDATES) {
859 // We need to redraw the rectangle that will be updated
860 // (pushed to the framebuffer).
861 // This is needed because PARTIAL_UPDATES only takes one
862 // rectangle instead of a region (see DisplayHardware::flip())
863 mDirtyRegion.set(mSwapRegion.bounds());
864 } else {
865 // we need to redraw everything (the whole screen)
866 mDirtyRegion.set(hw.bounds());
867 mSwapRegion = mDirtyRegion;
868 }
869 }
870
/*
* 此處先不考慮HWC,HWC另見後續MIMO display – Overlay & HWComposer
* 只考慮使用 OpenGL / 3D GPU render的狀況,即各layer->draw。
*/
871 setupHardwareComposer();
872 composeSurfaces(mDirtyRegion);
873
874 // update the swap region and clear the dirty region
875 mSwapRegion.orSelf(mDirtyRegion);
876 mDirtyRegion.clear();
877}
912void SurfaceFlinger::composeSurfaces(const Region& dirty)
913{
914 const DisplayHardware& hw(graphicPlane(0).displayHardware());
915 HWComposer& hwc(hw.getHwComposer());
916 hwc_layer_t* const cur(hwc.getLayers());
917
/*
* 不考慮HWC或者除HWC_OVERLAY有HWC_FB或者Layer數目超出HWC管道數時,
* 使用GPU render。
*/
918 const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
919 if (!cur || fbLayerCount) {
920 // Never touch the framebuffer if we don't have any framebuffer layers
921
/*
*有HWC_FB有HWC_OVERLAY共存的情形,如Camera或Video
*暫時認爲0不表,詳見後續 MIMO display – Overlay & HWComposer
*/
922 if (hwc.getLayerCount(HWC_OVERLAY)) {
923 // when using overlays, we assume a fully transparent framebuffer
924 // NOTE: we could reduce how much we need to clear, for instance
925 // remove where there are opaque FB layers. however, on some
926 // GPUs doing a "clean slate" glClear might be more efficient.
927 // We'll revisit later if needed.
928 const Region region(hw.bounds());
/*
*爲HWC先清原來的畫面
*/
929#ifdef QCOMHW
930 if (0 != qdutils::CBUtils::qcomuiClearRegion(region,
931 hw.getEGLDisplay()))
932#endif
933 {
934 glClearColor(0, 0, 0, 0);
935 glClear(GL_COLOR_BUFFER_BIT);
936 }
937 } else {
/*
*看來FB的時候不須要清屏;若是須要畫蟲洞,則爲該區域清屏以顯示蟲洞
*/
938 // screen is already cleared here
939 if (!mWormholeRegion.isEmpty()) {
940 // can happen with SurfaceView
941#ifdef QCOMHW
942 if (0 != qdutils::CBUtils::qcomuiClearRegion(mWormholeRegion,
943 hw.getEGLDisplay()))
944#endif
945 drawWormhole();
946 }
947 }
948
/*
*真正開畫
*/
949 /*
950 * and then, render the layers targeted at the framebuffer
951 */
952
953 const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
954 const size_t count = layers.size();
955
/*
*顯然的,從底層向頂層畫
*/
956 for (size_t i=0 ; i<count ; i++) {
957 const sp<LayerBase>& layer(layers[i]);
/*
*各Layer的贓區域
*/
958 const Region clip(dirty.intersect(layer->visibleRegionScreen));
959 if (!clip.isEmpty()) {
960 if (cur && (cur[i].compositionType == HWC_OVERLAY)) {
961 if (i && (cur[i].hints & HWC_HINT_CLEAR_FB)
962 && layer->isOpaque()) {
963 // never clear the very first layer since we're
964 // guaranteed the FB is already cleared
965#ifdef QCOMHW
966 if (0 != qdutils::CBUtils::qcomuiClearRegion(clip,
967 hw.getEGLDisplay()))
968#endif
969 layer->clearWithOpenGL(clip);
970 }
971 continue;
972 }
/*
*若是是HWC_OVERLAY的,不須要Layer本身畫
*/
973#ifdef QCOMHW
974 if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER))
975 continue;
976#endif
977
/*
* HWC_FB Layer,本身開畫
*/
978 // render the layer
979 layer->draw(clip);
980 }
981 }
982 } else if (cur && !mWormholeRegion.isEmpty()) {
983 const Region region(mWormholeRegion.intersect(mDirtyRegion));
984 if (!region.isEmpty()) {
985#ifdef QCOMHW
986 if (0 != qdutils::CBUtils::qcomuiClearRegion(region,
987 hw.getEGLDisplay()))
988#endif
989 drawWormhole();
990 }
991 }
992}
344void LayerBase::draw(const Region& clip) const
345{
346 //Dont draw External-only layers
347 if (isLayerExternalOnly(getLayer())) {
348 return;
349 }
350 onDraw(clip);
351}
/*
* Bind Texture and Draw using OpenGL for this layer on theBACK Framebuffer.
*/
321void Layer::onDraw(const Region& clip) const
322{
323 ATRACE_CALL();
324
325 if (CC_UNLIKELY(mActiveBuffer == 0)) {
326 // the texture has not been created yet, this Layer has
327 // in fact never been drawn into. This happens frequently with
328 // SurfaceView because the WindowManager can't know when the client
329 // has drawn the first time.
330
331 // If there is nothing under us, we paint the screen in black, otherwise
332 // we just skip this update.
333
334 // figure out if there is something below us
335 Region under;
336 const SurfaceFlinger::LayerVector& drawingLayers(
337 mFlinger->mDrawingState.layersSortedByZ);
338 const size_t count = drawingLayers.size();
339 for (size_t i=0 ; i<count ; ++i) {
340 const sp<LayerBase>& layer(drawingLayers[i]);
341 if (layer.get() == static_cast<LayerBase const*>(this))
342 break;
343 under.orSelf(layer->visibleRegionScreen);
344 }
345 // if not everything below us is covered, we plug the holes!
346 Region holes(clip.subtract(under));
347 if (!holes.isEmpty()) {
348 clearWithOpenGL(holes, 0, 0, 0, 1);
349 }
350 return;
351 }
352#ifdef QCOMHW
353 if (!qdutils::isGPUSupportedFormat(mActiveBuffer->format)) {
354 clearWithOpenGL(clip, 0, 0, 0, 1);
355 return;
356 }
357#endif
358 if (!isProtected()) {
359 // TODO: we could be more subtle with isFixedSize()
360 const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize();
361
362 // Query the texture matrix given our current filtering mode.
363 float textureMatrix[16];
364 mSurfaceTexture->setFilteringEnabled(useFiltering);
365 mSurfaceTexture->getTransformMatrix(textureMatrix);
366
367 // Set things up for texturing.
368 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
369 GLenum filter = GL_NEAREST;
370 if (useFiltering) {
371 filter = GL_LINEAR;
372 }
373 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter);
374 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter);
375 glMatrixMode(GL_TEXTURE);
376 glLoadMatrixf(textureMatrix);
377 glMatrixMode(GL_MODELVIEW);
378 glDisable(GL_TEXTURE_2D);
379 glEnable(GL_TEXTURE_EXTERNAL_OES);
380 } else {
381 glBindTexture(GL_TEXTURE_2D, mFlinger->getProtectedTexName());
382 glMatrixMode(GL_TEXTURE);
383 glLoadIdentity();
384 glMatrixMode(GL_MODELVIEW);
385 glDisable(GL_TEXTURE_EXTERNAL_OES);
386 glEnable(GL_TEXTURE_2D);
387 }
388
389 drawWithOpenGL(clip);
390
391 glDisable(GL_TEXTURE_EXTERNAL_OES);
392 glDisable(GL_TEXTURE_2D);
393}
/*
* 提交FrameBuffer
* 對於使用GPU的狀況,composeSurfaces已經將全部Surface都合成到BACK Framebuffer上了;
* 對於HWComposer的狀況,此時尚未啓動硬件合成,是在DisplayHardware::flip =>
* HWComposer::commit中合成到BACK Framebuffer上並交換Framebuffer的。
* 爲了統一,應該把HWC合成的功能也放到composeSurfaces相似的composeLayers裏面去,
* 不用Surface字樣是由於Surface是GPU使用的,MDP HWComposer並不具備
* 操做Surface/Texture的能力,而只能操做支持格式的GraphicBuffer。
*/
463void SurfaceFlinger::postFramebuffer()
464{
465 ATRACE_CALL();
466 // mSwapRegion can be empty here is some cases, for instance if a hidden
467 // or fully transparent window is updating.
468 // in that case, we need to flip anyways to not risk a deadlock with
469 // h/w composer.
470
471 const DisplayHardware& hw(graphicPlane(0).displayHardware());
472 const nsecs_t now = systemTime();
473 mDebugInSwapBuffers = now;
474 hw.flip(mSwapRegion);
475
476 size_t numLayers = mVisibleLayersSortedByZ.size();
477 for (size_t i = 0; i < numLayers; i++) {
478 mVisibleLayersSortedByZ[i]->onLayerDisplayed();
479 }
480
481
482 mLastSwapBufferTime = systemTime() - now;
483 mDebugInSwapBuffers = 0;
484 mSwapRegion.clear();
485}
435void DisplayHardware::flip(const Region& dirty) const
436{
437 checkGLErrors();
438
439 EGLDisplay dpy = mDisplay;
440 EGLSurface surface = mSurface;
441
442#ifdef EGL_ANDROID_swap_rectangle
443 if (mFlags & SWAP_RECTANGLE) {
444 const Region newDirty(dirty.intersect(bounds()));
445 const Rect b(newDirty.getBounds());
446 eglSetSwapRectangleANDROID(dpy, surface,
447 b.left, b.top, b.width(), b.height());
448 }
449#endif
450
451 if (mFlags & PARTIAL_UPDATES) {
452 mNativeWindow->setUpdateRectangle(dirty.getBounds());
453 }
454
455 mPageFlipCount++;
456
/*
* mHwc->commit中也會調用eglSwapBuffers,由於無論用什麼方式,
* EGL是FrameBufferNativeWindow的管理者,實現buffer swap,避免競爭。
*/
457 if (mHwc->initCheck() == NO_ERROR) {
458 mHwc->commit();
459 } else {
460 eglSwapBuffers(dpy, surface);
461 }
462 checkEGLErrors("eglSwapBuffers");
463
464 // for debugging
465 //glClearColor(1,0,0,0);
466 //glClear(GL_COLOR_BUFFER_BIT);
467}
沒有GPU的eglSwapBuffers實現,就看看軟的吧。
484EGLBoolean egl_window_surface_v2_t::swapBuffers()
485{
486 if (!buffer) {
487 return setError(EGL_BAD_ACCESS, EGL_FALSE);
488 }
489
490 /*
491 * Handle eglSetSwapRectangleANDROID()
492 * We copyback from the front buffer
493 */
494 if (!dirtyRegion.isEmpty()) {
495 dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
496 if (previousBuffer) {
497 // This was const Region copyBack, but that causes an
498 // internal compile error on simulator builds
/*
* front buffer和back buffer的贓區域的差值拷貝回back buffer中;
*由於front buffer的贓區域(即其重繪的區域)並未更新到back buffer中,
*因此須要考回來;可是back buffer的贓區域已經重繪了,是不能覆蓋掉的,
*因此兩個贓區域相減。
*這僅是double buffer的時候的實現,triple buffer兩個dirtyRegion就沒法保證了。
*/
499 /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
500 if (!copyBack.isEmpty()) {
501 void* prevBits;
502 if (lock(previousBuffer,
503 GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
504 // copy from previousBuffer to buffer
505 copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
506 unlock(previousBuffer);
507 }
508 }
509 }
510 oldDirtyRegion = dirtyRegion;
511 }
512 /*
* 釋放front framebuffer
*/
513 if (previousBuffer) {
514 previousBuffer->common.decRef(&previousBuffer->common);
515 previousBuffer = 0;
516 }
517
/*
* 解鎖back framebuffer,表用戶用完,要queue了。queueBuffer()
*/
518 unlock(buffer);
519 previousBuffer = buffer;
520 nativeWindow->queueBuffer(nativeWindow, buffer);
521 buffer = 0;
522
/*
* back framebuffer已經提交了,須要再dequeue下一個framebuffer來作back framebuffer
* 而且鎖住,供使用;
*/
523 // dequeue a new buffer
524 if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
525
526 // TODO: lockBuffer should rather be executed when the very first
527 // direct rendering occurs.
528 nativeWindow->lockBuffer(nativeWindow, buffer);
529
530 // reallocate the depth-buffer if needed
531 if ((width != buffer->width) || (height != buffer->height)) {
532 // TODO: we probably should reset the swap rect here
533 // if the window size has changed
534 width = buffer->width;
535 height = buffer->height;
536 if (depth.data) {
537 free(depth.data);
538 depth.width = width;
539 depth.height = height;
540 depth.stride = buffer->stride;
541 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
542 if (depth.data == 0) {
543 setError(EGL_BAD_ALLOC, EGL_FALSE);
544 return EGL_FALSE;
545 }
546 }
547 }
548
549 // keep a reference on the buffer
550 buffer->common.incRef(&buffer->common);
551
/*
* lock/unlock
*/
552 // finally pin the buffer down
553 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
554 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
555 ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
556 buffer, buffer->width, buffer->height);
557 return setError(EGL_BAD_ACCESS, EGL_FALSE);
558 // FIXME: we should make sure we're not accessing the buffer anymore
559 }
560 } else {
561 return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
562 }
563
564 return EGL_TRUE;
565}
*****************************************************************************
Android Overlay on QC MDP4平臺要點簡記
File Orgnization
目錄/hardware/qcom/display/liboverlay/
Android.mk
mdpRotator.cpp Overlay Rotator Wrpper
mdpWrapper.h MDP Normal and Overlay FrameBuffer IOCTL Wrapper
mdssRotator.cpp Overlay MDSS Rotator Wrapper
overlay.cpp Overlay Top level implementation file
overlay.h Overlay Top level declaration file
overlayCtrl.cpp OverlayCtrl implementation file
overlayCtrlData.h OverlayCtrl and OverlayData declaration file including OverlayData implementation
overlayImpl.h Overlay implementation which operates overlay pipes pair(LayerMixer)
overlayMdp.cpp Overlay implementation on MDP, used by OverlayCtrlData
overlayMdp.h Overlay on MDP
overlayMem.h Overlay VG pipe input kernel memory file descriptor, maybe graphic buffer or rotator output buffer
overlayRotator.cpp Overlay Rotator top level implementation
overlayRotator.h Overlay Rotator top level declaration
overlayState.h Overlay state machine
overlayUtils.cpp Overlay Utils
overlayUtils.h Overlay Utils
pipes/ Overlay Pipes, that is Overlay channel. It is a VG and RGB pipe pair on MDP.
Platform architecture
MDP中每一個VG和RGB pipe pair做爲一個LayerMixer的輸入,由LayerMixer完成Overlay功能,做爲一個Overlay channel。
注意,RGB和VG並不固定配對作爲某個LayerMixer的輸入。如MDP4.2的LayerMixer0能夠合成一個Border或BaseLayer和4個layer,便可以多達5個pipe輸入到LayerMixer0,從而用做Hardware Composer。
當使用Overlay功能時:
RGB pipe的輸入是普通的Framebuffer,是Surfaceflinger的合成輸出;
VG的輸入是video或graphics或camera圖像等,是內核空間內存buffer,其owner通常是Video、Graphics或V4L2等。當其前端是Rotator時,Rotator的輸入是這些buffer,Rotator的輸出Overlay rotator frame buffer做爲VG的輸入。
每一個Overlay Channel結構以下圖所示
關於Overlay Buffer(FrameBuffer RotatorBuffer OverlayBuffer)這些名稱並不特別明確,只要明白Overlay Channel數據流路上的各輸入輸出Buffer的位置和做用便可。
下面以Layermixer1(對應/dev/graphics/fb0)爲參考詳述各buffer:
只UI顯示時,
Framebuffer是fb0的framebuffer,是從啓動時預留出的bootmem中的分配出來的。LayerMixer1處於BLT模式,Layermixer1和DMA_P(Primary display driver)分離,能夠由軟件徹底控制。該Framebuffer作爲DMA_P的輸入,經MIPI_DSI輸出到主屏上。
啓用Overlay時,
上述Framebuffer作爲RGB1 pipe的輸入,而視頻或圖像的內核buffer作爲VG pipe的輸入,兩者經Layermixer1合成;此時LayerMixer1工做在非BLT模式,LayerMixer1和DMA_P attach在一塊兒,LayerMixer1輸出控制參數直接提供給DMA_P使用。此時LayerMixer1仍有兩種工做模式,FrameBuffer模式和DIRECT_OUT模式,前者時LayerMixer1和DMA_P之間使用一個overlaydouble buffer作緩衝,輸出給DMA_P;DIRECT_OUT模式下不使用該ovl double buffer,LayerMixer1直接輸出給DMA_P。
通常VG和RGB的輸入均可以是double buffer,ping-pang;LayerMixer的輸出也是double buffer。DMA_P/S/E作爲display driver傳輸前端buffer做爲後端接口控制器的輸入。
下面兩圖是QC MDP UI mirror和Video mirror時的兩結構圖,並無明確畫出LayerMix1的Overlay流程路徑,個別buffer的owner可能也有所差錯,buffer也並不全,僅是大體描述Overlay及其部分buffer。
MDP和DSI和後端顯示控制器和接口的鏈接結構以下圖。
Layer architecture
Overlay -> OverlayImpl |
OverlayCtrlData |
OverlayMDPCtrlData |
MDPWrapper |
FrameBuffer |
KeyPoint
Ctrl用來設置overlay channel的參數,Data用來提交buffer到Overlay channel queue。其實使用overlay本質上就是設置好pin路由,設置好通道工做參數,而後不停的提交數據讓Overlay Enginee工做。MDP的Overlay Channel並無別的特殊的編程接口,都是使用控制、狀態和數據寄存器來訪問。其實MDP提供了遠比Android Overlay實現強得多的Overlay功能。
Some flow
Ctrl::commit() -> MDPCtrl::set() -> mdp_wrapper::setOverlay() -> ioctl(fd, MSMFB_OVERLAY_SET, &ov)
-> msm_fb -> mdp4_overlay設置Overlay工做參數。
Data::queueBuffer -> MDPData::play -> mdp_wrapper::play() -> ioctl(fd, MSMFB_OVERLAY_PLAY, &od)
-> msm_fb -> mdp4_overlay進行Overlay合成。注意queueBuffer第一參數fd是memFd,是內核空間的buffer,並不在用戶空間和內核空間拷貝buffer數據。做用與framebuffer相似的是提交內核空間的該buffer到Overlay Enginee Queue。
有了這些平臺相關知識,msm_fb和mdp4_overlay驅動的功能也就容易理解了。
*****************************************************************************
Overlay & HWC on MDP -- MIMO Display軟硬整合
概述
Android顯示系統SurfaceFlinger使用Overlay和HWC(Hardware composer)完成Surface Layer的硬件合成。Overlay和HWC表現爲兩個HAL,爲芯片方案製造商留了實現餘地。
由於Overlay也時常被稱爲hardware composition,爲了不混淆,本文中Overlay專指Android Display Overlay HAL,對應liboverlay.so;HWC專指SurfaceFlinger使用的硬件合成器HAL,對應hwcomposer.msm8xxxx.so。
Qualcomm MSM8k系列平臺的MDP4.x(Mobile Display Platform)提供了硬件Overlay的功能,Android Overlay HAL與這個Overlay硬件相對應;固然,爲了與上段照應,須要說明的是,MDP並不存在一個實現HWC的專門硬件,HWC也是在Overlay上實現的;體如今Android軟件中,HWC HAL是創建在Overlay HAL基礎上的,是使用Overlay HAL來實現的。
所以,再次,準確地說,提供硬件合成功能的是模塊是Overlay,是MDP Overlay硬件的體現;而HWC則是SurfaceFlinger使用Overlay HAL的一個橋樑。
Overlay並不是僅僅由SurfaceFlinger獲得Surface後就再也不通過SurfaceFlinger而使用硬件直接輸出;從函數調用上看彷佛是這樣的,可是實際情形卻非如此。硬件合成僅是合成的一種手段,合成的結果輸出destination仍是必須受控,於是也必須歸入SurfaceFlinger的輸出管理範疇。
Overlay硬件平臺
MSM8k上目前有MDP4.0, MDP4.1, MDP4.2三個硬件版本,主要是合成能力和管道數目的區別。一般,一個RGB pipe和一個VG pipe組成一個pipe pair,前者是對應UI RGB圖像數據,後者對應Camera或Video的RGB或YUV數據,兩個pipe輸入到一個LayerMixer0用於合成;額外的,LayerMixer可能還有BF(Border Fill) pipe,用於視頻按比例顯示時屏幕多餘邊框填充,這個多用於Ext TV或HDMI輸出的時候。MDP4有7個pipe,3個LayerMixer,其中LayerMix0能夠配置有多達兩個RGB pipe,兩個VG pipe,一個BF pipe輸入,完成5 Layer合成。
上述pipe是LayerMixer的輸入元素,LayerMixer的輸出對應到LCD,TV,HDMI等,固然不是直接對應,而是由DMA channel和上述模塊的控制器相連。三個LayerMixer對應的三個輸出使用通常是約定的,固然,軟件層面上MDP driver中對每一個管道的目標LayerMixer也作了固定的配置。三個輸出通常標爲Primary, Seconday, Extra,對應的DMA通道爲DMA_P, DMA_S, DMA_E。
更直觀地,參見Android Overlay on QC MDP4平臺要點簡記
因爲LayerMixer0提供了多達5個Layer的合成能力,因此當沒有Camera或Video優先使用它的時候,它被充分利用來作Layer的Hardware composition。提早且概要地,這兒必須清楚說明的是,LayerMixer0使用的兩種情景:
當有Camera或Video的時候,SurfaceView對應的Layer爲HWC_OVERLAY,這時該Layer對應一個VG pipe,而其他HWC_FRAMEBUFFER Layer經3D GPU render到Framebuffer後,該Framebuffer輸入一個pipe(RGB1--base layer?),和VG pipe經LayerMixer0合成輸出。
當沒有Camera或Video的時候,若是UI Layer即HWC_FRAMEBUFFER Layer小於等於3個且都知足圖像格式條件,那麼這些Layer的CompositionType屬性會被修改成HWC_OVERLAY,爲每一個Layer分配pipe,經LayerMixer0合成經DMA_P輸出,這就是HWC。因爲BF pipe能力條件的限制,不使用其作HWC,而RGB1作預留的base layer Framebuffer使用,因此標榜的4-layer mdp composition support實際只能接受SurfceFlinger的3個Layer作合成,也就是SurfaceFlinger的屬性debug.mdpcomp.maxlayer=3。當超過3個Layer的時候,因爲管道數量的限制,不可以再使用LayerMixer0,就使用GPU render,也即每一個Layer->draw。固然GPU render也算是一個Hardware Composition,CompositionType方式的其中之一就是GPU。
Overlay HAL結構
MIMO輸入輸出代碼結構設計,簡單地講,分爲流路控制和數據流動兩部分;Overlay及構建在其上的hwcomposer都是採用這種流路控制和數據流動的結構。
Overlay有多種應用場景,具體設計上描述爲Overlay State。就是說若是容許管道任意靈活組合使用的話,能夠有不少種花樣的應用,可是這兒預先設計好這麼些應用場景,應用場景必定,須要的管道類型和數目隨之肯定,管道鏈接的LayerMixer及其輸出Video驅動控制器也肯定。
Overlay State具體實現使用模板類OverlayImpl<P0, P1, P2>,P0, P1, P2是3個pipe,最多可使用3個pipe。每一個pipe對應的類是模板類GenericPipe<int PANEL>,PANEL指定該pipe合成後圖像輸出目的,從而也決定其使用的LayerMixer。另外地,每一個OverlayImpl<P0, P1, P2>模板類的3個管道可能須要圖像旋轉,因此有可能使用3個Rotator。此處的P0, P1, P2只是邏輯索引,並不具體是MDP的管道索引,根據使用規格需求,從MDP管道中爲之動態分配。
hwcomposer也設計了幾個封裝類與Overlay應用場景對應,屏蔽了場景功能的具體實現。hwcomposer中定義的應用場景比Overlay提供的場景還要少,僅是有限幾個。大體結構圖以下:
因爲overlay場景太多,所以只示意了四個,OV_BYPASS_x_LAYER能夠是1,2,3個,分別對應1個,2個或3個HWC_FRAMEBUFFER Layer和base layer Framebuffer合成的情形。
hwc_prepare的設計邏輯過於固化和簡單,成了一種基於if-else判斷的優先配置方式,寬闊的城堡頂部建了個鳥籠似的小閣樓;應該設計成Policy或RouteState的形式更具有可擴展性。
Overlay進行流路控制的接口是commit,而後調用其具體實現類和MDP封裝類的相關接口,一個調用棧(適當向內核驅動作了擴展)以下:
mdp4_overlay_set()
msmfb_overlay_set()
ioctl(fb, MSMFB_OVERLAY_SET)
overlay::mdp_wrapper::setOverlay()
MdpCtrl::set()
Ctrl::commit()
pipe::commit() -> GernericPipe<utils::PRIMARY>::commit()
OverlayImplBase::commit() -> OverlayImpl<>::commit()
Overlay::commit(overlay::utils::eDest)
Overlay提交數據的接口是queueBuffer,而後一樣調用其具體實現類和MDP封裝類的相關接口,一個調用棧(適當向內核驅動作了擴展)以下:
mdp4_overlay_play()
msmfb_overlay_play()
ioctl(fd, MSMFB_OVERLAY_PLAY, &od) msmfb_overlay_data.id is mdp_overlay.id is the kernel pipe index in kernel db returned by MdpCtrl.commit()
overlay::mdp_wrapper::play()
MdpData::play(int fd, uint32_t offset)
Data::play()
GenericPipe<PANEL>::queueBuffer(int fd, uint32_t offset)
OverlayImplBase::queueBuffer() -> OverlayImpl<>::(int fd, uint32_t offset, utils::eDest dest)
Overlay::queueBuffer(int fd, uint32_t offset, utils::eDest dest)
Camera或Video Overlay
Camera Overlay通常有兩種實現模式,一種模式是V4L2不提供Overlay接口,在用戶態把V4L2 buffer handle傳遞給Framebuffer,由Framebuffer Overlay Implementation完成合成;另外一種模式是V4L2提供Overlay接口,能夠把Video buffer在V4L2內核驅動中提交給Framebuffer Overlay內核驅動完成合成。QC MSM8k Overlay是採用的第一種模式實現,可是V4L2和Framebuffer驅動也提供了第二種模式的實現;第二種模式可參見Freescale處理器上Android Overlay的實現。
Camera的取景器PreviewDisplay Window是個SurfaceView,所在的Layer(HWC_OVERLAY)在UI Layer底下,可是UI layer會開個全透的區域露出這個HWC_OVERLAY Layer。
下面描述其合成過程。
3D GPU 繪製:全部的HWC_FRAMEBUFFER layers會首先經OpenGL 3D GPU繪製到back Framebuffer上;
OV_PIPE0配置:而後在setupHardwareComposer=> HWComposer::prepare=>hwc_prepare=>VideoOverlay::prepare中使用HWC_OVERLAY Layer參數設置OV_PIPE0分配的類型爲Video/Graphic的MDP pipe;
OV_PIPE0提交:DisplayHardware::flip=>HWComposer::commit=>hwc_set=>VideoOverlay::draw提交HWC_OVERLAY Layer的圖像數據到OV_PIPE0的內核VG pipe的工做隊列中(單容量隊列便可);
OV_PIPE3配置:DisplayHardware::flip => HWComposer::commit=> hwc_set=>eglSwapBuffers => queueBuffer=> fb_post=>update_framebuffer中使用base layer back framebuffer參數配置OV_PIPE3即RGB1 pipe(注意base layer的特殊地位);
OV_PIPE3提交:當update_framebuffer真正提交圖像數據到RGB1 pipe時,對應stage 0 for base layer(內核驅動)會啓動MDP LayerMixer0進行Layers合成;
DMA傳輸:而後fb_post經過FBIOPUT_VSCREENINFO或PAN_DISPLAY啓動DMA_P送合成好的圖像經MIPI-DSI輸出顯示。
BufferFlip:queueBuffer後,該framebuffer即爲front framebuffer,而後eglSwapBuffers會dequeueBuffer下一個Framebuffer作爲back framebuffer。
此時Hardware Composer使用的是VideoOverlay@hwcomposer.msm8960.so對應的邏輯。VG pipe設置和提交的棧示例以下:
/system/lib/liboverlay.so (overlay::Overlay::commit(overlay::utils::eDest)+71)
/system/lib/liboverlay.so configPrimVid(hwc_context_t *ctx, hwc_layer_t *layer)
/system/lib/liboverlay.so VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *, hwc_layer_t *)
/system/lib/hw/hwcomposer.msm8960.so (qhwc::VideoOverlay::prepare(hwc_context_t *, hwc_layer_list_t *)+xxx)
/system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::setup(hwc_context_t*, hwc_layer_list*)+163) for each pipe.
/system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::configure(hwc_composer_device*, hwc_layer_list*)+59)
/system/lib/hw/hwcomposer.msm8960.so hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list)
/system/lib/libsurfaceflinger.so (android::HWComposer::prepare() const+9)
/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::setupHardwareComposer()+127)
/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::handleRepaint()+147)
/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+91)
/system/lib/liboverlay.so Overlay::queueBuffer(int fd, uint32_t offset, utils::eDest dest)
/system/lib/hw/hwcomposer.msm8960.so (qhwc::VideoOverlay::draw(hwc_context_t*, hwc_layer_list*)+xx) for each pipe.
/system/lib/hw/hwcomposer.msm8960.so static int hwc_set(hwc_composer_device_t *dev,hwc_display_t dpy,hwc_surface_t sur, hwc_layer_list_t* list)
/system/lib/libsurfaceflinger.so (android::HWComposer::commit() const+11)
/system/lib/libsurfaceflinger.so (android::DisplayHardware::flip(android::Region const&) const+59)
/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::postFramebuffer()+61)
/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+103)
Base layer對應的RGB pipe設置和提交的棧示例從略。Base layer提交到RGB1時真正啓動LayerMixer0的4-stage layer composition。
FB Layer Hardware Composition
當開啓硬件(debug.sf.hw=1)合成且合成方式選擇MDP時,屬性debug.mdpcomp.maxlayer決定了可使用的通道的個數,當前設置爲3,由於RGB1 pipe預留爲Camera或Video時的base layer使用,在全Framebuffer layer MDP合成情景下,RGB1對應的base layer是一個處於最頂端的全透明層。相關係統設置和屬性以下:
在系統根目錄文件 /systembuild.prop中,
debug.sf.hw=1
debug.egl.hw=1
debug.composition.type=mdp
debug.enable.wl_log=1
debug.mdpcomp.maxlayer=3
debug.mdpcomp.logs=0
其中CompositionType有 4種,debug.composition.type=dyn/c2d/mdp/cpu/gpu,dyn是根據c2d和mdp的硬件存在選擇使用兩者之一。
gpu/c2d/mdp能夠釋放cpu/gpu,減輕cpu/gpu的負擔,但並不必定能使顯示效果流暢。
SurfaceFlinger啓動時會取debug.mdpcomp.maxlayer屬性值記錄在全局變量sMaxLayers中。相關代碼以下:
782 sMaxLayers = 0;
783 if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) {
784 if(atoi(property) != 0)
785 sMaxLayers = atoi(property);
786 }
當沒有Camera/Video/HDMI/WFD等Overlay應用情景時,全部Layer都是HWC_FRAMEBUFFER的,MDP的LayerMixer0是閒置的,這時能夠優化利用其來作Framebuffer Layer合成。因爲管道數目限制的緣由,只能合成小於等於sMaxLayers個Layers。多於3個的時候是否能夠MDP合成其中的3個?可能須要考慮Layer buffer維度、格式、縮放、Z序等因素。當多於3個的時候,是遍歷layer::draw使用GPU來繪製紋理到back framebuffer上的。
下面着重看少於等於3個Layer,MDP合成的狀況。
首先,全部的Layer的compositiontype都是HWC_FRAMEBUFFER的;
而後SurfaceFlinger在setHardwareComposer時發現hwc_prepare沒有別的優先的Overlay情景,最後的一個if分支就是使用MDP來作Layer合成;SurfaceFlinger會檢查Layer的屬性看是否知足使用MDP的條件,而後設置知足條件的Layer的屬性[compositionType, flags] = (HWC_OVERLAY, MDPCOMP);這樣SurfaceFlinger::composeSurfaces時,就再也不經過layer::draw使用GPU來繪製;
PIPE配置:SurfaceFlinger爲HWC建立工做集,爲每一個Layer分配並使用MDPComp::prepare配置每一個pipe,若是有縮放需求,則會分配VG pipe,由於RGB pipe不支持縮放;有一個Layer則Overlay狀態爲BYPASS_1_LAYER,表示有1個Layer Bypass,不須要OpenGL繪製,同理2個Layer爲BYPASS_2_LAYER,3個爲BYPASS_3_LAYER;
PIPE提交:在DisplayHardware::flip中提交每一個Layer的數據到管道,即MDPComp::draw() => Overlay::queueBuffer()。注意Layer圖像數據是在PMEM/ASHMEM內存中而不是Framebuffer內存中,但仍物理連續或IOMMU映射連續,LayerMixerdraw可訪問。MDPComp::draw完即提交數據到對應管道的單容量隊列後,清layer->flags &= ~HWC_MDPCOMP標誌;
在eglSwapBuffers時,真正作back & front Buffer的切換(準確地說雙緩衝是切換,三緩衝是輪用)
OV_PIPE3配置:DisplayHardware::flip => HWComposer::commit=> hwc_set=>eglSwapBuffers => queueBuffer=> fb_post=>update_framebuffer中使用base layer back framebuffer參數配置OV_PIPE3即RGB1 pipe;
OV_PIPE3提交:當update_framebuffer真正提交圖像數據到RGB1 pipe時,對應stage 0 for base layer(內核驅動)會啓動MDP LayerMixer0進行Layers合成;此時base layer是個最頂層的全透明Layer,不妨礙底層Layer的顯示;
DMA傳輸:而後fb_post經過FBIOPUT_VSCREENINFO或PAN_DISPLAY啓動DMA_P送合成好的圖像經MIPI-DSI輸出顯示。
BufferFlip:queueBuffer後,該framebuffer即爲front framebuffer,而後eglSwapBuffers會dequeueBuffer下一個Framebuffer作爲back framebuffer。
HWC功能時,是MDPComp@hwcomposer.msm8960.so對應的邏輯,一個Layer對應的 pipe設置和提交的棧示例以下:
#00 pc 0000b0d0 /system/lib/liboverlay.so (overlay::Overlay::commit(overlay::utils::eDest)+71)
#01 pc 00005d16 /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::prepare(hwc_context_t*, hwc_layer*, qhwc::MDPComp::mdp_pipe_info&)+577)
#02 pc 00006190 /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::setup(hwc_context_t*, hwc_layer_list*)+163) for each pipe.
#03 pc 0000652c /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::configure(hwc_composer_device*, hwc_layer_list*)+59)
#04 pc 000037ea /system/lib/hw/hwcomposer.msm8960.so hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list)
#05 pc 0001ebba /system/lib/libsurfaceflinger.so (android::HWComposer::prepare() const+9)
#06 pc 00020df4 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::setupHardwareComposer()+127)
#07 pc 000212f4 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::handleRepaint()+147)
#08 pc 000222e8 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+91)
/system/lib/liboverlay.so Overlay::queueBuffer(int fd, uint32_t offset, utils::eDest dest)
#00 pc 00006592 /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::draw(hwc_context_t*, hwc_layer_list*)+85) for each pipe.
#01 pc 00003ae4 /system/lib/hw/hwcomposer.msm8960.so static int hwc_set(hwc_composer_device_t *dev,hwc_display_t dpy,hwc_surface_t sur, hwc_layer_list_t* list)
#02 pc 0001ed56 /system/lib/libsurfaceflinger.so (android::HWComposer::commit() const+11)
#03 pc 0001e57c /system/lib/libsurfaceflinger.so (android::DisplayHardware::flip(android::Region const&) const+59)
#04 pc 000209c6 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::postFramebuffer()+61)
#05 pc 00022474 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+103)
Base layer對應的RGB pipe設置和提交的棧示例從略。重複地,Base layer提交到RGB1時真正啓動LayerMixer0的4-stage layer composition。
HDMI / WFD
有機會待續。
LayerMixer0合成後圖像經DMA_P輸出時,在BLT模式和DIRECTOUT模式下LayerMixer0與DMA之間沒有buffer;即便FB模式,也是一個Overlay buffer而未必是作爲Framebuffer內存,固然這個Overlay buffer作爲DMA_P輸入傳輸給MIPI-DSI/LCDC。
*****************************************************************************
FrameBuffer driver including MDP Overlay
Framebuffer設備的sysfs
330static int msm_fb_create_sysfs(struct platform_device *pdev)
331{
332 int rc;
333 struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
334
335 rc = sysfs_create_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group);
336 if (rc)
337 MSM_FB_ERR("%s: sysfs group creation failed, rc=%d\n", __func__,
338 rc);
339 return rc;
340}
root@android:/sys/class/graphics/fb0 # ls -al
-rw-r--r-- root root 4096 1970-06-27 09:37 bits_per_pixel
-rw-r--r-- root root 4096 1970-06-27 09:37 blank
-rw-r--r-- root root 4096 1970-06-27 09:37 console
-rw-r--r-- root root 4096 1970-06-27 09:37 cursor
-r--r--r-- root root 4096 1970-06-27 09:37 dev
-rw-r--r-- root root 4096 1970-06-27 09:37 mode
-rw-r--r-- root root 4096 1970-06-27 09:37 modes
-r--r--r-- root root 4096 1970-06-27 09:37 msm_fb_type
-r--r--r-- root root 4096 1970-06-27 09:37 name
-rw-r--r-- root root 4096 1970-06-27 09:37 pan
drwxr-xr-x root root 1970-06-27 08:28 power
-rw-r--r-- root root 4096 1970-06-27 09:37 rotate
-rw-r--r-- root root 4096 1970-06-27 09:37 state
-r--r--r-- root root 4096 1970-06-27 09:37 stride
lrwxrwxrwx root root 1970-06-27 09:37 subsystem -> ../../../../class/graphics
-rw-r--r-- root root 4096 1970-06-27 08:28 uevent
-rw-r--r-- root root 4096 1970-06-27 09:37 virtual_size
-r--r--r-- root root 4096 1970-06-27 08:28 vsync_event
root@android:/sys/class/graphics/fb0 # cat msm_fb_type
mipi dsi cmd panel
root@android:/sys/class/graphics/fb0 # cat bits_per_pixel
32
130|root@android:/sys/class/graphics/fb0 # cat dev
29:0
root@android:/sys/class/graphics/fb0 # cat modes
U:480x854p-0
root@android:/sys/class/graphics/fb0 # cat name
msmfb42_90501
root@android:/sys/class/graphics/fb0 # cat stride
1920
root@android:/sys/class/graphics/fb0 # cat virtual_size
480,2566
cont_splash_done field
Add support for "Continuous Splash Screen" feature.
The image displayed on the screen by the android bootloaderdriver should continue till the android animation shows up.
Delay the display initialization for MDP, display dependent clocksand panel power on functions.
bootloader顯示的image在linux內核啓動過程當中保持顯示在屏幕上,知道開機動畫顯示,即linux內核啓動過程當中不要出現黑屏。
Early suspend & Early resume
Early suspend是有wakelock還佔有,系統還不能總體suspend,可是能夠關閉屏幕、背光、輸入等;在Early suspended狀態時,從新打開屏幕、背光和輸入,是爲對應的early resume。
fb_register中相關設置以下:
1551 mfd->early_suspend.suspend = msmfb_early_suspend;
1552 mfd->early_suspend.resume = msmfb_early_resume;
1553 mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
1554 register_early_suspend(&mfd->early_suspend);
數據結構定義以下:
23/* The early_suspend structure defines suspend and resume hooks to be called
24 * when the user visible sleep state of the system changes, and a level to
25 * control the order. They can be used to turn off the screen and input
26 * devices that are not used for wakeup.
27 * Suspend handlers are called in low to high level order, resume handlers are
28 * called in the opposite order. If, when calling register_early_suspend,
29 * the suspend handlers have already been called without a matching call to the
30 * resume handlers, the suspend handler will be called directly from
31 * register_early_suspend. This direct call can violate the normal level order.
32 */
33enum {
34 EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
35 EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
36 EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
37};
38struct early_suspend {
39#ifdef CONFIG_HAS_EARLYSUSPEND
40 struct list_head link;
41 int level;
42 void (*suspend)(struct early_suspend *h);
43 void (*resume)(struct early_suspend *h);
44#endif
45};
backlight
msm_fb_set_backlight之後是使用led_trigger調用真正led_classdev "wled"的brightnes_set去設置背光。
用戶態ioctl經過msm_fb_set_backlight調用到msm_fb_panel_data::set_backlight,
"lcd_backlight".brightness_set -> msm_fb_panel_data::set_backlight -> "bkl_trigger".led_trigger -> "wled".brightness_set。而後找真正操做硬件IC部分。
驅動中設置背光則是繞過"lcd_backlight"設備直接經過backlight_worker工做執行到msm_fb_panel_data::set_backlight,而後-> "bkl_trigger".led_trigger -> "wled".brightness_set。
能夠認爲"lcd_backlight"是背光抽象設備,經過led_trigger的led組映射到不一樣的led_classdev設備
以三星DSI CMD屏爲例:
In mipi_samsung.c
294static void mipi_samsung_set_backlight(struct msm_fb_data_type *mfd)
295{
296 if (!cci_fb_UpdateDone){
297 printk("Taylor: No BL before LCM on\n");
298 return;
299 }
300
301 pr_debug("Taylor: %s : Set BL:%d\n",__func__, mfd->bl_level);
302 if ((mipi_samsung_pdata->enable_wled_bl_ctrl)
303 && (wled_trigger_initialized)) {
304 led_trigger_event(bkl_led_trigger, mfd->bl_level);
305 return;
306 }
307}
kernel/drivers/leds/leds-pm8xxx.c
#define PM8XXX_LEDS_DEV_NAME "pm8xxx-led"
2283static struct platform_driver pm8xxx_led_driver = {
2284 .probe = pm8xxx_led_probe,
2285 .remove = __devexit_p(pm8xxx_led_remove),
2286 .driver = {
2287 .name = PM8XXX_LEDS_DEV_NAME,
2288 .owner = THIS_MODULE,
2289 },
2290};
pm8xxx_led_probe會對pm8038_led_info數組中的每一個led使用設置led_classdev字段,而且初始化work item,而後使用led_classdev_register向系統註冊每一個led設備。
2197 INIT_WORK(&led_dat->work, pm8xxx_led_work);
2198 INIT_WORK(&led_dat->modework, pm8xxx_mode_work);
2199 INIT_WORK(&led_dat->testwork, pm8xxx_test_work);
每一個led的brightness_set字段設置爲pm8xxx_led_set。
1790static void pm8xxx_led_set(struct led_classdev *led_cdev,
1791 enum led_brightness value)
1792{
1793 struct pm8xxx_led_data *led;
1794
1795 led = container_of(led_cdev, struct pm8xxx_led_data, cdev);
1796
1797 if (value < LED_OFF || value > led->cdev.max_brightness) {
1798 dev_err(led->cdev.dev, "Invalid brightness value exceeds");
1799 return;
1800 }
1801
1802 led->cdev.brightness = value;
1803 schedule_work(&led->work);
1804}
1730static void pm8xxx_led_work(struct work_struct *work)
1731{
1732 int rc;
1733
1734 struct pm8xxx_led_data *led = container_of(work,
1735 struct pm8xxx_led_data, work);
1736
1737 if (led->pwm_dev == NULL) {
1738 __pm8xxx_led_work(led, led->cdev.brightness);
1739 } else {
1740 rc = pm8xxx_led_pwm_work(led);
1741 if (rc)
1742 pr_err("could not configure PWM mode for LED:%d\n",
1743 led->id);
1744 }
1745}
對PM8XXX_ID_WLED,是使用__pm8xxx_led_work
1692static void __pm8xxx_led_work(struct pm8xxx_led_data *led,
1693 enum led_brightness level)
1694{
1695 int rc;
1696
1697 mutex_lock(&led->lock);
1698
1699 switch (led->id) {
1700 case PM8XXX_ID_LED_KB_LIGHT:
1701 led_kp_set(led, level);
1702 break;
1703 case PM8XXX_ID_LED_0:
1704 case PM8XXX_ID_LED_1:
1705 case PM8XXX_ID_LED_2:
1706 led_lc_set(led, level);
1707 break;
1708 case PM8XXX_ID_FLASH_LED_0:
1709 case PM8XXX_ID_FLASH_LED_1:
1710 led_flash_set(led, level);
1711 break;
1712 case PM8XXX_ID_WLED:
1713 rc = led_wled_set(led, level);
1714 if (rc < 0)
1715 pr_err("wled brightness set failed %d\n", rc);
1716 break;
1717 case PM8XXX_ID_RGB_LED_RED:
1718 case PM8XXX_ID_RGB_LED_GREEN:
1719 case PM8XXX_ID_RGB_LED_BLUE:
1720 led_rgb_set(led, level);
1721 break;
1722 default:
1723 dev_err(led->cdev.dev, "unknown led id %d", led->id);
1724 break;
1725 }
1726
1727 mutex_unlock(&led->lock);
1728}
led_wled_set寫電源管理芯片pm8xxx的控制寄存器,控制wled。
Framebuffer fb_info::node
registered_fb它是一個數組,它的類型就是struct fb_info,它用於保存咱們調用register_framebuffer傳進來的struct fb_info。
num_registered_fb表明註冊幀緩衝設備的個數。
1522 for (i = 0; i < FB_MAX; i++)
1523 if (!registered_fb[i])
1524 break;
1525 fb_info->node = i;
至關於找到一個空的次設備號。
Framebuffer像素格式
主屏RGBA8888
In mipi_dsi_probe()
481 /*
482 * get/set panel specific fb info
483 */
484 mfd->panel_info = pdata->panel_info;
485 pinfo = &mfd->panel_info;
486
487 if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
488 mfd->dest = DISPLAY_LCDC;
489 else
490 mfd->dest = DISPLAY_LCD;
491
492 if (mdp_rev == MDP_REV_303 &&
493 mipi_dsi_pdata->get_lane_config) {
494 if (mipi_dsi_pdata->get_lane_config() != 2) {
495 pr_info("Changing to DSI Single Mode Configuration\n");
496#ifdef CONFIG_FB_MSM_MDP303
497 update_lane_config(pinfo);
498#endif
499 }
500 }
501
502 if (mfd->index == 0)
503 mfd->fb_imgType = MSMFB_DEFAULT_TYPE; // configed as RGBA8888 for fb0
504 else
505 mfd->fb_imgType = MDP_RGB_565;
msmfb_update_notify/ msmfb_no_update_notify
用於CABL功能時,統計直方圖使用;
更新屏幕前complete(&msmfb_update_notify)從而在準確時間點啓動直方圖統計;2*HZ後,msmfb_no_update_notify_timer超時,在timer超時回調中complete(&mfd->msmfb_no_update_notify)結束直方圖統計。
sw_refresher
使用定時器去觸發mdp_refresh_screen,添加work進行dma_fnc調用。
針對某些接口的VIDEO模式屏且控制器沒有hw_refresh支持時,可使用sw_refresher。
FB_ACTIVATE_VBL標誌涵義
fb_var_screeninfo結構體的成員變量activate的值設置FB_ACTIVATE_VBL,表示要等到下一個垂直同步事件出現時,再將當前要渲染的圖形緩衝區的內容繪製出來。這樣作的目的是避免出現屏幕閃爍,即避免先後兩個圖形緩衝區的內容各有一部分同時出現屏幕中。
Framebuffer初始化
設備資源申請是在MACHINE_DESC中實現的。示例以下:
3463MACHINE_START(MSM8930_CDP, "QCT MSM8930 CDP")
3464 .map_io = msm8930_map_io,
3465 .reserve = msm8930_reserve,
3466 .init_irq = msm8930_init_irq,
3467 .handle_irq = gic_handle_irq,
3468 .timer = &msm_timer,
3469 .init_machine = msm8930_cdp_init,
3470 .init_early = msm8930_allocate_memory_regions,
3471 .init_very_early = msm8930_early_memory,
3472 .restart = msm_restart,
3473MACHINE_END
machine_desc{.init_very_early, .init_early, .init_machine, .restart}, module_init driver的初始化順序參考Machine_desc & boot & Kernel_init & initcall & module_init
函數msm8930_cdp_init作Machine級別的設備的註冊,部分代碼以下:
static void __init msm8930_cdp_init(void) @ kernel/arch/arm/mach-msm/board-8930.c
{
…
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8930_init_gpu();
msm8930_init_mmc();
msm8930_init_cam();
msm8930_init_fb();
}
msm8930_cdp_init中與display相關的是msm8930_init_fb()函數,這個函數註冊了幾個id爲0的設備。各主要設備名以下,
「msm_fb」 msm framebuffer設備,注意不是linux framebuffer設備,可是有對應關係;
「wfd」 wifi顯示設備;
「mipi_dsi_cmd_samsung_fwvga」 mipi-dsi接口cmd模式LCD屏設備;
「hdmi_msm」 HDMI顯示器設備;
「mdp」 mobile display station顯示引擎設備;
「mipi-dsi」 MIPI-DSI顯示器驅動設備(id例外用了1,可能有的平臺上有兩個MIPI-DSI,另外一個id爲0);
1168void __init msm8930_init_fb(void) @ kernel/arch/arm/mach-msm/board-8930-display.c
1169{
1170 platform_device_register(&msm_fb_device);
1171
1172#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
1173 platform_device_register(&wfd_panel_device);
1174 platform_device_register(&wfd_device);
1175#endif
1176
1178#ifdef CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
1179 platform_device_register(&mipi_dsi_novatek_panel_device);
1180#endif
1181
1184#ifdef CONFIG_FB_MSM_MIPI_SA77_CMD_FWVGA_PANEL
1185 platform_device_register(&mipi_dsi_cmd_chimei_fwvga_panel_device);
1186 platform_device_register(&mipi_dsi_cmd_samsung_fwvga_panel_device);
1187#endif
1189
1190#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
1191 platform_device_register(&hdmi_msm_device);
1192#endif
1193
1194 platform_device_register(&mipi_dsi_toshiba_panel_device);
1195
1196 msm_fb_register_device("mdp", &mdp_pdata);
1197 msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
1198#ifdef CONFIG_MSM_BUS_SCALING
1199#ifdef CONFIG_FB_MSM_DTV
1200 msm_fb_register_device("dtv", &dtv_pdata);
1201#endif
1202#endif
1203}
由於註冊這些設備的意圖主要是資源申請和初步初始化設備,因此各設備註冊順序並沒有關緊要。其初始化順序還與後來的驅動實際註冊順序有關。
首先註冊paltform_devicemsm_fb_device,設備定義以下
71static struct resource msm_fb_resources[] = {
72 {
73 .flags = IORESOURCE_DMA,
74 }
75};
135static struct msm_fb_platform_data msm_fb_pdata = {
136 .detect_client = msm_fb_detect_panel,
137};
138
139static struct platform_device msm_fb_device = {
140 .name = "msm_fb",
141 .id = 0,
142 .num_resources = ARRAY_SIZE(msm_fb_resources),
143 .resource = msm_fb_resources,
144 .dev.platform_data = &msm_fb_pdata,
145};
而後註冊panel設備,設備定義以下
845static struct mipi_dsi_panel_platform_data samsung_pdata = {
846 .enable_wled_bl_ctrl = 0x1,
847};
848
849static struct platform_device mipi_dsi_cmd_samsung_fwvga_panel_device = {
850 .name = "dsi_cmd_samsung_fwvga",
851 .id = 0,
852 .dev = {
853 .platform_data = &samsung_pdata,
854 }
855};
而後關鍵的註冊mdp和mipi-dsi controller,設備定義以下
1749void __init msm_fb_register_device(char *name, void *data)
1750{
1751 if (!strncmp(name, "mdp", 3))
1752 msm_register_device(&msm_mdp_device, data);
1753 else if (!strncmp(name, "lcdc", 4))
1754 msm_register_device(&msm_lcdc_device, data);
1755 else if (!strncmp(name, "mipi_dsi", 8))
1756 msm_register_device(&msm_mipi_dsi_device, data);
1757#ifdef CONFIG_FB_MSM_TVOUT
1758 else if (!strncmp(name, "tvenc", 5))
1759 msm_register_device(&msm_tvenc_device, data);
1760 else if (!strncmp(name, "tvout_device", 12))
1761 msm_register_device(&msm_tvout_device, data);
1762#endif
1763#ifdef CONFIG_MSM_BUS_SCALING
1764 else if (!strncmp(name, "dtv", 3))
1765 msm_register_device(&msm_dtv_device, data);
1766#endif
1767 else
1768 printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
1769}
mdp和mipi-dsi設備及寄存器映射和中斷需求以下
1484#define MIPI_DSI_HW_BASE 0x04700000
1485#define ROTATOR_HW_BASE 0x04E00000
1486#define TVENC_HW_BASE 0x04F00000
1487#define MDP_HW_BASE 0x05100000
1488
1489static struct resource msm_mipi_dsi_resources[] = {
1490 {
1491 .name = "mipi_dsi",
1492 .start = MIPI_DSI_HW_BASE,
1493 .end = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
1494 .flags = IORESOURCE_MEM,
1495 },
1496 {
1497 .start = DSI_IRQ,
1498 .end = DSI_IRQ,
1499 .flags = IORESOURCE_IRQ,
1500 },
1501};
1502
1503static struct platform_device msm_mipi_dsi_device = {
1504 .name = "mipi_dsi",
1505 .id = 1,
1506 .num_resources = ARRAY_SIZE(msm_mipi_dsi_resources),
1507 .resource = msm_mipi_dsi_resources,
1508};
1509
1510static struct resource msm_mdp_resources[] = {
1511 {
1512 .name = "mdp",
1513 .start = MDP_HW_BASE,
1514 .end = MDP_HW_BASE + 0x000F0000 - 1,
1515 .flags = IORESOURCE_MEM,
1516 },
1517 {
1518 .start = INT_MDP,
1519 .end = INT_MDP,
1520 .flags = IORESOURCE_IRQ,
1521 },
1522};
1523
1524static struct platform_device msm_mdp_device = {
1525 .name = "mdp",
1526 .id = 0,
1527 .num_resources = ARRAY_SIZE(msm_mdp_resources),
1528 .resource = msm_mdp_resources,
1529};
以上設備註冊時,其驅動並未加載,由於machine_desc.init_machine設備註冊的arch_initcall是在.initcall3.init中,而module_init driver註冊是在.initcall6.init中。等其驅動加載時,在對應的probe函數中,判斷設備id,初步初始化設備,保存其資源分配。
此時,如下id爲0的設備panel, dtv, hdmi, mdp, msm_fb, id爲1的mipi-dsi設備已經註冊進系統了。
dsi_cmd_chimei_fwvga.0
dsi_cmd_samsung_fwvga.0
dsi_cmd_samsung_fwvga.1281
dtv.0
dtv.458753
hdmi_msm.0
hdmi_msm.1
mdp.0
mdp.458753
mdp.591105
mdp.655361
mipi_dsi.1
mipi_dsi.591105
mipi_toshiba.0
msm_fb.0
msm_fb.458753
msm_fb.591105
msm_fb.655361
下面描述各驅動註冊,各驅動都是module_init的。
msm_fb驅動註冊以下
module_init(msm_fb_init);
3898int __init msm_fb_init(void) @ kernel/drivers/video/msm/msm_fb.c
3899{
3900 int rc = -ENODEV;
3901
3902 if (msm_fb_register_driver())
3903 return rc;
….
}
3705static int msm_fb_register_driver(void)
3706{
3707 return platform_driver_register(&msm_fb_driver);
3708}
msm_fb_driver驅動定義以下
734static struct platform_driver msm_fb_driver = {
735 .probe = msm_fb_probe,
736 .remove = msm_fb_remove,
737#ifndef CONFIG_HAS_EARLYSUSPEND
738 .suspend = msm_fb_suspend,
739 .resume = msm_fb_resume,
740#endif
741 .shutdown = NULL,
742 .driver = {
743 /* Driver name must match the device name added in platform.c. */
744 .name = "msm_fb",
745 .pm = &msm_fb_dev_pm_ops,
746 },
747};
platform_device 「msm_fb」的resource[0]是一塊DMA內存,是framebuffer內存,可是在資源定義中並無設置size,而在msm_fb_probe中從其使用能夠看到該DMA內存已經分配。其size是在machine的init_early中從bootmem中分配的,比machine級別設備註冊要早!
.init_early = msm8930_allocate_memory_regions,
msm8930_allocate_memory_regions(void) @ kernel/arch/arm/mach-msm/board-8930.c
1006static void __init msm8930_allocate_memory_regions(void)
1007{
1008 msm8930_allocate_fb_region();
1009}
msm8930_allocate_fb_region() @ kernel/arch/arm/mach-msm/board-8930-display.c
1205void __init msm8930_allocate_fb_region(void)
1206{
1207 void *addr;
1208 unsigned long size;
1209
1210 size = MSM_FB_SIZE;
1211 addr = alloc_bootmem_align(size, 0x1000);
1212 msm_fb_resources[0].start = __pa(addr);
1213 msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
1214 pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", size, addr, __pa(addr));
1216}
MSM_FB_SIZE宏定義以下,TRIPLE_BUFFER已經是主流
32#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
33#define MSM_FB_PRIM_BUF_SIZE \
34 (roundup((1920 * 1088 * 4), 4096) * 3) /* 4 bpp x 3 pages */
35#else
36#define MSM_FB_PRIM_BUF_SIZE \
37 (roundup((1920 * 1088 * 4), 4096) * 2) /* 4 bpp x 2 pages */
38#endif
39/* Note: must be multiple of 4096 */
40#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
當」msm_fb」註冊時,msm_fb_probe在設備和驅動match後被調用。對於msm_fb_device id=0,只作fbram保存和ION client建立;這時probe到的設備對應/sys/bus/platform/devices /msm_fb.0。
msm_ion_client_create(-1, pdev->name);
」mipi-dsi」 driver定義和註冊以下 (in kernel/drivers/video/msm/mipi_dsi.c)
55static struct platform_driver mipi_dsi_driver = {
56 .probe = mipi_dsi_probe,
57 .remove = mipi_dsi_remove,
58 .shutdown = NULL,
59 .driver = {
60 .name = "mipi_dsi",
61 },
62};
603static int mipi_dsi_register_driver(void)
604{
605 return platform_driver_register(&mipi_dsi_driver);
606}
607
608static int __init mipi_dsi_driver_init(void)
609{
610 int ret;
611
612 mipi_dsi_init();
613
614 ret = mipi_dsi_register_driver();
615
616 device_initialize(&dsi_dev);
617
618 if (ret) {
619 pr_err("mipi_dsi_register_driver() failed!\n");
620 return ret;
621 }
622
623 return ret;
624}
625
626module_init(mipi_dsi_driver_init);
「mdp」 driver定義和註冊以下(in kernel/drivers/video/msm/mdp.c)
2094static struct platform_driver mdp_driver = {
2095 .probe = mdp_probe,
2096 .remove = mdp_remove,
2097#ifndef CONFIG_HAS_EARLYSUSPEND
2098 .suspend = mdp_suspend,
2099 .resume = NULL,
2100#endif
2101 .shutdown = NULL,
2102 .driver = {
2103 /*
2104 * Driver name must match the device name added in
2105 * platform.c.
2106 */
2107 .name = "mdp",
2108 .pm = &mdp_dev_pm_ops,
2109 },
2110};
3001static int mdp_register_driver(void)
3002{
3003#ifdef CONFIG_HAS_EARLYSUSPEND
3004 early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1;
3005 early_suspend.suspend = mdp_early_suspend;
3006 early_suspend.resume = mdp_early_resume;
3007 register_early_suspend(&early_suspend);
3008#endif
3009
3010 return platform_driver_register(&mdp_driver);
3011}
3012
3013static int __init mdp_driver_init(void)
3014{
3015 int ret;
3016
3017 mdp_drv_init();
3018
3019 ret = mdp_register_driver();
3020 if (ret) {
3021 printk(KERN_ERR "mdp_register_driver() failed!\n");
3022 return ret;
3023 }
3024
3025#if defined(CONFIG_DEBUG_FS)
3026 mdp_debugfs_init();
3027#endif
3028
3029 return 0;
3030
3031}
3032
3033module_init(mdp_driver_init);
當真正從屏驅動中添加一塊顯示設備時,爲了讓上級設備(「mipi-dsi」 「mdp」 「msm_fb」 「fb」)使用下級設備,高通實現爲下級設備建立了每一個上級設備的實例,經過從下到上的設備probe鏈一級一級向上註冊。這時保證從下到上的設備註冊順序就是相當重要的了,probe鏈作註冊來保證這一點。
固然爲了達到上級設備使用和管理下級設備的目標,另外一種方法是下級設備向上級設備作register,這時要保證下級設備向上級設備註冊時,上級設備的用於管理的相關數據結構已經準備好。
下面描述由屏驅動添加屏到註冊linux framebuffer設備的流程。
在各自的屏設備註冊文件中,會去探測屏,這種探測不是作真正掃描,僅僅是使用設備名字驗證一下,以SAMSUNG MIPI DSI CMD屏爲例,驅動會使用相應規則ID註冊一塊屏。
static int __init mipi_cmd_samsung_fwvga_pt_init(void) @ kernel/drivers/video/msm/mipi_samsung_cmd_fwvga_pt.c
{
37 int ret;
38
39 if (msm_fb_detect_client("mipi_cmd_samsung_fwvga"))
40 return 0;
……
88 ret = mipi_samsung_device_register(&pinfo, MIPI_DSI_PRIM, MIPI_DSI_PANEL_QHD_PT);
90 if (ret)
91 pr_err("%s: failed to register device!\n", __func__);
92
93 return ret;
94}
95
96module_init(mipi_cmd_samsung_fwvga_pt_init);
探測函數int msm_fb_detect_client(const char *name)首先使用主屏和外屏名字匹配,匹配不成則使用msm_fd_device.dev.platform .detect_client = msm_fb_detect_panel去匹配。上面欲同時註冊SAMSUNG和CHIMEI兩塊屏設備,固然不能同時detect_panel成功,使用GPIO管腳配置作了二次匹配。實際不一樣批次的手機可能用到兩塊屏中的一種。
而後mipi_samsung_device_register()(對CHIMEI則是mipi_chimei_device_register)註冊屏驅動和屏設備。驅動定義和註冊具體以下,
358static struct platform_driver this_driver = {
359 .probe = mipi_samsung_lcd_probe,
360 .driver = {
361 .name = "dsi_cmd_samsung_fwvga",
362 },
363};
364
365static struct msm_fb_panel_data samsung_panel_data = {
366 .on = mipi_samsung_lcd_on,
367 .off = mipi_samsung_lcd_off,
368 .set_backlight = mipi_samsung_set_backlight,
369};
373int mipi_samsung_device_register(struct msm_panel_info *pinfo, u32 channel, u32 panel)
375{
376 struct platform_device *pdev = NULL;
377 int ret;
378
379 if ((channel >= 3) || ch_used[channel])
380 return -ENODEV;
381
382 ch_used[channel] = TRUE;
383
384 ret = mipi_samsung_lcd_init();
385 if (ret) {
386 pr_err("mipi_samsung_lcd_init() failed with ret %u\n", ret);
387 return ret;
388 }
389
390 pdev = platform_device_alloc("dsi_cmd_samsung_fwvga", (panel << 8)|channel);
391 if (!pdev)
392 return -ENOMEM;
393
394 samsung_panel_data.panel_info = *pinfo;
395
396 ret = platform_device_add_data(pdev, &samsung_panel_data,
397 sizeof(samsung_panel_data));
398 if (ret) {
399 printk(KERN_ERR
400 "%s: platform_device_add_data failed!\n", __func__);
401 goto err_device_put;
402 }
403
404 ret = platform_device_add(pdev);
405 if (ret) {
406 printk(KERN_ERR
407 "%s: platform_device_register failed!\n", __func__);
408 goto err_device_put;
409 }
410
411 return 0;
412
413err_device_put:
414 platform_device_put(pdev);
415 return ret;
416}
417
418static int mipi_samsung_lcd_init(void)
419{
420
421 led_trigger_register_simple("bkl_trigger", &bkl_led_trigger);
422 pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__);
423 wled_trigger_initialized = 1;
424
425 mipi_dsi_buf_alloc(&samsung_tx_buf, DSI_BUF_SIZE);
426 mipi_dsi_buf_alloc(&samsung_rx_buf, DSI_BUF_SIZE);
427
428 return platform_driver_register(&this_driver);
429}
在mipi_samsung_lcd_init()中註冊platform_driver屏驅動,而後分配註冊platform_device屏設備;platform_data設置爲msm_fb_panel_data向上傳遞參數並用於上級設備調用控制屏開關和背光。
屏設備註冊後,platform_device和platform_driver match,驅動的probe函數被調用,把參數一級一級向上帶,用於設置上級設備參數,向上一級一級註冊設備(「mipi-dsi」, 「mdp」, 「msm_fb」, 「framebuffer」)。
一個相似的調用棧以下
------------[ cut here ]------------
WARNING: at /home/CORPUSERS/xp010548/myworkdroid/7x25a/LINUX/kernel/drivers/video/msm/msm_fb.c:1221 msm_fb_probe+0xf4/0xcbc()
msm_fb_probe
Modules linked in:
[<c003fe0c>] (unwind_backtrace+0x0/0x12c) from [<c00adccc>] (warn_slowpath_common+0x4c/0x64)
[<c00adccc>] (warn_slowpath_common+0x4c/0x64) from [<c00add64>] (warn_slowpath_fmt+0x2c/0x3c)
[<c00add64>] (warn_slowpath_fmt+0x2c/0x3c) from [<c0223c44>] (msm_fb_probe+0xf4/0xcbc)
[<c0223c44>] (msm_fb_probe+0xf4/0xcbc) from [<c026e624>] (platform_drv_probe+0x18/0x1c)
[<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264)
[<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84)
[<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0)
[<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40)
[<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570)
[<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0)
[<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c02264b4>] (mdp_probe+0x828/0x940)
[<c02264b4>] (mdp_probe+0x828/0x940) from [<c026e624>] (platform_drv_probe+0x18/0x1c)
[<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264)
[<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84)
[<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0)
[<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40)
[<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570)
[<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0)
[<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c023db98>] (mipi_dsi_probe+0x514/0x5d0)
[<c023db98>] (mipi_dsi_probe+0x514/0x5d0) from [<c026e624>] (platform_drv_probe+0x18/0x1c)
[<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264)
[<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84)
[<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0)
[<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40)
[<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570)
[<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0)
[<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c02223b8>] (msm_fb_add_device+0x150/0x1b4)
[<c02223b8>] (msm_fb_add_device+0x150/0x1b4) from [<c051e830>] (mipi_himax_lcd_probe+0x38/0x108)
[<c051e830>] (mipi_himax_lcd_probe+0x38/0x108) from [<c026e624>] (platform_drv_probe+0x18/0x1c)
[<c026e624>] (platform_drv_probe+0x18/0x1c) from [<c026d354>] (driver_probe_device+0x144/0x264)
[<c026d354>] (driver_probe_device+0x144/0x264) from [<c026c78c>] (bus_for_each_drv+0x48/0x84)
[<c026c78c>] (bus_for_each_drv+0x48/0x84) from [<c026d5d0>] (device_attach+0x74/0xa0)
[<c026d5d0>] (device_attach+0x74/0xa0) from [<c026c5a4>] (bus_probe_device+0x24/0x40)
[<c026c5a4>] (bus_probe_device+0x24/0x40) from [<c026b4c4>] (device_add+0x3f0/0x570)
[<c026b4c4>] (device_add+0x3f0/0x570) from [<c026ec54>] (platform_device_add+0x13c/0x1a0)
[<c026ec54>] (platform_device_add+0x13c/0x1a0) from [<c02409ec>] (mipi_himax_device_register+0x7c/0xc0)
[<c02409ec>] (mipi_himax_device_register+0x7c/0xc0) from [<c001ac34>] (mipi_cmd_himax_hvga_pt_init+0x148/0x180)
[<c001ac34>] (mipi_cmd_himax_hvga_pt_init+0x148/0x180) from [<c0034388>] (do_one_initcall+0x94/0x164)
[<c0034388>] (do_one_initcall+0x94/0x164) from [<c00083d8>] (kernel_init+0x98/0x144)
[<c00083d8>] (kernel_init+0x98/0x144) from [<c003b0d0>] (kernel_thread_exit+0x0/0x8)
---[ end trace 65f8ea860415c051 ]---
下面考察設備probe鏈。
311static int __devinit mipi_samsung_lcd_probe(struct platform_device *pdev)
312{
…..
338 current_pdev = msm_fb_add_device(pdev);
339
340 if (current_pdev) {
341 mfd = platform_get_drvdata(current_pdev);
342 if (!mfd)
343 return -ENODEV;
344 if (mfd->key != MFD_KEY)
345 return -EINVAL;
346
347 mipi = &mfd->panel_info.mipi;
348
349 if (phy_settings != NULL)
350 mipi->dsi_phy_db = phy_settings;
351
352 if (dlane_swap)
353 mipi->dlane_swap = dlane_swap;
354 }
355 return 0;
356}
msm_fb_add_device作以下事情:
調用struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, u32 type, u32 id)函數分配platform_device 「mipi-dsi.type_devid」並設置其platform_data爲msm_fb_panel_data。
以額外msm_fb_data_type結構分配framebuffer。
註冊」mipi-dsi」設備platform_device_add(this_dev)。
「mipi-dsi」設備和驅動進行attach, match後,「mipi-dsi」 driver的probe被調用到。
static int mipi_dsi_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/mipi_dsi.c作以下事情(此次的設備ID是真正實例的了,不是1了):
分配」mdp」設備實例並設置其數據,設置」mipi-dsi」設備操做函數,用於向下操做一級一級設備;
繼續設置linux framebuffer的參數;
根據屏分辨率設置mipi-dsi工做頻率;
註冊該」mdp」設備實例;
「mdp」設備和驅動進行attach, match後,「mdp」 driver的probe被調用到。
static int mdp_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/mdp.c
分配」msm_fb」實例並設置其數據;
配置」mdp」工做模式;
註冊」msm_fb」實例;
「msm_fb」設備和驅動進行attach, match後,「msm_fb」 driver的probe被調用到。
static int msm_fb_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/msm_fb.c
調用msm_fb_register設置linux framebuffer並register_framebuffer。
至此,系統中相關設備以下:
dsi_cmd_chimei_fwvga.0
dsi_cmd_samsung_fwvga.0
dsi_cmd_samsung_fwvga.1281 ->mipi_dsi.591105 -> mdp.591105 -> msm_fb.591105 -> fbx
dtv.0
dtv.458753 ->mdp.458753 -> msm_fb.458753 -> fbx
hdmi_msm.0
hdmi_msm.1 ->mdp.655361 -> msm_fb.655361 -> fbx (hdmi)
mdp.0
mipi_dsi.1
mipi_toshiba.0
msm_fb.0
*******************************************************************************
MDP圖像合成和顯示過程—Framebuffer驅動
Overlay設置和提交過程
msmfb_overlay_set(struct fb_info *info, void __user *p)
è mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
申請pipe,並設置pipe的clock和bandwidth。
int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
è int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req)
計算pipe輸入緩衝地址、參數配置等;將request暫存,如對DSI CMD屏,是使用void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe),而DSI VIDEO屏是使用void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)。
base_pipe設置和提交,Layer Mix, DMA
當送FBIOPUT_VSCREENINFO或FBIOPAN_DISPLAY命令給FB設備時,最終會調用msm_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
msm_fb_pan_display
è mdp_set_dma_pan_info(info, dirtyPtr, (var->activate == FB_ACTIVATE_VBL)); //設置DMA區域
è mdp_dma_pan_update(info); //啓動DMA,包括Layer Mixer合成和DMA輸出
void mdp_dma_pan_update(struct fb_info *info)
è mfd->dma_fnc(mfd);
對MIPI DSI CMD屏,該DMA函數是mdp4_dsi_cmd_overlay。
void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)
{
……
pipe = vctrl->base_pipe;
……
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) { // it is certain for base_pipe
// it is setup in mdp4_overlay_update_dsi_cmd when dsi cmd panel is on.
mdp4_mipi_vsync_enable(mfd, pipe, 0);
mdp4_overlay_setup_pipe_addr(mfd, pipe);
mdp4_dsi_cmd_pipe_queue(0, pipe); // arm the base pipe with framebuffer
}
mdp4_overlay_mdp_perf_upd(mfd, 1); // level up the mdp performance
mutex_lock(&mfd->dma->ov_mutex);
mdp4_dsi_cmd_pipe_commit(cndx, 0); // fire the overlay layer mixer and dma
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
}
int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)
{
int i, undx;
int mixer = 0;
struct vsycn_ctrl *vctrl;
struct vsync_update *vp;
struct mdp4_overlay_pipe *pipe;
struct mdp4_overlay_pipe *real_pipe;
unsigned long flags;
int need_dmap_wait = 0;
int need_ov_wait = 0;
int cnt = 0;
/**
*static struct vsycn_ctrl { … } vsync_ctrl_db [MAX_CONTROLLER]
*在不一樣的顯示器文件中有不一樣的定義,注意其是static的。
*不一樣顯示應用時關聯不一樣的LayerMixer,因此同一種應用中,
*使用具備同一mixer_num的pipe,mixer_num由應用分配的主pipe即該應用對應的
* vsync_ctrl_db的base_pipe指定。全部pipe的LayerMixer0是驅動中固定指定好的。
*/
vctrl = &vsync_ctrl_db[0];
mutex_lock(&vctrl->update_lock);
undx = vctrl->update_ndx;
vp = &vctrl->vlist[undx];
pipe = vctrl->base_pipe;
mixer = pipe->mixer_num; // the Layer mixer used, LayerMixer0 here.
if (vp->update_cnt == 0) {
mutex_unlock(&vctrl->update_lock);
return cnt;
}
//vctrl->update_ndx++;
//vctrl->update_ndx &= 0x01;
vp->update_cnt = 0; /* reset */
if (vctrl->blt_free) {
vctrl->blt_free--;
if (vctrl->blt_free == 0)
mdp4_free_writeback_buf(vctrl->mfd, mixer);
}
mutex_unlock(&vctrl->update_lock);
/* free previous committed iommu back to pool */
mdp4_overlay_iommu_unmap_freelist(mixer);
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
/* Blt */
if (vctrl->blt_wait)
need_dmap_wait = 1;
if (vctrl->ov_koff != vctrl->ov_done) {
INIT_COMPLETION(vctrl->ov_comp);
need_ov_wait = 1;
}
} else {
/* direct out */
if (vctrl->dmap_koff != vctrl->dmap_done) {
INIT_COMPLETION(vctrl->dmap_comp);
pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n",
__func__, vctrl->ov_koff, vctrl->ov_done,
vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id());
need_dmap_wait = 1;
}
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
/* setup completion for dmap wait in DIRECTOUT mode or overlay wait in BLT mode */
if (need_dmap_wait) {
pr_debug("%s: wait4dmap\n", __func__);
mdp4_dsi_cmd_wait4dmap(0);
}
if (need_ov_wait) {
pr_debug("%s: wait4ov\n", __func__);
mdp4_dsi_cmd_wait4ov(0);
}
if (pipe->ov_blt_addr) {
if (vctrl->blt_end) {
vctrl->blt_end = 0;
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
pr_info("%s: reset ov_blt_addr and dma_blt_addr\n", __func__);
}
}
/* if blt has some change, reconfig overlay proccessor and dmap*/
if (vctrl->blt_change) {
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
vctrl->blt_change = 0;
}
pipe = vp->plist;
/*
*All pipes used here is targeted to LayerMixer0.
* These pipes are allocated with MIXER0 indeed,
* and queued in vctrl->vlist[undx]. >plist[pipe->pipe_ndx - 1] again.
* Obvious with target to MIXER0.
*/
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
if (pipe->pipe_used) {
/* pipes in vp->plist maybe point to same physical pipe */
cnt++;
real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
if (real_pipe && real_pipe->pipe_used) {
/* pipe not unset */
mdp4_overlay_vsync_commit(pipe);
}
/* free previous iommu to freelist
* which will be freed at next
* pipe_commit
*/
mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
pipe->pipe_used = 0; /* clear */
}
}
/* tx dcs command if had any */
mipi_dsi_cmdlist_commit(1);
/* mixer is MIXER0 here. Setup mixer’s each stage with pipe */
mdp4_mixer_stage_commit(mixer);
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
mdp4_dsi_cmd_blt_ov_update(pipe);
pipe->ov_cnt++;
vctrl->ov_koff++;
INIT_COMPLETION(vctrl->ov_comp);
vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
} else {
INIT_COMPLETION(vctrl->dmap_comp);
vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
vctrl->dmap_koff++;
}
pr_debug("%s: kickoff, pid=%d\n", __func__, current->pid);
/* kickoff overlay engine */
mdp4_stat.kickoff_ov0++;
outpdw(MDP_BASE + 0x0004, 0);
mb();
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
mdp4_stat.overlay_commit[pipe->mixer_num]++;
/* wait for vsync */
if (wait) {
long long tick;
mdp4_dsi_cmd_wait4vsync(cndx, &tick);
}
return cnt;
}
void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe)
{
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
else
mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,
(int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);
/* figure out the flush value to fill register */
mdp4_overlay_reg_flush(pipe, 1);
/* stage setup but not commit */
mdp4_mixer_stage_up(pipe, 0);
}
void mdp4_mixer_stage_commit(int mixer)
{
struct mdp4_overlay_pipe *pipe;
int i, num;
u32 data, stage;
int off;
unsigned long flags;
data = 0;
for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
pipe = ctrl->stage[mixer][i];
if (pipe == NULL)
continue;
pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,
mixer, pipe->pipe_ndx, i);
stage = pipe->mixer_stage;
if (mixer >= MDP4_MIXER1)
stage += 8;
stage <<= (4 * pipe->pipe_num);
data |= stage;
}
/*
* stage_commit may be called from overlay_unset
* for command panel, mdp clocks may be off at this time.
* so mdp clock enabled is necessary
*/
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_clk_ctrl(1);
mdp4_mixer_blend_setup(mixer);
off = 0;
if (data != ctrl->mixer_cfg[mixer]) {
ctrl->mixer_cfg[mixer] = data;
if (mixer >= MDP4_MIXER2) {
/* MDP_LAYERMIXER2_IN_CFG */
off = 0x100f0;
} else {
/* mixer 0 or 1 */
num = mixer + 1;
num &= 0x01;
data |= ctrl->mixer_cfg[num];
off = 0x10100;
}
pr_debug("%s: mixer=%d data=%x flush=%x pid=%d\n", __func__,
mixer, data, ctrl->flush[mixer], current->pid);
}
local_irq_save(flags);
if (off)
outpdw(MDP_BASE + off, data);
if (ctrl->flush[mixer]) {
outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);
ctrl->flush[mixer] = 0;
}
local_irq_restore(flags);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_clk_ctrl(0);
}
*****************************************************************************
[END]