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 = %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);
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