Android图形合成和显示系统---基于高通MSM8k MDP4平台

转自:http://www.verydemo.com/demo_c131_i133963.html

Android图形合成和显示系统---基于高通MSM8k MDP4平台

介绍了Android SurfaceFlinger层次以下的图形合成显示系统,主要基于高通MSM8k MDP4x平台。

做为Android Display专题。SurfaceFlinger的详细介绍参见链接文章。

Android GDI之SurfaceFlinger

SurfaceFinger按英文翻译过来就是Surface投递者。SufaceFlinger的构成并不是太复杂,复杂的是他的客户端建构。SufaceFlinger主要功能是:

1)将Layers(Surfaces)内容的刷新到屏幕上

2)维持Layer的Zorder序列,并对Layer最终输出做出裁剪计算。

3)响应Client要求,创建Layer与客户端的Surface建立连接

4)接收Client要求,修改Layer属性(输出大小,Alpha等设定)

但是作为投递者的实际意义,我们首先需要知道的是如何投递,投掷物,投递路线,投递目的地。

1 SurfaceFlinger的基本组成框架

SurfaceFlinger管理对象为:

mClientsMap:管理客户端与服务端的连接。

ISurface,IsurfaceComposer:AIDL调用接口实例

mLayerMap:服务端的Surface的管理对象。

mCurrentState.layersSortedByZ:以Surface的Z-order序列排列的Layer数组。

graphicPlane缓冲区输出管理

OpenGL ES:图形计算,图像合成图形库。

gralloc.xxx.so这是个跟平台相关的图形缓冲区管理器。

pmem Device:提供共享内存,在这里只是在gralloc.xxx.so可见,在上层被gralloc.xxx.so抽象了。

2 SurfaceFinger Client和服务端对象关系图

Client端与SurfaceFlinger连接图:

Client对象:一般的在客户端都是通过SurfaceComposerClient来跟SurfaceFlinger打交道。

3主要对象说明

3.1 DisplayHardware &FrameBuffer

首先SurfaceFlinger需要操作到屏幕,需要建立一个屏幕硬件缓冲区管理框架。Android在设计支持时,考虑多个屏幕的情况,引入了graphicPlane的概念。在SurfaceFlinger上有一个graphicPlane数组,每一个graphicPlane对象都对应一个DisplayHardware.在当前的Android(2.1)版本的设计中,系统支持一个graphicPlane,所以也就支持一个DisplayHardware。

SurfaceFlinger,Hardware硬件缓冲区的数据结构关系图。

3.2 Layer

method:setBuffer在SurfaceFlinger端建立显示缓冲区。这里的缓冲区是指的HW性质的,PMEM设备文件映射的内存。

1) layer的绘制

void Layer::onDraw(const Region& clip) const

{

    int index = mFrontBufferIndex;

    GLuint textureName = mTextures[index].name;

  drawWithOpenGL(clip, mTextures[index]);

}

3.2 mCurrentState.layersSortedByZ

以Surface的Z-order序列排列的LayerBase数组,该数组是层显示遮挡的依据。在每个层计算自己的可见区域时,从Z-order顶层开始计算,是考虑到遮挡区域的裁减,自己之前层的可见区域就是自己的不可见区域。而绘制Layer时,则从Z-order底层开始绘制,这个考虑到透明层的叠加。

4 SurfaceFlinger的运行框架

我们从前面的章节的基本原理可以知道,SurfaceFlinger的运行框架存在于:threadLoop,他是SurfaceFlinger的主循环体。SurfaceFlinger在进入主体循环之前会首先运行:SurfaceFlinger::readyToRun()。

4.1 SurfaceFlinger::readyToRun()

(1)建立GraphicPanle

(2)建立FrameBufferHardware(确定输出目标)

初始化:OpenGL ES

建立兼容的mainSurface.利用eglCreateWindowSurface。

建立OpenGL ES进程上下文。

建立主Surface(OpenGL ES)。 DisplayHardware的Init()@DisplayHardware.cpp函数对OpenGL做了初始化,并创建立主Surface。为什么叫主Surface,因为所有的Layer在绘制时,都需要先绘制在这个主Surface上,最后系统才将主Surface的内容”投掷”到真正的屏幕上。

(3)主Surface的绑定

1)在DisplayHandware初始完毕后,hw.makeCurrent()将主Surface,OpenGL ES进程上下文绑定到SurfaceFlinger的上下文中,

2)之后所有的SurfaceFlinger进程中使用EGL的所有的操作目的地都是mSurface@DisplayHardware。

这样,在OpenGL绘制图形时,主Surface被记录在进程的上下文中,所以看不到显示的主Surfce相关参数的传递。下面是Layer-Draw,Hardware.flip的动作示意图:

4.2 ThreadLoop

(1)handleTransaction(…):主要计算每个Layer有无属性修改,如果有修改着内用需要重画。

(2)handlePageFlip()

computeVisibleRegions:根据Z-Order序列计算每个Layer的可见区域和被覆盖区域。裁剪输出范围计算-

在生成裁剪区域的时候,根据Z_order依次,每个Layer在计算自己在屏幕的可显示区域时,需要经历如下步骤:

1)以自己的W,H给出自己初始的可见区域

2)减去自己上面窗口所覆盖的区域

在绘制时,Layer将根据自己的可将区域做相应的区域数据Copy。

(3)handleRepaint()

composeSurfaces(需要刷新区域):

根据每个Layer的可见区域与需要刷新区域的交集区域从Z-Order序列从底部开始绘制到主Surface上。

(4)postFramebuffer()

(DisplayHardware)hw.flip(mInvalidRegion);

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

5总结

现在SurfaceFlinger干的事情利用下面的示意图表示出来:

更详细地,参考

Android GUI之SurfaceFlinger系列

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

SurfaceFlinger使用的各组件,参考

Learning about Android Graphics Subsystem by MIPS Engineer

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

 

 

Copybit HAL Introduction

SurfaceFlinger layer的compositionType有三种:

HWC_FRAMEBUFFER的使用OpenGL ES来绘制;

HWC_OVERLAY的使用Overlay Engine来合成

HWC_USE_COPYBIT的使用Copybit硬件加速绘制;

 

MSM8xxx平台Jellybean代码中没有发现使用HWC_USE_COPYBIT的layer,该平台下 Copybit 硬件加速主要有两种:

PPP :vpe模块的PPP,direct copy;

C2D :可能是2D GPU OpenVG之类的。

PPP驱动实现是做为Framebuffer设备的一个命令MSMFB_BLIT,C2D是使用c2d hal库;

MSM7627平台下hwcomposer还是使用copybit的。

可能早期系统没有Hardware Composer,又没有GPU的时候,layer draw就要使用Copybit去一层一层一Rect一Rect的拷贝了。

 

Copybit的代码在display/libcopybit下,硬件合成器使用Copybit做的封装代码在display/libhwcomposer/copybit和copybit_c2d中,前者对应PPP,后者对应C2D。

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

 

AndroidGralloc流程分析for msm8960

主要介绍Gralloc/Framebuffer HAL设备,可以籍此考察显示Buffer(Ashmem、Pmem)的拥有者和传递。

平台中内存有ashmen、PMEM等多种内存类型,为了Video、Graphics、GPU内存访问的需要,android引入Gralloc模块实现内存的管理。Gralloc把FrameBuffer的分配也纳入了其中,并且新引入ION做为Gralloc的非FrameBuffer内存的分配器。ION对于内核态内存在用户进程之间的访问和硬件平台模块之间数据流转提供了高效的解决方案。

Android中 lcd 是一个帧缓冲设备,驱动程序通过处理器的 lcd控制器将物理内存的一段区域设置为显存,如果向这段内存区域写入数据就会马上在 lcd上显示出来。Android在 HAL 中提供了gralloc模块,封装了用户层对帧缓冲设备的所有操作接口,并通过 SurfaceFlinger服务向应用提供显示支持。在启动过程中系统会加载gralloc模块,然后打开帧缓冲设备,获取设备的各种参数并完成 gralloc模块的初始化。当应用程序需要把内容显示到 lcd上时,需要通过 gralloc模块申请一块图形缓冲区,然后将这块图形缓冲区映射到自己的地址空间并写入内容即可。当应用程序不再需要这块图形缓冲区时需要通过 gralloc模块释放掉,然后解除对缓冲区的映射。

1、基础数据结构

gralloc模块通过 struct private_module_t来描述,该结构定义如下:

1.  struct private_module_t {  

2.      gralloc_module_t base;  

3.    

4.      private_handle_t* framebuffer;  /* 指向图形缓冲区的句柄 */  

5.      uint32_t flags;                 /* 用来标志系统帧缓冲区是否支持双缓冲 */  

6.      uint32_t numBuffers;            /* 表示系统帧缓冲的个数 */  

7.      uint32_t bufferMask;            /* 记录系统帧缓冲的使用情况 */  

8.      pthread_mutex_t lock;           /* 保护结构体private_module_t的并行访问 */  

9.      buffer_handle_t currentBuffer;  /* 描述当前正在被渲染的图形缓冲区 */  

10.     int pmem_master;                /* pmem设备节点的描述符 */  

11.     void* pmem_master_base;         /* pmem的起始虚拟地址 */  

12.   

13.     struct fb_var_screeninfo info;  /* lcd的可变参数 */  

14.     struct fb_fix_screeninfo finfo; /* lcd的固定参数 */  

15.     float xdpi;                     /* x方向上每英寸的像素数量 */  

16.     float ydpi;                     /* y方向上每英寸的像素数量 */  

17.     float fps;                      /* lcd的刷新率 */  

18.       

19.     int orientation;                /* 显示方向 */  

20.   

21.     enum {  

22.         PRIV_USAGE_LOCKED_FOR_POST = 0x80000000  /* flag to indicate we'll post this buffer */  

23.     };  

24. };

该结构的成员记录了 gralloc模块的各种参数,主要为模块自己使用,应用程序操作的图形缓冲区的数据结构是struct private_handle_t,定义如下:

1.  >#ifdef __cplusplus  

2.  struct private_handle_t : public native_handle {  

3.  #else   

4.  struct private_handle_t {  

5.      struct native_handle nativeHandle;  /* 用来描述一个本地句柄值 */  

6.  #endif   

7.        

8.      enum {  

9.          PRIV_FLAGS_FRAMEBUFFER    = 0x00000001,  

10.         PRIV_FLAGS_USES_PMEM      = 0x00000002,  

11.         PRIV_FLAGS_USES_MMEM      = 0x00000004,  

12.         PRIV_FLAGS_NEEDS_FLUSH    = 0x00000008,  

13.     };  

14.   

15.     enum {  

16.         LOCK_STATE_WRITE     =   1<<31,  

17.         LOCK_STATE_MAPPED    =   1<<30,  

18.         LOCK_STATE_READ_MASK =   0x3FFFFFFF  

19.     };  

20.   

21.     /* 指向一个文件描述符,这个文件描述符要么指向帧缓冲区设备,要么指向一块匿名共享内存 

22.      * 取决于private_handle_t描述的图形缓冲区是在帧缓冲区分配的,还是在内存中分配的 */  

23.     int     fd;  

24.     /* 指向一个魔数,它的值由静态成员变量sMagic来指定,用来标识一个private_handle_t结构体 */  

25.     int     magic;  

26.     /* 用来描述一个图形缓冲区的标志,它的值要么等于0,要么等于PRIV_FLAGS_FRAMEBUFFER 

27.      * 当一个图形缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER的时候,就表示它是在帧缓冲区中分配的 */  

28.     int     flags;  

29.     int     size;   /* 描述一个图形缓冲区的大小 */  

30.     int     offset; /* 描述一个图形缓冲区的偏移地址 */  

31.   

32.     int     phys;   /* 图形缓冲区或帧缓冲的起始物理地址 */  

33.     int     base;   /* 图形缓冲区或帧缓冲的起始虚拟地址 */  

34.     int     lockState;  

35.     int     writeOwner;  

36.     int     pid;    /* 描述一个图形缓冲区的创建者的PID */  

37.   

38. #ifdef __cplusplus   

39.     static const int sNumInts = 9;  /* 有9个整数变量 */  

40.     static const int sNumFds = 1;   /* 有1个文件描述符 */  

41.     static const int sMagic = 0x3141592;  

42.   

43.     private_handle_t(int fd, int size, int flags) :  

44.         fd(fd), magic(sMagic), flags(flags), size(size), offset(0),  

45.         phys(0), base(0), lockState(0), writeOwner(0), pid(getpid())  

46.     {  

47.         version = sizeof(native_handle);  

48.         numInts = sNumInts;  

49.         numFds = sNumFds;  

50.     }  

51.     ~private_handle_t() {  

52.         magic = 0;  

53.     }  

54.   

55.     bool usesPhysicallyContiguousMemory() {  

56.         return (flags & PRIV_FLAGS_USES_PMEM) != 0;  

57.     }  

58.   

59.     /* 用来验证一个native_handle_t指针是否指向了一个private_handle_t结构体 */  

60.     static int validate(const native_handle* h) {  

61.         const private_handle_t* hnd = (const private_handle_t*)h;  

62.         if (!h || h->version != sizeof(native_handle) ||  

63.                 h->numInts != sNumInts || h->numFds != sNumFds ||  

64.                 hnd->magic != sMagic)   

65.         {  

66.             LOGE("invalid gralloc handle (at %p)", h);  

67.             return -EINVAL;  

68.         }  

69.         return 0;  

70.     }  

71.   

72.     static private_handle_t* dynamicCast(const native_handle* in) {  

73.         if (validate(in) == 0) {  

74.             return (private_handle_t*) in;  

75.         }  

76.         return NULL;  

77.     }  

78. #endif   

79. };

图形缓冲区的操作接口由结构struct gralloc_module_t 定义:

80. typedef struct gralloc_module_t {  

81.     struct hw_module_t common;  

82.   

83.     /* 注册一个图形缓冲区,这个指定的图形缓冲区使用一个buffer_handle_t句柄来描述 */  

84.     int (*registerBuffer)(struct gralloc_module_t const* module,  

85.             buffer_handle_t handle);  

86.   

87.     /* 注销一个图形缓冲区 */  

88.     int (*unregisterBuffer)(struct gralloc_module_t const* module,  

89.             buffer_handle_t handle);  

90.   

91.     /* 用来锁定一个图形缓冲区并将缓冲区映射到用户进程 

92.      * 在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小 

93.      * 这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置 

94.      * 而参数w和h指定的是要访问的图形缓冲区的宽度和长度 

95.      * 锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中 

96.      * 另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定 */  

97.     int (*lock)(struct gralloc_module_t const* module,  

98.             buffer_handle_t handle, int usage,  

99.             int l, int t, int w, int h,  

100.            void** vaddr);  

101.  

102.    int (*unlock)(struct gralloc_module_t const* module,  

103.            buffer_handle_t handle);  

104.  

105.    int (*perform)(struct gralloc_module_t const* module,  

106.            int operation, ... );  

107.  

108.    /* reserved for future use */  

109.    void* reserved_proc[7];  

110.} gralloc_module_t;

gralloc设备则用结构 struct alloc_device_t来描述,其定义如下:

111.typedef struct alloc_device_t {  

112.    struct hw_device_t common;  

113.  

114.    /* 申请图形缓冲区的内存空间 */      

115.    int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);  

116.  

117.    /* 释放图形缓冲区的内存空间 */  

118.    int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);  

119.} alloc_device_t;

帧缓冲设备则采用结构 struct framebuffer_device_t描述:

120.typedef struct framebuffer_device_t {  

121.    struct hw_device_t common;  

122.  

123.    const uint32_t  flags;  /* 用来记录系统帧缓冲区的标志 */  

124.  

125.    const uint32_t  width;  /* lcd显示区域的像素点数 */  

126.    const uint32_t  height;  

127.  

128.    const int       stride; /* 描述设备显示屏的一行有多少个像素点 */  

129.  

130.    /* 描述系统帧缓冲区的像素格式,主要有HAL_PIXEL_FORMAT_RGBX_8888和HAL_PIXEL_FORMAT_RGB_565两种 */  

131.    const int       format;  

132.  

133.    const float     xdpi;  

134.    const float     ydpi;  

135.    const float     fps;              /* lcd刷新率 */  

136.    const int       minSwapInterval;  /* 交换两帧图像的最小间隔时间 */  

137.    const int       maxSwapInterval;  /* 交换两帧图像的最大间隔时间 */  

138.  

139.    int reserved[8];  

140.  

141.    /* 设置帧交换间隔 */  

142.    int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);  

143.  

144.    /* 设置帧缓冲区的更新区域 */  

145.    int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);  

146.  

147.    /* 用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去 */  

148.    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);  

149.  

150.    /* 用来通知fb设备device,图形缓冲区的组合工作已经完成 */  

151.    int (*compositionComplete)(struct framebuffer_device_t* dev);  

152.  

153.    void* reserved_proc[8];  

154.        } framebuffer_device_t;

其中成员函数 post对应用程序来说是最重要的接口,它将完成数据写入显存的工作:

2、gralloc模块

HAL中通过 hw_get_module接口加载指定 id的模块,并获得一个 hw_module_t结构来打开设备,流程如下: 

1.  >#define HAL_LIBRARY_PATH1 "/system/lib/hw"  

2.  #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"   

3.    

4.  static const char *variant_keys[] = {  

5.      "ro.hardware",  /* This goes first so that it can pick up a different file on the emulator. */  

6.      "ro.product.board",  

7.      "ro.board.platform",  

8.      "ro.arch"  

9.  };  

10.   

11. static const int HAL_VARIANT_KEYS_COUNT =  

12.     (sizeof(variant_keys)/sizeof(variant_keys[0]));  

13.   

14. int hw_get_module(const char *id, const struct hw_module_t **module)   

15. {  

16.     int status;  

17.     int i;  

18.     const struct hw_module_t *hmi = NULL;  

19.     char prop[PATH_MAX];  

20.     char path[PATH_MAX];  

21.   

22.     /* 

23.      * Here we rely on the fact that calling dlopen multiple times on 

24.      * the same .so will simply increment a refcount (and not load 

25.      * a new copy of the library). 

26.      * We also assume that dlopen() is thread-safe. 

27.      */  

28.   

29.     /* Loop through the configuration variants looking for a module */  

30.     for (i=0 ; i

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(  

7. 101            module);  

8. 102        gpu_context_t *dev;  

9. 103        IAllocController* alloc_ctrl = IAllocController::getInstance();  

10.104        dev = new gpu_context_t(m, alloc_ctrl);  

11.105        *device = &dev->common;  

12.106        status = 0;

13. } else {  

14.         status = fb_device_open(module, name, device);  

15.     }  

16.   

17.     return status;  

18. }

可以认为Gralloc module中有两个设备gpu_alloc_device和fb_device,前者用于分配GPU0使用的内存和FB内存,GPU0内存管理使用ION allocator;后者用于获取分配Framebuffer Info并操作fb。

在android系统中,所有的图形缓冲区都是由SurfaceFlinger服务分配的,在系统帧缓冲区中分配的图形缓冲区只在 SurfaceFlinger服务中使用,而在内存中分配的图形缓冲区既可以在 SurfaceFlinger服务中使用,也可以在其它的应用程序中使用,当应用程序请求 SurfaceFlinger服务分配图形缓冲区时会发生两次映射:服务所在的进程首先会将申请到的缓冲区映射至服务的地址空间,然后应用程序使用这个图形缓冲时再将其映射至应用程序的地址空间。分配函数的实现如下:

1.  static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)  

2.  {  

3.      private_module_t* m = reinterpret_cast(  

4.              dev->common.module);  

5.      pthread_mutex_lock(&m->lock);  

6.      int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);  

7.      pthread_mutex_unlock(&m->lock);  

8.      return err;  

9.  }  

10.   

11. static int gralloc_alloc_buffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)  

12. {  

13. 127    int err = 0;  

14. 128    int flags = 0;  

15. 129    size = roundUpToPageSize(size);  

16. 130    alloc_data data;  

17. 131    data.offset = 0;  

18. 132    data.fd = -1;  

19. 133    data.base = 0;  

20. 134    data.size = size;  

21. 135    if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)  

22. 136        data.align = 8192;  

23. 137    else  

24. 138        data.align = getpagesize();  

25. 139    data.pHandle = (unsigned int) pHandle;  

26. 140    err = mAllocCtrl->allocate(data, usage);  

27. 141  

28. 142    if (!err) {  

29. 143        /* allocate memory for enhancement data */  

30. 144        alloc_data eData;  

31. 145        eData.fd = -1;  

32. 146        eData.base = 0;  

33. 147        eData.offset = 0;  

34. 148        eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));  

35. 149        eData.pHandle = data.pHandle;  

36. 150        eData.align = getpagesize();  

37. 151        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;  

38. 152        int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);  

39. 153        ALOGE_IF(eDataErr, "gralloc failed for eData err=%s", strerror(-err));  

40. 154  

41. 155        if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {  

42. 156            flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;  

43. 157        }  

44. 158  

45. 159        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {  

46. 160            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;  

47. 161            //The EXTERNAL_BLOCK flag is always an add-on  

48. 162            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {  

49. 163                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;  

50. 164            }  

51. 165            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {  

52. 166                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;  

53. 167            }  

54. 168        }  

55. 169  

56. 170        flags |= data.allocType;  

57. 171        int eBaseAddr = int(eData.base) + eData.offset;  

58. 172        private_handle_t *hnd = new private_handle_t(data.fd, size, flags,  

59. 173                bufferType, format, width, height, eData.fd, eData.offset,  

60. 174                eBaseAddr);  

61. 175  

62. 176        hnd->offset = data.offset;  

63. 177        hnd->base = int(data.base) + data.offset;  

64. 178        *pHandle = hnd;  

65. 179    }  

66. 180  

67. 181    ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));  

68. 182  

69. 183    return err;      

70. 184}  

71.   

72. /*****************************************************************************/  

73.   

74. static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format, int usage,  

75.                             buffer_handle_t* pHandle, int* pStride)  

76. {  

77.     if (!pHandle || !pStride)  

78.         return -EINVAL;  

79.   

80.     size_t size, stride;  

81.   

82.     int align = 4;  

83.     int bpp = 0;  

84.     switch (format) {  /* 一个像素点占用的字节数 */  

85.         case HAL_PIXEL_FORMAT_RGBA_8888:  

86.         case HAL_PIXEL_FORMAT_RGBX_8888:  

87.         case HAL_PIXEL_FORMAT_BGRA_8888:  

88.             bpp = 4;  

89.             break;  

90.         case HAL_PIXEL_FORMAT_RGB_888:  

91.             bpp = 3;  

92.             break;  

93.         case HAL_PIXEL_FORMAT_RGB_565:  

94.         case HAL_PIXEL_FORMAT_RGBA_5551:  

95.         case HAL_PIXEL_FORMAT_RGBA_4444:  

96.             bpp = 2;  

97.             break;  

98.         default:  

99.             return -EINVAL;  

100.    }  

101.    size_t bpr = (w*bpp + (align-1)) & ~(align-1);  

102.    size = bpr * h;  

103.    stride = bpr / bpp;  

104.  

105.    int err;  

106.    if (usage & GRALLOC_USAGE_HW_FB) {  

107.        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);  /* 在系统帧缓冲中分配图形缓冲区 */  

108.    } else {  

109.        err = gralloc_alloc_buffer(dev, size, usage, pHandle);       /* 在内存中分配图形缓冲区 */  

110.    }  

111.  

112.    if (err < 0) {  

113.        return err;  

114.    }  

115.  

116.    *pStride = stride;  

117.    return 0;  

118.}

3、gpu_alloc 模块

gpu0内存即非HW_FB内存使用ION分配器进行分配,此文不做详述。

4、fb模块

gralloc_device_open中会根据传递的参数分别初始化两个设备,定义如下:

1.  >#define GRALLOC_HARDWARE_FB0 "fb0"  

2.  #define GRALLOC_HARDWARE_GPU0 "gpu0"

如果参数不是 "gpu0",那么是"fb%u"的形式,则会调用fb_device_open 初始化 fb 设备,主要流程和打开gralloc基本一致,在函数中会通过调用 mapFrameBuffer->mapFrameBufferLocked获取帧缓存设备的参数并将其设备节点映射到用户空间,流程如下(大致如此,msm8960平台代码有所变化,msm平台上fb设备文件名是/dev/graphics/fb%u):

1.  int mapFrameBufferLocked(struct private_module_t* module)  

2.  {  

3.      if (module->framebuffer) {  

4.          return 0;  

5.      }  

6.            

7.      char const * const device_template[] = {  

8.              "/dev/graphics/fb%u",  

9.              "/dev/fb%u",  

10.             0 };  

11.   

12.     int fd = -1;  

13.     int i=0;  

14.     char name[64];  

15.   

16.     while ((fd==-1) && device_template[i]) {  

17.         snprintf(name, 64, device_template[i], 0);  

18.         fd = open(name, O_RDWR, 0);  

19.         i++;  

20.     }  

21.     if (fd < 0)  

22.         return -errno;  

23.   

24.     struct fb_fix_screeninfo finfo;  

25.     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  /* 获取帧缓冲的固定参数 */  

26.         return -errno;  

27.   

28.     struct fb_var_screeninfo info;  

29.     if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)   /* 获取帧缓冲的可变参数 */  

30.         return -errno;  

31.   

32.     info.reserved[0] = 0;  

33.     info.reserved[1] = 0;  

34.     info.reserved[2] = 0;  

35.     info.xoffset = 0;  

36.     info.yoffset = 0;  

37.     info.activate = FB_ACTIVATE_NOW;  

38.   

39.     info.bits_per_pixel = 32;  

40.     info.red.offset     = 16;  

41.     info.red.length     = 8;  

42.     info.green.offset   = 8;  

43.     info.green.length   = 8;  

44.     info.blue.offset    = 0;  

45.     info.blue.length    = 8;  

46.     info.transp.offset  = 24;  

47.     info.transp.length  = 8;  

48.   

49.     /* 

50.      * Request NUM_BUFFERS screens (at lest 2 for page flipping) 

51.      */  

52.     info.yres_virtual = info.yres * NUM_BUFFERS;  /* 帧缓冲总长度 */  

53.   

54.   

55.     uint32_t flags = PAGE_FLIP;  /* 支持缓冲交换 */  

56.     if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {  

57.         info.yres_virtual = info.yres;  

58.         flags &= ~PAGE_FLIP;  

59.         LOGW("FBIOPAN_DISPLAY failed, page flipping not supported");  

60.     }  

61.   

62.     if (info.yres_virtual < info.yres * 2) {  

63.         /* we need at least 2 for page-flipping */  

64.         info.yres_virtual = info.yres;  

65.         flags &= ~PAGE_FLIP;  

66.         LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",  

67.                 info.yres_virtual, info.yres*2);  

68.     }  

69.   

70.     if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)  

71.         return -errno;  

72.   

73.     int refreshRate = 1000000000000000LLU /  

74.     (  

75.             uint64_t( info.upper_margin + info.lower_margin + info.yres )  

76.             * ( info.left_margin  + info.right_margin + info.xres )  

77.             * info.pixclock  

78.     );  /* 计算lcd刷新率 */  

79.   

80.     if (refreshRate == 0) {  

81.         /* bleagh, bad info from the driver */  

82.         refreshRate = 60*1000;  // 60 Hz  

83.     }  

84.   

85.     if (int(info.width) <= 0 || int(info.height) <= 0) {  

86.         /* the driver doesn't return that information, default to 160 dpi */  

87.         info.width  = ((info.xres * 25.4f)/160.0f + 0.5f);  

88.         info.height = ((info.yres * 25.4f)/160.0f + 0.5f);  

89.     }  

90.   

91.     float xdpi = (info.xres * 25.4f) / info.width;  

92.     float ydpi = (info.yres * 25.4f) / info.height;  

93.     float fps  = refreshRate / 1000.0f;  

94.   

95.     LOGI(   "using (fd=%d)\n"  

96.             "id           = %s\n"  

97.             "xres         = %d px\n"  

98.             "yres         = %d px\n"  

99.             "xres_virtual = %d px\n"  

100.            "yres_virtual = %d px\n"  

101.            "bpp          = %d\n"  

102.            "r            = %2u:%u\n"  

103.            "g            = %2u:%u\n"  

104.            "b            = %2u:%u\n",  

105.            fd,  

106.            finfo.id,  

107.            info.xres,  

108.            info.yres,  

109.            info.xres_virtual,  

110.            info.yres_virtual,  

111.            info.bits_per_pixel,  

112.            info.red.offset, info.red.length,  

113.            info.green.offset, info.green.length,  

114.            info.blue.offset, info.blue.length  

115.    );  

116.  

117.    LOGI(   "width        = %d mm (%f dpi)\n"  

118.            "height       = %d mm (%f dpi)\n"  

119.            "refresh rate = %.2f Hz\n",  

120.            info.width,  xdpi,  

121.            info.height, ydpi,  

122.            fps  

123.    );  

124.  

125.    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  

126.        return -errno;  

127.  

128.    if (finfo.smem_len <= 0)  

129.        return -errno;  

130.  

131.    module->flags = flags;  

132.    module->info = info;  

133.    module->finfo = finfo;  

134.    module->xdpi = xdpi;  

135.    module->ydpi = ydpi;  

136.    module->fps = fps;  

137.  

138.    /* 

139.     * map the framebuffer 

140.     */  

141.  

142.    int err;  

143.    size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);  /* 帧缓冲大小 */  

144.    module->framebuffer = new private_handle_t(dup(fd), fbSize,  

145.            private_handle_t::PRIV_FLAGS_USES_PMEM);  

146.  

147.    module->numBuffers = info.yres_virtual / info.yres;  /* 计算系统帧缓冲的个数 */  

148.    module->bufferMask = 0;  

149.  

150.    void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);    /* 将fb映射到用户空间 */  

151.    if (vaddr == MAP_FAILED) {  

152.        LOGE("Error mapping the framebuffer (%s)", strerror(errno));  

153.        return -errno;  

154.    }  

155.    module->framebuffer->base = intptr_t(vaddr);         /* 帧缓冲的起始虚拟地址 */  

156.    memset(vaddr, 0, fbSize);  

157.    return 0;  

158.}

关于fb设备的打开和HW_FB内存的分配,是在FrameBufferNativeWindow的构造代码中,可以看到打开fb0设备获取Framebuffer Info,然后使用gralloc为该FrameBufferNativeWindow分配两个HW_FB内存即Framebuffer,即每个Window,double buffer。代码如下:

1.  62/* 

2.  63 * This implements the (main) framebuffer management. This class is used 

3.  64 * mostly by SurfaceFlinger, but also by command line GL application. 

4.  65 * 

5.  66 * In fact this is an implementation of ANativeWindow on top of 

6.  67 * the framebuffer. 

7.  68 * 

8.  69 * Currently it is pretty simple, it manages only two buffers (the front and 

9.  70 * back buffer). 

10. 71 * 

11. 72 */  

12. 73  

13. 74FramebufferNativeWindow::FramebufferNativeWindow()  

14. 75    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)  

15. 76{  

16. 77    hw_module_t const* module;  

17. 78    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {  

18. 79        int stride;  

19. 80        int err;  

20. 81        int i;  

21. 82        err = framebuffer_open(module, &fbDev);  

22. 83        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));  

23. 84  

24. 85        err = gralloc_open(module, &grDev);  

25. 86        ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));  

26. 87  

27. 88        // bail out if we can't initialize the modules  

28. 89        if (!fbDev || !grDev)  

29. 90            return;  

30. 91  

31. 92        mUpdateOnDemand = (fbDev->setUpdateRect != 0);  

32. 93  

33. 94        // initialize the buffer FIFO  

34. 95        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&  

35. 96           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){  

36. 97            mNumBuffers = fbDev->numFramebuffers;  

37. 98        } else {  

38. 99            mNumBuffers = MIN_NUM_FRAME_BUFFERS;  

39. 100        }  

40. 101        mNumFreeBuffers = mNumBuffers;  

41. 102        mBufferHead = mNumBuffers-1;  

42. 103  

43. 104        /* 

44. 105         * This does not actually change the framebuffer format. It merely 

45. 106         * fakes this format to surfaceflinger so that when it creates 

46. 107         * framebuffer surfaces it will use this format. It's really a giant 

47. 108         * HACK to allow interworking with buggy gralloc+GPU driver 

48. 109         * implementations. You should *NEVER* need to set this for shipping 

49. 110         * devices. 

50. 111         */  

51. 112#ifdef FRAMEBUFFER_FORCE_FORMAT  

52. 113        *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;  

53. 114#endif  

54. 115  

55. 116        for (i = 0; i < mNumBuffers; i++)  

56. 117        {  

57. 118                buffers[i] = new NativeBuffer(  

58. 119                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);  

59. 120        }  

60. 121  

61. 122        for (i = 0; i < mNumBuffers; i++)  

62. 123        {  

63. 124                err = grDev->alloc(grDev,  

64. 125                        fbDev->width, fbDev->height, fbDev->format,  

65. 126                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);  

66. 127  

67. 128                ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",  

68. 129                        i, fbDev->width, fbDev->height, strerror(-err));  

69. 130  

70. 131                if (err)  

71. 132                {  

72. 133                        mNumBuffers = i;  

73. 134                        mNumFreeBuffers = i;  

74. 135                        mBufferHead = mNumBuffers-1;  

75. 136                        break;  

76. 137                }  

77. 138        }  

78. 139  

79. 140        const_cast(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(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(buffer);  /* 图形缓冲区 */  

16.     private_module_t* m = reinterpret_cast(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. }

5、 Gralloc map/unmap、register/unregister

当GPU内存file descriptor从一个进程A传递到另一个进程B后,进程B做gralloc_register_buffer就是使用allocator此时是ION将该buffer在本进程映射一下,用于访问。这些功能做为gralloc的mapper功能。

关于内存file descriptor、binder传递该内存fd的具体机制参见ION的功能。

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

 

SurfaceFlinger Layer Clip & Draw

/*

 *收到VSYNC后 REFRESH显示

 */

413void SurfaceFlinger::onMessageReceived(int32_t what)

{

419            // if we're in a global transaction, don't do anything.

420            const uint32_t mask = eTransactionNeeded | eTraversalNeeded;

421            uint32_t transactionFlags = peekTransactionFlags(mask);

422            if (CC_UNLIKELY(transactionFlags)) {

423                handleTransaction(transactionFlags);

424            }

425

426            // post surfaces (if needed)

427            handlePageFlip();

428

435            handleRefresh();

436

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

438

443            if (CC_UNLIKELY(mHwWorkListDirty)) {

444                // build the h/w work list

445                handleWorkList();

446            }

447

448            if (CC_LIKELY(hw.canDraw())) {

449                // repaint the framebuffer (if needed)

450                handleRepaint();

451                // inform the h/w that we're done compositing

452                hw.compositionComplete();

453                postFramebuffer();

454            } else {

455                // pretend we did the post

456                hw.compositionComplete();

457            }

}

 

511void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)

512{

513    const LayerVector& currentLayers(mCurrentState.layersSortedByZ);

514    const size_t count = currentLayers.size();

515

516    /*

517     * Traversal of the children

518     * (perform the transaction for each of them if needed)

519     */

520

           /*

            * 针对每个Layer,提交其所做的状态变化

           */

521    const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;

522    if (layersNeedTransaction) {

523        for (size_t i=0 ; i

524            const sp& layer = currentLayers[i];

525            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);

526            if (!trFlags) continue;

527

528            const uint32_t flags = layer->doTransaction(0);

529            if (flags & Layer::eVisibleRegion)

530                mVisibleRegionsDirty = true;

531        }

532    }

533

534    /*

535     * Perform our own transaction if needed

536     */

537    /*

            * 处理SurfaceFlinger全局状态变化

           */

538    if (transactionFlags & eTransactionNeeded) {

               /*

                *如果屏幕发生旋转,则设置mDirtyRegion为整个屏幕范围,更新mServerCblk

* 客户端可以访问到,通知HWC屏幕位向改变重新设置其参数。

*/

539        if (mCurrentState.orientation != mDrawingState.orientation) {

540            // the orientation has changed, recompute all visible regions

541            // and invalidate everything.

542

543            const int dpy = 0;

544            const int orientation = mCurrentState.orientation;

545            // Currently unused: const uint32_t flags = mCurrentState.orientationFlags;

546            GraphicPlane& plane(graphicPlane(dpy));

547            plane.setOrientation(orientation);

548            const Transform& planeTransform(plane.transform());

549

550            // update the shared control block

551            const DisplayHardware& hw(plane.displayHardware());

552            volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;

553            dcblk->orientation = orientation;

554            dcblk->w = plane.getWidth();

555            dcblk->h = plane.getHeight();

556

557            mVisibleRegionsDirty = true;

558            mDirtyRegion.set(hw.bounds());

559

560            //set the new orientation to HWC

561            HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());

562            hwc.eventControl(DisplayHardware::EVENT_ORIENTATION,

563                                              planeTransform.getOrientation());

564

565        }

566

               /*

                 *如果有Layer增加,设置赃区域标志,此时mDirtyRegion还为空,

                 *每次Repaint后mDirtyRegion就清空了。

                 *此处的判断条件使用Layer个数比较,需要与下面mLayersRemoved结合看。

                 *如果Layer有减少,即使增加的个数小于减少的个数,

                 *那么mVisibleRegionsDirty一定会被设置。

                 *如果没有减少,增加Layer后数目一定会增多。可读性不好。

                 */

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

568            // layers have been added

569            mVisibleRegionsDirty = true;

570        }

571

               /*

                 *有减少的Layer,那么其下Layer可能会暴露出来,需要Invalidate该Layer

                 *暴露出来的区域,所以需要记录这块区域。

                 *所有移除layer暴露出来的区域累积,记录在mDirtyRegionRemovedLayer中。

                 * Invalidate的效果是在lockPageFlip后,将mDirtyRegionRemovedLayer加到

                 * mDirtyRegion中。

                 *用户绘图后Post的赃区域在unlockPageFlip时做。

                 */

572        // some layers might have been removed, so

573        // we need to update the regions they're exposing.

574        if (mLayersRemoved) {

575            mLayersRemoved = false;

576            mVisibleRegionsDirty = true;

577            const LayerVector& previousLayers(mDrawingState.layersSortedByZ);

578            const size_t count = previousLayers.size();

579            for (size_t i=0 ; i

580                const sp& layer(previousLayers[i]);

581                if (currentLayers.indexOf( layer ) < 0) {

582                    // this layer is not visible anymore

583                    mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);

584                }

585            }

586        }

587    }

588

          /*

            * 复制CurrentState到DrawingState中,即提交,下面代码处理Repaint时使用DrawingState

           */

589    commitTransaction();

590}

 

735void SurfaceFlinger::handlePageFlip()

736{

737    ATRACE_CALL();

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

739    const Region screenRegion(hw.bounds());

740

           /*

           * 更新每个Layer的脏区域,获取每Layer这次重绘所需要的GraphicBuffer,

           * 为每Layer生成纹理供GPU render使用。

           */

741    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);

742    const bool visibleRegions = lockPageFlip(currentLayers);

743

744    if (visibleRegions || mVisibleRegionsDirty) {

745            Region opaqueRegion;

                  /*

                   *计算更新mDirtyRegion,得到所有Opaqued Layers的总的Region。

                  */

746            computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);

747

748            /*

749             *  rebuild the visible layer list;重建mVisibleLayersSortedByZ

750             */

751            const size_t count = currentLayers.size();

752            mVisibleLayersSortedByZ.clear();

753            mVisibleLayersSortedByZ.setCapacity(count);

754            for (size_t i=0 ; i

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 const* layers = currentLayers.array();

780    for (size_t i=0 ; i

781        const sp& 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 oldActiveBuffer = mActiveBuffer;

546

               /*

                *因为有mRefreshPending时导致直接return,所有需要“引发”下个Frame的显示

                * signalLayerUpdate()即是requestNextVsync(),因为setRefreshRate(0)时,

                *不接收VSYNC,所以需要显式要求下一个VSYNC发过来,“引发”下帧显示

                */

547        // signal another event if we have more frames pending

548        if (android_atomic_dec(&mQueuedFrames) > 1) {

549            mFlinger->signalLayerUpdate();

550        }

551

               /*

                *内部类用于检验Queued过来的Buffer是否符合该Layer的显示要求,

                *不符合则reject,不予显示

                *如Camera或Video图像buffer的大小,格式等要符合。

                */

552        struct Reject : public SurfaceTexture::BufferRejecter {

553            Layer::State& front;

554            Layer::State& current;

555            bool& recomputeVisibleRegions;

556            Reject(Layer::State& front, Layer::State& current,

557                    bool& recomputeVisibleRegions)

558                : front(front), current(current),

559                  recomputeVisibleRegions(recomputeVisibleRegions) {

560            }

561

562            virtual bool reject(const sp& buf,

563                    const BufferQueue::BufferItem& item) {

564                if (buf == NULL) {

565                    return false;

566                }

567

568                uint32_t bufWidth  = buf->getWidth();

569                uint32_t bufHeight = buf->getHeight();

570

571                // check that we received a buffer of the right size

572                // (Take the buffer's orientation into account)

573                if (item.mTransform & Transform::ROT_90) {

574                    swap(bufWidth, bufHeight);

575                }

576

577

578                bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;

579                if (front.active != front.requested) {

580

581                    if (isFixedSize ||

582                            (bufWidth == front.requested.w &&

583                             bufHeight == front.requested.h))

584                    {

585                        // Here we pretend the transaction happened by updating the

586                        // current and drawing states. Drawing state is only accessed

587                        // in this thread, no need to have it locked

588                        front.active = front.requested;

589

590                        // We also need to update the current state so that

591                        // we don't end-up overwriting the drawing state with

592                        // this stale current state during the next transaction

593                        //

594                        // NOTE: We don't need to hold the transaction lock here

595                        // because State::active is only accessed from this thread.

596                        current.active = front.active;

597

598                        // recompute visible region

599                        recomputeVisibleRegions = true;

600                    }

601

622

623                if (!isFixedSize) {

624                    if (front.active.w != bufWidth ||

625                        front.active.h != bufHeight) {

626                        // reject this buffer

627                        return true;

628                    }

629                }

630                return false;

631            }

632        };

633

634

635        Reject r(mDrawingState, currentState(), recomputeVisibleRegions);

636       

              /*

               *使用该Layer的mActiveBuffer生成SurfaceTexture,用于OpenGL/3D GPU render。

               *图像格式不符合时,Reject::reject()被回调。

               */

637        if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) {

638            // something happened!

639            recomputeVisibleRegions = true;

640            return;

641        }

               /*************

               *updateTexImage会释放上轮该Layer使用的GraphicBuffer;

               *也即本轮使用的GraphicBuffer持续到下次需要重绘时释放。

               *记得其申请是在lockPageFlip中记录在mActiveBuffer。

               */

642

              /*

               *记录或更新当前使用的即mActiveBuffer字段

               *注意该buffer直到该Layer下轮重绘Repaint时才Release,

               *期间SurfaceTexture对该Buffer是不可用的。

               */

643        // update the active buffer

644        mActiveBuffer = mSurfaceTexture->getCurrentBuffer();

645        if (mActiveBuffer == NULL) {

646            // this can only happen if the very first buffer was rejected.

647            return;

648        }

649

           /*

              *设置mRefreshPending标志了,如果本轮还没有Paint而下次又来了,直接返回。

              */

650        mRefreshPending = true;

651        mFrameLatencyNeeded = true;

652        if (oldActiveBuffer == NULL) {

653             // the first time we receive a buffer, we need to trigger a

654             // geometry invalidation.

655             mFlinger->invalidateHwcGeometry();

656         }

657

              /*

               *如果Crop & Transform & Scale改变,重设HWC参数

               */

658        Rect crop(mSurfaceTexture->getCurrentCrop());

659        const uint32_t transform(mSurfaceTexture->getCurrentTransform());

660        const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());

661        if ((crop != mCurrentCrop) ||

662            (transform != mCurrentTransform) ||

663            (scalingMode != mCurrentScalingMode))

664        {

665            mCurrentCrop = crop;

666            mCurrentTransform = transform;

667            mCurrentScalingMode = scalingMode;

668            mFlinger->invalidateHwcGeometry();

669        }

670

               /*

                *比较GraphicBuffer的维度是否有改变,用于更新HWC的维度参数,

              *从而使HWC知道该准备多大的buffer空间,和图像参数用于合成

              */

671        if (oldActiveBuffer != NULL) {

672            uint32_t bufWidth  = mActiveBuffer->getWidth();

673            uint32_t bufHeight = mActiveBuffer->getHeight();

674            if (bufWidth != uint32_t(oldActiveBuffer->width) ||

675                bufHeight != uint32_t(oldActiveBuffer->height)) {

676                mFlinger->invalidateHwcGeometry();

677            }

678        }

679

680        mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);

681        if (oldOpacity != isOpaque()) {

682            recomputeVisibleRegions = true;

683        }

684

               /*

               * FIXME?每个layer的dirty是在后面调用的computeVisibleRegions()中计算出来的,

               *可以在彼时设置给Layer,记录脏区域是个很好的优化。

               *但是Region mPostedDirtyRegion是class Layer而不是class LayerBase的成员,

               *慢慢FIX! 此dirty非computeVisibleRegions中的dirty

               */

685        // FIXME: mPostedDirtyRegion = dirty & bounds

686        const Layer::State& front(drawingState());

687        mPostedDirtyRegion.set(front.active.w, front.active.h);

688

689        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

690        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

691    }

692}

 

Layer Clip精髓所在----

592void SurfaceFlinger::computeVisibleRegions(

593    const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)

594{

595    ATRACE_CALL();

596

597    const GraphicPlane& plane(graphicPlane(0));

598    const Transform& planeTransform(plane.transform());

599    const DisplayHardware& hw(plane.displayHardware());

600    const Region screenRegion(hw.bounds());

601

602    Region aboveOpaqueLayers;

603    Region aboveCoveredLayers;

604    Region dirty;

605

606    bool secureFrameBuffer = false;

607

608    size_t i = currentLayers.size();

          /*

           * Clip不就是计算遮挡吗?z-order从顶向底,合乎逻辑。

           */

609    while (i--) {

610        const sp& layer = currentLayers[i];

611        layer->validateVisibility(planeTransform);

612

613        // start with the whole surface at its current location

614        const Layer::State& s(layer->drawingState());

615

616        /*

617         * opaqueRegion: area of a surface that is fully opaque.

618         */

619        Region opaqueRegion;

620

621        /*

622         * visibleRegion: area of a surface that is visible on screen

623         * and not fully transparent. This is essentially the layer's

624         * footprint minus the opaque regions above it.

625         * Areas covered by a translucent surface are considered visible.

626         */

627        Region visibleRegion;

628

629        /*

630         * coveredRegion: area of a surface that is covered by all

631         * visible regions above it (which includes the translucent areas).

632         */

633        Region coveredRegion;

634

635

636        // handle hidden surfaces by setting the visible region to empty

637        if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {

                  //该Layer是否半透

638            const bool translucent = !layer->isOpaque();

                  //该Layer可见范围

639            const Rect bounds(layer->visibleBounds());

640            visibleRegion.set(bounds);

641            visibleRegion.andSelf(screenRegion);

642            if (!visibleRegion.isEmpty()) {

                       /*

                        *如果本layer具有全透明区域(全透明子窗口),如Video或Camera,

                        *本Layer该区域一定是不可见的,visibleRegion应该减去全透区域,

                        * translucent的判断条件并不表示该Layer为半透,而是有全透区域时,

                        *该Layer的Opaque属性应该设置为false,表并非Full Opaque。

                        * setTransparentRegion/setTransparentRegionWindow

                        *  => setTransparentRegionHint设置透明的。

                        *那半透明子窗口如何呢?因为Layer的地位相当于该应用的Parent most window,

                        *所以半透子窗口下的区域也一定是本Layer的子窗口,而不可能是别的Layer,

                        *从而该半透子窗口在本Layer范围内部就做Alpha混叠了,对于本Layer来说是

                        * Opaque的,所以不需要半透部分区域。半透属性是针对整个Layer的。

                        */

643                // Remove the transparent area from the visible region

644                if (translucent) {

645                    visibleRegion.subtractSelf(layer->transparentRegionScreen);

646                }

647

648                // compute the opaque region

649                const int32_t layerOrientation = layer->getOrientation();

                      /*

                       *如果该Layer是Opaque的,那么其整个可见区域一定是遮挡下面的层的。

                       *记录,累积到aboveOpaqueLayers, 供计算下面层的遮挡之用。

                       */

650                if (s.alpha==255 && !translucent &&

651                        ((layerOrientation & Transform::ROT_INVALID) == false)) {

652                    // the opaque region is the layer's footprint

653                    opaqueRegion = visibleRegion;

654                }

655            }

656        }

657

              /*

               * coveredRegion本层被覆盖的区域,包括被上面层半透覆盖的区域,覆盖并非遮挡。

               *本层可见区域总对下面层构成覆盖,累积到aboveCoveredLayers

               */

658        // Clip the covered region to the visible region

659        coveredRegion = aboveCoveredLayers.intersect(visibleRegion);

660

661        // Update aboveCoveredLayers for next (lower) layer

662        aboveCoveredLayers.orSelf(visibleRegion);

663

               /*

               *减去本层被上面层遮挡的区域

               */

664        // subtract the opaque region covered by the layers above us

665        visibleRegion.subtractSelf(aboveOpaqueLayers);

666

               /*

               *计算本层的脏区域,分内容是否为脏(size是否变化)两种情形。

               *如果是用内容脏,即size变化,那么认为整个区域都是脏的;

               *如果是移除上层的Layer暴露出本Layer区域,则计算可见的最小的脏区域;

               *此时赃区域是屏幕坐标系统

               *这么有用的个dirty为什么不保存给各个Layer?

               *此时的dirty还不包括用户Posted的真正意义上的脏区域!

               *为什么不直接地处理为visbleRegion.andSelf(mDirtyRegionRemovedLayer)?

               *因为mDirtyRegionRemovedLayer仅是个区域,并没有记录层的透明属性。

                */

667        // compute this layer's dirty region

668        if (layer->contentDirty) {

669            // we need to invalidate the whole region

670            dirty = visibleRegion;

671            // as well, as the old visible region

672            dirty.orSelf(layer->visibleRegionScreen);

673            layer->contentDirty = false;

674        } else {

675            /* compute the exposed region:

676             *   the exposed region consists of two components:

677             *   1) what's VISIBLE now and was COVERED before

678             *   2) what's EXPOSED now less what was EXPOSED before

679             *

680             * note that (1) is conservative, we start with the whole

681             * visible region but only keep what used to be covered by

682             * something -- which mean it may have been exposed.

683             *

684             * (2) handles areas that were not covered by anything but got

685             * exposed because of a resize.

686             */

687            const Region newExposed = visibleRegion - coveredRegion;

688            const Region oldVisibleRegion = layer->visibleRegionScreen;

689            const Region oldCoveredRegion = layer->coveredRegionScreen;

690            const Region oldExposed = oldVisibleRegion - oldCoveredRegion;

691            dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);

692        }

               /*

               *被遮挡区域不需要重绘,从脏区域里除去

               */

693        dirty.subtractSelf(aboveOpaqueLayers);

694

               /*

                *累积总的脏区域

                */

695        // accumulate to the screen dirty region

696        dirtyRegion.orSelf(dirty);

697

              /*

                *累积遮挡区域

               */

698        // Update aboveOpaqueLayers for next (lower) layer

699        aboveOpaqueLayers.orSelf(opaqueRegion);

700

               /*

                *为每个Layer记录其mVisibleRegion和mCoveredRegion

              */

701        // Store the visible region is screen space

702        layer->setVisibleRegion(visibleRegion);

703        layer->setCoveredRegion(coveredRegion);

704

705        // If a secure layer is partially visible, lock-down the screen!

706        if (layer->isSecure() && !visibleRegion.isEmpty()) {

707            secureFrameBuffer = true;

708        }

709    }

710

          /*

           * 把mDirtyRegionRemovedLayer并到mDirtyRegion中去。

           * 有移除Layers暴露出来的区域需要其下的Layers重绘,其实这个在dirty计算时已处理

           * 关键的是移除的Layer是最底层Layer的时候则直接露出屏底色,所以要此处要或上。

           */

711    // invalidate the areas where a layer was removed

712    dirtyRegion.orSelf(mDirtyRegionRemovedLayer);

713    mDirtyRegionRemovedLayer.clear();

714

          /*

           * 抓屏相关?

           */

715    mSecureFrameBuffer = secureFrameBuffer;

           /*

            * 传出遮挡区域,Opaque Region为所有Opaque Layer Area之和

            */

716    opaqueRegion = aboveOpaqueLayers;

717}

 

787void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)

788{

789    const GraphicPlane& plane(graphicPlane(0));

790    const Transform& planeTransform(plane.transform());

791    const size_t count = currentLayers.size();

792    sp const* layers = currentLayers.array();

793    for (size_t i=0 ; i

794        const sp& layer(layers[i]);

795        layer->unlockPageFlip(planeTransform, mDirtyRegion);

796    }

797}

 

694void Layer::unlockPageFlip(

695        const Transform& planeTransform, Region& outDirtyRegion)

696{

697    ATRACE_CALL();

698

699    Region postedRegion(mPostedDirtyRegion);

700    if (!postedRegion.isEmpty()) {

701        mPostedDirtyRegion.clear();

702        if (!visibleRegionScreen.isEmpty()) {

703            // The dirty region is given in the layer's coordinate space

704            // transform the dirty region by the surface's transformation

705            // and the global transformation.

706            const Layer::State& s(drawingState());

707            const Transform tr(planeTransform * s.transform);

708            postedRegion = tr.transform(postedRegion);

709

                   /*

                   * computeVisibleRegions处理的赃区域是size变化和上层遮挡移除的情况,需要重绘;

                   *而用户修改提交的区域也需要重绘,还未加到赃区域中,此时并进来。

                   */

710            // At this point, the dirty region is in screen space.

711            // Make sure it's constrained by the visible region (which

712            // is in screen space as well).

713            postedRegion.andSelf(visibleRegionScreen);

714            outDirtyRegion.orSelf(postedRegion);

715        }

716    }

717}

 

handleRefresh()没什么作用了。

handleWorkList()是为HWComposer分配缓冲工作集,用于硬件合成,暂不考察。

 

DisplayHardware.canDraw()用于判断当前是否处于draw过程中,屏是否已经关闭等,得出需要Repaint的判断。

835void SurfaceFlinger::handleRepaint()

836{

837    ATRACE_CALL();

838

839    // compute the invalid region

840    mSwapRegion.orSelf(mDirtyRegion);

841

842    if (CC_UNLIKELY(mDebugRegion)) {

843        debugFlashRegions();

844    }

845

846    // set the frame buffer

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

848    glMatrixMode(GL_MODELVIEW);

849    glLoadIdentity();

850

           /*

           * 针对DisplayHardware是支持RECT更新还是RECTS更新,做相应处理。

           */

851    uint32_t flags = hw.getFlags();

852    if (flags & DisplayHardware::SWAP_RECTANGLE) {

853        // we can redraw only what's dirty, but since SWAP_RECTANGLE only

854        // takes a rectangle, we must make sure to update that whole

855        // rectangle in that case

856        mDirtyRegion.set(mSwapRegion.bounds());

857    } else {

858        if (flags & DisplayHardware::PARTIAL_UPDATES) {

859            // We need to redraw the rectangle that will be updated

860            // (pushed to the framebuffer).

861            // This is needed because PARTIAL_UPDATES only takes one

862            // rectangle instead of a region (see DisplayHardware::flip())

863            mDirtyRegion.set(mSwapRegion.bounds());

864        } else {

865            // we need to redraw everything (the whole screen)

866            mDirtyRegion.set(hw.bounds());

867            mSwapRegion = mDirtyRegion;

868        }

869    }

870

           /*

           * 此处先不考虑HWC,HWC另见后续MIMO display – Overlay & HWComposer

           * 只考虑使用 OpenGL / 3D GPU render的情况,即各layer->draw。

           */

871    setupHardwareComposer();

872    composeSurfaces(mDirtyRegion);

873

874    // update the swap region and clear the dirty region

875    mSwapRegion.orSelf(mDirtyRegion);

876    mDirtyRegion.clear();

877}

 

912void SurfaceFlinger::composeSurfaces(const Region& dirty)

913{

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

915    HWComposer& hwc(hw.getHwComposer());

916    hwc_layer_t* const cur(hwc.getLayers());

917

           /*

           * 不考虑HWC或者除HWC_OVERLAY有HWC_FB或者Layer数目超出HWC管道数时,

           * 使用GPU render。

          */

918    const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);

919    if (!cur || fbLayerCount) {

920        // Never touch the framebuffer if we don't have any framebuffer layers

921

               /*

               *有HWC_FB有HWC_OVERLAY共存的情形,如Camera或Video

               *暂时认为0不表,详见后续 MIMO display – Overlay & HWComposer

               */

922        if (hwc.getLayerCount(HWC_OVERLAY)) {

923            // when using overlays, we assume a fully transparent framebuffer

924            // NOTE: we could reduce how much we need to clear, for instance

925            // remove where there are opaque FB layers. however, on some

926            // GPUs doing a "clean slate" glClear might be more efficient.

927            // We'll revisit later if needed.

928             const Region region(hw.bounds());

                   /*

                    *为HWC先清原来的画面

                    */

929#ifdef QCOMHW

930             if (0 != qdutils::CBUtils::qcomuiClearRegion(region,

931                                              hw.getEGLDisplay()))

932#endif

933             {

934                 glClearColor(0, 0, 0, 0);

935                 glClear(GL_COLOR_BUFFER_BIT);

936             }

937        } else {

                  /*

                  *看来FB的时候不需要清屏;如果需要画虫洞,则为该区域清屏以显示虫洞

                  */

938            // screen is already cleared here

939            if (!mWormholeRegion.isEmpty()) {

940                // can happen with SurfaceView

941#ifdef QCOMHW

942                if (0 != qdutils::CBUtils::qcomuiClearRegion(mWormholeRegion,

943                                            hw.getEGLDisplay()))

944#endif

945                    drawWormhole();

946            }

947        }

948

               /*

                *真正开画

                */

949        /*

950         * and then, render the layers targeted at the framebuffer

951         */

952

953        const Vector< sp >& layers(mVisibleLayersSortedByZ);

954        const size_t count = layers.size();

955

               /*

                *显然的,从底层向顶层画

                */

956        for (size_t i=0 ; i

957            const sp& 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

340            const sp& layer(drawingLayers[i]);

341            if (layer.get() == static_cast(this))

342                break;

343            under.orSelf(layer->visibleRegionScreen);

344        }

345        // if not everything below us is covered, we plug the holes!

346        Region holes(clip.subtract(under));

347        if (!holes.isEmpty()) {

348            clearWithOpenGL(holes, 0, 0, 0, 1);

349        }

350        return;

351    }

352#ifdef QCOMHW

353    if (!qdutils::isGPUSupportedFormat(mActiveBuffer->format)) {

354        clearWithOpenGL(clip, 0, 0, 0, 1);

355        return;

356    }

357#endif

358    if (!isProtected()) {

359        // TODO: we could be more subtle with isFixedSize()

360        const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize();

361

362        // Query the texture matrix given our current filtering mode.

363        float textureMatrix[16];

364        mSurfaceTexture->setFilteringEnabled(useFiltering);

365        mSurfaceTexture->getTransformMatrix(textureMatrix);

366

367        // Set things up for texturing.

368        glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);

369        GLenum filter = GL_NEAREST;

370        if (useFiltering) {

371            filter = GL_LINEAR;

372        }

373        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter);

374        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter);

375        glMatrixMode(GL_TEXTURE);

376        glLoadMatrixf(textureMatrix);

377        glMatrixMode(GL_MODELVIEW);

378        glDisable(GL_TEXTURE_2D);

379        glEnable(GL_TEXTURE_EXTERNAL_OES);

380    } else {

381        glBindTexture(GL_TEXTURE_2D, mFlinger->getProtectedTexName());

382        glMatrixMode(GL_TEXTURE);

383        glLoadIdentity();

384        glMatrixMode(GL_MODELVIEW);

385        glDisable(GL_TEXTURE_EXTERNAL_OES);

386        glEnable(GL_TEXTURE_2D);

387    }

388

389    drawWithOpenGL(clip);

390

391    glDisable(GL_TEXTURE_EXTERNAL_OES);

392    glDisable(GL_TEXTURE_2D);

393}

 

/*

 * 提交FrameBuffer

 * 对于使用GPU的情况,composeSurfaces已经将所有Surface都合成到BACK Framebuffer上了;

 * 对于HWComposer的情况,此时还没有启动硬件合成,是在DisplayHardware::flip =>

 * HWComposer::commit中合成到BACK Framebuffer上并交换Framebuffer的。

 * 为了统一,应该把HWC合成的功能也放到composeSurfaces类似的composeLayers里面去,

 * 不用Surface字样是因为Surface是GPU使用的,MDP HWComposer并不具有

 * 操作Surface/Texture的能力,而只能操作支持格式的GraphicBuffer。

*/

463void SurfaceFlinger::postFramebuffer()

464{

465    ATRACE_CALL();

466    // mSwapRegion can be empty here is some cases, for instance if a hidden

467    // or fully transparent window is updating.

468    // in that case, we need to flip anyways to not risk a deadlock with

469    // h/w composer.

470

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

472    const nsecs_t now = systemTime();

473    mDebugInSwapBuffers = now;

474    hw.flip(mSwapRegion);

475

476    size_t numLayers = mVisibleLayersSortedByZ.size();

477    for (size_t i = 0; i < numLayers; i++) {

478        mVisibleLayersSortedByZ[i]->onLayerDisplayed();

479    }

480

481

482    mLastSwapBufferTime = systemTime() - now;

483    mDebugInSwapBuffers = 0;

484    mSwapRegion.clear();

485}

 

435void DisplayHardware::flip(const Region& dirty) const

436{

437    checkGLErrors();

438

439    EGLDisplay dpy = mDisplay;

440    EGLSurface surface = mSurface;

441

442#ifdef EGL_ANDROID_swap_rectangle

443    if (mFlags & SWAP_RECTANGLE) {

444        const Region newDirty(dirty.intersect(bounds()));

445        const Rect b(newDirty.getBounds());

446        eglSetSwapRectangleANDROID(dpy, surface,

447                b.left, b.top, b.width(), b.height());

448    }

449#endif

450

451    if (mFlags & PARTIAL_UPDATES) {

452        mNativeWindow->setUpdateRectangle(dirty.getBounds());

453    }

454

455    mPageFlipCount++;

456

           /*

            * mHwc->commit中也会调用eglSwapBuffers,因为不管用什么方式,

            * EGL是FrameBufferNativeWindow的管理者,实现buffer swap,避免竞争。

            */

457    if (mHwc->initCheck() == NO_ERROR) {

458        mHwc->commit();

459    } else {

460        eglSwapBuffers(dpy, surface);

461    }

462    checkEGLErrors("eglSwapBuffers");

463

464    // for debugging

465    //glClearColor(1,0,0,0);

466    //glClear(GL_COLOR_BUFFER_BIT);

467}

 

没有GPU的eglSwapBuffers实现,就看看软的吧。

484EGLBoolean egl_window_surface_v2_t::swapBuffers()

485{

486    if (!buffer) {

487        return setError(EGL_BAD_ACCESS, EGL_FALSE);

488    }

489

490    /*

491     * Handle eglSetSwapRectangleANDROID()

492     * We copyback from the front buffer

493     */

494    if (!dirtyRegion.isEmpty()) {

495        dirtyRegion.andSelf(Rect(buffer->width, buffer->height));

496        if (previousBuffer) {

497            // This was const Region copyBack, but that causes an

498            // internal compile error on simulator builds

                   /*

                    * front buffer和back buffer的赃区域的差值拷贝回back buffer中;

                    *因为front buffer的赃区域(即其重绘的区域)并未更新到back buffer中,

                    *所以需要考回来;但是back buffer的赃区域已经重绘了,是不能覆盖掉的,

                    *所以两个赃区域相减。

                    *这仅是double buffer的时候的实现,triple buffer两个dirtyRegion就无法保证了。

                   */

499            /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));

500            if (!copyBack.isEmpty()) {

501                void* prevBits;

502                if (lock(previousBuffer,

503                        GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {

504                    // copy from previousBuffer to buffer

505                    copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);

506                    unlock(previousBuffer);

507                }

508            }

509        }

510        oldDirtyRegion = dirtyRegion;

511    }

512    /*

           * 释放front framebuffer

            */

513    if (previousBuffer) {

514        previousBuffer->common.decRef(&previousBuffer->common);

515        previousBuffer = 0;

516    }

517

           /*

           * 解锁back framebuffer,表用户用完,要queue了。queueBuffer()

           */

518    unlock(buffer);

519    previousBuffer = buffer;

520    nativeWindow->queueBuffer(nativeWindow, buffer);

521    buffer = 0;

522

           /*

             * back framebuffer已经提交了,需要再dequeue下一个framebuffer来做back framebuffer

             * 并且锁住,供使用;

             */

523    // dequeue a new buffer

524    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {

525

526        // TODO: lockBuffer should rather be executed when the very first

527        // direct rendering occurs.

528        nativeWindow->lockBuffer(nativeWindow, buffer);

529

530        // reallocate the depth-buffer if needed

531        if ((width != buffer->width) || (height != buffer->height)) {

532            // TODO: we probably should reset the swap rect here

533            // if the window size has changed

534            width = buffer->width;

535            height = buffer->height;

536            if (depth.data) {

537                free(depth.data);

538                depth.width   = width;

539                depth.height  = height;

540                depth.stride  = buffer->stride;

541                depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);

542                if (depth.data == 0) {

543                    setError(EGL_BAD_ALLOC, EGL_FALSE);

544                    return EGL_FALSE;

545                }

546            }

547        }

548

549        // keep a reference on the buffer

550        buffer->common.incRef(&buffer->common);

551

               /*

                * lock/unlock

                */

552        // finally pin the buffer down

553        if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |

554                GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {

555            ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",

556                    buffer, buffer->width, buffer->height);

557            return setError(EGL_BAD_ACCESS, EGL_FALSE);

558            // FIXME: we should make sure we're not accessing the buffer anymore

559        }

560    } else {

561        return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);

562    }

563

564    return EGL_TRUE;

565}

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

 

Android Overlay on QC MDP4平台要点简记

File Orgnization

目录/hardware/qcom/display/liboverlay/

Android.mk

mdpRotator.cpp               Overlay Rotator Wrpper

mdpWrapper.h                 MDP Normal and Overlay FrameBuffer IOCTL Wrapper

mdssRotator.cpp             Overlay MDSS Rotator Wrapper

overlay.cpp        Overlay Top level implementation file

overlay.h             Overlay Top level declaration file

overlayCtrl.cpp   OverlayCtrl implementation file

overlayCtrlData.h       OverlayCtrl and OverlayData declaration file including OverlayData implementation

overlayImpl.h    Overlay implementation which operates overlay pipes pair(LayerMixer)              

overlayMdp.cpp    Overlay implementation on MDP, used by OverlayCtrlData    

overlayMdp.h   Overlay on MDP

overlayMem.h  Overlay VG pipe input kernel memory file descriptor, maybe graphic buffer or rotator output buffer

overlayRotator.cpp         Overlay Rotator top level implementation

overlayRotator.h              Overlay Rotator top level declaration

overlayState.h  Overlay state machine

overlayUtils.cpp                 Overlay Utils

overlayUtils.h    Overlay Utils

pipes/   Overlay Pipes, that is Overlay channel. It is a VG and RGB pipe pair on MDP.

 

Platform architecture

MDP中每个VG和RGB pipe pair作为一个LayerMixer的输入,由LayerMixer完成Overlay功能,作为一个Overlay channel。

注意,RGB和VG并不固定配对做为某个LayerMixer的输入。如MDP4.2的LayerMixer0可以合成一个Border或BaseLayer和4个layer,即可以多达5个pipe输入到LayerMixer0,从而用作Hardware Composer。

当使用Overlay功能时:

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

VG的输入是video或graphics或camera图像等,是内核空间内存buffer,其owner一般是Video、Graphics或V4L2等。当其前端是Rotator时,Rotator的输入是这些buffer,Rotator的输出Overlay rotator frame buffer作为VG的输入。

每个Overlay Channel结构如下图所示

关于Overlay Buffer(FrameBuffer RotatorBuffer OverlayBuffer)这些名称并不特别明确,只要明白Overlay Channel数据流路上的各输入输出Buffer的位置和作用即可。

下面以Layermixer1(对应/dev/graphics/fb0)为参考详述各buffer:

只UI显示时,

Framebuffer是fb0的framebuffer,是从启动时预留出的bootmem中的分配出来的。LayerMixer1处于BLT模式,Layermixer1和DMA_P(Primary display driver)分离,可以由软件完全控制。该Framebuffer做为DMA_P的输入,经MIPI_DSI输出到主屏上。

启用Overlay时,

上述Framebuffer做为RGB1 pipe的输入,而视频或图像的内核buffer做为VG pipe的输入,二者经Layermixer1合成;此时LayerMixer1工作在非BLT模式,LayerMixer1和DMA_P attach在一起,LayerMixer1输出控制参数直接提供给DMA_P使用。此时LayerMixer1仍有两种工作模式,FrameBuffer模式和DIRECT_OUT模式,前者时LayerMixer1和DMA_P之间使用一个overlaydouble buffer做缓冲,输出给DMA_P;DIRECT_OUT模式下不使用该ovl double buffer,LayerMixer1直接输出给DMA_P。

一般VG和RGB的输入都可以是double buffer,ping-pang;LayerMixer的输出也是double buffer。DMA_P/S/E做为display driver传输前端buffer作为后端接口控制器的输入。

下面两图是QC MDP UI mirror和Video mirror时的两结构图,并没有明确画出LayerMix1的Overlay流程路径,个别buffer的owner可能也有所差错,buffer也并不全,仅是大致描述Overlay及其部分buffer。

 

MDP和DSI和后端显示控制器和接口的连接结构如下图。

 

Layer architecture

Overlay   ->  OverlayImpl

OverlayCtrlData

OverlayMDPCtrlData

MDPWrapper

FrameBuffer

 

KeyPoint

Ctrl用来设置overlay channel的参数,Data用来提交buffer到Overlay channel queue。其实使用overlay本质上就是设置好pin路由,设置好通道工作参数,然后不停的提交数据让Overlay Enginee工作。MDP的Overlay Channel并没有别的特殊的编程接口,都是使用控制、状态和数据寄存器来访问。其实MDP提供了远比Android Overlay实现强得多的Overlay功能。

Some flow

Ctrl::commit()  ->  MDPCtrl::set() -> mdp_wrapper::setOverlay()  -> ioctl(fd, MSMFB_OVERLAY_SET, &ov)

-> msm_fb -> mdp4_overlay设置Overlay工作参数。

Data::queueBuffer -> MDPData::play -> mdp_wrapper::play() -> ioctl(fd, MSMFB_OVERLAY_PLAY, &od)

-> msm_fb -> mdp4_overlay进行Overlay合成。注意queueBuffer第一参数fd是memFd,是内核空间的buffer,并不在用户空间和内核空间拷贝buffer数据。作用与framebuffer类似的是提交内核空间的该buffer到Overlay Enginee Queue。

有了这些平台相关知识,msm_fb和mdp4_overlay驱动的功能也就容易理解了。

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

 

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

概述

Android显示系统SurfaceFlinger使用Overlay和HWC(Hardware composer)完成Surface Layer的硬件合成。Overlay和HWC表现为两个HAL,为芯片方案制造商留了实现余地。

因为Overlay也时常被称为hardware composition,为了避免混淆,本文中Overlay专指Android Display Overlay HAL,对应liboverlay.so;HWC专指SurfaceFlinger使用的硬件合成器HAL,对应hwcomposer.msm8xxxx.so。

Qualcomm MSM8k系列平台的MDP4.x(Mobile Display Platform)提供了硬件Overlay的功能,Android Overlay HAL与这个Overlay硬件相对应;当然,为了与上段照应,需要说明的是,MDP并不存在一个实现HWC的专门硬件,HWC也是在Overlay上实现的;体现在Android软件中,HWC HAL是建立在Overlay HAL基础上的,是使用Overlay HAL来实现的。

因此,再次,准确地说,提供硬件合成功能的是模块是Overlay,是MDP Overlay硬件的体现;而HWC则是SurfaceFlinger使用Overlay HAL的一个桥梁。

Overlay并非仅仅由SurfaceFlinger得到Surface后就不再经过SurfaceFlinger而使用硬件直接输出;从函数调用上看似乎是这样的,但是实际情形却非如此。硬件合成仅是合成的一种手段,合成的结果输出destination还是必须受控,因而也必须纳入SurfaceFlinger的输出管理范畴。

Overlay硬件平台

MSM8k上目前有MDP4.0, MDP4.1, MDP4.2三个硬件版本,主要是合成能力和管道数目的区别。通常,一个RGB pipe和一个VG pipe组成一个pipe pair,前者是对应UI RGB图像数据,后者对应Camera或Video的RGB或YUV数据,两个pipe输入到一个LayerMixer0用于合成;额外的,LayerMixer可能还有BF(Border Fill) pipe,用于视频按比例显示时屏幕多余边框填充,这个多用于Ext TV或HDMI输出的时候。MDP4有7个pipe,3个LayerMixer,其中LayerMix0可以配置有多达两个RGB pipe,两个VG pipe,一个BF pipe输入,完成5 Layer合成

上述pipe是LayerMixer的输入元素,LayerMixer的输出对应到LCD,TV,HDMI等,当然不是直接对应,而是由DMA channel和上述模块的控制器相连。三个LayerMixer对应的三个输出使用一般是约定的,当然,软件层面上MDP driver中对每个管道的目标LayerMixer也做了固定的配置。三个输出一般标为Primary, Seconday, Extra,对应的DMA通道为DMA_P, DMA_S, DMA_E。

更直观地,参见Android Overlay on QC MDP4平台要点简记

由于LayerMixer0提供了多达5个Layer的合成能力,所以当没有Camera或Video优先使用它的时候,它被充分利用来做Layer的Hardware composition。提前且概要地,这儿必须清楚说明的是,LayerMixer0使用的两种情景:

当有Camera或Video的时候,SurfaceView对应的Layer为HWC_OVERLAY,这时该Layer对应一个VG pipe,而其余HWC_FRAMEBUFFER Layer经3D GPU render到Framebuffer后,该Framebuffer输入一个pipe(RGB1--base layer?),和VG pipe经LayerMixer0合成输出。

当没有Camera或Video的时候,如果UI Layer即HWC_FRAMEBUFFER Layer小于等于3个且都满足图像格式条件,那么这些Layer的CompositionType属性会被修改为HWC_OVERLAY,为每个Layer分配pipe,经LayerMixer0合成经DMA_P输出,这就是HWC。由于BF pipe能力条件的限制,不使用其做HWC,而RGB1做预留的base layer Framebuffer使用,所以标榜的4-layer mdp composition support实际只能接受SurfceFlinger的3个Layer做合成,也就是SurfaceFlinger的属性debug.mdpcomp.maxlayer=3。当超过3个Layer的时候,由于管道数量的限制,不能够再使用LayerMixer0,就使用GPU render,也即每个Layer->draw。当然GPU render也算是一个Hardware Composition,CompositionType方式的其中之一就是GPU。

 

Overlay HAL结构

MIMO输入输出代码结构设计,简单地讲,分为流路控制和数据流动两部分;Overlay及构建在其上的hwcomposer都是采用这种流路控制和数据流动的结构。

Overlay有多种应用场景,具体设计上描述为Overlay State。就是说如果允许管道任意灵活组合使用的话,可以有很多种花样的应用,但是这儿预先设计好这么些应用场景,应用场景一定,需要的管道类型和数目随之确定,管道连接的LayerMixer及其输出Video驱动控制器也确定。

Overlay State具体实现使用模板类OverlayImpl,P0, P1, P2是3个pipe,最多可以使用3个pipe。每个pipe对应的类是模板类GenericPipe,PANEL指定该pipe合成后图像输出目的,从而也决定其使用的LayerMixer。另外地,每个OverlayImpl模板类的3个管道可能需要图像旋转,所以有可能使用3个Rotator。此处的P0, P1, P2只是逻辑索引,并不具体是MDP的管道索引,根据使用规格需求,从MDP管道中为之动态分配。

hwcomposer也设计了几个封装类与Overlay应用场景对应,屏蔽了场景功能的具体实现。hwcomposer中定义的应用场景比Overlay提供的场景还要少,仅是有限几个。大致结构图如下:

由于overlay场景太多,因此只示意了四个,OV_BYPASS_x_LAYER可以是1,2,3个,分别对应1个,2个或3个HWC_FRAMEBUFFER Layer和base layer Framebuffer合成的情形。

hwc_prepare的设计逻辑过于固化和简单,成了一种基于if-else判断的优先配置方式,宽阔的城堡顶部建了个鸟笼似的小阁楼;应该设计成Policy或RouteState的形式更具备可扩展性。

 

Overlay进行流路控制的接口是commit,然后调用其具体实现类和MDP封装类的相关接口,一个调用栈(适当向内核驱动做了扩展)如下:

mdp4_overlay_set()

msmfb_overlay_set()

ioctl(fb, MSMFB_OVERLAY_SET)

overlay::mdp_wrapper::setOverlay()

MdpCtrl::set()

Ctrl::commit()

pipe::commit() -> GernericPipe::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::queueBuffer(int fd, uint32_t offset)

OverlayImplBase::queueBuffer() -> OverlayImpl<>::(int fd, uint32_t offset, utils::eDest dest)

Overlay::queueBuffer(int fd, uint32_t offset, utils::eDest dest)

 

Camera或Video Overlay

Camera Overlay一般有两种实现模式,一种模式是V4L2不提供Overlay接口,在用户态把V4L2 buffer handle传递给Framebuffer,由Framebuffer Overlay Implementation完成合成;另一种模式是V4L2提供Overlay接口,可以把Video buffer在V4L2内核驱动中提交给Framebuffer Overlay内核驱动完成合成。QC MSM8k Overlay是采用的第一种模式实现,但是V4L2和Framebuffer驱动也提供了第二种模式的实现;第二种模式可参见Freescale处理器上Android Overlay的实现。

Camera的取景器PreviewDisplay Window是个SurfaceView,所在的Layer(HWC_OVERLAY)在UI Layer底下,但是UI layer会开个全透的区域露出这个HWC_OVERLAY Layer。

下面描述其合成过程。

3D GPU 绘制:所有的HWC_FRAMEBUFFER layers会首先经OpenGL 3D GPU绘制到back Framebuffer上;

OV_PIPE0配置:然后在setupHardwareComposer=> HWComposer::prepare=>hwc_prepare=>VideoOverlay::prepare中使用HWC_OVERLAY Layer参数设置OV_PIPE0分配的类型为Video/Graphic的MDP pipe;

OV_PIPE0提交:DisplayHardware::flip=>HWComposer::commit=>hwc_set=>VideoOverlay::draw提交HWC_OVERLAY Layer的图像数据到OV_PIPE0的内核VG pipe的工作队列中(单容量队列即可);

OV_PIPE3配置:DisplayHardware::flip => HWComposer::commit=> hwc_set=>eglSwapBuffers => queueBuffer=> fb_post=>update_framebuffer中使用base layer back framebuffer参数配置OV_PIPE3即RGB1 pipe(注意base layer的特殊地位);

OV_PIPE3提交:当update_framebuffer真正提交图像数据到RGB1 pipe时,对应stage 0 for base layer(内核驱动)会启动MDP LayerMixer0进行Layers合成

DMA传输:然后fb_post通过FBIOPUT_VSCREENINFO或PAN_DISPLAY启动DMA_P送合成好的图像经MIPI-DSI输出显示

BufferFlip:queueBuffer后,该framebuffer即为front framebuffer,然后eglSwapBuffers会dequeueBuffer下一个Framebuffer做为back framebuffer。

此时Hardware Composer使用的是[email protected]对应的逻辑。VG pipe设置和提交的栈示例如下:

/system/lib/liboverlay.so (overlay::Overlay::commit(overlay::utils::eDest)+71)

/system/lib/liboverlay.so  configPrimVid(hwc_context_t *ctx, hwc_layer_t *layer)

/system/lib/liboverlay.so  VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *, hwc_layer_t *)

/system/lib/hw/hwcomposer.msm8960.so (qhwc::VideoOverlay::prepare(hwc_context_t *, hwc_layer_list_t *)+xxx)

/system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::setup(hwc_context_t*, hwc_layer_list*)+163) for each pipe.

/system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::configure(hwc_composer_device*, hwc_layer_list*)+59)

/system/lib/hw/hwcomposer.msm8960.so hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list)

 

/system/lib/libsurfaceflinger.so (android::HWComposer::prepare() const+9)

/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::setupHardwareComposer()+127)

/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::handleRepaint()+147)

/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+91)

 

/system/lib/liboverlay.so Overlay::queueBuffer(int fd, uint32_t offset, utils::eDest dest)

/system/lib/hw/hwcomposer.msm8960.so (qhwc::VideoOverlay::draw(hwc_context_t*, hwc_layer_list*)+xx) for each pipe.

/system/lib/hw/hwcomposer.msm8960.so static int hwc_set(hwc_composer_device_t *dev,hwc_display_t dpy,hwc_surface_t sur, hwc_layer_list_t* list)

/system/lib/libsurfaceflinger.so (android::HWComposer::commit() const+11)

/system/lib/libsurfaceflinger.so (android::DisplayHardware::flip(android::Region const&) const+59)

/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::postFramebuffer()+61)

/system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+103)

Base layer对应的RGB pipe设置和提交的栈示例从略。Base layer提交到RGB1时真正启动LayerMixer0的4-stage layer composition。

FB Layer Hardware Composition

当开启硬件(debug.sf.hw=1)合成合成方式选择MDP时,属性debug.mdpcomp.maxlayer决定了可以使用的通道的个数,当前设置为3,因为RGB1 pipe预留为Camera或Video时的base layer使用,在全Framebuffer layer MDP合成情景下,RGB1对应的base layer是一个处于最顶端的全透明层。相关系统设置和属性如下:

系统根目录文件 /systembuild.prop中,

debug.sf.hw=1

debug.egl.hw=1

debug.composition.type=mdp

debug.enable.wl_log=1

debug.mdpcomp.maxlayer=3

debug.mdpcomp.logs=0

其中CompositionType有 4种,debug.composition.type=dyn/c2d/mdp/cpu/gpu,dyn是根据c2d和mdp的硬件存在选择使用二者之一。

gpu/c2d/mdp可以释放cpu/gpu,减轻cpu/gpu的负担,但并不一定能使显示效果流畅。

SurfaceFlinger启动时会取debug.mdpcomp.maxlayer属性值记录在全局变量sMaxLayers中。相关代码如下:

782    sMaxLayers = 0;

783    if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) {

784        if(atoi(property) != 0)

785           sMaxLayers = atoi(property);

786    }

当没有Camera/Video/HDMI/WFD等Overlay应用情景时,所有Layer都是HWC_FRAMEBUFFER的,MDP的LayerMixer0是闲置的,这时可以优化利用其来做Framebuffer Layer合成。由于管道数目限制的原因,只能合成小于等于sMaxLayers个Layers。多于3个的时候是否可以MDP合成其中的3个?可能需要考虑Layer buffer维度、格式、缩放、Z序等因素。当多于3个的时候,是遍历layer::draw使用GPU来绘制纹理到back framebuffer上的。

下面着重看少于等于3个Layer,MDP合成的情况。

首先,所有的Layer的compositiontype都是HWC_FRAMEBUFFER的;

然后SurfaceFlinger在setHardwareComposer时发现hwc_prepare没有别的优先的Overlay情景,最后的一个if分支就是使用MDP来做Layer合成;SurfaceFlinger会检查Layer的属性看是否满足使用MDP的条件,然后设置满足条件的Layer的属性[compositionType, flags] = (HWC_OVERLAY, MDPCOMP);这样SurfaceFlinger::composeSurfaces时,就不再通过layer::draw使用GPU来绘制;

PIPE配置:SurfaceFlinger为HWC创建工作集,为每个Layer分配并使用MDPComp::prepare配置每个pipe,如果有缩放需求,则会分配VG pipe,因为RGB pipe不支持缩放;有一个Layer则Overlay状态为BYPASS_1_LAYER,表示有1个Layer Bypass,不需要OpenGL绘制,同理2个Layer为BYPASS_2_LAYER,3个为BYPASS_3_LAYER;

PIPE提交:在DisplayHardware::flip中提交每个Layer的数据到管道,即MDPComp::draw() => Overlay::queueBuffer()。注意Layer图像数据是在PMEM/ASHMEM内存中而不是Framebuffer内存中,但仍物理连续或IOMMU映射连续,LayerMixerdraw可访问。MDPComp::draw完即提交数据到对应管道的单容量队列后,清layer->flags &= ~HWC_MDPCOMP标志;

在eglSwapBuffers时,真正做back & front Buffer的切换(准确地说双缓冲是切换,三缓冲是轮用)

OV_PIPE3配置:DisplayHardware::flip => HWComposer::commit=> hwc_set=>eglSwapBuffers => queueBuffer=> fb_post=>update_framebuffer中使用base layer back framebuffer参数配置OV_PIPE3即RGB1 pipe;

OV_PIPE3提交:当update_framebuffer真正提交图像数据到RGB1 pipe时,对应stage 0 for base layer(内核驱动)会启动MDP LayerMixer0进行Layers合成;此时base layer是个最顶层的全透明Layer,不妨碍底层Layer的显示

DMA传输:然后fb_post通过FBIOPUT_VSCREENINFO或PAN_DISPLAY启动DMA_P送合成好的图像经MIPI-DSI输出显示

BufferFlip:queueBuffer后,该framebuffer即为front framebuffer,然后eglSwapBuffers会dequeueBuffer下一个Framebuffer做为back framebuffer。

HWC功能时,是[email protected]对应的逻辑,一个Layer对应的 pipe设置和提交的栈示例如下:

#00  pc 0000b0d0  /system/lib/liboverlay.so (overlay::Overlay::commit(overlay::utils::eDest)+71)

#01  pc 00005d16  /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::prepare(hwc_context_t*, hwc_layer*, qhwc::MDPComp::mdp_pipe_info&)+577)

#02  pc 00006190  /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::setup(hwc_context_t*, hwc_layer_list*)+163) for each pipe.

#03  pc 0000652c  /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::configure(hwc_composer_device*, hwc_layer_list*)+59)

#04  pc 000037ea  /system/lib/hw/hwcomposer.msm8960.so hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list)

#05  pc 0001ebba  /system/lib/libsurfaceflinger.so (android::HWComposer::prepare() const+9)

#06  pc 00020df4  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::setupHardwareComposer()+127)

#07  pc 000212f4  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::handleRepaint()+147)

#08  pc 000222e8  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+91)

 

/system/lib/liboverlay.so Overlay::queueBuffer(int fd, uint32_t offset, utils::eDest dest)

#00  pc 00006592  /system/lib/hw/hwcomposer.msm8960.so (qhwc::MDPComp::draw(hwc_context_t*, hwc_layer_list*)+85) for each pipe.

#01  pc 00003ae4  /system/lib/hw/hwcomposer.msm8960.so static int hwc_set(hwc_composer_device_t *dev,hwc_display_t dpy,hwc_surface_t sur, hwc_layer_list_t* list)

#02  pc 0001ed56  /system/lib/libsurfaceflinger.so (android::HWComposer::commit() const+11)

#03  pc 0001e57c  /system/lib/libsurfaceflinger.so (android::DisplayHardware::flip(android::Region const&) const+59)

#04  pc 000209c6  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::postFramebuffer()+61)

#05  pc 00022474  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+103)

Base layer对应的RGB pipe设置和提交的栈示例从略。重复地,Base layer提交到RGB1时真正启动LayerMixer0的4-stage layer composition。

HDMI / WFD

有机会待续。

 

LayerMixer0合成后图像经DMA_P输出时,在BLT模式和DIRECTOUT模式下LayerMixer0与DMA之间没有buffer;即使FB模式,也是一个Overlay buffer而未必是做为Framebuffer内存,当然这个Overlay buffer做为DMA_P输入传输给MIPI-DSI/LCDC。 

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

 

FrameBuffer driver including MDP Overlay

Framebuffer设备的sysfs

330static int msm_fb_create_sysfs(struct platform_device *pdev)

331{

332         int rc;

333         struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);

334

335         rc = sysfs_create_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group);

336         if (rc)

337                         MSM_FB_ERR("%s: sysfs group creation failed, rc=%d\n", __func__,

338                                         rc);

339         return rc;

340}

 

root@android:/sys/class/graphics/fb0 # ls -al

-rw-r--r-- root     root         4096 1970-06-27 09:37 bits_per_pixel

-rw-r--r-- root     root         4096 1970-06-27 09:37 blank

-rw-r--r-- root     root         4096 1970-06-27 09:37 console

-rw-r--r-- root     root         4096 1970-06-27 09:37 cursor

-r--r--r-- root     root         4096 1970-06-27 09:37 dev

-rw-r--r-- root     root         4096 1970-06-27 09:37 mode

-rw-r--r-- root     root         4096 1970-06-27 09:37 modes

-r--r--r-- root     root         4096 1970-06-27 09:37 msm_fb_type

-r--r--r-- root     root         4096 1970-06-27 09:37 name

-rw-r--r-- root     root         4096 1970-06-27 09:37 pan

drwxr-xr-x root     root              1970-06-27 08:28 power

-rw-r--r-- root     root         4096 1970-06-27 09:37 rotate

-rw-r--r-- root     root         4096 1970-06-27 09:37 state

-r--r--r-- root     root         4096 1970-06-27 09:37 stride

lrwxrwxrwx root     root              1970-06-27 09:37 subsystem -> ../../../../class/graphics

-rw-r--r-- root     root         4096 1970-06-27 08:28 uevent

-rw-r--r-- root     root         4096 1970-06-27 09:37 virtual_size

-r--r--r-- root     root         4096 1970-06-27 08:28 vsync_event

root@android:/sys/class/graphics/fb0 # cat msm_fb_type                        

mipi dsi cmd panel

root@android:/sys/class/graphics/fb0 # cat bits_per_pixel                     

32

130|root@android:/sys/class/graphics/fb0 # cat dev

29:0

root@android:/sys/class/graphics/fb0 # cat modes

U:480x854p-0

root@android:/sys/class/graphics/fb0 # cat name

msmfb42_90501

root@android:/sys/class/graphics/fb0 # cat stride

1920

root@android:/sys/class/graphics/fb0 # cat virtual_size                      

480,2566

 

cont_splash_done field

Add support for "Continuous Splash Screen" feature.

The image displayed on the screen by the android bootloaderdriver should continue till the android animation shows up.

Delay the display initialization for MDP, display dependent clocksand panel power on functions.

bootloader显示的image在linux内核启动过程中保持显示在屏幕上,知道开机动画显示,即linux内核启动过程中不要出现黑屏。

 

Early suspend & Early resume

Early suspend是有wakelock还占有,系统还不能整体suspend,但是可以关闭屏幕、背光、输入等;在Early suspended状态时,重新打开屏幕、背光和输入,是为对应的early resume。

fb_register中相关设置如下:

1551                       mfd->early_suspend.suspend = msmfb_early_suspend;

1552                       mfd->early_suspend.resume = msmfb_early_resume;

1553                       mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;

1554                       register_early_suspend(&mfd->early_suspend);

数据结构定义如下:

23/* The early_suspend structure defines suspend and resume hooks to be called

24 * when the user visible sleep state of the system changes, and a level to

25 * control the order. They can be used to turn off the screen and input

26 * devices that are not used for wakeup.

27 * Suspend handlers are called in low to high level order, resume handlers are

28 * called in the opposite order. If, when calling register_early_suspend,

29 * the suspend handlers have already been called without a matching call to the

30 * resume handlers, the suspend handler will be called directly from

31 * register_early_suspend. This direct call can violate the normal level order.

32 */

33enum {

34           EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,

35           EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,

36           EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,

37};

38struct early_suspend {

39#ifdef CONFIG_HAS_EARLYSUSPEND

40           struct list_head link;

41           int level;

42           void (*suspend)(struct early_suspend *h);

43           void (*resume)(struct early_suspend *h);

44#endif

45};

 

backlight

msm_fb_set_backlight以后是使用led_trigger调用真正led_classdev "wled"的brightnes_set去设置背光。

用户态ioctl通过msm_fb_set_backlight调用到msm_fb_panel_data::set_backlight,

"lcd_backlight".brightness_set -> msm_fb_panel_data::set_backlight -> "bkl_trigger".led_trigger -> "wled".brightness_set。然后找真正操作硬件IC部分。

驱动中设置背光则是绕过"lcd_backlight"设备直接通过backlight_worker工作执行到msm_fb_panel_data::set_backlight,然后-> "bkl_trigger".led_trigger -> "wled".brightness_set。

可以认为"lcd_backlight"是背光抽象设备,通过led_trigger的led组映射到不同的led_classdev设备

以三星DSI CMD屏为例:

In mipi_samsung.c

294static void mipi_samsung_set_backlight(struct msm_fb_data_type *mfd)

295{

296         if (!cci_fb_UpdateDone){

297                         printk("Taylor: No BL before LCM on\n");

298                         return;

299         }

300

301         pr_debug("Taylor: %s : Set BL:%d\n",__func__, mfd->bl_level);

302         if ((mipi_samsung_pdata->enable_wled_bl_ctrl)

303             && (wled_trigger_initialized)) {

304                         led_trigger_event(bkl_led_trigger, mfd->bl_level);

305                         return;

306         }

307}

 

kernel/drivers/leds/leds-pm8xxx.c

#define PM8XXX_LEDS_DEV_NAME       "pm8xxx-led"

2283static struct platform_driver pm8xxx_led_driver = {

2284       .probe                  = pm8xxx_led_probe,

2285       .remove                               = __devexit_p(pm8xxx_led_remove),

2286       .driver                   = {

2287                       .name   = PM8XXX_LEDS_DEV_NAME,

2288                       .owner = THIS_MODULE,

2289       },

2290};

 

pm8xxx_led_probe会对pm8038_led_info数组中的每个led使用设置led_classdev字段,并且初始化work item,然后使用led_classdev_register向系统注册每个led设备。

2197                       INIT_WORK(&led_dat->work, pm8xxx_led_work);

2198                       INIT_WORK(&led_dat->modework, pm8xxx_mode_work);

2199                       INIT_WORK(&led_dat->testwork, pm8xxx_test_work);

 

每个led的brightness_set字段设置为pm8xxx_led_set。

1790static void pm8xxx_led_set(struct led_classdev *led_cdev,

1791       enum led_brightness value)

1792{

1793       struct    pm8xxx_led_data *led;

1794

1795       led = container_of(led_cdev, struct pm8xxx_led_data, cdev);

1796

1797       if (value < LED_OFF || value > led->cdev.max_brightness) {

1798                       dev_err(led->cdev.dev, "Invalid brightness value exceeds");

1799                       return;

1800       }

1801

1802       led->cdev.brightness = value;

1803       schedule_work(&led->work);

1804}

 

1730static void pm8xxx_led_work(struct work_struct *work)

1731{

1732       int rc;

1733

1734       struct pm8xxx_led_data *led = container_of(work,

1735                                                                       struct pm8xxx_led_data, work);

1736

1737       if (led->pwm_dev == NULL) {

1738                       __pm8xxx_led_work(led, led->cdev.brightness);

1739       } else {

1740                       rc = pm8xxx_led_pwm_work(led);

1741                       if (rc)

1742                                       pr_err("could not configure PWM mode for LED:%d\n",

1743                                                                                                                       led->id);

1744       }

1745}

对PM8XXX_ID_WLED,是使用__pm8xxx_led_work

1692static void __pm8xxx_led_work(struct pm8xxx_led_data *led,

1693                                                                       enum led_brightness level)

1694{

1695       int rc;

1696

1697       mutex_lock(&led->lock);

1698

1699       switch (led->id) {

1700       case PM8XXX_ID_LED_KB_LIGHT:

1701                       led_kp_set(led, level);

1702                       break;

1703       case PM8XXX_ID_LED_0:

1704       case PM8XXX_ID_LED_1:

1705       case PM8XXX_ID_LED_2:

1706                       led_lc_set(led, level);

1707                       break;

1708       case PM8XXX_ID_FLASH_LED_0:

1709       case PM8XXX_ID_FLASH_LED_1:

1710                       led_flash_set(led, level);

1711                       break;

1712      case PM8XXX_ID_WLED:

1713                      rc = led_wled_set(led, level);

1714                       if (rc < 0)

1715                                       pr_err("wled brightness set failed %d\n", rc);

1716                       break;

1717       case PM8XXX_ID_RGB_LED_RED:

1718       case PM8XXX_ID_RGB_LED_GREEN:

1719       case PM8XXX_ID_RGB_LED_BLUE:

1720                       led_rgb_set(led, level);

1721                       break;

1722       default:

1723                       dev_err(led->cdev.dev, "unknown led id %d", led->id);

1724                       break;

1725       }

1726

1727       mutex_unlock(&led->lock);

1728}

led_wled_set写电源管理芯片pm8xxx的控制寄存器,控制wled。

 

Framebuffer fb_info::node

registered_fb它是一个数组,它的类型就是struct fb_info,它用于保存我们调用register_framebuffer传进来的struct fb_info。

num_registered_fb代表注册帧缓冲设备的个数。

   1522         for (i = 0; i < FB_MAX; i++)
   1523                 if (!registered_fb[i])
   1524                         break;
   1525         fb_info->node = i;

相当于找到一个空的次设备号。

 

Framebuffer像素格式

主屏RGBA8888

In mipi_dsi_probe()

481         /*

482         * get/set panel specific fb info

483         */

484         mfd->panel_info = pdata->panel_info;

485         pinfo = &mfd->panel_info;

486

487         if (mfd->panel_info.type == MIPI_VIDEO_PANEL)

488                         mfd->dest = DISPLAY_LCDC;

489         else

490                         mfd->dest = DISPLAY_LCD;

491

492         if (mdp_rev == MDP_REV_303 &&

493                         mipi_dsi_pdata->get_lane_config) {

494                         if (mipi_dsi_pdata->get_lane_config() != 2) {

495                                         pr_info("Changing to DSI Single Mode Configuration\n");

496#ifdef CONFIG_FB_MSM_MDP303

497                                         update_lane_config(pinfo);

498#endif

499                         }

500         }

501

502         if (mfd->index == 0)

503                         mfd->fb_imgType = MSMFB_DEFAULT_TYPE;   // configed as RGBA8888 for fb0

504         else

505                         mfd->fb_imgType = MDP_RGB_565;

 

msmfb_update_notify/ msmfb_no_update_notify

用于CABL功能时,统计直方图使用;

更新屏幕前complete(&msmfb_update_notify)从而在准确时间点启动直方图统计;2*HZ后,msmfb_no_update_notify_timer超时,在timer超时回调中complete(&mfd->msmfb_no_update_notify)结束直方图统计。

 

sw_refresher

使用定时器去触发mdp_refresh_screen,添加work进行dma_fnc调用。

针对某些接口的VIDEO模式屏且控制器没有hw_refresh支持时,可以使用sw_refresher。

FB_ACTIVATE_VBL标志涵义

fb_var_screeninfo结构体的成员变量activate的值设置FB_ACTIVATE_VBL,表示要等到下一个垂直同步事件出现时,再将当前要渲染的图形缓冲区的内容绘制出来。这样做的目的是避免出现屏幕闪烁,即避免前后两个图形缓冲区的内容各有一部分同时出现屏幕中。

 

Framebuffer初始化

设备资源申请是在MACHINE_DESC中实现的。示例如下:

3463MACHINE_START(MSM8930_CDP, "QCT MSM8930 CDP")

3464       .map_io = msm8930_map_io,

3465       .reserve = msm8930_reserve,

3466       .init_irq = msm8930_init_irq,

3467       .handle_irq = gic_handle_irq,

3468       .timer = &msm_timer,

3469       .init_machine = msm8930_cdp_init,

3470       .init_early = msm8930_allocate_memory_regions,

3471       .init_very_early = msm8930_early_memory,

3472       .restart = msm_restart,

3473MACHINE_END

machine_desc{.init_very_early, .init_early, .init_machine, .restart}, module_init driver的初始化顺序参考Machine_desc & boot & Kernel_init & initcall & module_init

函数msm8930_cdp_init做Machine级别的设备的注册,部分代码如下:

static void __init msm8930_cdp_init(void) @ kernel/arch/arm/mach-msm/board-8930.c

{

    …

platform_add_devices(common_devices, ARRAY_SIZE(common_devices));

                msm8930_init_gpu();   

                msm8930_init_mmc();

                msm8930_init_cam();

                msm8930_init_fb();

}

msm8930_cdp_init中与display相关的是msm8930_init_fb()函数,这个函数注册了几个id为0的设备。各主要设备名如下,

“msm_fb” msm framebuffer设备,注意不是linux framebuffer设备,但是有对应关系;

“wfd” wifi显示设备;

“mipi_dsi_cmd_samsung_fwvga”  mipi-dsi接口cmd模式LCD屏设备;

“hdmi_msm” HDMI显示器设备;

“mdp” mobile display station显示引擎设备;

“mipi-dsi” MIPI-DSI显示器驱动设备(id例外用了1,可能有的平台上有两个MIPI-DSI,另一个id为0);

1168void __init msm8930_init_fb(void) @ kernel/arch/arm/mach-msm/board-8930-display.c

1169{

1170       platform_device_register(&msm_fb_device);

1171

1172#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL

1173       platform_device_register(&wfd_panel_device);

1174       platform_device_register(&wfd_device);

1175#endif

1176

1178#ifdef CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT

1179       platform_device_register(&mipi_dsi_novatek_panel_device);

1180#endif

1181

1184#ifdef CONFIG_FB_MSM_MIPI_SA77_CMD_FWVGA_PANEL

1185       platform_device_register(&mipi_dsi_cmd_chimei_fwvga_panel_device);

1186       platform_device_register(&mipi_dsi_cmd_samsung_fwvga_panel_device);

1187#endif

1189

1190#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL

1191       platform_device_register(&hdmi_msm_device);

1192#endif

1193

1194       platform_device_register(&mipi_dsi_toshiba_panel_device);

1195

1196       msm_fb_register_device("mdp", &mdp_pdata);

1197       msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);

1198#ifdef CONFIG_MSM_BUS_SCALING

1199#ifdef CONFIG_FB_MSM_DTV

1200       msm_fb_register_device("dtv", &dtv_pdata);

1201#endif

1202#endif

1203}

因为注册这些设备的意图主要是资源申请和初步初始化设备,所以各设备注册顺序并无关紧要。其初始化顺序还与后来的驱动实际注册顺序有关。

 

首先注册paltform_devicemsm_fb_device,设备定义如下

71static struct resource msm_fb_resources[] = {

72           {

73                           .flags = IORESOURCE_DMA,

74           }

75};

135static struct msm_fb_platform_data msm_fb_pdata = {

136         .detect_client = msm_fb_detect_panel,

137};

138

139static struct platform_device msm_fb_device = {

140         .name   = "msm_fb",

141         .id     = 0,

142         .num_resources     = ARRAY_SIZE(msm_fb_resources),

143         .resource          = msm_fb_resources,

144         .dev.platform_data = &msm_fb_pdata,

145};

然后注册panel设备,设备定义如下

845static struct mipi_dsi_panel_platform_data samsung_pdata = {

846         .enable_wled_bl_ctrl = 0x1,

847};

848

849static struct platform_device mipi_dsi_cmd_samsung_fwvga_panel_device = {

850         .name = "dsi_cmd_samsung_fwvga",

851         .id = 0,

852         .dev = {

853                         .platform_data = &samsung_pdata,

854         }

855};

然后关键的注册mdp和mipi-dsi controller,设备定义如下

1749void __init msm_fb_register_device(char *name, void *data)

1750{

1751       if (!strncmp(name, "mdp", 3))

1752                       msm_register_device(&msm_mdp_device, data);

1753       else if (!strncmp(name, "lcdc", 4))

1754                       msm_register_device(&msm_lcdc_device, data);

1755       else if (!strncmp(name, "mipi_dsi", 8))

1756                       msm_register_device(&msm_mipi_dsi_device, data);

1757#ifdef CONFIG_FB_MSM_TVOUT

1758       else if (!strncmp(name, "tvenc", 5))

1759                       msm_register_device(&msm_tvenc_device, data);

1760       else if (!strncmp(name, "tvout_device", 12))

1761                       msm_register_device(&msm_tvout_device, data);

1762#endif

1763#ifdef CONFIG_MSM_BUS_SCALING

1764       else if (!strncmp(name, "dtv", 3))

1765                       msm_register_device(&msm_dtv_device, data);

1766#endif

1767       else

1768                       printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);

1769}

mdp和mipi-dsi设备及寄存器映射和中断需求如下

1484#define MIPI_DSI_HW_BASE            0x04700000

1485#define ROTATOR_HW_BASE           0x04E00000

1486#define TVENC_HW_BASE                 0x04F00000

1487#define MDP_HW_BASE                     0x05100000

1488

1489static struct resource msm_mipi_dsi_resources[] = {

1490       {

1491                       .name   = "mipi_dsi",

1492                       .start  = MIPI_DSI_HW_BASE,

1493                       .end    = MIPI_DSI_HW_BASE + 0x000F0000 - 1,

1494                       .flags  = IORESOURCE_MEM,

1495       },

1496       {

1497                       .start  = DSI_IRQ,

1498                       .end    = DSI_IRQ,

1499                       .flags  = IORESOURCE_IRQ,

1500       },

1501};

1502

1503static struct platform_device msm_mipi_dsi_device = {

1504       .name   = "mipi_dsi",

1505       .id     = 1,

1506       .num_resources  = ARRAY_SIZE(msm_mipi_dsi_resources),

1507       .resource       = msm_mipi_dsi_resources,

1508};

1509

1510static struct resource msm_mdp_resources[] = {

1511       {

1512                       .name   = "mdp",

1513                       .start  = MDP_HW_BASE,

1514                       .end    = MDP_HW_BASE + 0x000F0000 - 1,

1515                       .flags  = IORESOURCE_MEM,

1516       },

1517       {

1518                       .start  = INT_MDP,

1519                       .end    = INT_MDP,

1520                       .flags  = IORESOURCE_IRQ,

1521       },

1522};

1523

1524static struct platform_device msm_mdp_device = {

1525       .name   = "mdp",

1526       .id     = 0,

1527       .num_resources  = ARRAY_SIZE(msm_mdp_resources),

1528       .resource       = msm_mdp_resources,

1529};

以上设备注册时,其驱动并未加载,因为machine_desc.init_machine设备注册的arch_initcall是在.initcall3.init中,而module_init driver注册是在.initcall6.init中。等其驱动加载时,在对应的probe函数中,判断设备id,初步初始化设备,保存其资源分配。

此时,以下id为0的设备panel, dtv, hdmi, mdp, msm_fb, id为1的mipi-dsi设备已经注册进系统了。

dsi_cmd_chimei_fwvga.0

dsi_cmd_samsung_fwvga.0

dsi_cmd_samsung_fwvga.1281

dtv.0

dtv.458753

hdmi_msm.0

hdmi_msm.1

 

mdp.0

mdp.458753

mdp.591105

mdp.655361

mipi_dsi.1

mipi_dsi.591105

mipi_toshiba.0

 

msm_fb.0

msm_fb.458753

msm_fb.591105

msm_fb.655361

 

下面描述各驱动注册,各驱动都是module_init的。

msm_fb驱动注册如下

module_init(msm_fb_init);

3898int __init msm_fb_init(void) @ kernel/drivers/video/msm/msm_fb.c

3899{

3900       int rc = -ENODEV;

3901

3902       if (msm_fb_register_driver())

3903                       return rc;

                ….

}

3705static int msm_fb_register_driver(void)

3706{

3707       return platform_driver_register(&msm_fb_driver);

3708}

msm_fb_driver驱动定义如下

734static struct platform_driver msm_fb_driver = {

735         .probe = msm_fb_probe,

736         .remove = msm_fb_remove,

737#ifndef CONFIG_HAS_EARLYSUSPEND

738         .suspend = msm_fb_suspend,

739         .resume = msm_fb_resume,

740#endif

741         .shutdown = NULL,

742         .driver = {

743                            /* Driver name must match the device name added in platform.c. */

744                            .name = "msm_fb",

745                            .pm = &msm_fb_dev_pm_ops,

746                            },

747};

platform_device “msm_fb”的resource[0]是一块DMA内存,是framebuffer内存,但是在资源定义中并没有设置size,而在msm_fb_probe中从其使用可以看到该DMA内存已经分配。其size是在machine的init_early中从bootmem中分配的,比machine级别设备注册要早!

                .init_early = msm8930_allocate_memory_regions,

msm8930_allocate_memory_regions(void) @ kernel/arch/arm/mach-msm/board-8930.c

1006static void __init msm8930_allocate_memory_regions(void)

1007{

1008       msm8930_allocate_fb_region();

1009}

 

msm8930_allocate_fb_region() @ kernel/arch/arm/mach-msm/board-8930-display.c

1205void __init msm8930_allocate_fb_region(void)

1206{

1207       void *addr;

1208       unsigned long size;

1209

1210       size = MSM_FB_SIZE;

1211       addr = alloc_bootmem_align(size, 0x1000);

1212       msm_fb_resources[0].start = __pa(addr);

1213       msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;

1214       pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", size, addr, __pa(addr));

1216}

MSM_FB_SIZE宏定义如下,TRIPLE_BUFFER已是主流

32#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER

33#define MSM_FB_PRIM_BUF_SIZE \

34                           (roundup((1920 * 1088 * 4), 4096) * 3) /* 4 bpp x 3 pages */

35#else

36#define MSM_FB_PRIM_BUF_SIZE \

37                           (roundup((1920 * 1088 * 4), 4096) * 2) /* 4 bpp x 2 pages */

38#endif

39/* Note: must be multiple of 4096 */

40#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)

当”msm_fb”注册时,msm_fb_probe在设备和驱动match后被调用。对于msm_fb_device id=0,只做fbram保存和ION client创建;这时probe到的设备对应/sys/bus/platform/devices /msm_fb.0。

msm_ion_client_create(-1, pdev->name);

”mipi-dsi” driver定义和注册如下 (in kernel/drivers/video/msm/mipi_dsi.c)

55static struct platform_driver mipi_dsi_driver = {

56           .probe = mipi_dsi_probe,

57           .remove = mipi_dsi_remove,

58           .shutdown = NULL,

59           .driver = {

60                             .name = "mipi_dsi",

61                              },

62};

603static int mipi_dsi_register_driver(void)

604{

605         return platform_driver_register(&mipi_dsi_driver);

606}

607

608static int __init mipi_dsi_driver_init(void)

609{

610         int ret;

611

612         mipi_dsi_init();

613

614         ret = mipi_dsi_register_driver();

615

616         device_initialize(&dsi_dev);

617

618         if (ret) {

619                         pr_err("mipi_dsi_register_driver() failed!\n");

620                         return ret;

621         }

622

623         return ret;

624}

625

626module_init(mipi_dsi_driver_init);

“mdp” driver定义和注册如下(in kernel/drivers/video/msm/mdp.c)

2094static struct platform_driver mdp_driver = {

2095       .probe = mdp_probe,

2096       .remove = mdp_remove,

2097#ifndef CONFIG_HAS_EARLYSUSPEND

2098       .suspend = mdp_suspend,

2099       .resume = NULL,

2100#endif

2101       .shutdown = NULL,

2102       .driver = {

2103                       /*

2104                       * Driver name must match the device name added in

2105                       * platform.c.

2106                       */

2107                       .name = "mdp",

2108                       .pm = &mdp_dev_pm_ops,

2109       },

2110};

3001static int mdp_register_driver(void)

3002{

3003#ifdef CONFIG_HAS_EARLYSUSPEND

3004       early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1;

3005       early_suspend.suspend = mdp_early_suspend;

3006       early_suspend.resume = mdp_early_resume;

3007       register_early_suspend(&early_suspend);

3008#endif

3009

3010       return platform_driver_register(&mdp_driver);

3011}

3012

3013static int __init mdp_driver_init(void)

3014{

3015       int ret;

3016

3017       mdp_drv_init();

3018

3019       ret = mdp_register_driver();

3020       if (ret) {

3021                       printk(KERN_ERR "mdp_register_driver() failed!\n");

3022                       return ret;

3023       }

3024

3025#if defined(CONFIG_DEBUG_FS)

3026       mdp_debugfs_init();

3027#endif

3028

3029       return 0;

3030

3031}

3032

3033module_init(mdp_driver_init);

 

当真正从屏驱动中添加一块显示设备时,为了让上级设备(“mipi-dsi” “mdp” “msm_fb” “fb”)使用下级设备,高通实现为下级设备创建了每个上级设备的实例,通过从下到上的设备probe链一级一级向上注册。这时保证从下到上的设备注册顺序就是至关重要的了,probe链做注册来保证这一点。

当然为了达到上级设备使用和管理下级设备的目标,另一种方法是下级设备向上级设备做register,这时要保证下级设备向上级设备注册时,上级设备的用于管理的相关数据结构已经准备好。

下面描述由屏驱动添加屏到注册linux framebuffer设备的流程。

在各自的屏设备注册文件中,会去探测屏,这种探测不是做真正扫描,仅仅是使用设备名字验证一下,以SAMSUNG MIPI DSI CMD屏为例,驱动会使用相应规则ID注册一块屏。

static int __init mipi_cmd_samsung_fwvga_pt_init(void) @ kernel/drivers/video/msm/mipi_samsung_cmd_fwvga_pt.c

{

37           int ret;

38

39           if (msm_fb_detect_client("mipi_cmd_samsung_fwvga"))

40                           return 0;

                ……

88           ret = mipi_samsung_device_register(&pinfo, MIPI_DSI_PRIM, MIPI_DSI_PANEL_QHD_PT);

90           if (ret)

91                           pr_err("%s: failed to register device!\n", __func__);

92

93           return ret;

94}

95

96module_init(mipi_cmd_samsung_fwvga_pt_init);

探测函数int msm_fb_detect_client(const char *name)首先使用主屏和外屏名字匹配,匹配不成则使用msm_fd_device.dev.platform .detect_client = msm_fb_detect_panel去匹配。上面欲同时注册SAMSUNG和CHIMEI两块屏设备,当然不能同时detect_panel成功,使用GPIO管脚配置做了二次匹配。实际不同批次的手机可能用到两块屏中的一种。

然后mipi_samsung_device_register()(对CHIMEI则是mipi_chimei_device_register)注册屏驱动和屏设备。驱动定义和注册具体如下,

358static struct platform_driver this_driver = {

359         .probe  = mipi_samsung_lcd_probe,

360         .driver = {

361                         .name   = "dsi_cmd_samsung_fwvga",

362         },

363};

364

365static struct msm_fb_panel_data samsung_panel_data = {

366         .on                         = mipi_samsung_lcd_on,

367         .off                         = mipi_samsung_lcd_off,

368         .set_backlight = mipi_samsung_set_backlight,

369};

373int mipi_samsung_device_register(struct msm_panel_info *pinfo, u32 channel, u32 panel)

375{

376         struct platform_device *pdev = NULL;

377         int ret;

378

379         if ((channel >= 3) || ch_used[channel])

380                         return -ENODEV;

381

382         ch_used[channel] = TRUE;

383

384         ret = mipi_samsung_lcd_init();

385         if (ret) {

386                         pr_err("mipi_samsung_lcd_init() failed with ret %u\n", ret);

387                         return ret;

388         }

389

390         pdev = platform_device_alloc("dsi_cmd_samsung_fwvga", (panel << 8)|channel);

391         if (!pdev)

392                         return -ENOMEM;

393

394         samsung_panel_data.panel_info = *pinfo;

395

396         ret = platform_device_add_data(pdev, &samsung_panel_data,

397                         sizeof(samsung_panel_data));

398         if (ret) {

399                         printk(KERN_ERR

400                           "%s: platform_device_add_data failed!\n", __func__);

401                         goto err_device_put;

402         }

403

404         ret = platform_device_add(pdev);

405         if (ret) {

406                         printk(KERN_ERR

407                           "%s: platform_device_register failed!\n", __func__);

408                         goto err_device_put;

409         }

410

411         return 0;

412

413err_device_put:

414         platform_device_put(pdev);

415         return ret;

416}

417

418static int mipi_samsung_lcd_init(void)

419{

420

421         led_trigger_register_simple("bkl_trigger", &bkl_led_trigger);

422         pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__);

423         wled_trigger_initialized = 1;

424

425         mipi_dsi_buf_alloc(&samsung_tx_buf, DSI_BUF_SIZE);

426         mipi_dsi_buf_alloc(&samsung_rx_buf, DSI_BUF_SIZE);

427

428         return platform_driver_register(&this_driver);

429}

在mipi_samsung_lcd_init()中注册platform_driver屏驱动,然后分配注册platform_device屏设备;platform_data设置为msm_fb_panel_data向上传递参数并用于上级设备调用控制屏开关和背光。

屏设备注册后,platform_device和platform_driver match,驱动的probe函数被调用,把参数一级一级向上带,用于设置上级设备参数,向上一级一级注册设备(“mipi-dsi”, “mdp”, “msm_fb”, “framebuffer”)。

一个类似的调用栈如下

------------[ cut here ]------------

WARNING: at /home/CORPUSERS/xp010548/myworkdroid/7x25a/LINUX/kernel/drivers/video/msm/msm_fb.c:1221 msm_fb_probe+0xf4/0xcbc()

msm_fb_probe

Modules linked in:

 [] (unwind_backtrace+0x0/0x12c) from [] (warn_slowpath_common+0x4c/0x64)

 [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_fmt+0x2c/0x3c)

 [] (warn_slowpath_fmt+0x2c/0x3c) from [] (msm_fb_probe+0xf4/0xcbc)

 [] (msm_fb_probe+0xf4/0xcbc) from [] (platform_drv_probe+0x18/0x1c)

 [] (platform_drv_probe+0x18/0x1c) from [] (driver_probe_device+0x144/0x264)

 [] (driver_probe_device+0x144/0x264) from [] (bus_for_each_drv+0x48/0x84)

 [] (bus_for_each_drv+0x48/0x84) from [] (device_attach+0x74/0xa0)

 [] (device_attach+0x74/0xa0) from [] (bus_probe_device+0x24/0x40)

 [] (bus_probe_device+0x24/0x40) from [] (device_add+0x3f0/0x570)

 [] (device_add+0x3f0/0x570) from [] (platform_device_add+0x13c/0x1a0)

 [] (platform_device_add+0x13c/0x1a0) from [] (mdp_probe+0x828/0x940)

 [] (mdp_probe+0x828/0x940) from [] (platform_drv_probe+0x18/0x1c)

 [] (platform_drv_probe+0x18/0x1c) from [] (driver_probe_device+0x144/0x264)

 [] (driver_probe_device+0x144/0x264) from [] (bus_for_each_drv+0x48/0x84)

 [] (bus_for_each_drv+0x48/0x84) from [] (device_attach+0x74/0xa0)

 [] (device_attach+0x74/0xa0) from [] (bus_probe_device+0x24/0x40)

 [] (bus_probe_device+0x24/0x40) from [] (device_add+0x3f0/0x570)

 [] (device_add+0x3f0/0x570) from [] (platform_device_add+0x13c/0x1a0)

 [] (platform_device_add+0x13c/0x1a0) from [] (mipi_dsi_probe+0x514/0x5d0)

 [] (mipi_dsi_probe+0x514/0x5d0) from [] (platform_drv_probe+0x18/0x1c)

 [] (platform_drv_probe+0x18/0x1c) from [] (driver_probe_device+0x144/0x264)

 [] (driver_probe_device+0x144/0x264) from [] (bus_for_each_drv+0x48/0x84)

 [] (bus_for_each_drv+0x48/0x84) from [] (device_attach+0x74/0xa0)

 [] (device_attach+0x74/0xa0) from [] (bus_probe_device+0x24/0x40)

[] (bus_probe_device+0x24/0x40) from [] (device_add+0x3f0/0x570)

 [] (device_add+0x3f0/0x570) from [] (platform_device_add+0x13c/0x1a0)

 [] (platform_device_add+0x13c/0x1a0) from [] (msm_fb_add_device+0x150/0x1b4)

 [] (msm_fb_add_device+0x150/0x1b4) from [] (mipi_himax_lcd_probe+0x38/0x108)

 [] (mipi_himax_lcd_probe+0x38/0x108) from [] (platform_drv_probe+0x18/0x1c)

 [] (platform_drv_probe+0x18/0x1c) from [] (driver_probe_device+0x144/0x264)

 [] (driver_probe_device+0x144/0x264) from [] (bus_for_each_drv+0x48/0x84)

 [] (bus_for_each_drv+0x48/0x84) from [] (device_attach+0x74/0xa0)

 [] (device_attach+0x74/0xa0) from [] (bus_probe_device+0x24/0x40)

 [] (bus_probe_device+0x24/0x40) from [] (device_add+0x3f0/0x570)

 [] (device_add+0x3f0/0x570) from [] (platform_device_add+0x13c/0x1a0)

 [] (platform_device_add+0x13c/0x1a0) from [] (mipi_himax_device_register+0x7c/0xc0)

 [] (mipi_himax_device_register+0x7c/0xc0) from [] (mipi_cmd_himax_hvga_pt_init+0x148/0x180)

 [] (mipi_cmd_himax_hvga_pt_init+0x148/0x180) from [] (do_one_initcall+0x94/0x164)

 [] (do_one_initcall+0x94/0x164) from [] (kernel_init+0x98/0x144)

 [] (kernel_init+0x98/0x144) from [] (kernel_thread_exit+0x0/0x8)

---[ end trace 65f8ea860415c051 ]---

下面考察设备probe链。

311static int __devinit mipi_samsung_lcd_probe(struct platform_device *pdev)

312{

                …..

338         current_pdev = msm_fb_add_device(pdev);

339

340         if (current_pdev) {

341                         mfd = platform_get_drvdata(current_pdev);

342                         if (!mfd)

343                                         return -ENODEV;

344                         if (mfd->key != MFD_KEY)

345                                         return -EINVAL;

346

347                         mipi  = &mfd->panel_info.mipi;

348

349                         if (phy_settings != NULL)

350                                         mipi->dsi_phy_db = phy_settings;

351

352                         if (dlane_swap)

353                                         mipi->dlane_swap = dlane_swap;

354         }

355         return 0;

356}

msm_fb_add_device做如下事情:

调用struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, u32 type, u32 id)函数分配platform_device “mipi-dsi.type_devid”并设置其platform_data为msm_fb_panel_data。

以额外msm_fb_data_type结构分配framebuffer。

注册”mipi-dsi”设备platform_device_add(this_dev)。

“mipi-dsi”设备和驱动进行attach, match后,“mipi-dsi” driver的probe被调用到。

static int mipi_dsi_probe(struct platform_device *pdev) @ kernel/drivers/video/msm/mipi_dsi.c做如下事情(这次的设备ID是真正实例的了,不是1了):

分配”mdp”设备实例并设置其数据,设置”mipi-dsi”设备操作函数,用于向下操作一级一级设备;

继续设置linux framebuffer的参数;

根据屏分辨率设置mipi-dsi工作频率;

注册该”mdp”设备实例;

“mdp”设备和驱动进行attach, match后,“mdp” driver的probe被调用到。

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

分配”msm_fb”实例并设置其数据;

配置”mdp”工作模式;

注册”msm_fb”实例;

“msm_fb”设备和驱动进行attach, match后,“msm_fb” driver的probe被调用到。

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

调用msm_fb_register设置linux framebuffer并register_framebuffer。

至此,系统中相关设备如下:

dsi_cmd_chimei_fwvga.0

dsi_cmd_samsung_fwvga.0

dsi_cmd_samsung_fwvga.1281 ->mipi_dsi.591105 -> mdp.591105 -> msm_fb.591105 -> fbx

dtv.0

dtv.458753 ->mdp.458753 -> msm_fb.458753  -> fbx

hdmi_msm.0

hdmi_msm.1 ->mdp.655361 -> msm_fb.655361 -> fbx (hdmi)

mdp.0

mipi_dsi.1

mipi_toshiba.0

msm_fb.0

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

 

MDP图像合成显示过程—Framebuffer驱动

Overlay设置和提交过程

msmfb_overlay_set(struct fb_info *info, void __user *p)

è mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)

申请pipe,并设置pipe的clock和bandwidth。

int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)

è int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req)

计算pipe输入缓冲地址、参数配置等;将request暂存,如对DSI CMD屏,是使用void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe),而DSI VIDEO屏是使用void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)。

base_pipe设置和提交,Layer Mix, DMA

当送FBIOPUT_VSCREENINFO或FBIOPAN_DISPLAY命令给FB设备时,最终会调用msm_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)

 

msm_fb_pan_display

è mdp_set_dma_pan_info(info, dirtyPtr, (var->activate == FB_ACTIVATE_VBL));   //设置DMA区域

è mdp_dma_pan_update(info);       //启动DMA,包括Layer Mixer合成和DMA输出

void mdp_dma_pan_update(struct fb_info *info)

è mfd->dma_fnc(mfd);

对MIPI DSI CMD屏,该DMA函数是mdp4_dsi_cmd_overlay。

void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)

{

……

                pipe = vctrl->base_pipe;

……

                if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {    // it is certain for base_pipe

                                  // it is setup in mdp4_overlay_update_dsi_cmd when dsi cmd panel is on.

                                mdp4_mipi_vsync_enable(mfd, pipe, 0);

                                mdp4_overlay_setup_pipe_addr(mfd, pipe);

                                mdp4_dsi_cmd_pipe_queue(0, pipe);                   // arm the base pipe with framebuffer

                }

 

                mdp4_overlay_mdp_perf_upd(mfd, 1);                            // level up the mdp performance

 

                mutex_lock(&mfd->dma->ov_mutex);

                mdp4_dsi_cmd_pipe_commit(cndx, 0);                            // fire the overlay layer mixer and dma

                mdp4_overlay_mdp_perf_upd(mfd, 0);

                mutex_unlock(&mfd->dma->ov_mutex);

}

 

int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)

{

                int  i, undx;

                int mixer = 0;

                struct vsycn_ctrl *vctrl;

                struct vsync_update *vp;

                struct mdp4_overlay_pipe *pipe;

                struct mdp4_overlay_pipe *real_pipe;

                unsigned long flags;

                int need_dmap_wait = 0;

                int need_ov_wait = 0;

                int cnt = 0;

 

               /**

                   *static struct vsycn_ctrl { … } vsync_ctrl_db [MAX_CONTROLLER]

                   *在不同的显示器文件中有不同的定义,注意其是static的。

                   *不同显示应用时关联不同的LayerMixer,所以同一种应用中,

                   *使用具有同一mixer_num的pipe,mixer_num由应用分配的主pipe即该应用对应的

                   * vsync_ctrl_db的base_pipe指定。所有pipe的LayerMixer0是驱动中固定指定好的。

                    */

                vctrl = &vsync_ctrl_db[0];

 

                mutex_lock(&vctrl->update_lock);

                undx =  vctrl->update_ndx;

                vp = &vctrl->vlist[undx];

                pipe = vctrl->base_pipe;

                mixer = pipe->mixer_num;              // the Layer mixer used, LayerMixer0 here.

 

                if (vp->update_cnt == 0) {

                                mutex_unlock(&vctrl->update_lock);

                                return cnt;

                }

 

                //vctrl->update_ndx++;

                //vctrl->update_ndx &= 0x01;

                vp->update_cnt = 0;     /* reset */

                if (vctrl->blt_free) {

                                vctrl->blt_free--;

                                if (vctrl->blt_free == 0)

                                                mdp4_free_writeback_buf(vctrl->mfd, mixer);

                }

                mutex_unlock(&vctrl->update_lock);

 

                /* free previous committed iommu back to pool */

                mdp4_overlay_iommu_unmap_freelist(mixer);

 

                spin_lock_irqsave(&vctrl->spin_lock, flags);

                if (pipe->ov_blt_addr) {

                                /* Blt */

                                if (vctrl->blt_wait)

                                                need_dmap_wait = 1;

                                if (vctrl->ov_koff != vctrl->ov_done) {

                                                INIT_COMPLETION(vctrl->ov_comp);

                                                need_ov_wait = 1;

                                }

                } else {

                                /* direct out */

                                if (vctrl->dmap_koff != vctrl->dmap_done) {

                                                INIT_COMPLETION(vctrl->dmap_comp);

                                                pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n",

                                                 __func__, vctrl->ov_koff, vctrl->ov_done,

                                                vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id());

                                                need_dmap_wait = 1;

                                }

                }

                spin_unlock_irqrestore(&vctrl->spin_lock, flags);

               /* setup completion for dmap wait in DIRECTOUT mode or overlay wait in BLT mode */

                if (need_dmap_wait) {

                                pr_debug("%s: wait4dmap\n", __func__);

                                mdp4_dsi_cmd_wait4dmap(0);

                }

 

                if (need_ov_wait) {

                                pr_debug("%s: wait4ov\n", __func__);

                                mdp4_dsi_cmd_wait4ov(0);

                }

               

                if (pipe->ov_blt_addr) {

                                if (vctrl->blt_end) {

                                                vctrl->blt_end = 0;

                                                pipe->ov_blt_addr = 0;

                                                pipe->dma_blt_addr =  0;

                                                pr_info("%s: reset ov_blt_addr and dma_blt_addr\n", __func__);

                                }

                }

 

                /* if blt has some change, reconfig overlay proccessor and dmap*/

                if (vctrl->blt_change) {

                                mdp4_overlayproc_cfg(pipe);

                                mdp4_overlay_dmap_xy(pipe);

                                vctrl->blt_change = 0;

                }

 

                pipe = vp->plist;

               /*

                 *All pipes used here is targeted to LayerMixer0.

                 * These pipes are allocated with MIXER0 indeed,

               * and queued in vctrl->vlist[undx]. >plist[pipe->pipe_ndx - 1] again.

               * Obvious with target to MIXER0.

               */

                for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {

                                if (pipe->pipe_used) {

                                            /* pipes in vp->plist maybe point to same physical pipe */

                                                cnt++;

                                                real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);

                                                if (real_pipe && real_pipe->pipe_used) {

                                                                /* pipe not unset */

                                                                mdp4_overlay_vsync_commit(pipe);

                                                }

                                                /* free previous iommu to freelist

                                                * which will be freed at next

                                                * pipe_commit

                                                */

                                                mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);

                                                pipe->pipe_used = 0; /* clear */

                                }

                }

 

                /* tx dcs command if had any */

                mipi_dsi_cmdlist_commit(1);

              /* mixer is MIXER0  here. Setup mixer’s each stage with pipe */

                mdp4_mixer_stage_commit(mixer);

 

                pipe = vctrl->base_pipe;

                spin_lock_irqsave(&vctrl->spin_lock, flags);

                if (pipe->ov_blt_addr) {

                                mdp4_dsi_cmd_blt_ov_update(pipe);

                                pipe->ov_cnt++;

                                vctrl->ov_koff++;

                                INIT_COMPLETION(vctrl->ov_comp);

                                vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);

                } else {

                                INIT_COMPLETION(vctrl->dmap_comp);

                                vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);

                                vctrl->dmap_koff++;

                }

                pr_debug("%s: kickoff, pid=%d\n", __func__, current->pid);

                /* kickoff overlay engine */

                mdp4_stat.kickoff_ov0++;

                outpdw(MDP_BASE + 0x0004, 0);

                mb();

                spin_unlock_irqrestore(&vctrl->spin_lock, flags);

 

                mdp4_stat.overlay_commit[pipe->mixer_num]++;

               /* wait for vsync */

                if (wait) {

                                long long tick;

 

                                mdp4_dsi_cmd_wait4vsync(cndx, &tick);

                }

 

                return cnt;

}

void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe)

{

                if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)

                                mdp4_overlay_vg_setup(pipe);               /* video/graphic pipe */

                else

                                mdp4_overlay_rgb_setup(pipe);             /* rgb pipe */

 

                pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,

                                (int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);

                /* figure out the flush value to fill register */

               mdp4_overlay_reg_flush(pipe, 1);

               /* stage setup but not commit */

                mdp4_mixer_stage_up(pipe, 0);

}

void mdp4_mixer_stage_commit(int mixer)

{

                struct mdp4_overlay_pipe *pipe;

                int i, num;

                u32 data, stage;

                int off;

                unsigned long flags;

 

                data = 0;

                for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {

                                pipe = ctrl->stage[mixer][i];

                                if (pipe == NULL)

                                                continue;

                                pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,

                                                                                mixer, pipe->pipe_ndx, i);

                                stage = pipe->mixer_stage;

                                if (mixer >= MDP4_MIXER1)

                                                stage += 8;

                                stage <<= (4 * pipe->pipe_num);

                                data |= stage;

                }

 

                /*

                 * stage_commit may be called from overlay_unset

                 * for command panel, mdp clocks may be off at this time.

                 * so mdp clock enabled is necessary

                 */

                mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);

                mdp_clk_ctrl(1);

 

                mdp4_mixer_blend_setup(mixer);

 

                off = 0;

                if (data != ctrl->mixer_cfg[mixer]) {

                                ctrl->mixer_cfg[mixer] = data;

                                if (mixer >= MDP4_MIXER2) {

                                                /* MDP_LAYERMIXER2_IN_CFG */

                                                off = 0x100f0;

                                } else {

                                                /* mixer 0 or 1 */

                                                num = mixer + 1;

                                                num &= 0x01;

                                                data |= ctrl->mixer_cfg[num];

                                                off = 0x10100;

                                }

                                pr_debug("%s: mixer=%d data=%x flush=%x pid=%d\n", __func__,

                                                                mixer, data, ctrl->flush[mixer], current->pid);

                }

 

                local_irq_save(flags);

                if (off)

                                outpdw(MDP_BASE + off, data);

 

                if (ctrl->flush[mixer]) {

                                outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);

                                ctrl->flush[mixer] = 0;

                }

                local_irq_restore(flags);

                mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);

                mdp_clk_ctrl(0);

}

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

[END]

 


你可能感兴趣的:(Andriod_overlay)