4. 分配图形缓冲区
前面提到,用户空间的应用程序用到的图形缓冲区是由Gralloc模块中的函数gralloc_alloc来分配的,这个函数实如今文件hardware/libhardware/modules/gralloc/gralloc.cpp中,以下所示:
-
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;
-
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;
-
}
参数format用来描述要分配的图形缓冲区的颜色格式。当format值等于HAL_PIXEL_FORMAT_RGBA_888八、HAL_PIXEL_FORMAT_RGBX_8888或者HAL_PIXEL_FORMAT_BGRA_8888的时候,一个像素须要使用32位来表示,即4个字节。当format值等于HAL_PIXEL_FORMAT_RGB_888的时候,一个像素须要使用24位来描述,即3个字节。当format值等于HAL_PIXEL_FORMAT_RGB_56五、HAL_PIXEL_FORMAT_RGBA_5551或者HAL_PIXEL_FORMAT_RGBA_4444的时候,一个像须要使用16位来描述,即2个字节。最终一个像素须要使用的字节数保存在变量bpp中。
参数w表示要分配的图形缓冲区所保存的图像的宽度,将它乘以bpp,就能够获得保存一行像素所须要使用的字节数。咱们须要将这个字节数对齐到4个字节边界,最后获得一行像素所须要的字节数就保存在变量bpr中。
参数h表示要分配的图形缓冲区所保存的图像的高度,将它乘以bpr,就能够获得保存整个图像所须要使用的字节数。
将变量bpr的值除以变量bpp的值,就获得要分配的图形缓冲区一行包含有多少个像素点,这个结果须要保存在输出参数pStride中,以即可以返回给调用者。
参数usage用来描述要分配的图形缓冲区的用途。若是是用来在系统帧缓冲区中渲染的,即参数usage的GRALLOC_USAGE_HW_FB位等于1,那么就必需要系统帧缓冲区中分配,不然的话,就在内存中分配。注意,在内存中分配的图形缓冲区,最终是须要拷贝到系统帧缓冲区去的,以即可以将它所描述的图形渲染出来。
函数gralloc_alloc_framebuffer用来在系统帧缓冲区中分配图形缓冲区,而函数gralloc_alloc_buffer用来在内存在分配图形缓冲区,接下来咱们就分别分析这两个函数的实现。
函数gralloc_alloc_framebuffer实如今文件hardware/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;
-
}
这个函数调用了另一个函数gralloc_alloc_framebuffer_locked来分配图形缓冲区。
函数gralloc_alloc_framebuffer_locked也是实如今文件hardware/libhardware/modules/gralloc/gralloc.cpp中,以下所示:
-
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.
-
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;
-
hnd->offset = vaddr - intptr_t(m->framebuffer->base);
-
*pHandle = hnd;
-
-
return 0;
-
}
在系统帧缓冲区分配图形缓冲区以前,首先要对系统帧缓冲区进行过初始化,即这里的变量m所指向的一个private_module_t结构体的成员变量framebuffer的值不能等于NULL。若是等于NULL的话,那么就必需要调用另一个函数mapFrameBufferLocked来初始化系统帧缓冲区。初始化系统帧缓冲区的过程能够参考前面第3部分的内容。
变量bufferMask用来描述系统帧缓冲区的使用状况,而变量numBuffers用来描述系统帧缓冲区能够划分为多少个图形缓冲区来使用,另一个变量bufferSize用来描述设备显示屏一屏内容所占用的内存的大小。
若是系统帧缓冲区只有一个图形缓冲区大小,即变量numBuffers的值等于1,那么这个图形缓冲区就始终用做系统主图形缓冲区来使用。在这种状况下,咱们就不可以在系统帧缓冲区中分配图形缓冲区来给用户空间的应用程序使用,所以,这时候就会转向内存中来分配图形缓冲区,即调用函数gralloc_alloc_buffer来分配图形缓冲区。注意,这时候分配的图形缓冲区的大小为一屏内容的大小,即bufferSize。
若是bufferMask的值大于等于((1LU<<numBuffers)-1)的值,那么就说明系统帧缓冲区中的图形缓冲区所有都分配出去了,这时候分配图形缓冲区就失败了。例如,假设图形缓冲区的个数为2,那么((1LU<<numBuffers)-1)的值就等于3,即二制制0x11。若是这时候bufferMask的值也等于0x11,那么就表示第一个和第二个图形缓冲区都已经分配出去了。所以,这时候就不能再在系统帧缓冲区中分配图形缓冲区。
假设此时系统帧缓冲区中尚有空闲的图形缓冲区的,接下来函数就会建立一个private_handle_t结构体hnd来描述这个即将要分配出去的图形缓冲区。注意,这个图形缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER,即表示这是一块在系统帧缓冲区中分配的图形缓冲区。
接下来的for循环从低位到高位检查变量bufferMask的值,而且找到第一个值等于0的位,这样就能够知道在系统帧缓冲区中,第几个图形缓冲区的是空闲的。注意,变量vadrr的值开始的时候指向系统帧缓冲区的基地址,在下面的for循环中,每循环一次它的值都会增长bufferSize。从这里就能够看出,每次从系统帧缓冲区中分配出去的图形缓冲区的大小都是恰好等于显示屏一屏内容大小的。
最后分配出去的图形缓冲区的开始地址就保存在前面所建立的private_handle_t结构体hnd的成员变量base中,这样,用户空间的应用程序就能够直接将要渲染的图形内容拷贝到这个地址上去,这就至关因而直接将图形渲染到系统帧缓冲区中去。
在将private_handle_t结构体hnd返回给调用者以前,还须要设置它的成员变量offset,以即可以知道它所描述的图形缓冲区的起始地址相对于系统帧缓冲区的基地址的偏移量。
至此,在系统帧缓冲区中分配图形缓冲区的过程就分析完成了,接下来咱们再分析在内存在分析图形缓冲区的过程,即分析函数gralloc_alloc_buffer的实现。
函数gralloc_alloc_buffer也是实如今文件hardware/libhardware/modules/gralloc/gralloc.cpp中,以下所示:
-
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) {
-
LOGE("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<gralloc_module_t*>(
-
dev->common.module);
-
err = mapBuffer(module, hnd);
-
if (err == 0) {
-
*pHandle = hnd;
-
}
-
}
-
-
LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
-
-
return err;
-
}
从匿名共享内存中分配的图形缓冲区还须要映射到进程的地址空间来,而后才可使用,这是经过调用函数mapBuffer来实现的。
函数mapBuffer实如今文件hardware/libhardware/modules/gralloc/mapper.cpp中,以下所示:
-
int mapBuffer(gralloc_module_t const* module,
-
private_handle_t* hnd)
-
{
-
void* vaddr;
-
return gralloc_map(module, hnd, &vaddr);
-
}
它经过调用另一个函数gralloc_map来将参数hnd所描述的一个图形缓冲区映射到当前进程的地址空间来。后面在分析图形缓冲区的注册过程时,咱们再分析函数gralloc_map的实现。
注意,在Android系统中,在系统帧缓冲区中分配的图形缓冲区是在SurfaceFlinger服务中使用的,而在内存中分配的图形缓冲区既能够在SurfaceFlinger服务中使用,也能够在其它的应用程序中使用。当其它的应用程序须要使用图形缓冲区的时候,它们就会请求SurfaceFlinger服务为它们分配,所以,对于其它的应用程序来讲,它们只须要将SurfaceFlinger服务返回来的图形缓冲区映射到本身的进程地址空间来使用就能够了,这就是后面咱们所要分析的图形缓冲区的注册过程。
至此,图形缓冲区的分配过程就分析完成了,接下来咱们继续分析图形缓冲区的释放过程。