欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android8.0 帧缓冲硬件抽象层

程序员文章站 2024-03-07 08:40:38
...

之前用了一个月的时间去看Android对媒体系统,主要包括Audio,Media,Camera三个子系统;今天我们开始Android图形系统,图形系统在Android操作系统中的地位举足轻重,是用户最直接的交互界面,同时也是Android中最复杂的系统,近年来AR,VR,的发展使得图形系统变得越发复杂。我们将从图形系统的核心引擎SurfaceFlinger入手,一路往上到Framework层,从多个层次来看图形系统,但在此之前我们先得把与图形引擎相关的帧缓冲硬件抽象层理理清楚。

Android8.0 帧缓冲硬件抽象层

Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。最后,用户空间中的应用程序就通过fb设备来将已经准备好了的图形缓冲区渲染到帧缓冲区中去,即将图形缓冲区的内容绘制到显示屏中去。相应地,当用户空间中的应用程序不再需要使用一块图形缓冲区的时候,就可以通过gralloc设备来释放它,并且将它从地址空间中解除映射。

既然要剖析Gralloc模块,从Treble架构的视角去看那是最好不过了,我们来一探究竟。

1. Treble下的Gralloc

hardware\interfaces\graphics\allocator\2.0\default\Gralloc.cpp
直通模式下 ServiceManagment 通过 hw_get_module 获取gralloc模块结构体

IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
    const hw_module_t* module = nullptr;
    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); //熟悉的操作
    if (err) {
        ALOGE("failed to get gralloc module");
        return nullptr;
    }

    uint8_t major = (module->module_api_version >> 8) & 0xff;
    switch (major) {
        case 1:
            return new Gralloc1Allocator(module); 
        case 0:
            return new Gralloc0Allocator(module);//按API版本返回具体的Allocator
        default:
            ALOGE("unknown gralloc module major version %d", major);
            return nullptr;
    }
}

hardware\interfaces\graphics\allocator\2.0\default\Gralloc0Allocator.cpp
初始化Allocator时调用硬件抽象层的gralloc_open

Gralloc0Allocator::Gralloc0Allocator(const hw_module_t* module) {
    int result = gralloc_open(module, &mDevice); //打开gralloc
    ......
}

hardware\interfaces\graphics\allocator\2.0\default\Gralloc1Allocator.cpp

Gralloc1Allocator::Gralloc1Allocator(const hw_module_t* module)
    : mDevice(nullptr), mCapabilities(), mDispatch() {
    int result = gralloc1_open(module, &mDevice);  //打开gralloc1
    ......
    initCapabilities();
    initDispatch(); //比较重要
}

2. 硬件抽象层

hardware\libhardware\include\hardware\gralloc.h
通过hw_module_t结构体调用gralloc.cpp的gralloc_device_open函数

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

hardware\libhardware\modules\gralloc\gralloc.cpp
open函数通过gralloc_module_methods关联gralloc_device_open

static struct hw_module_methods_t gralloc_module_methods = {
        .open = gralloc_device_open
};

gralloc_module_methods 是在加载模块库时候由硬件抽象层通过HAL_MODULE_INFO_SYM关联的,同样被关联的还有gralloc_register_buffer, gralloc_unregister_buffer函数

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

那么gralloc_device_open函数又干了哪些事情,它调用的fb_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); //打卡FrameBuffer
    }
    return status;
}

hardware\libhardware\modules\gralloc\framebuffer.cpp
主要做了一些准备工作,绑定了一些方法,映射帧缓冲区,初始化了一些参数

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)) {
        /* initialize our state here */
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev)); //转换为上下文
        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; //提交数据
        dev->device.setUpdateRect = 0;

        private_module_t* m = (private_module_t*)module;
        status = mapFrameBuffer(m); //映射帧缓冲
        //初始化一些设备参数
        ......
        }
    }
    return status;
}

3. 缓冲区分配与映射

hardware\interfaces\graphics\allocator\2.0\default\Gralloc0Allocator.cpp
在Gralloc0Allocator中allocateOne调用了mDevice->alloc()函数,而在gralloc_device_open时已经将alloc绑定为gralloc_alloc函数

Error Gralloc0Allocator::allocateOne(const IMapper::BufferDescriptorInfo& info,
                                     buffer_handle_t* outBuffer,
                                     uint32_t* outStride) {
    if (info.layerCount > 1 || (info.usage >> 32) != 0) {
        return Error::BAD_VALUE;
    }

    buffer_handle_t buffer = nullptr;
    int stride = 0;
    int result = mDevice->alloc(mDevice, info.width, info.height,
                                static_cast<int>(info.format), info.usage,
                                &buffer, &stride);
    ......
    *outBuffer = buffer;
    *outStride = stride;

    return Error::NONE;
}
static int gralloc_alloc(alloc_device_t* dev,
        int width, int height, int format, int usage,
        buffer_handle_t* pHandle, int* pStride)
{
    ......
    int err;
    if (usage & GRALLOC_USAGE_HW_FB) {
        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); //使用FrameBuffer
    } else {
        err = gralloc_alloc_buffer(dev, size, usage, pHandle); //直接分配
    }

    if (err < 0) {
        return err;
    }

    *pStride = stride;
    return 0;
}
static int gralloc_alloc_framebuffer_locked(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);

    // allocate the framebuffer
    if (m->framebuffer == NULL) {
        // initialize the framebuffer, the framebuffer is mapped once
        // and forever.
        int err = mapFrameBufferLocked(m);
        if (err < 0) {
            return err;
        }
    }

    ......

    return 0;
}

hardware\libhardware\modules\gralloc\framebuffer.cpp
最终通过framebuffer分配缓冲,映射内存空间

int mapFrameBufferLocked(struct private_module_t* module)
{
    // already initialized...
    if (module->framebuffer) {
        return 0;
    }

    ......

    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;

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

    module->numBuffers = info.yres_virtual / info.yres;
    module->bufferMask = 0;

    void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (vaddr == MAP_FAILED) {
        ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
        return -errno;
    }
    module->framebuffer->base = intptr_t(vaddr);
    memset(vaddr, 0, fbSize);
    return 0;
}

hardware\libhardware\modules\gralloc\gralloc.cpp

static int gralloc_alloc_buffer(alloc_device_t* dev,
        size_t size, int /*usage*/, buffer_handle_t* pHandle)
{
    int err = 0;
    int fd = -1;

    size = roundUpToPageSize(size);

    fd = ashmem_create_region("gralloc-buffer", size);
    if (fd < 0) {
        ALOGE("couldn't create ashmem (%s)", strerror(-errno));
        err = -errno;
    }

    if (err == 0) {
        private_handle_t* hnd = new private_handle_t(fd, size, 0);
        gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
                dev->common.module);
        err = mapBuffer(module, hnd); //直接分配
        if (err == 0) {
            *pHandle = hnd;
        }
    }

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

    return err;
}

hardware\libhardware\modules\gralloc\mapper.cpp

int mapBuffer(gralloc_module_t const* module,
        private_handle_t* hnd)
{
    void* vaddr;
    return gralloc_map(module, hnd, &vaddr);
}

至此,整个帧缓冲硬件抽象层就清晰了,gralloc设备负责分配图形缓冲区,Gralloc模块负责注册图形缓冲区,而fb设备负责渲染图形缓冲区。主要流程: 加载Gralloc模块,打开Gralloc模块中的gralloc设备和fb设备,分配一个匹配屏幕大小的图形缓冲区,将分配好的图形缓冲区注册(映射)到当前进程的地址空间来,将要绘制的画面的内容写入到已经注册好的图形缓冲区中去,并且渲染(拷贝)到系统帧缓冲区中去。