android gralloc流程分析for msm8960

原文转载自http://blog.csdn.net/g_salamander/article/details/8424334

增加了Gralloc模块的平台背景和功能概述部分。

对原文针对msm8960 Android display做了修正。

增加了Surfaceflinger初始化FrameBufferNativeWindow的代码部分。

平台中内存有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. <span style="font-size:12px;">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. };</span>  
struct private_module_t {
    gralloc_module_t base;

    private_handle_t* framebuffer;  /* 指向图形缓冲区的句柄 */
    uint32_t flags;                 /* 用来标志系统帧缓冲区是否支持双缓冲 */
    uint32_t numBuffers;            /* 表示系统帧缓冲的个数 */
    uint32_t bufferMask;            /* 记录系统帧缓冲的使用情况 */
    pthread_mutex_t lock;           /* 保护结构体private_module_t的并行访问 */
    buffer_handle_t currentBuffer;  /* 描述当前正在被渲染的图形缓冲区 */
    int pmem_master;                /* pmem设备节点的描述符 */
    void* pmem_master_base;         /* pmem的起始虚拟地址 */

    struct fb_var_screeninfo info;  /* lcd的可变参数 */
    struct fb_fix_screeninfo finfo; /* lcd的固定参数 */
    float xdpi;                     /* x方向上每英寸的像素数量 */
    float ydpi;                     /* y方向上每英寸的像素数量 */
    float fps;                      /* lcd的刷新率 */
    
    int orientation;                /* 显示方向 */

    enum {
        PRIV_USAGE_LOCKED_FOR_POST = 0x80000000  /* flag to indicate we'll post this buffer */
    };
};
该结构的成员记录了 gralloc 模块的各种参数,主要为模块自己使用,应用程序操作的图形缓冲区的数据结构是struct private_handle_t,定义如下:
  1. <span style="font-size:12px;">#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. };</span>  
#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {
    struct native_handle nativeHandle;  /* 用来描述一个本地句柄值 */
#endif
    
    enum {
        PRIV_FLAGS_FRAMEBUFFER    = 0x00000001,
        PRIV_FLAGS_USES_PMEM      = 0x00000002,
        PRIV_FLAGS_USES_MMEM      = 0x00000004,
        PRIV_FLAGS_NEEDS_FLUSH    = 0x00000008,
    };

    enum {
        LOCK_STATE_WRITE     =   1<<31,
        LOCK_STATE_MAPPED    =   1<<30,
        LOCK_STATE_READ_MASK =   0x3FFFFFFF
    };

    /* 指向一个文件描述符,这个文件描述符要么指向帧缓冲区设备,要么指向一块匿名共享内存
     * 取决于private_handle_t描述的图形缓冲区是在帧缓冲区分配的,还是在内存中分配的 */
    int     fd;
    /* 指向一个魔数,它的值由静态成员变量sMagic来指定,用来标识一个private_handle_t结构体 */
    int     magic;
    /* 用来描述一个图形缓冲区的标志,它的值要么等于0,要么等于PRIV_FLAGS_FRAMEBUFFER
     * 当一个图形缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER的时候,就表示它是在帧缓冲区中分配的 */
    int     flags;
    int     size;   /* 描述一个图形缓冲区的大小 */
    int     offset; /* 描述一个图形缓冲区的偏移地址 */

    int     phys;   /* 图形缓冲区或帧缓冲的起始物理地址 */
    int     base;   /* 图形缓冲区或帧缓冲的起始虚拟地址 */
    int     lockState;
    int     writeOwner;
    int     pid;    /* 描述一个图形缓冲区的创建者的PID */

#ifdef __cplusplus
    static const int sNumInts = 9;  /* 有9个整数变量 */
    static const int sNumFds = 1;   /* 有1个文件描述符 */
    static const int sMagic = 0x3141592;

    private_handle_t(int fd, int size, int flags) :
        fd(fd), magic(sMagic), flags(flags), size(size), offset(0),
        phys(0), base(0), lockState(0), writeOwner(0), pid(getpid())
    {
        version = sizeof(native_handle);
        numInts = sNumInts;
        numFds = sNumFds;
    }
    ~private_handle_t() {
        magic = 0;
    }

    bool usesPhysicallyContiguousMemory() {
        return (flags & PRIV_FLAGS_USES_PMEM) != 0;
    }

    /* 用来验证一个native_handle_t指针是否指向了一个private_handle_t结构体 */
    static int validate(const native_handle* h) {
        const private_handle_t* hnd = (const private_handle_t*)h;
        if (!h || h->version != sizeof(native_handle) ||
                h->numInts != sNumInts || h->numFds != sNumFds ||
                hnd->magic != sMagic) 
        {
            LOGE("invalid gralloc handle (at %p)", h);
            return -EINVAL;
        }
        return 0;
    }

    static private_handle_t* dynamicCast(const native_handle* in) {
        if (validate(in) == 0) {
            return (private_handle_t*) in;
        }
        return NULL;
    }
#endif
};

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

  1. <span style="font-size:12px;">typedef struct gralloc_module_t {  
  2.     struct hw_module_t common;  
  3.   
  4.     /* 注册一个图形缓冲区,这个指定的图形缓冲区使用一个buffer_handle_t句柄来描述 */  
  5.     int (*registerBuffer)(struct gralloc_module_t const* module,  
  6.             buffer_handle_t handle);  
  7.   
  8.     /* 注销一个图形缓冲区 */  
  9.     int (*unregisterBuffer)(struct gralloc_module_t const* module,  
  10.             buffer_handle_t handle);  
  11.   
  12.     /* 用来锁定一个图形缓冲区并将缓冲区映射到用户进程 
  13.      * 在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小 
  14.      * 这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置 
  15.      * 而参数w和h指定的是要访问的图形缓冲区的宽度和长度 
  16.      * 锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中 
  17.      * 另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定 */  
  18.     int (*lock)(struct gralloc_module_t const* module,  
  19.             buffer_handle_t handle, int usage,  
  20.             int l, int t, int w, int h,  
  21.             void** vaddr);  
  22.   
  23.     int (*unlock)(struct gralloc_module_t const* module,  
  24.             buffer_handle_t handle);  
  25.   
  26.     int (*perform)(struct gralloc_module_t const* module,  
  27.             int operation, ... );  
  28.   
  29.     /* reserved for future use */  
  30.     void* reserved_proc[7];  
  31. } gralloc_module_t;</span>  
typedef struct gralloc_module_t {
    struct hw_module_t common;

    /* 注册一个图形缓冲区,这个指定的图形缓冲区使用一个buffer_handle_t句柄来描述 */
    int (*registerBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);

    /* 注销一个图形缓冲区 */
    int (*unregisterBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);

    /* 用来锁定一个图形缓冲区并将缓冲区映射到用户进程
     * 在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小
     * 这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置
     * 而参数w和h指定的是要访问的图形缓冲区的宽度和长度
     * 锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中
     * 另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定 */
    int (*lock)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            void** vaddr);

    int (*unlock)(struct gralloc_module_t const* module,
            buffer_handle_t handle);

    int (*perform)(struct gralloc_module_t const* module,
            int operation, ... );

    /* reserved for future use */
    void* reserved_proc[7];
} gralloc_module_t;

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

  1. <span style="font-size:12px;">typedef struct alloc_device_t {  
  2.     struct hw_device_t common;  
  3.   
  4.     /* 申请图形缓冲区的内存空间 */      
  5.     int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);  
  6.   
  7.     /* 释放图形缓冲区的内存空间 */  
  8.     int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);  
  9. } alloc_device_t;</span>  
typedef struct alloc_device_t {
    struct hw_device_t common;

    /* 申请图形缓冲区的内存空间 */    
    int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);

    /* 释放图形缓冲区的内存空间 */
    int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);
} alloc_device_t;
帧缓冲设备则采用结构 struct framebuffer_device_t 描述:
  1. <span style="font-size:12px;">typedef struct framebuffer_device_t {  
  2.     struct hw_device_t common;  
  3.   
  4.     const uint32_t  flags;  /* 用来记录系统帧缓冲区的标志 */  
  5.   
  6.     const uint32_t  width;  /* lcd显示区域的像素点数 */  
  7.     const uint32_t  height;  
  8.   
  9.     const int       stride; /* 描述设备显示屏的一行有多少个像素点 */  
  10.   
  11.     /* 描述系统帧缓冲区的像素格式,主要有HAL_PIXEL_FORMAT_RGBX_8888和HAL_PIXEL_FORMAT_RGB_565两种 */  
  12.     const int       format;  
  13.   
  14.     const float     xdpi;  
  15.     const float     ydpi;  
  16.     const float     fps;              /* lcd刷新率 */  
  17.     const int       minSwapInterval;  /* 交换两帧图像的最小间隔时间 */  
  18.     const int       maxSwapInterval;  /* 交换两帧图像的最大间隔时间 */  
  19.   
  20.     int reserved[8];  
  21.   
  22.     /* 设置帧交换间隔 */  
  23.     int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);  
  24.   
  25.     /* 设置帧缓冲区的更新区域 */  
  26.     int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);  
  27.   
  28.     /* 用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去 */  
  29.     int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);  
  30.   
  31.     /* 用来通知fb设备device,图形缓冲区的组合工作已经完成 */  
  32.     int (*compositionComplete)(struct framebuffer_device_t* dev);  
  33.   
  34.     void* reserved_proc[8];  
  35. } framebuffer_device_t;</span>  
typedef struct framebuffer_device_t {
    struct hw_device_t common;

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

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

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

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

    const float     xdpi;
    const float     ydpi;
    const float     fps;              /* lcd刷新率 */
    const int       minSwapInterval;  /* 交换两帧图像的最小间隔时间 */
    const int       maxSwapInterval;  /* 交换两帧图像的最大间隔时间 */

    int reserved[8];

    /* 设置帧交换间隔 */
    int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);

    /* 设置帧缓冲区的更新区域 */
    int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);

    /* 用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去 */
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);

    /* 用来通知fb设备device,图形缓冲区的组合工作已经完成 */
    int (*compositionComplete)(struct framebuffer_device_t* dev);

    void* reserved_proc[8];
} framebuffer_device_t;
其中成员函数 post对应用程序来说是最重要的接口,它将完成数据写入显存的工作。

2、gralloc 模块

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

  1. <span style="font-size:12px;">#define HAL_LIBRARY_PATH1 "/system/lib/hw"  
  2. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  
  3.   
  4. static const char *variant_keys[] = {  
  5.     "ro.hardware",  /* This goes first so that it can pick up a different file on the emulator. */  
  6.     "ro.product.board",  
  7.     "ro.board.platform",  
  8.     "ro.arch"  
  9. };  
  10.   
  11. static const int HAL_VARIANT_KEYS_COUNT =  
  12.     (sizeof(variant_keys)/sizeof(variant_keys[0]));  
  13.   
  14. int hw_get_module(const char *id, const struct hw_module_t **module)   
  15. {  
  16.     int status;  
  17.     int i;  
  18.     const struct hw_module_t *hmi = NULL;  
  19.     char prop[PATH_MAX];  
  20.     char path[PATH_MAX];  
  21.   
  22.     /* 
  23.      * Here we rely on the fact that calling dlopen multiple times on 
  24.      * the same .so will simply increment a refcount (and not load 
  25.      * a new copy of the library). 
  26.      * We also assume that dlopen() is thread-safe. 
  27.      */  
  28.   
  29.     /* Loop through the configuration variants looking for a module */  
  30.     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  
  31.         if (i < HAL_VARIANT_KEYS_COUNT) {  
  32.             if (property_get(variant_keys[i], prop, NULL) == 0) {  /* 读取variant_keys数组指定的属性值 */  
  33.                 continue;  
  34.             }  
  35.             snprintf(path, sizeof(path), "%s/%s.%s.so",  /* 格式化模块名和路径,如:/system/lib/hw/gralloc.xxx.so */  
  36.                     HAL_LIBRARY_PATH1, id, prop);  
  37.             if (access(path, R_OK) == 0) break;  
  38.   
  39.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
  40.                      HAL_LIBRARY_PATH2, id, prop);  
  41.             if (access(path, R_OK) == 0) break;  
  42.         } else {  
  43.             snprintf(path, sizeof(path), "%s/%s.default.so",  
  44.                      HAL_LIBRARY_PATH1, id);  
  45.             if (access(path, R_OK) == 0) break;  
  46.         }  
  47.     }  
  48.   
  49.     status = -ENOENT;  
  50.     if (i < HAL_VARIANT_KEYS_COUNT+1) {  
  51.         /* load the module, if this fails, we're doomed, and we should not try to load a different variant. */  
  52.         status = load(id, path, module);                 /* 加载模块 */  
  53.     }  
  54.   
  55.     return status;  
  56. }</span>  
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));

int hw_get_module(const char *id, const struct hw_module_t **module) 
{
    int status;
    int i;
    const struct hw_module_t *hmi = NULL;
    char prop[PATH_MAX];
    char path[PATH_MAX];

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {  /* 读取variant_keys数组指定的属性值 */
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",  /* 格式化模块名和路径,如:/system/lib/hw/gralloc.xxx.so */
                    HAL_LIBRARY_PATH1, id, prop);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, id, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, id);
            if (access(path, R_OK) == 0) break;
        }
    }

    status = -ENOENT;
    if (i < HAL_VARIANT_KEYS_COUNT+1) {
        /* load the module, if this fails, we're doomed, and we should not try to load a different variant. */
        status = load(id, path, module);                 /* 加载模块 */
    }

    return status;
}

可以看出,是使用id和系统平台的名字组合出so的文件名,去设定的目录动态加载该库文件然后解析特定符号,找到hw_module_t object

函数会在 /system/lib/hw 或者 /vendor/lib/hw 目录中去寻找gralloc.xxx.so 文件,如果找到了就调用load接口完成加载。

最终会调用 gralloc_device_open完成 gralloc 设备成员的初始化:

  1. <span style="font-size:12px;">int gralloc_device_open(const hw_module_t* module, const char* name,  
  2.         hw_device_t** device)  
  3. {  
  4. 98    int status = -EINVAL;  
  5. 99    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {  
  6. 100        const private_module_t* m = reinterpret_cast<const private_module_t*>(  
  7. 101            module);  
  8. 102        gpu_context_t *dev;  
  9. 103        IAllocController* alloc_ctrl = IAllocController::getInstance();  
  10. 104        dev = new gpu_context_t(m, alloc_ctrl);  
  11. 105        *device = &dev->common;  
  12. 106        status = 0;</span>  
int gralloc_device_open(const hw_module_t* module, const char* name,
        hw_device_t** device)
{
98    int status = -EINVAL;
99    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
100        const private_module_t* m = reinterpret_cast<const private_module_t*>(
101            module);
102        gpu_context_t *dev;
103        IAllocController* alloc_ctrl = IAllocController::getInstance();
104        dev = new gpu_context_t(m, alloc_ctrl);
105        *device = &dev->common;
106        status = 0;
  1. <span style="font-size:12px;">  } else {  
  2.         status = fb_device_open(module, name, device);  
  3.     }  
  4.   
  5.     return status;  
  6. }</span>  
  } else {
        status = fb_device_open(module, name, device);
    }

    return status;
}
可以认为Gralloc module中有两个设备gpu_alloc_device和fb_device,前者用于分配GPU0使用的内存和FB内存,GPU0内存管理使用ION allocator;后者用于获取分配Framebuffer Info并操作fb。
在 android 系统中,所有的图形缓冲区都是由 SurfaceFlinger服务分配的,在系统帧缓冲区中分配的图形缓冲区只在 SurfaceFlinger 服务中使用,而在内存中分配的图形缓冲区既可以在 SurfaceFlinger 服务中使用,也可以在其它的应用程序中使用,当应用程序请求 SurfaceFlinger 服务分配图形缓冲区时会发生两次映射:服务所在的进程首先会将申请到的缓冲区映射至服务的地址空间,然后应用程序使用这个图形缓冲时再将其映射至应用程序的地址空间。分配函数的实现如下:
 
  1. <span style="font-size:12px;">static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)  
  2. {  
  3.     private_module_t* m = reinterpret_cast<private_module_t*>(  
  4.             dev->common.module);  
  5.     pthread_mutex_lock(&m->lock);  
  6.     int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);  
  7.     pthread_mutex_unlock(&m->lock);  
  8.     return err;  
  9. }  
  10.   
  11. static int gralloc_alloc_buffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)  
  12. {  
  13. 127    int err = 0;  
  14. 128    int flags = 0;  
  15. 129    size = roundUpToPageSize(size);  
  16. 130    alloc_data data;  
  17. 131    data.offset = 0;  
  18. 132    data.fd = -1;  
  19. 133    data.base = 0;  
  20. 134    data.size = size;  
  21. 135    if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)  
  22. 136        data.align = 8192;  
  23. 137    else  
  24. 138        data.align = getpagesize();  
  25. 139    data.pHandle = (unsigned int) pHandle;  
  26. 140    err = mAllocCtrl->allocate(data, usage);  
  27. 141  
  28. 142    if (!err) {  
  29. 143        /* allocate memory for enhancement data */  
  30. 144        alloc_data eData;  
  31. 145        eData.fd = -1;  
  32. 146        eData.base = 0;  
  33. 147        eData.offset = 0;  
  34. 148        eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));  
  35. 149        eData.pHandle = data.pHandle;  
  36. 150        eData.align = getpagesize();  
  37. 151        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;  
  38. 152        int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);  
  39. 153        ALOGE_IF(eDataErr, "gralloc failed for eData err=%s", strerror(-err));  
  40. 154  
  41. 155        if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {  
  42. 156            flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;  
  43. 157        }  
  44. 158  
  45. 159        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {  
  46. 160            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;  
  47. 161            //The EXTERNAL_BLOCK flag is always an add-on  
  48. 162            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {  
  49. 163                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;  
  50. 164            }  
  51. 165            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {  
  52. 166                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;  
  53. 167            }  
  54. 168        }  
  55. 169  
  56. 170        flags |= data.allocType;  
  57. 171        int eBaseAddr = int(eData.base) + eData.offset;  
  58. 172        private_handle_t *hnd = new private_handle_t(data.fd, size, flags,  
  59. 173                bufferType, format, width, height, eData.fd, eData.offset,  
  60. 174                eBaseAddr);  
  61. 175  
  62. 176        hnd->offset = data.offset;  
  63. 177        hnd->base = int(data.base) + data.offset;  
  64. 178        *pHandle = hnd;  
  65. 179    }  
  66. 180  
  67. 181    ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));  
  68. 182  
  69. 183    return err;      
  70. 184}  
  71.   
  72. /*****************************************************************************/  
  73.   
  74. static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format, int usage,  
  75.                             buffer_handle_t* pHandle, int* pStride)  
  76. {  
  77.     if (!pHandle || !pStride)  
  78.         return -EINVAL;  
  79.   
  80.     size_t size, stride;  
  81.   
  82.     int align = 4;  
  83.     int bpp = 0;  
  84.     switch (format) {  /* 一个像素点占用的字节数 */  
  85.         case HAL_PIXEL_FORMAT_RGBA_8888:  
  86.         case HAL_PIXEL_FORMAT_RGBX_8888:  
  87.         case HAL_PIXEL_FORMAT_BGRA_8888:  
  88.             bpp = 4;  
  89.             break;  
  90.         case HAL_PIXEL_FORMAT_RGB_888:  
  91.             bpp = 3;  
  92.             break;  
  93.         case HAL_PIXEL_FORMAT_RGB_565:  
  94.         case HAL_PIXEL_FORMAT_RGBA_5551:  
  95.         case HAL_PIXEL_FORMAT_RGBA_4444:  
  96.             bpp = 2;  
  97.             break;  
  98.         default:  
  99.             return -EINVAL;  
  100.     }  
  101.     size_t bpr = (w*bpp + (align-1)) & ~(align-1);  
  102.     size = bpr * h;  
  103.     stride = bpr / bpp;  
  104.   
  105.     int err;  
  106.     if (usage & GRALLOC_USAGE_HW_FB) {  
  107.         err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);  /* 在系统帧缓冲中分配图形缓冲区 */  
  108.     } else {  
  109.         err = gralloc_alloc_buffer(dev, size, usage, pHandle);       /* 在内存中分配图形缓冲区 */  
  110.     }  
  111.   
  112.     if (err < 0) {  
  113.         return err;  
  114.     }  
  115.   
  116.     *pStride = stride;  
  117.     return 0;  
  118. }</span>  
static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
{
    private_module_t* m = reinterpret_cast<private_module_t*>(
            dev->common.module);
    pthread_mutex_lock(&m->lock);
    int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
    pthread_mutex_unlock(&m->lock);
    return err;
}

static int gralloc_alloc_buffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
{
127    int err = 0;
128    int flags = 0;
129    size = roundUpToPageSize(size);
130    alloc_data data;
131    data.offset = 0;
132    data.fd = -1;
133    data.base = 0;
134    data.size = size;
135    if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)
136        data.align = 8192;
137    else
138        data.align = getpagesize();
139    data.pHandle = (unsigned int) pHandle;
140    err = mAllocCtrl->allocate(data, usage);
141
142    if (!err) {
143        /* allocate memory for enhancement data */
144        alloc_data eData;
145        eData.fd = -1;
146        eData.base = 0;
147        eData.offset = 0;
148        eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
149        eData.pHandle = data.pHandle;
150        eData.align = getpagesize();
151        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
152        int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);
153        ALOGE_IF(eDataErr, "gralloc failed for eData err=%s", strerror(-err));
154
155        if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {
156            flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
157        }
158
159        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
160            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
161            //The EXTERNAL_BLOCK flag is always an add-on
162            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {
163                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
164            }
165            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {
166                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;
167            }
168        }
169
170        flags |= data.allocType;
171        int eBaseAddr = int(eData.base) + eData.offset;
172        private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
173                bufferType, format, width, height, eData.fd, eData.offset,
174                eBaseAddr);
175
176        hnd->offset = data.offset;
177        hnd->base = int(data.base) + data.offset;
178        *pHandle = hnd;
179    }
180
181    ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
182
183    return err;    
184}

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

static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format, int usage,
                            buffer_handle_t* pHandle, int* pStride)
{
    if (!pHandle || !pStride)
        return -EINVAL;

    size_t size, stride;

    int align = 4;
    int bpp = 0;
    switch (format) {  /* 一个像素点占用的字节数 */
        case HAL_PIXEL_FORMAT_RGBA_8888:
        case HAL_PIXEL_FORMAT_RGBX_8888:
        case HAL_PIXEL_FORMAT_BGRA_8888:
            bpp = 4;
            break;
        case HAL_PIXEL_FORMAT_RGB_888:
            bpp = 3;
            break;
        case HAL_PIXEL_FORMAT_RGB_565:
        case HAL_PIXEL_FORMAT_RGBA_5551:
        case HAL_PIXEL_FORMAT_RGBA_4444:
            bpp = 2;
            break;
        default:
            return -EINVAL;
    }
    size_t bpr = (w*bpp + (align-1)) & ~(align-1);
    size = bpr * h;
    stride = bpr / bpp;

    int err;
    if (usage & GRALLOC_USAGE_HW_FB) {
        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);  /* 在系统帧缓冲中分配图形缓冲区 */
    } else {
        err = gralloc_alloc_buffer(dev, size, usage, pHandle);       /* 在内存中分配图形缓冲区 */
    }

    if (err < 0) {
        return err;
    }

    *pStride = stride;
    return 0;
}
3、gpu_alloc 模块
gpu0内存即非HW_FB内存使用ION分配器进行分配,此文不做详述。
 
4、fb 模块

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

  1. <span style="font-size:12px;">#define GRALLOC_HARDWARE_FB0 "fb0"  
  2. #define GRALLOC_HARDWARE_GPU0 "gpu0"</span>  
#define GRALLOC_HARDWARE_FB0 "fb0"
#define GRALLOC_HARDWARE_GPU0 "gpu0"
如果参数不是 "gpu0" ,那么是"fb%u"的形式,则会调用fb_device_open 初始化 fb 设备,主要流程和打开 gralloc 基本一致,在函数中会通过调用 mapFrameBuffer->mapFrameBufferLocked 获取帧缓存设备的参数并将其设备节点映射到用户空间,流程如下(大致如此,msm8960平台代码有所变化,msm平台上fb设备文件名是/dev/graphics/fb%u):
  1. <span style="font-size:12px;">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. }</span>  
int mapFrameBufferLocked(struct private_module_t* module)
{
    if (module->framebuffer) {
        return 0;
    }
        
    char const * const device_template[] = {
            "/dev/graphics/fb%u",
            "/dev/fb%u",
            0 };

    int fd = -1;
    int i=0;
    char name[64];

    while ((fd==-1) && device_template[i]) {
        snprintf(name, 64, device_template[i], 0);
        fd = open(name, O_RDWR, 0);
        i++;
    }
    if (fd < 0)
        return -errno;

    struct fb_fix_screeninfo finfo;
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  /* 获取帧缓冲的固定参数 */
        return -errno;

    struct fb_var_screeninfo info;
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)   /* 获取帧缓冲的可变参数 */
        return -errno;

    info.reserved[0] = 0;
    info.reserved[1] = 0;
    info.reserved[2] = 0;
    info.xoffset = 0;
    info.yoffset = 0;
    info.activate = FB_ACTIVATE_NOW;

    info.bits_per_pixel = 32;
    info.red.offset     = 16;
    info.red.length     = 8;
    info.green.offset   = 8;
    info.green.length   = 8;
    info.blue.offset    = 0;
    info.blue.length    = 8;
    info.transp.offset  = 24;
    info.transp.length  = 8;

    /*
     * Request NUM_BUFFERS screens (at lest 2 for page flipping)
     */
    info.yres_virtual = info.yres * NUM_BUFFERS;  /* 帧缓冲总长度 */


    uint32_t flags = PAGE_FLIP;  /* 支持缓冲交换 */
    if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
        info.yres_virtual = info.yres;
        flags &= ~PAGE_FLIP;
        LOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
    }

    if (info.yres_virtual < info.yres * 2) {
        /* we need at least 2 for page-flipping */
        info.yres_virtual = info.yres;
        flags &= ~PAGE_FLIP;
        LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
                info.yres_virtual, info.yres*2);
    }

    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
        return -errno;

    int refreshRate = 1000000000000000LLU /
    (
            uint64_t( info.upper_margin + info.lower_margin + info.yres )
            * ( info.left_margin  + info.right_margin + info.xres )
            * info.pixclock
    );  /* 计算lcd刷新率 */

    if (refreshRate == 0) {
        /* bleagh, bad info from the driver */
        refreshRate = 60*1000;  // 60 Hz
    }

    if (int(info.width) <= 0 || int(info.height) <= 0) {
        /* the driver doesn't return that information, default to 160 dpi */
        info.width  = ((info.xres * 25.4f)/160.0f + 0.5f);
        info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
    }

    float xdpi = (info.xres * 25.4f) / info.width;
    float ydpi = (info.yres * 25.4f) / info.height;
    float fps  = refreshRate / 1000.0f;

    LOGI(   "using (fd=%d)\n"
            "id           = %s\n"
            "xres         = %d px\n"
            "yres         = %d px\n"
            "xres_virtual = %d px\n"
            "yres_virtual = %d px\n"
            "bpp          = %d\n"
            "r            = %2u:%u\n"
            "g            = %2u:%u\n"
            "b            = %2u:%u\n",
            fd,
            finfo.id,
            info.xres,
            info.yres,
            info.xres_virtual,
            info.yres_virtual,
            info.bits_per_pixel,
            info.red.offset, info.red.length,
            info.green.offset, info.green.length,
            info.blue.offset, info.blue.length
    );

    LOGI(   "width        = %d mm (%f dpi)\n"
            "height       = %d mm (%f dpi)\n"
            "refresh rate = %.2f Hz\n",
            info.width,  xdpi,
            info.height, ydpi,
            fps
    );

    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        return -errno;

    if (finfo.smem_len <= 0)
        return -errno;

    module->flags = flags;
    module->info = info;
    module->finfo = finfo;
    module->xdpi = xdpi;
    module->ydpi = ydpi;
    module->fps = fps;

    /*
     * map the framebuffer
     */

    int err;
    size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);  /* 帧缓冲大小 */
    module->framebuffer = new private_handle_t(dup(fd), fbSize,
            private_handle_t::PRIV_FLAGS_USES_PMEM);

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

    void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);    /* 将fb映射到用户空间 */
    if (vaddr == MAP_FAILED) {
        LOGE("Error mapping the framebuffer (%s)", strerror(errno));
        return -errno;
    }
    module->framebuffer->base = intptr_t(vaddr);         /* 帧缓冲的起始虚拟地址 */
    memset(vaddr, 0, fbSize);
    return 0;
}

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

  1. <span style="font-size:12px;">62/* 
  2. 63 * This implements the (main) framebuffer management. This class is used 
  3. 64 * mostly by SurfaceFlinger, but also by command line GL application. 
  4. 65 * 
  5. 66 * In fact this is an implementation of ANativeWindow on top of 
  6. 67 * the framebuffer. 
  7. 68 * 
  8. 69 * Currently it is pretty simple, it manages only two buffers (the front and 
  9. 70 * back buffer). 
  10. 71 * 
  11. 72 */  
  12. 73  
  13. 74FramebufferNativeWindow::FramebufferNativeWindow()  
  14. 75    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)  
  15. 76{  
  16. 77    hw_module_t const* module;  
  17. 78    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {  
  18. 79        int stride;  
  19. 80        int err;  
  20. 81        int i;  
  21. 82        err = framebuffer_open(module, &fbDev);  
  22. 83        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));  
  23. 84  
  24. 85        err = gralloc_open(module, &grDev);  
  25. 86        ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));  
  26. 87  
  27. 88        // bail out if we can't initialize the modules  
  28. 89        if (!fbDev || !grDev)  
  29. 90            return;  
  30. 91  
  31. 92        mUpdateOnDemand = (fbDev->setUpdateRect != 0);  
  32. 93  
  33. 94        // initialize the buffer FIFO  
  34. 95        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&  
  35. 96           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){  
  36. 97            mNumBuffers = fbDev->numFramebuffers;  
  37. 98        } else {  
  38. 99            mNumBuffers = MIN_NUM_FRAME_BUFFERS;  
  39. 100        }  
  40. 101        mNumFreeBuffers = mNumBuffers;  
  41. 102        mBufferHead = mNumBuffers-1;  
  42. 103  
  43. 104        /* 
  44. 105         * This does not actually change the framebuffer format. It merely 
  45. 106         * fakes this format to surfaceflinger so that when it creates 
  46. 107         * framebuffer surfaces it will use this format. It's really a giant 
  47. 108         * HACK to allow interworking with buggy gralloc+GPU driver 
  48. 109         * implementations. You should *NEVER* need to set this for shipping 
  49. 110         * devices. 
  50. 111         */  
  51. 112#ifdef FRAMEBUFFER_FORCE_FORMAT  
  52. 113        *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;  
  53. 114#endif  
  54. 115  
  55. 116        for (i = 0; i < mNumBuffers; i++)  
  56. 117        {  
  57. 118                buffers[i] = new NativeBuffer(  
  58. 119                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);  
  59. 120        }  
  60. 121  
  61. 122        for (i = 0; i < mNumBuffers; i++)  
  62. 123        {  
  63. 124                err = grDev->alloc(grDev,  
  64. 125                        fbDev->width, fbDev->height, fbDev->format,  
  65. 126                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);  
  66. 127  
  67. 128                ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",  
  68. 129                        i, fbDev->width, fbDev->height, strerror(-err));  
  69. 130  
  70. 131                if (err)  
  71. 132                {  
  72. 133                        mNumBuffers = i;  
  73. 134                        mNumFreeBuffers = i;  
  74. 135                        mBufferHead = mNumBuffers-1;  
  75. 136                        break;  
  76. 137                }  
  77. 138        }  
  78. 139  
  79. 140        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;  
  80. 141        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;  
  81. 142        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;  
  82. 143        const_cast<int&>(ANativeWindow::minSwapInterval) =  
  83. 144            fbDev->minSwapInterval;  
  84. 145        const_cast<int&>(ANativeWindow::maxSwapInterval) =  
  85. 146            fbDev->maxSwapInterval;  
  86. 147    } else {  
  87. 148        ALOGE("Couldn't get gralloc module");  
  88. 149    }  
  89. 150  
  90. 151    ANativeWindow::setSwapInterval = setSwapInterval;  
  91. 152    ANativeWindow::dequeueBuffer = dequeueBuffer;  
  92. 153    ANativeWindow::lockBuffer = lockBuffer;  
  93. 154    ANativeWindow::queueBuffer = queueBuffer;  
  94. 155    ANativeWindow::query = query;  
  95. 156    ANativeWindow::perform = perform;  
  96. 157    ANativeWindow::cancelBuffer = NULL;  
  97. 158}</span>  
62/*
63 * This implements the (main) framebuffer management. This class is used
64 * mostly by SurfaceFlinger, but also by command line GL application.
65 *
66 * In fact this is an implementation of ANativeWindow on top of
67 * the framebuffer.
68 *
69 * Currently it is pretty simple, it manages only two buffers (the front and
70 * back buffer).
71 *
72 */
73
74FramebufferNativeWindow::FramebufferNativeWindow()
75    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
76{
77    hw_module_t const* module;
78    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
79        int stride;
80        int err;
81        int i;
82        err = framebuffer_open(module, &fbDev);
83        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
84
85        err = gralloc_open(module, &grDev);
86        ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
87
88        // bail out if we can't initialize the modules
89        if (!fbDev || !grDev)
90            return;
91
92        mUpdateOnDemand = (fbDev->setUpdateRect != 0);
93
94        // initialize the buffer FIFO
95        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
96           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
97            mNumBuffers = fbDev->numFramebuffers;
98        } else {
99            mNumBuffers = MIN_NUM_FRAME_BUFFERS;
100        }
101        mNumFreeBuffers = mNumBuffers;
102        mBufferHead = mNumBuffers-1;
103
104        /*
105         * This does not actually change the framebuffer format. It merely
106         * fakes this format to surfaceflinger so that when it creates
107         * framebuffer surfaces it will use this format. It's really a giant
108         * HACK to allow interworking with buggy gralloc+GPU driver
109         * implementations. You should *NEVER* need to set this for shipping
110         * devices.
111         */
112#ifdef FRAMEBUFFER_FORCE_FORMAT
113        *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
114#endif
115
116        for (i = 0; i < mNumBuffers; i++)
117        {
118                buffers[i] = new NativeBuffer(
119                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
120        }
121
122        for (i = 0; i < mNumBuffers; i++)
123        {
124                err = grDev->alloc(grDev,
125                        fbDev->width, fbDev->height, fbDev->format,
126                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
127
128                ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
129                        i, fbDev->width, fbDev->height, strerror(-err));
130
131                if (err)
132                {
133                        mNumBuffers = i;
134                        mNumFreeBuffers = i;
135                        mBufferHead = mNumBuffers-1;
136                        break;
137                }
138        }
139
140        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
141        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
142        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
143        const_cast<int&>(ANativeWindow::minSwapInterval) =
144            fbDev->minSwapInterval;
145        const_cast<int&>(ANativeWindow::maxSwapInterval) =
146            fbDev->maxSwapInterval;
147    } else {
148        ALOGE("Couldn't get gralloc module");
149    }
150
151    ANativeWindow::setSwapInterval = setSwapInterval;
152    ANativeWindow::dequeueBuffer = dequeueBuffer;
153    ANativeWindow::lockBuffer = lockBuffer;
154    ANativeWindow::queueBuffer = queueBuffer;
155    ANativeWindow::query = query;
156    ANativeWindow::perform = perform;
157    ANativeWindow::cancelBuffer = NULL;
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. }  
150void DisplayHardware::init(uint32_t dpy)
151{
152    mNativeWindow = new FramebufferNativeWindow();  //******
153    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
154    if (!fbDev) {
155        ALOGE("Display subsystem failed to initialize. check logs. exiting...");
156        exit(0);
157    }
158
159    int format;
160    ANativeWindow const * const window = mNativeWindow.get();
161    window->query(window, NATIVE_WINDOW_FORMAT, &format);
162    mDpiX = mNativeWindow->xdpi;
163    mDpiY = mNativeWindow->ydpi;
164    mRefreshRate = fbDev->fps;
....
}


而DisplayHardware的真正构造仅在Surfacelinger启动后readyToRun中,其余都是使用拷贝构造默认的Bitwise Copy,当然这仅仅是针对一块屏的情况,当前大屏主流。相关代码片段如下:

  1. 217status_t SurfaceFlinger::readyToRun()  
  2. 218{  
  3. 219    ALOGI(   "SurfaceFlinger's main thread ready to run. "  
  4. 220            "Initializing graphics H/W...");  
  5. 221  
  6. 222    // we only support one display currently  
  7. 223    int dpy = 0;  
  8. 224  
  9. 225    {  
  10. 226        // initialize the main display  
  11. 227        GraphicPlane& plane(graphicPlane(dpy));  
  12. 228        DisplayHardware* const hw = new DisplayHardware(this, dpy); //*******  
  13. 229        plane.setDisplayHardware(hw);  
  14. 230    }  
  15. 231  
  16. 232    // create the shared control-block  
  17. 233    mServerHeap = new MemoryHeapBase(4096,  
  18. 234            MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");  
  19. 235    ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");  
  20. 236  
  21. 237    mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());  
  22. 238    ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");  
  23. 239  
  24. 240    new(mServerCblk) surface_flinger_cblk_t;  
  25. 241  
  26. 242    // initialize primary screen  
  27. 243    // (other display should be initialized in the same manner, but  
  28. 244    // asynchronously, as they could come and go. None of this is supported  
  29. 245    // yet).  
  30. 246    const GraphicPlane& plane(graphicPlane(dpy));  
  31. 247    const DisplayHardware& hw = plane.displayHardware();  
  32. 248    const uint32_t w = hw.getWidth();  
  33. 249    const uint32_t h = hw.getHeight();  
  34. 250    const uint32_t f = hw.getFormat();  
  35. 251    hw.makeCurrent();  
  36. .....  
  37. }  
217status_t SurfaceFlinger::readyToRun()
218{
219    ALOGI(   "SurfaceFlinger's main thread ready to run. "
220            "Initializing graphics H/W...");
221
222    // we only support one display currently
223    int dpy = 0;
224
225    {
226        // initialize the main display
227        GraphicPlane& plane(graphicPlane(dpy));
228        DisplayHardware* const hw = new DisplayHardware(this, dpy); //*******
229        plane.setDisplayHardware(hw);
230    }
231
232    // create the shared control-block
233    mServerHeap = new MemoryHeapBase(4096,
234            MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
235    ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
236
237    mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
238    ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
239
240    new(mServerCblk) surface_flinger_cblk_t;
241
242    // initialize primary screen
243    // (other display should be initialized in the same manner, but
244    // asynchronously, as they could come and go. None of this is supported
245    // yet).
246    const GraphicPlane& plane(graphicPlane(dpy));
247    const DisplayHardware& hw = plane.displayHardware();
248    const uint32_t w = hw.getWidth();
249    const uint32_t h = hw.getHeight();
250    const uint32_t f = hw.getFormat();
251    hw.makeCurrent();
.....
}

 

fb 模块最重要的工作就是将应用程序指定的内容写入显存中,是通过函数 fb_post完成的,流程如下(msm8960代码大致如此,不过使用的是FBIOPUT_VSCREENINFO IOCTL_CODE):

  1. <span style="font-size:12px;">/* 将图形缓冲区buffer的内容渲染到帧缓冲区中去 */  
  2. static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)  
  3. {  
  4.     unsigned int phys;  
  5.     void* virt;  
  6.     int pitch;  
  7.     int format;  
  8.   
  9.     /* 首先验证参数handle指向的一块图形缓冲区的确是由Gralloc模块分配的 */  
  10.     if (private_handle_t::validate(buffer) < 0)  
  11.         return -EINVAL;  
  12.   
  13.     fb_context_t* ctx = (fb_context_t*)dev;  
  14.   
  15.     private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);  /* 图形缓冲区 */  
  16.     private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);    /* 帧缓冲区 */  
  17.   
  18.     if (m->currentBuffer) {  /* 当前正在渲染的图形缓冲区 */  
  19.         m->base.unlock(&m->base, m->currentBuffer);  
  20.         m->currentBuffer = 0;  
  21.     }  
  22.   
  23.     if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {  /* 如果图形缓冲区是在系统帧缓冲中分配的 */  
  24.         m->base.lock(&m->base, buffer,  /* 锁定图像缓冲区 */  
  25.                 private_module_t::PRIV_USAGE_LOCKED_FOR_POST,  
  26.                 0, 0, m->info.xres, m->info.yres, NULL);  
  27.   
  28.         const size_t offset = hnd->base - m->framebuffer->base; /* 计算图形缓冲区与帧缓冲的偏移 */  
  29.         /* 将作为参数的fb_var_screeninfo结构体的成员变量activate的值设置FB_ACTIVATE_VBL 
  30.          * 表示要等到下一个垂直同步事件出现时,再将当前要渲染的图形缓冲区的内容绘制出来 
  31.          * 这样做的目的是避免出现屏幕闪烁,即避免前后两个图形缓冲区的内容各有一部分同时出现屏幕中 */  
  32.         m->info.activate = FB_ACTIVATE_VBL;  
  33.         m->info.yoffset = offset / m->finfo.line_length;  /* 得到偏移的起始行 */  
  34.   
  35.         if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1) {  /* 刷新显示内容 */  
  36.             LOGE("FBIOPAN_DISPLAY failed");  
  37.             m->base.unlock(&m->base, buffer);   
  38.             return -errno;  
  39.         }  
  40.   
  41.         if (UNLIKELY(mDebugFps)) {  
  42.             debugShowFPS();  
  43.         }  
  44.   
  45.         m->currentBuffer = buffer;  /* 设置当前图形缓冲区 */  
  46.     return 0;  
  47. }</span>  
/* 将图形缓冲区buffer的内容渲染到帧缓冲区中去 */
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
	unsigned int phys;
	void* virt;
	int pitch;
	int format;

    /* 首先验证参数handle指向的一块图形缓冲区的确是由Gralloc模块分配的 */
    if (private_handle_t::validate(buffer) < 0)
        return -EINVAL;

    fb_context_t* ctx = (fb_context_t*)dev;

    private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);  /* 图形缓冲区 */
    private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);    /* 帧缓冲区 */

    if (m->currentBuffer) {  /* 当前正在渲染的图形缓冲区 */
        m->base.unlock(&m->base, m->currentBuffer);
        m->currentBuffer = 0;
    }

    if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {  /* 如果图形缓冲区是在系统帧缓冲中分配的 */
        m->base.lock(&m->base, buffer,  /* 锁定图像缓冲区 */
                private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
                0, 0, m->info.xres, m->info.yres, NULL);

        const size_t offset = hnd->base - m->framebuffer->base; /* 计算图形缓冲区与帧缓冲的偏移 */
        /* 将作为参数的fb_var_screeninfo结构体的成员变量activate的值设置FB_ACTIVATE_VBL
         * 表示要等到下一个垂直同步事件出现时,再将当前要渲染的图形缓冲区的内容绘制出来
         * 这样做的目的是避免出现屏幕闪烁,即避免前后两个图形缓冲区的内容各有一部分同时出现屏幕中 */
        m->info.activate = FB_ACTIVATE_VBL;
        m->info.yoffset = offset / m->finfo.line_length;  /* 得到偏移的起始行 */

        if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1) {  /* 刷新显示内容 */
            LOGE("FBIOPAN_DISPLAY failed");
            m->base.unlock(&m->base, buffer); 
            return -errno;
        }

        if (UNLIKELY(mDebugFps)) {
            debugShowFPS();
        }

        m->currentBuffer = buffer;  /* 设置当前图形缓冲区 */
    return 0;
}

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的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值