这篇文章我们主要分析下显示中gralloc模块分配内存以及一些数据结构的介绍。
在博客http://blog.csdn.net/kc58236582/article/details/52681363中,我们分析过了从BufferQueueProducer的dequeueBuffer函数开始分配内存的流程。我们直接从如下开始分析。
分配内存流程
我们是调用了GraphicBufferAllocator的alloc函数,并且最后内存地址是保存在buffer_handle_t类型的handle入参中。
status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage, buffer_handle_t* handle,
uint32_t* stride)
{
if (!width || !height)
width = height = 1;
// we have a h/w allocator and h/w buffer is requested
status_t err;
// Filter out any usage bits that should not be passed to the gralloc module
usage &= GRALLOC_USAGE_ALLOC_MASK;
int outStride = 0;
err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
static_cast<int>(height), format, static_cast<int>(usage), handle,
&outStride);
......
}
我们是调用了mAllocDev的alloc函数,而mAllocDev的赋值如下
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
gralloc_open(module, &mAllocDev);
}
}
这个函数的定义在hardware/libhardware/include/hardware/gralloc.h中
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);
}
再看如下定义,当然这块hal就是每个厂商自己的了(比如arm 高通),因此最后gralloc_open函数是调用了gralloc_device_open函数
static struct hw_module_methods_t gralloc_module_methods =
{
open: gralloc_device_open
};
private_module_t::private_module_t()
{
#define INIT_ZERO(obj) (memset(&(obj),0,sizeof((obj))))
base.common.tag = HARDWARE_MODULE_TAG;
base.common.version_major = 1;
base.common.version_minor = 0;
base.common.id = GRALLOC_HARDWARE_MODULE_ID;
base.common.name = "Graphics Memory Allocator Module";
base.common.author = "Leadcore Ltd.";
base.common.methods = &gralloc_module_methods;
因为传进来的name是GRALLOC_HARDWARE_GPU0,最后是调用了alloc_device_open函数
static int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)
{
int status = -EINVAL;
if (!strncmp(name, GRALLOC_HARDWARE_GPU0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN))
{
status = alloc_device_open(module, name, device);
}
else if (!strncmp(name, GRALLOC_HARDWARE_FB0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN))
{
status = framebuffer_device_open(module, name, device);
}
return status;
}
在alloc_device_open中,我们就找到了我们需要的alloc函数就是alloc_device_alloc
int alloc_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
{
alloc_device_t *dev;
dev = new alloc_device_t;
if (NULL == dev)
{
return -1;
}
#if USE_VIVANTE_2D == 1
if (has2Ddev == -1)
{
struct stat buf;
if (stat("/dev/graphics/galcore_smmu", &buf) == 0)
{
ALOGI("%s: galcore and smmu both exist!", __FUNCTION__);
has2Ddev = 1;
SMMUEnable = 1;
}
else if (stat("/dev/graphics/galcore", &buf) == 0)
{
ALOGI("%s: only galcore exist!", __FUNCTION__);
has2Ddev = 1;
SMMUEnable = 0;
}
else
{
ALOGI("%s: check galcore failed", __FUNCTION__);
has2Ddev = 0;
SMMUEnable = 0;
}
}
#endif
/* initialize our state here */
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = const_cast<hw_module_t*>(module);
dev->common.close = alloc_backend_close;
dev->alloc = alloc_device_alloc;//alloc函数
dev->free = alloc_device_free;
if (0 != alloc_backend_open(dev)) {
delete dev;
return -1;
}
*device = &dev->common;
return 0;
}
alloc_device_alloc又会调用alloc_backend_alloc函数,而我们的alloc_backend_alloc函数最终是在ion模块的,是在Alloc_ion.c中。这个函数先是调用了ion_share得到共享文件,然后再调用mmap函数得到映射地址。最后新建一个private_handle_t对象,并且把这个映射地址给了base变量。最后再把这一个private_handle_t给了buffer_handle_t对象也就是最后输出的handle对象。
int alloc_backend_alloc(alloc_device_t* dev, size_t size, int usage, buffer_handle_t* pHandle, uint64_t fmt, int w, int h)
{
private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);
ion_user_handle_t ion_hnd;
unsigned char *cpu_ptr = NULL;
int shared_fd;
int ret;
unsigned int heap_mask, priv_heap_flag = 0;
int ion_flags = 0;
static int support_protected = 1; /* initially, assume we support protected memory */
int lock_state = 0;
int min_pgsz = 0;
heap_mask = pick_ion_heap(usage);
set_ion_flags(heap_mask, usage, &priv_heap_flag, &ion_flags);
ion_hnd = alloc_from_ion_heap(m->ion_client, size, heap_mask, ion_flags, &min_pgsz);
if (ion_hnd <= ION_INVALID_HANDLE)
{
AERR("Failed to ion_alloc from ion_client:%d", m->ion_client);
return -1;
}
ret = ion_share( m->ion_client, ion_hnd, &shared_fd );//获取到共享文件的fd
if ( ret != 0 )
{
AERR( "ion_share( %d ) failed", m->ion_client );
if ( 0 != ion_free( m->ion_client, ion_hnd ) ) AERR( "ion_free( %d ) failed", m->ion_client );
return -1;
}
if (!(usage & GRALLOC_USAGE_PROTECTED))
{
cpu_ptr = (unsigned char*)mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shared_fd, 0 );//映射地址
if ( MAP_FAILED == cpu_ptr )
{
AERR( "ion_map( %d ) failed", m->ion_client );
if ( 0 != ion_free( m->ion_client, ion_hnd ) ) AERR( "ion_free( %d ) failed", m->ion_client );
close( shared_fd );
return -1;
}
lock_state = private_handle_t::LOCK_STATE_MAPPED;
#if GRALLOC_INIT_AFBC == 1
if (fmt & (GRALLOC_ARM_INTFMT_AFBC | GRALLOC_ARM_INTFMT_AFBC_SPLITBLK | GRALLOC_ARM_INTFMT_AFBC_WIDEBLK))
{
init_afbc(cpu_ptr, fmt, w, h);
}
#endif /* GRALLOC_INIT_AFBC == 1 */
}
private_handle_t *hnd = new private_handle_t( private_handle_t::PRIV_FLAGS_USES_ION | priv_heap_flag, usage, size, cpu_ptr,
lock_state );//新建一个private_handle_t把映射的地址给handle的base变量
if ( NULL != hnd )
{
uint64_t phys_addr;
hnd->share_fd = shared_fd;
hnd->ion_hnd = ion_hnd;
hnd->min_pgsz = min_pgsz;
hnd->ion_hnd_debug = ion_hnd;
if(ion_flags & (ION_HEAP_LC_VIDEO_MASK|ION_HEAP_LC_ISP_MASK))
{
ret = ion_phys(m->ion_client, shared_fd, &phys_addr);
if(ret == 0)
{
hnd->phys_addr = phys_addr;
*pHandle = hnd;
return 0;
}
} else {
*pHandle = hnd;//最后把这个private_handle_t给了buffer_handle_t就是最后要的handle对象
return 0;
}
}
else
{
AERR( "Gralloc out of mem for ion_client:%d", m->ion_client );
}
close( shared_fd );
if(!(usage & GRALLOC_USAGE_PROTECTED))
{
ret = munmap( cpu_ptr, size );
if ( 0 != ret ) AERR( "munmap failed for base:%p size: %zd", cpu_ptr, size );
}
ret = ion_free( m->ion_client, ion_hnd );
if ( 0 != ret ) AERR( "ion_free( %d ) failed", m->ion_client );
return -1;
}
最后我们把private_handle_t的指针给了buffer_handle_t对象,我们看看这两个结构体有什么关系。
buffer_handle_t和private_handle_t关系
首先在system/core/include/system/window.h中有如下定义
typedef const native_handle_t* buffer_handle_t;
在system/core/include/utils/NativeHandle.h有如下定义
typedef struct native_handle native_handle_t;
再来看看native_handle_t的定义
typedef struct native_handle
{
int version; /* sizeof(native_handle_t) */
int numFds; /* number of file-descriptors at &data[0] */
int numInts; /* number of ints at &data[numFds] */
int data[0]; /* numFds + numInts ints */
} native_handle_t;
这样说native_handle就是buffer_handle_t的指针
我们再来看看private_handle_t 的定义,这里我们可以看到c++和c做了区别。c++的话直接继承native_handle这样native_handle的内存地址就在前面了,c的话直接把native_handle nativeHandle放在第一个,意思其实是一样的。而当我们把private_handle_t的指针强制转成buffer_handle_t的指针时。由于前面的内容都是native_handle的,这样也就没啥区别了,只是在用的时候再把buffer_handle_t的指针强制转成private_hanele_t类型的,就可以继续调用private_handle_t的变量了。
#ifdef __cplusplus
struct private_handle_t : public native_handle
{
#else
struct private_handle_t
{
struct native_handle nativeHandle;
#endif
enum
{
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
PRIV_FLAGS_USES_UMP = 0x00000002,
PRIV_FLAGS_USES_ION = 0x00000004,
PRIV_FLAGS_USES_ION_DMA_HEAP = 0x00000008,
PRIV_FLAGS_WIFI_DISPLAY = 0x01000000,
};
enum
{
LOCK_STATE_WRITE = 1<<31,
LOCK_STATE_MAPPED = 1<<30,
LOCK_STATE_READ_MASK = 0x3FFFFFFF
};
/*
* Shared file descriptor for dma_buf sharing. This must be the first element in the
* structure so that binder knows where it is and can properly share it between
* processes.
* DO NOT MOVE THIS ELEMENT!
*/
int share_fd;
#if MALI_AFBC_GRALLOC == 1
int share_attr_fd;
#endif
ion_user_handle_t ion_hnd;
ion_user_handle_t ion_hnd_debug;
// ints
int magic;
int req_format;
uint64_t internal_format __attribute__((aligned(8)));
int byte_stride;
int flags;
int usage;
int size;
int width;
int height;
int format;
int internalWidth;
int internalHeight;
int stride;
union {
void* base;//虚拟地址
uint64_t padding __attribute__((aligned(8)));
};
int lockState;
int writeOwner;
int pid;
#if MALI_AFBC_GRALLOC == 1
// locally mapped shared attribute area
union {
void* attr_base;
uint64_t padding3 __attribute__((aligned(8)));
};
#endif
mali_gralloc_yuv_info yuv_info;
#if USE_VIVANTE_2D
/* Vivante private ints. */
int viv_priv[24];
#endif
uint64_t phys_addr __attribute__((aligned(8)));//物理地址
// Following members is for framebuffer only
int fd;
union {
off_t offset;
uint64_t padding4 __attribute__((aligned(8)));
};