本文主要是介绍gralloc,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
系统中有好几个gralloc的模块,
分别是:
/hardware/libhardware/modules/gralloc/
/hardware/msm7k/libgralloc-qsd8k/
/hardware/msm7k/libgralloc/
但实际上调用的是第二个模块,通过logcat可以查到.
gralloc被编译成模块gralloc.$(TARGET_BOARD_PLATFORM).so
/hardware/libhardware/modules/gralloc/分析:
提供给上层的接口函数有:
open: gralloc_device_open
registerBuffer: gralloc_register_buffer,
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
open函数
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
该函数首先判断传入的module的类型,类型有两个,分别为:
#define GRALLOC_HARDWARE_FB0 "fb0"
#define GRALLOC_HARDWARE_GPU0 "gpu0"
在gralloc.h文件中定义了,该文件页定义了调用gralloc_device_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);
}
static inline int framebuffer_open(const struct hw_module_t* module,
struct framebuffer_device_t** device) {
return module->methods->open(module,
GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
}
这两个函数其实就是调用了gralloc_device_open(),只不过参数不同而已;
如果参数是:GRALLOC_HARDWARE_GPU0
为定义的gralloc_context_t 指针分配内存,调用memset()初始化指针为空,并将该指针变量的函数指针指向
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
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;
所以可以说Gralloc模块就是为分配显存的。位于framebuffer和surface两层之间。
如果参数是:GRALLOC_HARDWARE_FB0
执行:status = fb_device_open(module, name, device);
fb_device_open()函数调用gralloc_open()函数,这个framebuffer_open()函数的调用打开了gralloc_device_open()两次,第一次根据module的类型为:GRALLOC_HARDWARE_FB0,调用了fb_device_open()这个函数,而fb_device_open()这个函数中又调用了gralloc_open这个函数,这个函数中的module为GRALLOC_HARDWARE_GPU0。
继续分析fb_device_open()函数,
alloc_device_t* gralloc_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
return status;
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
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;
该函数同理定义了fb_context_t的指针,并分配了内存,并初始化了几个函数指针。
然后调用mapFramebuffer() ---->mapFramebufferLocked()
在mapFramebufferLocked()函数中,打开了/dev/graphics/fb0的设备,调用ioctl函数的
FBIOGET_FSCREENINFO,FBIOGET_VSCREENINFO取得了fb_fix_screeninfo,fb_var_screeninfo结构体的数据,
并初始化了fb_var_screeninfo结构体变量info的数据:
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
info.bits_per_pixel = 16;
info.red.offset = 11;
info.red.length = 5;
info.green.offset = 5;
info.green.length = 6;
info.blue.offset = 0;
info.blue.length = 5;
info.transp.offset = 0;
info.transp.length = 0;
都是初始话像素的深度和红绿蓝分量在每个像素中的偏移。
随后调用ioctl的FBIOPUT_VSCREENINFO将info的数据写回到framebuffer中。
随后计算刷新的频率,
int refreshRate = 1000000000000000LLU /
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);
if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;
uint32_t flags = PAGE_FLIP;//从代码可以看出,支不支持PAGE_FLIP就看是不是:info.yres_virtual < info.yres * 2
最终把这些变量写入到module中:
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;
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;
调用mmap将内核的fd映射到用户空间
并 module->framebuffer->base = intptr_t(vaddr);将vaddr的类型转化为int16_t的,之后memset将vaddr的数据初始化为空。
再来看fb_device_open()函数,
其实这一系列的过程就是初始化了两个结构体:
fb_context_t *dev ;
gralloc_context_t *dev;
为两个结构体分配了内存,并初始化.
gralloc_alloc()函数
该函数主要的作用就是分配内存的,如果支持PAGE_FLIP(双缓冲)模式,则调用gralloc_alloc_framebuffer(),否则,调用gralloc_alloc_buffer()
gralloc_alloc_framebuffer()函数:
调用gralloc_alloc_framebuffer_locked()函数,
在该函数中,调用mapFrameBufferLocked()函数得到fb的参数,并初始化private_module_t* m这个结构体,重新创建了一个private_handle_t* hnd,这个hndflags为private_handle_t::PRIV_FLAGS_FRAMEBUFFER.bufferMask应该等于11,numBuffers应该等于2,vaddr应该为第二块framebuffer的地址 (vaddr += bufferSize;),offset也相应改变.
gralloc_free()函数:
该函数正好和gralloc_alloc函数相反,是释放内存的,首先判断
hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER
之后,计算bufferSize大小,计算这个handle在framebuffer中的索引,根据索引来
const size_t bufferSize = m->finfo.line_length * m->info.yres;
int index = (hnd->base - m->framebuffer->base) / bufferSize;
m->bufferMask &= ~(1<<index);
index应该等于1,则m->bufferMask计算之后等于1.
最开始调用fb_device_open创建的hnd的flags=0,走的是else后面的路,最终调用到mnumap()函数解除对内存的映射.
fb_post()分析:
首先也是判断
(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)
如果flags相等,则重新设置了一下该framebuffer_device_t的fb_var_screeninfo结构体的activate和yoffset信息,之后ioctl将fb_var_screeninfo写入到fb中,然后直接将当前的currentBuffer指向这个buffer_handle_t.
如果flags不相等,则调用gralloc_lock函数,得到两个buffer的地址,再调用memcpy()将buffer复制.
/
struct private_handle_t : public native_handle {}
typedef const native_handle* buffer_handle_t;
typedef struct gralloc_module_t {
struct hw_module_t common;
} gralloc_module_t;
typedef struct alloc_device_t {
struct hw_device_t common;
} alloc_device_t;
typedef struct framebuffer_device_t {
struct hw_device_t common;
} framebuffer_device_t;
typedef native_handle_t native_handle;
typedef struct
{
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;
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
/** major version number for the module */
uint16_t version_major;
/** minor version number of the module */
uint16_t version_minor;
/** Identifier of module */
const char *id;
/** Name of this module */
const char *name;
/** Author/owner/implementor of the module */
const char *author;
/** Modules methods */
struct hw_module_methods_t* methods;
/** module's dso */
void* dso;
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;
typedef struct hw_module_methods_t {
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
/** version number for hw_device_t */
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
struct private_module_t {
gralloc_module_t base;
private_handle_t* framebuffer;
uint32_t flags;
uint32_t numBuffers;
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
int pmem_master;
void* pmem_master_base;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
};
这篇关于gralloc的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!