android的Gralloc模块

Gralloc模块是一个HAL模块,所以他有自定义的module:gralloc_module_t,和自定义的gralloc设备(alloc_device_t来描述) 和自定义的fb设备(framebuffer_device_t 来描述)。设备和模块之间互相关联。

Gralloc模块使用gralloc_module_t结构描述,gralloc_module_t有一个子类private_module_t ,使用模块的时候,我们使用private_module_t这个结构。

struct private_module_t {
    gralloc_module_t base;
    //描述了fb设备(/dev/fbx)的帧缓冲区的一些信息,包括帧缓存区的基址,某进程中打开时的fd,mmap时的        
    //大小[虚拟分辨率那么大],它可以用来分配图形缓冲区,也可以拿着基址往屏幕输送图像数据
    private_handle_t* framebuffer;
    uint32_t flags;
    uint32_t numBuffers;//图形缓冲区的个数
    uint32_t bufferMask;// 1表示忙,0表示空闲,若有2个图形缓冲区,11,10,01,00都代表什么?
    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;
};

gralloc设备使用alloc_device_t 描述:

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;

fb设备使用framebuffer_device_t 描述:

typedef struct framebuffer_device_t {
    struct hw_device_t common;
 
    /* flags describing some attributes of the framebuffer */
    const uint32_t  flags;
 
    /* dimensions of the framebuffer in pixels */
    const uint32_t  width;
    const uint32_t  height;
 
    /* frambuffer stride in pixels */
    const int       stride;
 
    /* framebuffer pixel format */
    const int       format;
 
    /* resolution of the framebuffer's display panel in pixel per inch*/
    const float     xdpi;
    const float     ydpi;
 
    /* framebuffer's display panel refresh rate in frames per second */
    const float     fps;
 
    /* min swap interval supported by this framebuffer */
    const int       minSwapInterval;
 
    /* max swap interval supported by this framebuffer */
    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);
 
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
 
    int (*compositionComplete)(struct framebuffer_device_t* dev);
 
    void* reserved_proc[8];
 
} framebuffer_device_t;

其中,gralloc设备负责分配图形缓冲区,Gralloc模块负责注册图形缓冲区,而fb设备负责渲染图形缓冲区。

图形缓冲区既可以使用内核的匿名共享内存来分配,这样可以让应用程序和SurfaceFinger进程共享操作,应用程序负责往图形缓冲区填充ui数据,SurfaceFinger进程负责一些处理(例如多个图层的合成)再送往帧缓冲区,进而显示在屏幕上。

图形缓冲区也可以直接在帧缓冲区中分配,当然应用程序还是填充ui数据,SurfaceFinger进程收到应用程序填充完数据的消息后,再让fb设备显示。帧缓冲区只是对一些硬件设备的抽象,在帧缓冲区中分配完全取决于帧缓冲设备所对应的的驱动怎么干,说不定驱动还是在内存中分配呢,管他呢。

首先使用他们(模块和设备)的时候,如下:

hw_module_t const* module;
    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
        int stride;
        int err;
        int i;
        err = framebuffer_open(module, &fbDev);
        LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
 
        err = gralloc_open(module, &grDev);
//这样就得到了fbDev,和grDev设备结构体

以上gralloc_open在创建hw_device_t设备的同时,主要是给该结构注册如下两个函数:

device.alloc   = gralloc_alloc;
device.free    = gralloc_free;

framebuffer_open在创建framebuffer_device_t设备的同时,主要也是给该结构注册fb_post函数:

device.common.close = fb_close;
device.setSwapInterval = fb_setSwapInterval;
#!
device.post            = fb_post;

以下我们直击 “gralloc设备负责分配”,“Gralloc模块负责注册”,“fb设备负责渲染”。

gralloc设备负责分配,讲的就是gralloc_alloc和gralloc_free方法:

//分配的结果保存在pHandle中
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;

    //在硬件帧缓冲区中分配图形缓冲区,这里主要是供给框架中的FramebufferNativeWindow来使用
    //在SF中,GPU渲染完成的数据 可以 放在FramebufferNativeWindow提供的back缓存中,也就是这里分        
    //配的缓存里;
    //显示的时候使用FBIOPUT_VSCREENINFO控制命令,就可以在显示屏上出现要绘制的数据:
    //    const size_t offset = hnd->base - m->framebuffer->base;
    //    m->info.activate = FB_ACTIVATE_VBL;
    //    m->info.yoffset = offset / m->finfo.line_length;
    //    ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info)

    if (usage & GRALLOC_USAGE_HW_FB) {
        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);
    } else {//在匿名共享内存中分配。。。。。这里供客户端和SF来使用的图形缓冲区
        err = gralloc_alloc_buffer(dev, size, usage, pHandle);
    }
 
    if (err < 0) {
        return err;
    }
 
    *pStride = stride;
    return 0;
}
//以上两分叉的方法,可参考AOSP2.3.7hardware/libhardware/modules/gralloc/gralloc.cpp


//我们只看帧缓冲区中如何的分配
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_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.
        //fb设备上还没有帧缓冲区,那么就分配一块儿帧缓冲区,通过该函数知道这块缓冲区被分为了前后缓冲区俩块
        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* 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;
    }
 
    hnd->base = vaddr;
    //这里的offset是关键,说明了基于整块已经分配好的空间的偏差位置
    hnd->offset = vaddr - intptr_t(m->framebuffer->base);
    *pHandle = hnd;
 
    return 0;
}

//那么整块空间何时分配的,怎么分配的,分配的大小?,那只能看mapFrameBufferLocked函数了
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;
    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;
 
#if defined(NO_32BPP)
    /*
     * Explicitly request 5/6/5
     */
    info.bits_per_pixel = 16;
    info.red.offset     = 11;
    info.red.length     = 5;
    info.green.offset   = 5;
    info.green.length   = 6;
    info.blue.offset    = 0;
    info.blue.length    = 5;
    info.transp.offset  = 0;
    info.transp.length  = 0;
#endif
 
    /*
     * Request NUM_BUFFERS screens (at lest 2 for page flipping)
     * 这里看到yres_virtual是虚拟分辨率的高度,它是实际分辨率高度的2倍,后面计算分配帧缓冲区的大小的时候,用的是yres_virtual值,也就是分配的帧缓冲区可以装载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;
        LOGW("FBIOPUT_VSCREENINFO 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;
 
    uint64_t  refreshQuotient =
    (
            uint64_t( info.upper_margin + info.lower_margin + info.yres )
            * ( info.left_margin  + info.right_margin + info.xres )
            * info.pixclock
    );
 
    /* 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;
 
    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;
    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 fbSize根据yres_virtual虚拟分辨率的高度来计算,它是数据分辨率的高度的2倍
     */
 
    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;
    //映射FB设备中分配的缓冲区的起始地址到本进程的地址空间
    void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    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;
}

Gralloc模块负责注册,讲的是gralloc_module_t结构中的registerBuffer方法(在hw_get_module方法中注册该方法为gralloc_register_buffer,以上未列出的hw_get_module加载某块的方法)。所谓注册图形缓冲区,实际上就是将一块图形缓冲区映射到一个进程的地址空间去,而注销图形缓冲区就是执行相反的操作。

//AOSP2.3.7 hardware/libhardware/modules/gralloc/mapper.cpp
int 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;
        //在本进程内映射SF在匿名共享内存中已经分配好的一块图形缓冲区
        err = gralloc_map(module, handle, &vaddr);
    }
    return err;
}

fb设备负责渲染,讲的就是fb_post方法:

//显示
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;
        if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
            LOGE("FBIOPUT_VSCREENINFO failed");
            m->base.unlock(&m->base, buffer);
            return -errno;
        }
        m->currentBuffer = buffer;
 
    } else {//在匿名内村中的话,需要从内存copy往硬件帧缓冲区中
        // 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);
 
        m->base.unlock(&m->base, buffer);
        m->base.unlock(&m->base, m->framebuffer);
    }
 
    return 0;
}

以上发生在用户空间中。

高版本的本模块中加入了ion的参与,ION是google在Android4.0 为了解决内存碎片管理而引入的通用内存管理器,在面向程序员编程方面,它和ashmem很相似。但是终究还是ION更胜一筹。ION 定义了多种不同的heap,实现不同的内存分配策略。

参考:老罗的博客

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值