该系列文章总纲链接:Android GUI系统之SurfaceFlinger 系列文章目录
本章节思维导图如上。主要讲述了gralloc模块 内存分配的概念,这里 主要关注 构造器 和 alloc方法。
Android帧缓冲区硬件抽象层模块Gralloc的实现原理如下:
为了实现以上三个操作,我们还需要:
其中,gralloc设备负责分配图形缓冲区,Gralloc模块负责注册图形缓冲区,而fb设备负责渲染图形缓冲区。在GrafficBuffer中,内存是由Gralloc模块中分配的,基于上一节 FB的工作原理,这里主要分析Gralloc模块如何分配内存。
1 GraphicBufferAllocator分析
在GraficBuffer中,内存申请使用的类是GraphicBufferAllocator,头文件代码如下:
class GraphicBufferAllocator : public Singleton//单例模式类
{
public:
...
//主要用来获取GraphicBufferAllocator对象
static inline GraphicBufferAllocator& get() { return getInstance(); }
//分配图像缓冲区
status_t alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage,buffer_handle_t* handle, int32_t* stride);
//释放图像缓冲区
status_t free(buffer_handle_t handle);
...
};
继续查看cpp文件中的构造方法,代码如下:
GraphicBufferAllocator::GraphicBufferAllocator(): mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);//打开Gralloc模块
if (err == 0) {
gralloc_open(module, &mAllocDev);
}
}
继续分析gralloc_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, (struct hw_device_t**)device);
}
但是与FB相比,这一次传递的参数是GRALLOC_HARDWARE_GPU0,open函数在Gralloc模块中对应的函数是gralloc_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));//创建结构体dev
memset(dev, 0, sizeof(*dev));
//初始化结构体
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;//分配内存的函数
dev->device.free = gralloc_free;//释放内存的函数
*device = &dev->device.common;
status = 0;
} else {
... //走if分支,忽略此处FB操作
}
return status;
}
说明:在调用完open函数后,GraphicBufferAllocator和Gralloc函数就建立了联系。
2 GraphicBufferAllocator的alloc方法分析
接下来从GraphicBufferAllocator的alloc方法开始分析,代码如下:
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
ATRACE_CALL();
if (!w || !h)//如果制定的w或者h其中一个为0,则分配一个1*1大小的buffer
w = h = 1;
// we have a h/w allocator and h/w buffer is requested
status_t err;
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector& list(sAllocList);
int bpp = bytesPerPixel(format);
if (bpp < 0) {
// probably a HAL custom format. in any case, we don't know what its pixel size is.
bpp = 0;
}
//创建并初始化结构体变量rec
alloc_rec_t rec;
rec.w = w;
rec.h = h;
rec.s = *stride;
rec.format = format;
rec.usage = usage;
rec.size = h * stride[0] * bpp;
list.add(*handle, rec);
}
return err;
}
这里alloc调用了Gralloc函数中分配的函数指针,即Gralloc模块中的函数gralloc_alloc,代码如下:
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_RAW_SENSOR:
bpp = 2;
break;
default:
return -EINVAL;
}
size_t bpr = (w*bpp + (align-1)) & ~(align-1);//计算每行字节数,因为要对其字节,要保证每行大小都是4的倍数
size = bpr * h;//总内存大小
stride = bpr / bpp;//每行的像素数(>=w*h),方法原理:每行的总字节数/每个像素的字节数==一行的像素
int err;
if (usage & GRALLOC_USAGE_HW_FB) {//分析usage标志中是否有GRALLOC_USAGE_HW_FB
err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);//从硬件缓冲区中分配内存,关键点1
} else {
err = gralloc_alloc_buffer(dev, size, usage, pHandle);//从内存中分配缓冲区,关键点2
}
if (err < 0) {
return err;
}
*pStride = stride;
return 0;
}
2.1 gralloc_alloc_framebuffer分析
如果从硬件缓冲区中分配内存,会调用gralloc_alloc_framebuffer方法,代码如下:
static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast(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;
}
继续分析gralloc_alloc_framebuffer_locked的实现,代码如下:
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(dev->common.module);
if (m->framebuffer == NULL) {//第一次调用会走这里
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) {
//单缓冲的FrameBuffer,使用普通内存来分配
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
}
//对于多缓冲区,采取这样的方法
if (bufferMask >= ((1LU<framebuffer->base);
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
//因为FB缓冲区块数是有限的,因此需要遍历找到一个空闲块
for (uint32_t i=0 ; ibufferMask |= (1LU<base = vaddr;
hnd->offset = vaddr - intptr_t(m->framebuffer->base);
*pHandle = hnd;
return 0;
}
2.2 gralloc_alloc_buffer分析
如果从内存缓冲区中分配内存,会调用gralloc_alloc_buffer方法,代码如下:
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);//创建匿名共享内存,使用ashmem机制
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(
dev->common.module);
err = mapBuffer(module, hnd);//使用mmap来创建内存,把共享内存的句柄和首地址关联到module
if (err == 0) {
*pHandle = hnd;//把创建的结构返回回去
}
}
return err;
}
因为Android的图像缓冲区是需要进程间共享访问的,因此使用了匿名共享内存(使用共享内存前必须通过Binder来传递句柄,这里通过private_handle_t结构把共享内存的fd传递出去,这样缓冲区才可以使用)。