【android开发】Android GUI系统学习1:Gralloc

时间:2022-05-04
本文章向大家介绍【android开发】Android GUI系统学习1:Gralloc,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Gralloc模块是从Android Eclair(android 2.1)开始加入的一个HAL模块,Gralloc的含义为是Graphics Alloc(图形分配)。他对上为libui提供服务,为其分配显存,刷新显示等。对下对framebuffer进行管理。

gralloc代码通常位于hardware/libhardware/modules/gralloc目录下。包含以下几个文件:

Android.mk framebuffer.cpp gralloc.cpp gralloc_priv.h gr.h mapper.cpp

另外,与其相关的头文件位于hardware/libhardware/include/hardware,涉及fb.h和gralloc.h。

下面从gralloc的调用开始学习gralloc的代码。代码基于android4.4。

gralloc的调用是从FramebufferNativeWindow.cpp的构造函数开始的。FramebufferNativeWindow实现FrameBuffer的管理,它主要被SurfaceFlinger使用,也可以被OpenGL Native程序使用。在本质上,它在Framebuffer之上实现了一个ANativeWindow,目前它只管理两个buffers:front and back buffer。

如下所示(FramebufferNativeWindow.cpp):

FramebufferNativeWindow::FramebufferNativeWindow()
 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
 {
 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);
 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));

err = gralloc_open(module, &grDev);
 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));

// bail out if we can't initialize the modules
 if (!fbDev || !grDev)
 return;

mUpdateOnDemand = (fbDev->setUpdateRect != 0);

// initialize the buffer FIFO
 if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
 fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){ mNumBuffers = fbDev->numFramebuffers;
 } else {
 mNumBuffers = MIN_NUM_FRAME_BUFFERS;
 }
 mNumFreeBuffers = mNumBuffers;
 mBufferHead = mNumBuffers-1;

/*
 * This does not actually change the framebuffer format. It merely
 * fakes this format to surfaceflinger so that when it creates
 * framebuffer surfaces it will use this format. It's really a giant
 * HACK to allow interworking with buggy gralloc+GPU driver
 * implementations. You should *NEVER* need to set this for shipping
 * devices.
 */
 #ifdef FRAMEBUFFER_FORCE_FORMAT
 *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
 #endif

for (i = 0; i < mNumBuffers; i++) { buffers[i] = new NativeBuffer( fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
 }

for (i = 0; i < mNumBuffers; i++) { err = grDev->alloc(grDev,
 fbDev->width, fbDev->height, fbDev->format,
 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);

ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
 i, fbDev->width, fbDev->height, strerror(-err));

if (err)
 {
 mNumBuffers = i;
 mNumFreeBuffers = i;
 mBufferHead = mNumBuffers-1;
 break;
 }
 }

const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
 const_cast<int&>(ANativeWindow::minSwapInterval) =
 fbDev->minSwapInterval;
 const_cast<int&>(ANativeWindow::maxSwapInterval) =
 fbDev->maxSwapInterval;
 } else {
 ALOGE("Couldn't get gralloc module");
 }

ANativeWindow::setSwapInterval = setSwapInterval;
 ANativeWindow::dequeueBuffer = dequeueBuffer;
 ANativeWindow::queueBuffer = queueBuffer;
 ANativeWindow::query = query;
 ANativeWindow::perform = perform;

ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
 ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
 ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
 }

这里会先根据gralloc的module ID来得到hw_module_t结构。hw_get_module->hw_get_module_by_class。在hw_get_module_by_class里面,首先根据平台配置找到gralloc动态库的位置,默认使用gralloc.default.so。 参见以下代码(hardware.c):

 for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, name, prop);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH2, name);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, name);
            if (access(path, R_OK) == 0) break;
        }
    }
 status = -ENOENT;
 if (i < HAL_VARIANT_KEYS_COUNT+1) {
 /* load the module, if this fails, we're doomed, and we should not try
 * to load a different variant. */
 status = load(class_id, path, module);
 }

找到gralloc库的路径后,会调用load函数,在load函数中使用dlopen打开找到的库,并根据HAL_MODULE_INFO_SYM_AS_STR(其值为HMI)获取到hw_module_t(即HAL_MODULE_INFO_SYM)结构体指针,以及把dlopen返回的handle保存在hw_module_t中。而hw_module_t HMI 结构是一个全局结构,在gralloc.cpp中已经得到初始化了。这也是为什么每一个HAL模块都要定义并初始化一个名字为HAL_MODULE_INFO_SYM的hw_module_t结构

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

回过头,回到FramebufferNativeWindow的构造函数出,接下来调用了err = framebuffer_open(module, &fbDev);framebuffer_open定义在fb.h中,是一个inline函数,其实最终调用了就是上面结构体中初始化的open函数,open函数指向gralloc_device_open,其实现为(gralloc.cpp):

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

fb_device_open的定义如下所示(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);
        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_open也是调用了gralloc_device_open,只不过name参数一个是GRALLOC_HARDWARE_GPU0,而另外一个是GRALLOC_HARDWARE_FB0,这两个函数分别得到alloc_device_t 和 framebuffer_device_t结构。到现在为止,gralloc模块的三个主要结构体,gralloc_module_t,alloc_device_t,framebuffer_device_t都已经获取到了。其中在fb_device_open函数中会获取实际的framebuffer设备(通常是/dev/graphics/fb0)的一些重要参数以及能力,比如分辨率信息以及支持多少个缓冲等,另外会把framebuffer映射到内测的地址保存到alloc_module_t中。android一般使用的都是双缓冲机制。具体代码如下(framebuffer.cpp),其中涉及到对private_module_t中一些成员的完善,涉及到gralloc_module_t以及private_handle_t等,其定义在gralloc_priv.h中,这两个结构中都保存了framebuffer的一些私有信息。

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;

/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
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");
}

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

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;

ALOGI( "using (fd=%d)n"
"id = %sn"
"xres = %d pxn"
"yres = %d pxn"
"xres_virtual = %d pxn"
"yres_virtual = %d pxn"
"bpp = %dn"
"r = %2u:%un"
"g = %2u:%un"
"b = %2u:%un",
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 Hzn",
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);
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;
}

由上面函数看出,mapFrameBufferLocked主要做了下面几件事情: 1. 打开framebuffer设备

2. 获取 fb_fix_screeninfo and fb_var_screeninfo

3. refill fb_var_screeninfo

4. 判断是否支持PAGE_FLIP

5. 计算刷新率

6. 打印gralloc信息

7. 填充private_module_t

8. mmap the framebuffer

由于篇幅限制,这里暂时说道这里,如要查看后续内容请查看原文:http://www.coderonline.net/android-gui%e7%b3%bb%e7%bb%9f%e5%ad%a6%e4%b9%a01%ef%bc%9agralloc.html