Android Gralloc模块分析--深入分析

来源:互联网 发布:json字符串中url编码 编辑:程序博客网 时间:2024/06/05 16:59

前一篇的文章Android Gralloc模块分析》从功能的角度分析了Gralloc模块,基本掌握了Gralloc的总体结构,但是具体函数还有待进一步学习与分析。它们包括:

      

分别对应gralloc.cpp、framebuffer.cpp、mapper.cpp

这里的组织感觉不太合理,应该改成:gralloc_module.cpp跟映射相关、alloc_device.cpp跟分配图形缓冲区相关、framebuffer_device.cpp跟渲染相关。今天看了瑞星微的gralloc代码,组织得就很好,逻辑性强。

回顾

        上一篇文章提到,模块在被框架层加载后,就导出了HMI符号地址对应的hw_module_t结构。实际上导出了

        gralloc_device_open方法

        gralloc_register_buffer方法

        其中后者用来将图形缓冲区映射进程地址空间中;而前者用来打开两个设备,这两个设备分别是alloc_device_t和framebuffer_device_t,它们返回了主要函数有:

        gralloc_alloc方法

         fb_post方法

        上面两种方法,分别用来分配图形缓冲区,渲染帧缓冲区。本文下面的内容具体分析这些函数及相关的函数。


gralloc设备                                                                             gralloc.cpp
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <limits.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <pthread.h>#include <stdlib.h>#include <string.h>#include <sys/mman.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>#include <cutils/ashmem.h>#include <cutils/log.h>#include <cutils/atomic.h>#include <hardware/hardware.h>#include <hardware/gralloc.h>#include "gralloc_priv.h"#include "gr.h"/*****************************************************************************/struct gralloc_context_t {    alloc_device_t  device;    /* our private data here */};static int gralloc_alloc_buffer(alloc_device_t* dev,        size_t size, int usage, buffer_handle_t* pHandle);/*****************************************************************************/int fb_device_open(const hw_module_t* module, const char* name,        hw_device_t** device);static int gralloc_device_open(const hw_module_t* module, const char* name,        hw_device_t** device);extern int gralloc_lock(gralloc_module_t const* module,        buffer_handle_t handle, int usage,        int l, int t, int w, int h,        void** vaddr);extern int gralloc_unlock(gralloc_module_t const* module,         buffer_handle_t handle);extern int gralloc_register_buffer(gralloc_module_t const* module,        buffer_handle_t handle);extern int gralloc_unregister_buffer(gralloc_module_t const* module,        buffer_handle_t handle);/*****************************************************************************///模块被加载后,会执行的open方法,用来打开设备static struct hw_module_methods_t gralloc_module_methods = {        open: gralloc_device_open};// 导出符号HMI,是HAL框架编程规范定义的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,};/*****************************************************************************///帧缓冲区锁定后的操作,在帧缓冲区找一个空闲的图形缓冲区,记录到private_handle_t结构中并返回// dev :gralloc设备// size:整个图像所占用的字节数// usage:图形缓冲区位置标志位:fb、内存// pHandle: 图形缓冲区描述符static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,        size_t size, int usage, buffer_handle_t* pHandle){//将至类型转化,hw_module_t转化为private_module_t    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;        }    }//得到帧缓冲区使用情况    const uint32_t bufferMask = m->bufferMask;//得到帧缓冲区划分为多少个图形缓冲区使用    const uint32_t numBuffers = m->numBuffers;//设备显示器显示一屏图形所占用的内存大小    const size_t bufferSize = m->finfo.line_length * m->info.yres;    if (numBuffers == 1) {        // If we have only one buffer, we never use page-flipping. Instead,        // we return a regular buffer which will be memcpy'ed to the main        // screen when post is called.//不能再帧缓冲区中分配,就在内存中分配图形缓冲区        int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;        return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);    }//系统帧缓冲区中的图形缓冲区都被分配出去了    if (bufferMask >= ((1LU<<numBuffers)-1)) {        // We ran out of buffers.        return -ENOMEM;    }//指向系统缓冲区的基址    // create a "fake" handles for it    intptr_t vaddr = intptr_t(m->framebuffer->base);//创建一个private_handle_t来描述一个将要分配出去的图形缓冲区    private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,            private_handle_t::PRIV_FLAGS_FRAMEBUFFER);//找帧缓冲区中一个空闲的图形缓冲区    // find a free slot    for (uint32_t i=0 ; i<numBuffers ; i++) {        if ((bufferMask & (1LU<<i)) == 0) {            m->bufferMask |= (1LU<<i);            break;        }//每次查找偏移一个图形缓冲区的大小        vaddr += bufferSize;    }    //分配出去的图形缓冲区的基地址保存在private_handle_t的base变量中    hnd->base = vaddr;//相对于帧缓冲区的基地址偏移保存在private_handle_t的offset变量中    hnd->offset = vaddr - intptr_t(m->framebuffer->base);//返回private_handle_t这个图形缓冲区描述符    *pHandle = hnd;    return 0;}/*****************************************************************************///1.在帧缓冲区中分配图形缓冲区// dev :gralloc设备// size:整个图像所占用的字节数// usage:图形缓冲区位置标志位:fb、内存// pHandle: 图形缓冲区描述符static int gralloc_alloc_framebuffer(alloc_device_t* dev,        size_t size, int usage, buffer_handle_t* pHandle){//将至类型转化,hw_module_t转化为private_module_t    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;}/*****************************************************************************///2.在内存中分配图形缓冲区// dev :gralloc设备// size:整个图像所占用的字节数// usage:图形缓冲区位置标志位:fb、内存// pHandle: 图形缓冲区描述符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;    }//创建成功后,分配一个private_handle_t用来记录图形缓冲区,并返回给调用者    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;}/*****************************************************************************///用来分配图形缓冲区// int w : 图形缓冲区所保存图像的宽度,即一行多少个像素点// int h : 图形缓冲区所保存图像的高度,即一共有多少行// format: 表示图形的格式// usage : 标志位,GRALLOC_USAGE_HW_FB值表示在帧缓冲区中分配图形缓冲区// pHandle: 图形缓冲区句柄,用来描述一个图形缓冲区// pStride: 用来返回一行的像素点个数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:        case HAL_PIXEL_FORMAT_RAW_SENSOR:            bpp = 2;            break;        default:            return -EINVAL;    }//将一行所占的字节数对齐到4个字节,例如:2013对齐到四个字节会变为2016    size_t bpr = (w*bpp + (align-1)) & ~(align-1);//对齐后乘以高度,表示整个图像所占的字节数    size = bpr * h;//stride表示一行的像素点个数    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;}/*****************************************************************************///用来释放图形缓冲区static int gralloc_free(alloc_device_t* dev,        buffer_handle_t handle){    if (private_handle_t::validate(handle) < 0)        return -EINVAL;    private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);//图形缓冲区在帧缓冲区分配    if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {        // free this buffer        private_module_t* m = reinterpret_cast<private_module_t*>(                dev->common.module);//计算该图形缓冲区的大小        const size_t bufferSize = m->finfo.line_length * m->info.yres;        int index = (hnd->base - m->framebuffer->base) / bufferSize;//图形缓冲区使用情况记录到buffer屏蔽位中        m->bufferMask &= ~(1<<index);     } else { //图形缓冲区是匿名内存        gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(                dev->common.module);//在mapper.cpp中实现的        terminateBuffer(module, const_cast<private_handle_t*>(hnd));    }    close(hnd->fd);    delete hnd;    return 0;}/*****************************************************************************/static int gralloc_close(struct hw_device_t *dev){    gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev);    if (ctx) {        /* TODO: keep a list of all buffer_handle_t created, and free them         * all here.         */        free(ctx);    }    return 0;}//模块的入口函数,用来打开gralloc设备、fb设备int gralloc_device_open(const hw_module_t* module, const char* name,        hw_device_t** device){    int status = -EINVAL;//1. 打开gralloc设备    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {        gralloc_context_t *dev;//对gralloc设备的封装结构        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;//gralloc封装的主要方法gralloc_alloc,用来分配图形缓冲区        dev->device.alloc   = gralloc_alloc;        dev->device.free    = gralloc_free;//设备指针返回给框架层,即封装方法返回给框架层        *device = &dev->device.common;        status = 0;    } else {//2. 打开fb设备        status = fb_device_open(module, name, device);    }    return status;}

fb设备

/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <sys/mman.h>#include <dlfcn.h>#include <cutils/ashmem.h>#include <cutils/log.h>#include <hardware/hardware.h>#include <hardware/gralloc.h>#include <fcntl.h>#include <errno.h>#include <sys/ioctl.h>#include <string.h>#include <stdlib.h>#include <cutils/log.h>#include <cutils/atomic.h>#if HAVE_ANDROID_OS#include <linux/fb.h>#endif#include "gralloc_priv.h"#include "gr.h"/*****************************************************************************/// numbers of buffers for page flipping#define NUM_BUFFERS 2enum {    PAGE_FLIP = 0x00000001,    LOCKED = 0x00000002};struct fb_context_t {    framebuffer_device_t  device;};/*****************************************************************************///检查两个图形缓冲区渲染到帧缓冲区的间隔时间是否合法static int fb_setSwapInterval(struct framebuffer_device_t* dev,            int interval){    fb_context_t* ctx = (fb_context_t*)dev;    if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)        return -EINVAL;    // FIXME: implement fb_setSwapInterval    return 0;}//设置可以更新的区域,放在fix_var_screeninfo的保留字段当中static int fb_setUpdateRect(struct framebuffer_device_t* dev,        int l, int t, int w, int h){    if (((w|h) <= 0) || ((l|t)<0))        return -EINVAL;            fb_context_t* ctx = (fb_context_t*)dev;    private_module_t* m = reinterpret_cast<private_module_t*>(            dev->common.module);    m->info.reserved[0] = 0x54445055; // "UPDT";    m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);    m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);    return 0;}//用来渲染图形缓冲区数据到系统缓冲区// dev :fb设备// buffer:图形缓冲区描述符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) {//图形缓冲区在帧缓冲区中,是不需要拷贝的,但是需要告诉帧缓冲区设备,这个图形缓冲区是要输出的图形缓冲区        const size_t offset = hnd->base - m->framebuffer->base;//表示下一个垂直同步事件出现时,才将要输出的图形缓冲区绘制出来。这样避免了闪烁        m->info.activate = FB_ACTIVATE_VBL;        m->info.yoffset = offset / m->finfo.line_length;//用哪一个图形缓冲区,不用设置成员变量xoffset的值是因为所有的图形缓冲区的宽度是相等的//根据上面两个参数,设置帧缓冲区中绘制的图形缓冲区        if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {//设置输出缓冲区            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);//参数1:图形缓冲区的起始地址   参数2:帧缓冲区的起始地址    参数3:一帧图形的大小(字节)        memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);        //解锁操作        m->base.unlock(&m->base, buffer);         m->base.unlock(&m->base, m->framebuffer);     }        return 0;}/*疑问: 这里为什么没有指定yoffset来指定系统缓冲区使用哪一个图形缓冲区呢。解答: 原来这里有个模式问题。      1.当虚拟屏幕的图形缓冲区只有一个时,是不支持PAGE_FLIP的,    这时分配的图形缓冲区必然在内存中,而帧缓冲区中输出的只有一个图形缓冲区  2.当虚拟屏幕的图形缓冲区有两个或以上是,才支持PAGE_FLIP,    这是分配的图形缓冲区就在帧缓冲区中,这样帧缓冲区才有选择哪一个输出的问题*//*****************************************************************************///获取帧缓冲区信息,映射到当前进程的虚拟地址空间中int mapFrameBufferLocked(struct private_module_t* module){//已经初始化完成    // already initialized...    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;//通过ioctl获取fb_fix_screeninfo信息    struct fb_fix_screeninfo finfo;    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)        return -errno;//通过ioctl获取fb_var_screeninfo信息    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;    /*     * Request NUM_BUFFERS screens (at lest 2 for page flipping)     *///NUM_BUFFERS = 2,虚拟屏容纳两个可见屏,虚拟和可见的宽度值不变,高度前者是后者的整数倍    info.yres_virtual = info.yres * NUM_BUFFERS;//设置虚拟显示屏和像素格式    uint32_t flags = PAGE_FLIP;    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {        info.yres_virtual = info.yres;        flags &= ~PAGE_FLIP;        ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");    }//若设置完毕后,若虚拟屏的高度小于可见屏的2倍,那么说明帧缓冲区不支持双图形缓冲区    if (info.yres_virtual < info.yres * 2) {        // we need at least 2 for page-flipping        info.yres_virtual = info.yres;        flags &= ~PAGE_FLIP;        ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",                info.yres_virtual, info.yres*2);    }//设置成功后再次或者fb_var_screen信息    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)        return -errno;//计算刷新频率,先计算扫描一帧图形需要的时间//每个像素点扫描的时间为pixclock//一共有 ( info.upper_margin + info.lower_margin + info.yres ) * ( info.left_margin  + info.right_margin + info.xres ) 个像素点    uint64_t  refreshQuotient =    (            uint64_t( info.upper_margin + info.lower_margin + info.yres )            * ( info.left_margin  + info.right_margin + info.xres )            * info.pixclock    );    //求倒数得到1s钟能刷新的次数    /* Beware, info.pixclock might be 0 under emulation, so avoid a     * division-by-0 here (SIGFPE on ARM) */    int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;//默认60HZ    if (refreshRate == 0) {        // bleagh, bad info from the driver        refreshRate = 60*1000;  // 60 Hz    }//dpi默认 160    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;    ALOGI(   "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    );    ALOGI(   "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);//分配描述符并记录到模块中,private_handle_t中的framebuffer结构用来描述帧缓冲区    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;    }//private_handle_t中的framebuffer结构中记录帧缓冲区的基址    module->framebuffer->base = intptr_t(vaddr);    memset(vaddr, 0, fbSize);    return 0;}static int mapFrameBuffer(struct private_module_t* module){//针对多线程并发问题加锁    pthread_mutex_lock(&module->lock);    int err = mapFrameBufferLocked(module);    pthread_mutex_unlock(&module->lock);    return err;}/*****************************************************************************/static int fb_close(struct hw_device_t *dev){    fb_context_t* ctx = (fb_context_t*)dev;    if (ctx) {        free(ctx);    }    return 0;}//fb设备的打开函数//module : 用来描述模块的//name   : 打开哪一个fb设备文件//device : 用来描述设备的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设备的抽象封装结构        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;    //获取帧缓冲区信息,并保存到m中        private_module_t* m = (private_module_t*)module;        status = mapFrameBuffer(m);//根据帧缓冲区信息来初始化alloc_device_t相关的结构        if (status >= 0) {            int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);            int format = (m->info.bits_per_pixel == 32)                         ? 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;}


gralloc模块

/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <limits.h>#include <errno.h>#include <pthread.h>#include <unistd.h>#include <string.h>#include <sys/mman.h>#include <sys/stat.h>#include <sys/types.h>#include <cutils/log.h>#include <cutils/atomic.h>#include <hardware/hardware.h>#include <hardware/gralloc.h>#include "gralloc_priv.h"/* desktop Linux needs a little help with gettid() */#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)#define __KERNEL__# include <linux/unistd.h>pid_t gettid() { return syscall(__NR_gettid);}#undef __KERNEL__#endif/*****************************************************************************///图形缓冲区的映射static int gralloc_map(gralloc_module_t const* module,        buffer_handle_t handle,        void** vaddr){    private_handle_t* hnd = (private_handle_t*)handle;//在内存中分配的话,需要映射到进程虚拟地址空间中,并需要计算图形缓冲区的在匿名内存中的基地址再返回    if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {        size_t size = hnd->size;        void* mappedAddress = mmap(0, size,                PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);        if (mappedAddress == MAP_FAILED) {            ALOGE("Could not mmap %s", strerror(errno));            return -errno;        }        hnd->base = intptr_t(mappedAddress) + hnd->offset;        //ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",        //        hnd->fd, hnd->offset, hnd->size, mappedAddress);    }//在帧缓冲区中分配的话,是不需要计算的,因为在初始化帧缓冲区时已经做了    *vaddr = (void*)hnd->base;    return 0;}static int gralloc_unmap(gralloc_module_t const* module,        buffer_handle_t handle){    private_handle_t* hnd = (private_handle_t*)handle;//内存中    if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {        void* base = (void*)hnd->base;        size_t size = hnd->size;        //ALOGD("unmapping from %p, size=%d", base, size);//注销图形缓冲区,与上面函数执行过程相反        if (munmap(base, size) < 0) {            ALOGE("Could not unmap %s", strerror(errno));        }    }//帧缓冲区中    hnd->base = 0;    return 0;}/*****************************************************************************/static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; /*****************************************************************************/// 关键调用gralloc_mapint gralloc_register_buffer(gralloc_module_t const* module,        buffer_handle_t handle){    if (private_handle_t::validate(handle) < 0)        return -EINVAL;    // if this handle was created in this process, then we keep it as is.    int err = 0;    private_handle_t* hnd = (private_handle_t*)handle;    if (hnd->pid != getpid()) {        void *vaddr;        err = gralloc_map(module, handle, &vaddr);    }    return err;}// 关键调用gralloc_unmapint gralloc_unregister_buffer(gralloc_module_t const* module,        buffer_handle_t handle){    if (private_handle_t::validate(handle) < 0)        return -EINVAL;    // never unmap buffers that were created in this process    private_handle_t* hnd = (private_handle_t*)handle;    if (hnd->pid != getpid()) {        if (hnd->base) {            gralloc_unmap(module, handle);        }    }    return 0;}int mapBuffer(gralloc_module_t const* module,        private_handle_t* hnd){    void* vaddr;    return gralloc_map(module, hnd, &vaddr);}int terminateBuffer(gralloc_module_t const* module,        private_handle_t* hnd){    if (hnd->base) {        // this buffer was mapped, unmap it now        gralloc_unmap(module, hnd);    }    return 0;}//图形缓冲区的锁定int gralloc_lock(gralloc_module_t const* module,        buffer_handle_t handle, int usage,        int l, int t, int w, int h,        void** vaddr){    // this is called when a buffer is being locked for software    // access. in thin implementation we have nothing to do since    // not synchronization with the h/w is needed.    // typically this is used to wait for the h/w to finish with    // this buffer if relevant. the data cache may need to be    // flushed or invalidated depending on the usage bits and the    // hardware.    if (private_handle_t::validate(handle) < 0)        return -EINVAL;//检测参数并返回帧缓冲区的基址,锁定操作并没有实现,需要调用者实现    private_handle_t* hnd = (private_handle_t*)handle;    *vaddr = (void*)hnd->base;    return 0;}//图形缓冲区的解锁定int gralloc_unlock(gralloc_module_t const* module,         buffer_handle_t handle){    // we're done with a software buffer. nothing to do in this    // implementation. typically this is used to flush the data cache.//解锁操作没实现,交给调用者实现    if (private_handle_t::validate(handle) < 0)        return -EINVAL;    return 0;}

总结

        经过详细的分析发现,分配图形缓冲区和映射过程是有重叠逻辑的,在分配的过程中就需要做映射操作;还有帧缓冲区初始化时,也会有映射操作。只不过Gralloc模块单独将映射过程封装出来了,即提供register_gralloc_buffer给调用者,用来映射图形缓冲区到进程的虚拟地址空间。
       总体上,Gralloc模块还是提供了这三种抽象功能:分配、映射、渲染。其中gralloc设备打开过程,为调用者返回了gralloc_alloc方法;fb设备打开过程,获取了帧缓冲区的信息、并初始化了虚拟显示屏,同时映射了帧缓冲区,并返回了渲染方法fb_post。而gralloc模块,提供了register_gralloc_buffer方法给调用者用来映射。











参考:http://www.myexception.cn/image/1442367.html
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 天正软件显示过期了怎么办 四岁宝宝经常吐怎么办 穿越火线登陆不上去怎么办 猫猫呕吐带血怎么办 狗又吐又拉稀怎么办 狗狗肠炎拉血怎么办 拉大便有血怎么办呢 工作中遇到不公待遇怎么办 老兵丢了退伍证怎么办 我的退伍证丢了怎么办 退伍证丢了怎么办啊 银行卡更换之前的卡号怎么办 收到联通欠费催款律师函怎么办 苹果5s玩王者卡怎么办 电信宽带包年用户欠费怎么办 员工不处理考勤异常怎么办 移动号码特殊原因强制停机怎么办 下雨天我怎么办我好想你 免检标志领晚了怎么办 激光点太田痣揉搓了泛红怎么办 花束与衣服颜色相称怎么办 吃鸡狙击枪距离怎么办 环世界敌人炸墙怎么办 水阀断在墙里面怎么办 内陷螺丝扣秃了怎么办 五菱仪表盘不亮怎么办 瞒着老婆欠了钱怎么办 m8螺丝牙距孔距差一个毫米怎么办 内丝弯头坏了怎么办 螺纹底孔打大了怎么办 内螺纹止规过了怎么办 牌照螺丝装错了怎么办 帽式扳手大了怎么办 内六角扳手小了怎么办 内六角扳手不够大怎么办? 苹果6螺丝拧花了怎么办 苹果电脑螺丝拧花了怎么办 苹果螺丝滑牙了怎么办 苹果7螺丝滑丝了怎么办 外六角螺丝滑牙怎么办 六角螺帽滑丝了怎么办