Android圖形合成和顯示系統---基於高通MSM8k MDP4平臺

介紹了Android SurfaceFlinger層次如下的圖形合成和顯示系統,主要基於高通MSM8k MDP4x平臺。前端

作爲Android Display專題。SurfaceFlinger的詳細介紹參見連接文章。node

Android GDISurfaceFlingerlinux

SurfaceFinger按英文翻譯過來就是Surface投遞者。SufaceFlinger的構成並非太複雜,複雜的是他的客戶端建構。SufaceFlinger主要功能是:android

1LayersSurfaces內容的刷新到屏幕上編程

2維持LayerZorder序列,並對Layer最終輸出作出裁剪計算。後端

3響應Client要求,建立Layer與客戶端的Surface創建鏈接數組

4接收Client要求,修改Layer屬性(輸出大小,Alpha等設定)緩存

可是做爲投遞者的實際意義,咱們首先須要知道的是如何投遞,投擲物,投遞路線,投遞目的地。數據結構

1 SurfaceFlinger的基本組成框架架構

SurfaceFlinger管理對象爲:

mClientsMap:管理客戶端與服務端的鏈接。

ISurfaceIsurfaceComposerAIDL調用接口實例

mLayerMap:服務端的Surface的管理對象。

mCurrentState.layersSortedByZ:以SurfaceZ-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.在當前的Android2.1)版本的設計中,系統支持一個graphicPlane,因此也就支持一個DisplayHardware

SurfaceFlingerHardware硬件緩衝區的數據結構關係圖。

3.2 Layer

method:setBufferSurfaceFlinger端創建顯示緩衝區。這裏的緩衝區是指的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

SurfaceZ-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進程上下文。

創建主SurfaceOpenGL ES)。 DisplayHardwareInit()@DisplayHardware.cpp函數對OpenGL作了初始化,並建立立主Surface。爲何叫主Surface,由於全部的Layer在繪製時,都須要先繪製在這個主Surface上,最後系統纔將主Surface的內容投擲到真正的屏幕上。

3Surface的綁定

1)在DisplayHandware初始完畢後,hw.makeCurrent()將主SurfaceOpenGL ES進程上下文綁定到SurfaceFlinger的上下文中,

2)以後全部的SurfaceFlinger進程中使用EGL的全部的操做目的地都是mSurface@DisplayHardware

這樣,在OpenGL繪製圖形時,主Surface被記錄在進程的上下文中,因此看不到顯示的主Surfce相關參數的傳遞。下面是Layer-DrawHardware.flip的動做示意圖:

4.2 ThreadLoop

(1)handleTransaction(…):主要計算每一個Layer有無屬性修改,若是有修改着內用須要重畫。

(2)handlePageFlip()

computeVisibleRegions:根據Z-Order序列計算每一個Layer的可見區域和被覆蓋區域。裁剪輸出範圍計算-

在生成裁剪區域的時候,根據Z_order依次,每一個Layer在計算本身在屏幕的可顯示區域時,須要經歷以下步驟:

1)以本身的W,H給出本身初始的可見區域

2)減去本身上面窗口所覆蓋的區域

在繪製時,Layer將根據本身的可將區域作相應的區域數據Copy

3handleRepaint()

composeSurfaces(須要刷新區域):

根據每一個Layer的可見區域與須要刷新區域的交集區域從Z-Order序列從底部開始繪製到主Surface上。

4postFramebuffer()

DisplayHardwarehw.flip(mInvalidRegion);

eglSwapBuffers(display,mSurface) :mSruface投遞到屏幕。

5總結

如今SurfaceFlinger乾的事情利用下面的示意圖表示出來:

更詳細地,參考

Android GUISurfaceFlinger系列

Android display架構分析-SW架構分析(1-8)

SurfaceFlinger使用的各組件,參考

Learning about Android Graphics Subsystem by MIPS Engineer

*******************************************************************************

 

 

Copybit HAL Introduction

SurfaceFlinger layercompositionType有三種:

HWC_FRAMEBUFFER的使用OpenGL ES來繪製;

HWC_OVERLAY的使用Overlay Engine來合成;

HWC_USE_COPYBIT的使用Copybit硬件加速繪製;

 

MSM8xxx平臺Jellybean代碼中沒有發現使用HWC_USE_COPYBITlayer,該平臺下 Copybit 硬件加速主要有兩種:

PPP vpe模塊的PPPdirect copy

C2D :多是2D GPU OpenVG之類的。

PPP驅動實現是作爲Framebuffer設備的一個命令MSMFB_BLITC2D是使用c2d hal庫;

MSM7627平臺下hwcomposer仍是使用copybit的。

可能早期系統沒有Hardware Composer,又沒有GPU的時候,layer draw就要使用Copybit去一層一層一RectRect的拷貝了。

 

Copybit的代碼在display/libcopybit下,硬件合成器使用Copybit作的封裝代碼在display/libhwcomposer/copybitcopybit_c2d中,前者對應PPP,後者對應C2D

*******************************************************************************

 

AndroidGralloc流程分析for msm8960

主要介紹Gralloc/Framebuffer HAL設備,能夠籍此考察顯示Buffer(Ashmem、Pmem)的擁有者和傳遞。

平臺中內存有ashmenPMEM等多種內存類型,爲了VideoGraphicsGPU內存訪問的須要,android引入Gralloc模塊實現內存的管理。GrallocFrameBuffer的分配也歸入了其中,而且新引入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.      * 這是經過參數ltwh來指定的,其中,參數lt指定的是要訪問的圖形緩衝區的左上角位置 

94.      * 而參數wh指定的是要訪問的圖形緩衝區的寬度和長度 

95.      * 鎖定以後,就能夠得到由參數參數ltwh所圈定的一塊緩衝區的起始地址,保存在輸出參數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對應用程序來講是最重要的接口,它將完成數據寫入顯存的工做:

2gralloc模塊

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_devicefb_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.}

3gpu_alloc 模塊

gpu0內存即非HW_FB內存使用ION分配器進行分配,此文不作詳述。

4fb模塊

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,即每一個Windowdouble 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/unmapregister/unregister

GPU內存file descriptor從一個進程A傳遞到另外一個進程B後,進程Bgralloc_register_buffer就是使用allocator此時是ION將該buffer在本進程映射一下,用於訪問。這些功能作爲grallocmapper功能。

關於內存file descriptorbinder傳遞該內存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還爲空,

                 *每次RepaintmDirtyRegion就清空了。

                 *此處的判斷條件使用Layer個數比較,須要與下面mLayersRemoved結合看。

                 *若是Layer有減小,即便增長的個數小於減小的個數,

                 *那麼mVisibleRegionsDirty必定會被設置。

                 *若是沒有減小,增長Layer後數目必定會增多。可讀性很差。

                 */

567        if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {

568            // layers have been added

569            mVisibleRegionsDirty = true;

570        }

571

               /*

                 *有減小的Layer,那麼其下Layer可能會暴露出來,須要InvalidateLayer

                 *暴露出來的區域,因此須要記錄這塊區域。

                 *全部移除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

          /*

            * 複製CurrentStateDrawingState中,即提交,下面代碼處理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,不予顯示。

                *CameraVideo圖像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       

              /*

               *使用該LayermActiveBuffer生成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?每一個layerdirty是在後面調用的computeVisibleRegions()中計算出來的,

               *能夠在彼時設置給Layer,記錄髒區域是個很好的優化。

               *可是Region mPostedDirtyRegionclass Layer而不是class LayerBase的成員,

               *慢慢FIX! dirtycomputeVisibleRegions中的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具備全透明區域(全透明子窗口),如VideoCamera

                        *Layer該區域必定是不可見的,visibleRegion應該減去全透區域,

                        * translucent的判斷條件並不表示該Layer爲半透,而是有全透區域時,

                        *LayerOpaque屬性應該設置爲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();

                      /*

                       *若是該LayerOpaque的,那麼其整個可見區域必定是遮擋下面的層的。

                       *記錄,累積到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記錄其mVisibleRegionmCoveredRegion

              */

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

           /*

           * 此處先不考慮HWCHWC另見後續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_OVERLAYHWC_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_FBHWC_OVERLAY共存的情形,如CameraVideo

               *暫時認爲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字樣是由於SurfaceGPU使用的,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,由於無論用什麼方式,

            * EGLFrameBufferNativeWindow的管理者,實現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}

 

沒有GPUeglSwapBuffers實現,就看看軟的吧。

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 bufferback 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中每一個VGRGB pipe pair做爲一個LayerMixer的輸入,由LayerMixer完成Overlay功能,做爲一個Overlay channel

注意,RGBVG並不固定配對作爲某個LayerMixer的輸入。如MDP4.2LayerMixer0能夠合成一個BorderBaseLayer4layer,便可以多達5pipe輸入到LayerMixer0,從而用做Hardware Composer

當使用Overlay功能時:

RGB pipe的輸入是普通的Framebuffer,是Surfaceflinger的合成輸出;

VG的輸入是videographicscamera圖像等,是內核空間內存buffer,其owner通常是VideoGraphicsV4L2等。當其前端是Rotator時,Rotator的輸入是這些bufferRotator的輸出Overlay rotator frame buffer做爲VG的輸入。

每一個Overlay Channel結構以下圖所示

關於Overlay Buffer(FrameBuffer RotatorBuffer OverlayBuffer)這些名稱並不特別明確,只要明白Overlay Channel數據流路上的各輸入輸出Buffer的位置和做用便可。

下面以Layermixer1(對應/dev/graphics/fb0)爲參考詳述各buffer

UI顯示時,

Framebufferfb0framebuffer,是從啓動時預留出的bootmem中的分配出來的。LayerMixer1處於BLT模式,Layermixer1DMA_P(Primary display driver)分離,能夠由軟件徹底控制。該Framebuffer作爲DMA_P的輸入,經MIPI_DSI輸出到主屏上。

啓用Overlay時,

上述Framebuffer作爲RGB1 pipe的輸入,而視頻或圖像的內核buffer作爲VG pipe的輸入,兩者經Layermixer1合成;此時LayerMixer1工做在非BLT模式,LayerMixer1DMA_P attach在一塊兒,LayerMixer1輸出控制參數直接提供給DMA_P使用。此時LayerMixer1仍有兩種工做模式,FrameBuffer模式和DIRECT_OUT模式,前者時LayerMixer1DMA_P之間使用一個overlaydouble buffer作緩衝,輸出給DMA_PDIRECT_OUT模式下不使用該ovl double bufferLayerMixer1直接輸出給DMA_P

通常VGRGB的輸入均可以是double bufferping-pangLayerMixer的輸出也是double bufferDMA_P/S/E作爲display driver傳輸前端buffer做爲後端接口控制器的輸入。

下面兩圖是QC MDP UI mirrorVideo mirror時的兩結構圖,並無明確畫出LayerMix1Overlay流程路徑,個別bufferowner可能也有所差錯,buffer也並不全,僅是大體描述Overlay及其部分buffer

 

MDPDSI和後端顯示控制器和接口的鏈接結構以下圖。

 

Layer architecture

Overlay   ->  OverlayImpl

OverlayCtrlData

OverlayMDPCtrlData

MDPWrapper

FrameBuffer

 

KeyPoint

Ctrl用來設置overlay channel的參數,Data用來提交bufferOverlay channel queue。其實使用overlay本質上就是設置好pin路由,設置好通道工做參數,而後不停的提交數據讓Overlay Enginee工做。MDPOverlay 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第一參數fdmemFd,是內核空間的buffer,並不在用戶空間和內核空間拷貝buffer數據。做用與framebuffer相似的是提交內核空間的該bufferOverlay Enginee Queue

有了這些平臺相關知識,msm_fbmdp4_overlay驅動的功能也就容易理解了。

*****************************************************************************

 

Overlay & HWC on MDP -- MIMO Display軟硬整合

概述

Android顯示系統SurfaceFlinger使用OverlayHWC(Hardware composer)完成Surface Layer的硬件合成。OverlayHWC表現爲兩個HAL,爲芯片方案製造商留了實現餘地。

由於Overlay也時常被稱爲hardware composition,爲了不混淆,本文中Overlay專指Android Display Overlay HAL,對應liboverlay.soHWC專指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圖像數據,後者對應CameraVideoRGBYUV數據,兩個pipe輸入到一個LayerMixer0用於合成;額外的,LayerMixer可能還有BF(Border Fill) pipe,用於視頻按比例顯示時屏幕多餘邊框填充,這個多用於Ext TVHDMI輸出的時候。MDP47pipe3LayerMixer,其中LayerMix0能夠配置有多達兩個RGB pipe,兩個VG pipe,一個BF pipe輸入,完成5 Layer合成。

上述pipeLayerMixer的輸入元素,LayerMixer的輸出對應到LCDTVHDMI等,固然不是直接對應,而是由DMA channel和上述模塊的控制器相連。三個LayerMixer對應的三個輸出使用通常是約定的,固然,軟件層面上MDP driver中對每一個管道的目標LayerMixer也作了固定的配置。三個輸出通常標爲Primary, Seconday, Extra,對應的DMA通道爲DMA_P, DMA_S, DMA_E

更直觀地,參見Android Overlay on QC MDP4平臺要點簡記

因爲LayerMixer0提供了多達5Layer的合成能力,因此當沒有CameraVideo優先使用它的時候,它被充分利用來作LayerHardware composition。提早且概要地,這兒必須清楚說明的是,LayerMixer0使用的兩種情景:

當有CameraVideo的時候,SurfaceView對應的LayerHWC_OVERLAY,這時該Layer對應一個VG pipe,而其他HWC_FRAMEBUFFER Layer3D GPU renderFramebuffer後,該Framebuffer輸入一個pipe(RGB1--base layer?),和VG pipeLayerMixer0合成輸出。

當沒有CameraVideo的時候,若是UI LayerHWC_FRAMEBUFFER Layer小於等於3個且都知足圖像格式條件,那麼這些LayerCompositionType屬性會被修改成HWC_OVERLAY,爲每一個Layer分配pipe,經LayerMixer0合成經DMA_P輸出,這就是HWC。因爲BF pipe能力條件的限制,不使用其作HWC,而RGB1作預留的base layer Framebuffer使用,因此標榜的4-layer mdp composition support實際只能接受SurfceFlinger3Layer作合成,也就是SurfaceFlinger的屬性debug.mdpcomp.maxlayer=3。當超過3Layer的時候,因爲管道數量的限制,不可以再使用LayerMixer0,就使用GPU render,也即每一個Layer->draw。固然GPU render也算是一個Hardware CompositionCompositionType方式的其中之一就是GPU

 

Overlay HAL結構

MIMO輸入輸出代碼結構設計,簡單地講,分爲流路控制和數據流動兩部分;Overlay及構建在其上的hwcomposer都是採用這種流路控制和數據流動的結構。

Overlay有多種應用場景,具體設計上描述爲Overlay State。就是說若是容許管道任意靈活組合使用的話,能夠有不少種花樣的應用,可是這兒預先設計好這麼些應用場景,應用場景必定,須要的管道類型和數目隨之肯定,管道鏈接的LayerMixer及其輸出Video驅動控制器也肯定。

Overlay State具體實現使用模板類OverlayImpl<P0, P1, P2>P0, P1, P23pipe,最多可使用3pipe。每一個pipe對應的類是模板類GenericPipe<int PANEL>PANEL指定該pipe合成後圖像輸出目的,從而也決定其使用的LayerMixer。另外地,每一個OverlayImpl<P0, P1, P2>模板類的3個管道可能須要圖像旋轉,因此有可能使用3Rotator。此處的P0, P1, P2只是邏輯索引,並不具體是MDP的管道索引,根據使用規格需求,從MDP管道中爲之動態分配。

hwcomposer也設計了幾個封裝類與Overlay應用場景對應,屏蔽了場景功能的具體實現。hwcomposer中定義的應用場景比Overlay提供的場景還要少,僅是有限幾個。大體結構圖以下:

因爲overlay場景太多,所以只示意了四個,OV_BYPASS_x_LAYER能夠是123個,分別對應1個,2個或3HWC_FRAMEBUFFER Layerbase layer Framebuffer合成的情形。

hwc_prepare的設計邏輯過於固化和簡單,成了一種基於if-else判斷的優先配置方式,寬闊的城堡頂部建了個鳥籠似的小閣樓;應該設計成PolicyRouteState的形式更具有可擴展性。

 

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)

 

CameraVideo Overlay

Camera Overlay通常有兩種實現模式,一種模式是V4L2不提供Overlay接口,在用戶態把V4L2 buffer handle傳遞給Framebuffer,由Framebuffer Overlay Implementation完成合成;另外一種模式是V4L2提供Overlay接口,能夠把Video bufferV4L2內核驅動中提交給Framebuffer Overlay內核驅動完成合成。QC MSM8k Overlay是採用的第一種模式實現,可是V4L2Framebuffer驅動也提供了第二種模式的實現;第二種模式可參見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/GraphicMDP 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_PIPE3RGB1 pipe(注意base layer的特殊地位);

OV_PIPE3提交:當update_framebuffer真正提交圖像數據到RGB1 pipe時,對應stage 0 for base layer(內核驅動)會啓動MDP LayerMixer0進行Layers合成;

DMA傳輸:而後fb_post經過FBIOPUT_VSCREENINFOPAN_DISPLAY啓動DMA_P送合成好的圖像經MIPI-DSI輸出顯示。

BufferFlipqueueBuffer後,該framebuffer即爲front framebuffer,而後eglSwapBuffersdequeueBuffer下一個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時真正啓動LayerMixer04-stage layer composition

FB Layer Hardware Composition

當開啓硬件(debug.sf.hw=1)合成且合成方式選擇MDP時,屬性debug.mdpcomp.maxlayer決定了可使用的通道的個數,當前設置爲3,由於RGB1 pipe預留爲CameraVideo時的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/gpudyn是根據c2dmdp的硬件存在選擇使用兩者之一。

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/WFDOverlay應用情景時,全部Layer都是HWC_FRAMEBUFFER的,MDPLayerMixer0是閒置的,這時能夠優化利用其來作Framebuffer Layer合成。因爲管道數目限制的緣由,只能合成小於等於sMaxLayersLayers。多於3個的時候是否能夠MDP合成其中的3個?可能須要考慮Layer buffer維度、格式、縮放、Z序等因素。當多於3個的時候,是遍歷layer::draw使用GPU來繪製紋理到back framebuffer上的。

下面着重看少於等於3LayerMDP合成的狀況。

首先,全部的Layercompositiontype都是HWC_FRAMEBUFFER的;

而後SurfaceFlingersetHardwareComposer時發現hwc_prepare沒有別的優先的Overlay情景,最後的一個if分支就是使用MDP來作Layer合成;SurfaceFlinger會檢查Layer的屬性看是否知足使用MDP的條件,而後設置知足條件的Layer的屬性[compositionType, flags] = (HWC_OVERLAY, MDPCOMP);這樣SurfaceFlinger::composeSurfaces時,就再也不經過layer::draw使用GPU來繪製;

PIPE配置:SurfaceFlingerHWC建立工做集,爲每一個Layer分配並使用MDPComp::prepare配置每一個pipe,若是有縮放需求,則會分配VG pipe,由於RGB pipe不支持縮放;有一個LayerOverlay狀態爲BYPASS_1_LAYER,表示有1Layer Bypass,不須要OpenGL繪製,同理2LayerBYPASS_2_LAYER3個爲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_PIPE3RGB1 pipe

OV_PIPE3提交:當update_framebuffer真正提交圖像數據到RGB1 pipe時,對應stage 0 for base layer(內核驅動)會啓動MDP LayerMixer0進行Layers合成;此時base layer是個最頂層的全透明Layer,不妨礙底層Layer的顯示

DMA傳輸:而後fb_post經過FBIOPUT_VSCREENINFOPAN_DISPLAY啓動DMA_P送合成好的圖像經MIPI-DSI輸出顯示。

BufferFlipqueueBuffer後,該framebuffer即爲front framebuffer,而後eglSwapBuffersdequeueBuffer下一個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時真正啓動LayerMixer04-stage layer composition

HDMI / WFD

有機會待續。

 

LayerMixer0合成後圖像經DMA_P輸出時,在BLT模式和DIRECTOUT模式下LayerMixer0DMA之間沒有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顯示的imagelinux內核啓動過程當中保持顯示在屏幕上,知道開機動畫顯示,即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_triggerled組映射到不一樣的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);

 

每一個ledbrightness_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_initMachine級別的設備的註冊,部分代碼以下:

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()函數,這個函數註冊了幾個id0的設備。各主要設備名以下,

「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,另外一個id0);

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};

而後關鍵的註冊mdpmipi-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}

mdpmipi-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,初步初始化設備,保存其資源分配。

此時,如下id0的設備panel, dtv, hdmi, mdp, msm_fb id1mipi-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是在machineinit_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去匹配。上面欲同時註冊SAMSUNGCHIMEI兩塊屏設備,固然不能同時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_deviceplatform_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_datamsm_fb_panel_data

以額外msm_fb_data_type結構分配framebuffer

註冊」mipi-dsi」設備platform_device_add(this_dev)

「mipi-dsi」設備和驅動進行attach, match後,「mipi-dsi」 driverprobe被調用到。

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」 driverprobe被調用到。

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」 driverprobe被調用到。

static int msm_fb_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/msm_fb.c

調用msm_fb_register設置linux framebufferregister_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,並設置pipeclockbandwidth

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_VSCREENINFOFBIOPAN_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_numpipemixer_num由應用分配的主pipe即該應用對應的

                   * vsync_ctrl_dbbase_pipe指定。全部pipeLayerMixer0是驅動中固定指定好的。

                    */

                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]

相關文章
相關標籤/搜索