Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

【图形图像】Android SurfaceFlinger之Gralloc

$
0
0

1、SurfaceFlinger模块

Android中SurfaceFlinger与其它模块的关系图如下所示:

这里写图片描述

上图中,最底层的是Linux内核提供的framebuffer显示驱动,设备节点为/dev/graphics/fb*或/dev/fb*,其中fb0表示第一个monitor。HAL层提供了Gralloc和Composer,其中Gralloc包括fb和gralloc两个设备,fb负责打开内核中的framebuffer、初始化配置,gralloc管理帧缓冲区的分配和释放,而Composer为UI合成提供接口,直接使用者是SurfaceFlinger中的HWComposer,HWComposer管理HAL层的Composer并负责VSync信号的产生和控制。FramebufferNativeWindow是OpengGL ES在Android平台上本地化的中介之一,EGL为OpengGL ES配置本地窗口,OpengGL ES支持软件实现libagl和硬件实现libhgl,DisplayDevice用于构建OpenGL ES运行环境。

2、HAL与Gralloc

HAL是位于Linux Kernel之上的硬件抽象层,旨在降低Android系统与硬件的耦合性,提供了统一的硬件无关的抽象接口。Android的各子系统通常不会直接使用内核驱动,而是由HAL层来间接引用底层架构,显示系统也同样如此,它借助于HAL层来操作帧缓冲区,而完成这一中介任务的就是Gralloc,Android中源码位置在hardware/libhardware/modules/gralloc/,包括三个文件,framebuffer.cpp、gralloc.cpp和mapper.cpp。

为了做到与硬件无关的抽象配置,在hardware/libhardware/include/hardware.h中定义了三个重要的数据结构,如下所示:

struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;

其中,hw_module_t有如下要求:

/**
 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct hw_module_t {
    uint32_t tag;
    uint16_t module_api_version;
    uint16_t hal_api_version;
    const char *id;
    const char *name;
    const char *author;
    struct hw_module_methods_t* methods;
    void* dso;
#ifdef __LP64__
    uint64_t reserved[32-7];
#else
    uint32_t reserved[32-7];
#endif
} hw_module_t;

也就是说,每个硬件模块都要有一个名为HAL_MODULE_INFO_SYM的变量,这个变量的数据结构的第一个字段类型为hw_module_t,犹如面向对象编程语言如C++的继承机制一样,以实现接口抽象。下面看一下Gralloc是如何实现的。

struct private_module_t HAL_MODULE_INFO_SYM = {
    .base = {
        .common = {
            .tag = HARDWARE_MODULE_TAG,
            .version_major = 1,
            .version_minor = 0,
            .id = GRALLOC_HARDWARE_MODULE_ID,
            .name = "Graphics Memory Allocator Module",
            .author = "The Android Open Source Project",
            .methods = &gralloc_module_methods
        },
        .registerBuffer = gralloc_register_buffer,
        .unregisterBuffer = gralloc_unregister_buffer,
        .lock = gralloc_lock,
        .unlock = gralloc_unlock,
    },
    .framebuffer = 0,
    .flags = 0,
    .numBuffers = 0,
    .bufferMask = 0,
    .lock = PTHREAD_MUTEX_INITIALIZER,
    .currentBuffer = 0,
};

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;
    buffer_handle_t currentBuffer;
    int pmem_master;
    void* pmem_master_base;

    struct fb_var_screeninfo info;
    struct fb_fix_screeninfo finfo;
    float xdpi;
    float ydpi;
    float fps;
};

typedef struct gralloc_module_t {
    struct hw_module_t common;

    int (*registerBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
    int (*unregisterBuffer)(struct gralloc_module_t const* module,
            buffer_handle_t handle);
    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);
    /* reserved for future use */
    int (*perform)(struct gralloc_module_t const* module,
            int operation, ... );
    int (*lock_ycbcr)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            struct android_ycbcr *ycbcr);
    int (*lockAsync)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            void** vaddr, int fenceFd);
    int (*unlockAsync)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int* fenceFd);
    int (*lockAsync_ycbcr)(struct gralloc_module_t const* module,
            buffer_handle_t handle, int usage,
            int l, int t, int w, int h,
            struct android_ycbcr *ycbcr, int fenceFd);
    void* reserved_proc[3];
} gralloc_module_t;

可以看出,HAL_MODULE_INFO_SYM通过private_module_t、gralloc_module_t最终包含了hw_module_t。

3、Gralloc模块加载过程

Gralloc模块加载通过hardware/libhardware/include/hardware.h声明的如下函数完成。

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

#define GRALLOC_HARDWARE_MODULE_ID "gralloc"

通过hw_get_module加载Gralloc时,参数id为GRALLOC_HARDWARE_MODULE_ID,随后会走到如下hw_get_module_by_class函数,其中参数inst为NULL。

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};


    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    return load(class_id, path, module);
}

hw_get_module_by_class的实现逻辑是先获取ro.hardware.graphic属性,属性获取成功后就到指定的目录检查gralloc库是否存在,对于64位的机器来说在如下几个目录检查:

#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"

库的名字为gralloc..so。如果ro.hardware.graphic属性获取失败或者在指定的目录找不到gralloc库时就逐个获取如下几个属性:

"ro.hardware"
"ro.product.board"
"ro.board.platform"
"ro.arch"

属性获取成功后,再到上面提到的几个目录查找gralloc..so,如果还是找不到,最后则查找Android默认的库gralloc.default.so。上面几个步骤中一旦找到了gralloc库,就立即通过dlopen函数打开,否则gralloc模块加载失败。dlopen成功后,通过dlsym获取HAL_MODULE_INFO_SYM_AS_STR即名为HMI的函数地址,dlsym成功后再判断其模块id是否为gralloc,如果是的话,预示着gralloc模块加载成功,最后将dlopen结果保存到hw_module_t的dso成员,即一开始调用hw_get_module函数的参数module中,这是个二级指针,至此,Gralloc模块加载完成。总结一下,Gralloc模块的加载就是在指定的几个目录中逐个查找gralloc库,因为gralloc库有不同的表示形式,gralloc库存在的话进而使用dlopen、dlsym进行处理。

4、Gralloc接口

从上面的数据结构中可以看出,gralloc_module_t继承了hw_module_t,进而包含了如下hw_module_methods_t:

typedef struct hw_module_methods_t {
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;

这是一个重要的接口,目前只是一个函数指针open,用来打开某个特定的设备文件。既然有open,那么必然有close,在如下的hw_device_t中。

/**
 * Every device data structure must begin with hw_device_t
 * followed by module specific public methods and attributes.
 */
typedef struct hw_device_t {
    uint32_t tag;
    uint32_t version;
#ifdef __LP64__
    uint64_t reserved[12];
#else
    uint32_t reserved[12];
#endif

    int (*close)(struct hw_device_t* device);

} hw_device_t;

上述open用来打开设备gpu0和fb0,两者用法类似,如下函数所示:

// gralloc.h

#define GRALLOC_HARDWARE_GPU0 "gpu0"

static inline int gralloc_open(const struct hw_module_t* module, 
        struct alloc_device_t** device) {
    return module->methods->open(module, 
            GRALLOC_HARDWARE_GPU0, TO_HW_DEVICE_T_OPEN(device));
}

static inline int gralloc_close(struct alloc_device_t* device) {
    return device->common.close(&device->common);
}

// fb.h

#define GRALLOC_HARDWARE_FB0 "fb0"

static inline int framebuffer_open(const struct hw_module_t* module,
        struct framebuffer_device_t** device) {
    return module->methods->open(module,
            GRALLOC_HARDWARE_FB0, TO_HW_DEVICE_T_OPEN(device));
}

static inline int framebuffer_close(struct framebuffer_device_t* device) {
    return device->common.close(&device->common);
}

上面提到了每一个HAL模块如这里的Gralloc都应该有一个HAL_MODULE_INFO_SYM,其中指定了open函数指针为gralloc_device_open函数,具体如下:

int gralloc_device_open(const hw_module_t* module, const char* name,
        hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
        gralloc_context_t *dev;
        dev = (gralloc_context_t*)malloc(sizeof(*dev));

        /* initialize our state here */
        memset(dev, 0, sizeof(*dev));

        /* initialize the procs */
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = gralloc_close;

        dev->device.alloc   = gralloc_alloc;
        dev->device.free    = gralloc_free;

        *device = &dev->device.common;
        status = 0;
    } else {
        status = fb_device_open(module, name, device);
    }
    return status;
}

从上面的gralloc_device_open可以看出,会判断打开gpu还是fb,下面分开介绍。

5、device-gpu

gpu相关device的数据结构如下:

struct gralloc_context_t {
    alloc_device_t  device;
};

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

    void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len);

    void* reserved_proc[7];
} alloc_device_t;

在gralloc_device_open中,malloc一个gralloc_context_t,然后指定了对应的close、alloc和free接口,其中close用于free刚刚malloc的gralloc_context_t,alloc和free用于管理帧缓冲区,涉及字节对齐(包括页对齐)、共享内存、设备管理、内存映射等,以及一个新的数据结构private_handle_t(管理文件描述符),后面着重说明。

6、device-fb

framebuffer相关device的数据结构如下:

struct fb_context_t {
    framebuffer_device_t  device;
};

typedef struct framebuffer_device_t {
    struct hw_device_t common;

    const uint32_t  flags;
    const uint32_t  width;
    const uint32_t  height;
    const int       stride;
    const int       format;
    const float     xdpi;
    const float     ydpi;
    const float     fps;
    const int       minSwapInterval;
    const int       maxSwapInterval;
    const int       numFramebuffers;
    int reserved[7];

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


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

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

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

    void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);

    int (*enableScreen)(struct framebuffer_device_t* dev, int enable);

    void* reserved_proc[6];

} framebuffer_device_t;

fb_device_open函数如下:

int fb_device_open(hw_module_t const* module, const char* name,
        hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
        memset(dev, 0, sizeof(*dev));

        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = fb_close;
        dev->device.setSwapInterval = fb_setSwapInterval;
        dev->device.post            = fb_post;
        dev->device.setUpdateRect = 0;

        private_module_t* m = (private_module_t*)module;
        status = mapFrameBuffer(m);
        if (status >= 0) {
            int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
            int format = (m->info.bits_per_pixel == 32)
                         ? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888)
                         : HAL_PIXEL_FORMAT_RGB_565;
            const_cast<uint32_t&>(dev->device.flags) = 0;
            const_cast<uint32_t&>(dev->device.width) = m->info.xres;
            const_cast<uint32_t&>(dev->device.height) = m->info.yres;
            const_cast<int&>(dev->device.stride) = stride;
            const_cast<int&>(dev->device.format) = format;
            const_cast<float&>(dev->device.xdpi) = m->xdpi;
            const_cast<float&>(dev->device.ydpi) = m->ydpi;
            const_cast<float&>(dev->device.fps) = m->fps;
            const_cast<int&>(dev->device.minSwapInterval) = 1;
            const_cast<int&>(dev->device.maxSwapInterval) = 1;
            *device = &dev->device.common;
        }
    }
    return status;
}

可以看出,fb与gpu设备的处理类似,重要的一步在与mapFrameBuffer,此时有posix mutex作同步保护。这一步才是真正的open操作,首先尝试打开/dev/graphics/fb0、/dev/fb0,成功则继续,随后是一些ioctl操作,用于获取屏幕信息,并通过这些屏幕信息算出fb的长度,最后mmap映射到刚打开的fb0设备文件,长度为刚算出的fb长度。在打开gpu0时,可以像fb0一样分配framebuffer,也可以是普通的buffer,这个普通的buffer映射的为共享内存区,即文件描述符通过ashmem_create_region函数(属于Android的libcutils库)创建。

作者:iEearth 发表于2017/2/23 20:50:33 原文链接
阅读:143 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>