GUI系统之SurfaceFlinger-HAL层

837 阅读4分钟

SurfaceFlinger是GUI系统的核心,本篇将以自底向上的方式对其展开介绍。

硬件层面

Linux 内核提供了统一的famebuffer显示驱动,设备节点/dev/graphics/fb* 或者 /dev/fb*,fb0是第一个显示屏。

HAL层面

HAL即硬件抽象层,Android的各个子系统通常不会直接使用内核驱动,而是由HAL层简介引用底层架构。Android的HAL层提供了Gralloc,包括了fb和gralloc两个设备。前者负责打开内核中的framebuffer,初始化配置;后者则管理帧缓冲去的分配和释放。

在HAL层中还有一个重要的模块 “Composer”,它为厂商自定制“UI合成”提供了接口。Composer的直接使用者是SurfaceFlinger中的HWComposer

Gralloc模块

下面我们就从HAL层来看看Gralloc的结构

hardware\libhardware\include\hardware\gralloc.h
typedef struct gralloc_module_t {
    struct hw_module_t common;//每个硬件模块对应的结构都需要hw_module_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);
    
        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);
      ……………
    void* reserved_proc[3];
} gralloc_module_t;

对于以上的结构体需要注意的是: 1.每一个硬件都有其对应的模块结构,并且该结构的第一个成员必须为hw_module_t结构,该结构是HAL层对硬件的统一抽象。所以每一个硬件模块都要对应一个hw_module_t结构,并且名称必须为HAL_MODULE_INFO_SYM。

hardware\libhardware\include\hardware\hardware.h
typedef struct hw_module_t {
    uint32_t tag;
    uint16_t module_api_version;//version_major
    uint16_t hal_api_version;//version_minor
    const char *id;
    const char *name;
    const char *author;
    struct hw_module_methods_t* methods;

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

hw_module_t结构用来描述硬件模块的基本信息,如当前的版本,模块Id以及硬件模块对应的打开方法。

Gralloc模块负责管理gralloc设备和fb设备,它是处于HAL层的,向上提供了这个两个设备的功能。其中最主要的两个接口分别为gralloc_device_open和gralloc_alloc。 我们先看gralloc_device_open,这个方法负责打开gralloc或者fb设备的。

//gralloc模块的打开设备方法
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)) {//打开GPU
        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 {//打开fb设备
        status = fb_device_open(module, name, device);
    }
    return status;
}

参数name指定了要打开的模块,Name为GRALLOC_HARDWARE_GPU0说明打开的是GPU,否则打开fb设备。

//对外的分配缓冲区的方法
static int gralloc_alloc(alloc_device_t* dev,
        int width, int height, int format, int usage,
        buffer_handle_t* pHandle, int* pStride)
{
    if (!pHandle || !pStride)
        return -EINVAL;

    int bytesPerPixel = 0;
    switch (format) {//指定的缓冲区像素格式
        case HAL_PIXEL_FORMAT_RGBA_FP16:
            bytesPerPixel = 8;
            break;
        case HAL_PIXEL_FORMAT_RGBA_8888:
        case HAL_PIXEL_FORMAT_RGBX_8888:
        case HAL_PIXEL_FORMAT_BGRA_8888:
            bytesPerPixel = 4;
            break;
        case HAL_PIXEL_FORMAT_RGB_888:
            bytesPerPixel = 3;
            break;
        case HAL_PIXEL_FORMAT_RGB_565:
        case HAL_PIXEL_FORMAT_RAW16:
            bytesPerPixel = 2;
            break;
        default:
            return -EINVAL;
    }

    const size_t tileWidth = 2;
    const size_t tileHeight = 2;

    size_t stride = align(width, tileWidth);
    size_t size = align(height, tileHeight) * stride * bytesPerPixel + 4;

    int err;
    if (usage & GRALLOC_USAGE_HW_FB) {//在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;
}

另一个方法gralloc_alloc 负责为上层分配缓冲区,注意这里的缓冲区既可以是内存缓冲区,也可以是fb的帧缓冲区。这分别是通过gralloc_alloc_buffer 和 gralloc_alloc_framebuffer来实现的。在内存中创建缓冲区是基于asheme的方式来创建一块匿名共享内存来作为缓冲区的,而如果是从fb中分配则只需要将fb的帧缓冲区映射到当前进程来即可。具体可以参见famebuffer.cpp中的mapFrameBufferLocked方法。

关于fb设备 其最重要的功能是将上层缓冲区的内容通过交换显示在屏幕上,这个功能是通过fb_post来实现的,在这之前我们看看如何打开fb设备

//打开fb设备 这个方法通过HAL层的Gralloc模块提供给上层接口
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设备
        /* initialize our state here */
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));//分配fb_context_t 结构
        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 = fb_close;
        dev->device.setSwapInterval = fb_setSwapInterval;
        dev->device.post   = fb_post;//设置设备post回调接口,这个接口将缓冲区的内容显示在屏幕上
        dev->device.setUpdateRect = 0;

        private_module_t* m = (private_module_t*)module;
        status = mapFrameBuffer(m);//对fb设备进行映射 其实是调用mapFrameBufferLocked
        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;
}
//将缓冲区的内容显示在屏幕上
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
    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 (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { //如果缓冲区是来自于fb设备的帧缓冲区
        const size_t offset = hnd->base - m->framebuffer->base;
        m->info.activate = FB_ACTIVATE_VBL;
        m->info.yoffset = offset / m->finfo.line_length;//直接调整y方向的分辨率偏移既可,不需要做任何拷贝
        if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {//通过FBIOPUT_VSCREENINFO命令
            ALOGE("FBIOPUT_VSCREENINFO failed");                                       //显示在屏幕上
            m->base.unlock(&m->base, buffer); 
            return -errno;
        }
        m->currentBuffer = buffer;
        
    } else { //否则是来自内存的缓冲区
        // If we can't do the page_flip, just copy the buffer to the front 
        // FIXME: use copybit HAL instead of memcpy
        
        void* fb_vaddr;
        void* buffer_vaddr;
        
        m->base.lock(&m->base, m->framebuffer, 
                GRALLOC_USAGE_SW_WRITE_RARELY, 
                0, 0, m->info.xres, m->info.yres,
                &fb_vaddr);//对帧缓冲区加锁

        m->base.lock(&m->base, buffer, 
                GRALLOC_USAGE_SW_READ_RARELY, 
                0, 0, m->info.xres, m->info.yres,
                &buffer_vaddr);//对内存缓冲区加锁

        memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);//需要将内存的缓冲区拷贝到fb的帧                              缓冲中
        
        m->base.unlock(&m->base, buffer); 
        m->base.unlock(&m->base, m->framebuffer); 
    }
    return 0;
}

好了,对于HAL层的模块分析就到这里了,下篇我们介绍下VSYNC信号相关的内容。