之前分析过Android HAL层关于hal库是如何加载的一个小框架,源于笔者需要分析Android display框架,Android display HAL层最重要的就是Gralloc和Framebuffer。在《深入理解Android内核设计思想》一书中,有提到:Android终端显示设备的”化身“–Gralloc与Framebuffer。
在Android系统中,Framebuffer提供的设备文件节点是/dev/graphics/fb*。
Framebuffer容易理解,那Gralloc是个什么东西。
Android的各个子系统通常不会直接使用内核驱动,而是由HAL层来间接引用底层架构。
显示系统也是同样如此–它借助HAL层来操作帧缓冲区,而完成这一中介任务的就是Gralloc。
gralloc hal库源码位于hardware/libhardware/modules/gralloc/
主要包括:Android.mk framebuffer.cpp gralloc.cpp gralloc_priv.h gr.h mapper.cpp
加粗的则是最重要的三个实现文件
先看gralloc的加载,可以参照之前的blog。
通过之前分析到的hw_get_module即可加载对应的hal库,这里即是gralloc库。
可以看到在gralloc.h中hardware/libhardware/include/hardware/gralloc.h
/**
* The id of this module
*/
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
关于GRALLOC_HARDWARE_MODULE_ID根据注释大致可以判断出来就是module ID,也就是struct hw_module_t里面必须的ID。现在来验证下:
有一点不需质疑,该ID肯定在gralloc.c中使用
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,
};
没错,确实在C文件中找到了,但初始化是在struct private_module_t中base 的common里。有趣的来了,要想知道为啥会是这个结果,先从源头找起,private_module_t是个什么东西,看名称大致是私有的module?
该结构图定义在gralloc_priv.h中
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;
};
可以看到base是gralloc_module_t类型的。gralloc_module_t在哪定义的?这个应该很简单,大致是在gralloc.h
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
typedef struct gralloc_module_t {
struct hw_module_t common; //hw_module_t 类型
/*
* (*registerBuffer)() must be called before a buffer_handle_t that has not
* been created with (*alloc_device_t::alloc)() can be used.
*
* This is intended to be used with buffer_handle_t's that have been
* received in this process through IPC.
*
* This function checks that the handle is indeed a valid one and prepares
* it for use with (*lock)() and (*unlock)().
*
* It is not necessary to call (*registerBuffer)() on a handle created
* with (*alloc_device_t::alloc)().
*
* returns an error if this buffer_handle_t is not valid.
*/
int (*registerBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
/*
* (*unregisterBuffer)() is called once this handle is no longer needed in
* this process. After this call, it is an error to call (*lock)(),
* (*unlock)(), or (*registerBuffer)().
*
* This function doesn't close or free the handle itself; this is done
* by other means, usually through libcutils's native_handle_close() and
* native_handle_free().
*
* It is an error to call (*unregisterBuffer)() on a buffer that wasn't
* explicitly registered first.
*/
int (*unregisterBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
/*
* The (*lock)() method is called before a buffer is accessed for the
* specified usage. This call may block, for instance if the h/w needs
* to finish rendering or if CPU caches need to be synchronized.
*
* The caller promises to modify only pixels in the area specified
* by (l,t,w,h).
*
* The content of the buffer outside of the specified area is NOT modified
* by this call.
*
* If usage specifies GRALLOC_USAGE_SW_*, vaddr is filled with the address
* of the buffer in virtual memory.
*
* Note calling (*lock)() on HAL_PIXEL_FORMAT_YCbCr_*_888 buffers will fail
* and return -EINVAL. These buffers must be locked with (*lock_ycbcr)()
* instead.
*
* THREADING CONSIDERATIONS:
*
* It is legal for several different threads to lock a buffer from
* read access, none of the threads are blocked.
*
* However, locking a buffer simultaneously for write or read/write is
* undefined, but:
* - shall not result in termination of the process
* - shall not block the caller
* It is acceptable to return an error or to leave the buffer's content
* into an indeterminate state.
*
* If the buffer was created with a usage mask incompatible with the
* requested usage flags here, -EINVAL is returned.
*
*/
int (*lock)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
/*
* The (*unlock)() method must be called after all changes to the buffer
* are completed.
*/
int (*unlock)(struct gralloc_module_t const* module,
buffer_handle_t handle);
/* reserved for future use */
int (*perform)(struct gralloc_module_t const* module,
int operation, ... );
/*
* The (*lock_ycbcr)() method is like the (*lock)() method, with the
* difference that it fills a struct ycbcr with a description of the buffer
* layout, and zeroes out the reserved fields.
*
* If the buffer format is not compatible with a flexible YUV format (e.g.
* the buffer layout cannot be represented with the ycbcr struct), it
* will return -EINVAL.
*
* This method must work on buffers with HAL_PIXEL_FORMAT_YCbCr_*_888
* if supported by the device, as well as with any other format that is
* requested by the multimedia codecs when they are configured with a
* flexible-YUV-compatible color-format with android native buffers.
*
* Note that this method may also be called on buffers of other formats,
* including non-YUV formats.
*
* Added in GRALLOC_MODULE_API_VERSION_0_2.
*/
int (*lock_ycbcr)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
struct android_ycbcr *ycbcr);
/*
* The (*lockAsync)() method is like the (*lock)() method except
* that the buffer's sync fence object is passed into the lock
* call instead of requiring the caller to wait for completion.
*
* The gralloc implementation takes ownership of the fenceFd and
* is responsible for closing it when no longer needed.
*
* Added in GRALLOC_MODULE_API_VERSION_0_3.
*/
int (*lockAsync)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr, int fenceFd);
/*
* The (*unlockAsync)() method is like the (*unlock)() method
* except that a buffer sync fence object is returned from the
* lock call, representing the completion of any pending work
* performed by the gralloc implementation.
*
* The caller takes ownership of the fenceFd and is responsible
* for closing it when no longer needed.
*
* Added in GRALLOC_MODULE_API_VERSION_0_3.
*/
int (*unlockAsync)(struct gralloc_module_t const* module,
buffer_handle_t handle, int* fenceFd);
/*
* The (*lockAsync_ycbcr)() method is like the (*lock_ycbcr)()
* method except that the buffer's sync fence object is passed
* into the lock call instead of requiring the caller to wait for
* completion.
*
* The gralloc implementation takes ownership of the fenceFd and
* is responsible for closing it when no longer needed.
*
* Added in GRALLOC_MODULE_API_VERSION_0_3.
*/
int (*lockAsync_ycbcr)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
struct android_ycbcr *ycbcr, int fenceFd);
/* reserved for future use */
void* reserved_proc[3];
} gralloc_module_t;
gralloc_module_t看着很长,其实嘛,被注释占了太多空间了,这里我们先仅仅关注common这个变量。它就是struct hw_module_t类型的。那就没错了,我们猜想是对的。
在具体加载hal库的时候,HAL作了这样的事。
hw_module_t 被 gralloc_module_t 继承,然后 gralloc_module_t 被 private_module_t 继承。
这应该是为了区分不同厂商对应的hal库所采取的对应措施。
这样一来,在gralloc库编译出来后,会通过hardware中的hw_get_module方式去加载(通过匹配ID值的方式。上面跟踪的ID就是这个)。
分析完gralloc.default.so库的具体加载。既然知道Android系统中是通过这个库来操作fb,那么来看看它提供的一些接口
Gralloc.c本身提供的接口应该就一个了。可以看到之前hardware中struct hw_module_methods_t必须注册的一个函数–open
在这里即是gralloc_device_open
static struct hw_module_methods_t gralloc_module_methods = {
.open = 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设备
...
} else {
status = fb_device_open(module, name, device);//打开fb设备
}
return status;
}
可以看到这里即是gralloc会根据设备名判断是打开什么(gralloc设备还是fb设备)
另外可以看到,上面提到的gralloc_module_t里面除了继承了struct hw_module_t的变量common,同时还有一些接口函数。
registerBuffer,unregisterBuffer,loc和unlock。它们分别在gralloc.c中以gralloc_register_buffer,gralloc_unregister_buffer,gralloc_lock和gralloc_unlock注册实现。根据函数名可大致得到这些应该是针对buffer做一些操作的。
那趁热打铁,先看看gralloc模块对gralloc设备的打开过程:
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; //分配alloc_device_t (用gralloc_context_t 包装起来) 空间,这是一个“壳”
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(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;//从提供的接口来看,gralloc主要负责图形缓冲区“分配和释放”的操作
*device = &dev->device.common;
status = 0;
} else {
......
}
return status;
}
struct gralloc_context_t {
alloc_device_t device;
/* our private data here */
};
接下来看看fb设备的打开流程,相对gralloc设备的打开流程要稍许复杂:
谈到fb设备的打开流程,就要联系到framebuffer.cpp了。
既然在gralloc模块中是通过fb_device_open进行操作。
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)); //同上面gralloc设备打开类似,这里fb_context_t是包装了framebuffer_device_t结构体,framebuffer_device_t是framebuffer中内部类,声明在fb.h中,后面单独分析
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(module);
dev->device.common.close = fb_close; //fb_close,fb_setSwapInterval,fb_post这几个接口是fb设备的核心
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)
? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888)
: HAL_PIXEL_FORMAT_RGB_565;
const_cast(dev->device.flags) = 0;
const_cast(dev->device.width) = m->info.xres;
const_cast(dev->device.height) = m->info.yres;
const_cast(dev->device.stride) = stride;
const_cast(dev->device.format) = format;
const_cast(dev->device.xdpi) = m->xdpi;
const_cast(dev->device.ydpi) = m->ydpi;
const_cast(dev->device.fps) = m->fps;
const_cast(dev->device.minSwapInterval) = 1;
const_cast(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common; //“壳”与“核心”的关系
}
}
return status;
}
struct fb_context_t {
framebuffer_device_t device;
};
一个标准的fb设备通常要提供一些“标准”的接口,这些接口声明在fb.h中framebuffer_device_t结构体中。
typedef struct framebuffer_device_t {
/**
* Common methods of the framebuffer device. This *must* be the first member of
* framebuffer_device_t as users of this structure will cast a hw_device_t to
* framebuffer_device_t pointer in contexts where it's known the hw_device_t references a
* framebuffer_device_t.
*/
struct hw_device_t common;
/* flags describing some attributes of the framebuffer */
const uint32_t flags;
/* dimensions of the framebuffer in pixels */
const uint32_t width;
const uint32_t height;
/* frambuffer stride in pixels */
const int stride;
/* framebuffer pixel format */
const int format;
/* resolution of the framebuffer's display panel in pixel per inch*/
const float xdpi;
const float ydpi;
/* framebuffer's display panel refresh rate in frames per second */
const float fps;
/* min swap interval supported by this framebuffer */
const int minSwapInterval;
/* max swap interval supported by this framebuffer */
const int maxSwapInterval;
/* Number of framebuffers supported*/
const int numFramebuffers;
int reserved[7];
/*
* requests a specific swap-interval (same definition than EGL)
*
* Returns 0 on success or -errno on error.
*/
int (*setSwapInterval)(struct framebuffer_device_t* window,
int interval);
/*
* This hook is OPTIONAL.
*
* It is non NULL If the framebuffer driver supports "update-on-demand"
* and the given rectangle is the area of the screen that gets
* updated during (*post)().
*
* This is useful on devices that are able to DMA only a portion of
* the screen to the display panel, upon demand -- as opposed to
* constantly refreshing the panel 60 times per second, for instance.
*
* Only the area defined by this rectangle is guaranteed to be valid, that
* is, the driver is not allowed to post anything outside of this
* rectangle.
*
* The rectangle evaluated during (*post)() and specifies which area
* of the buffer passed in (*post)() shall to be posted.
*
* return -EINVAL if width or height <=0, or if left or top < 0
*/
int (*setUpdateRect)(struct framebuffer_device_t* window,
int left, int top, int width, int height);
/*
* Post to the display (display it on the screen)
* The buffer must have been allocated with the
* GRALLOC_USAGE_HW_FB usage flag.
* buffer must be the same width and height as the display and must NOT
* be locked.
*
* The buffer is shown during the next VSYNC.
*
* If the same buffer is posted again (possibly after some other buffer),
* post() will block until the the first post is completed.
*
* Internally, post() is expected to lock the buffer so that a
* subsequent call to gralloc_module_t::(*lock)() with USAGE_RENDER or
* USAGE_*_WRITE will block until it is safe; that is typically once this
* buffer is shown and another buffer has been posted.
*
* Returns 0 on success or -errno on error.
*/
int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
/*
* The (*compositionComplete)() method must be called after the
* compositor has finished issuing GL commands for client buffers.
*/
int (*compositionComplete)(struct framebuffer_device_t* dev);
/*
* This hook is OPTIONAL.
*
* If non NULL it will be caused by SurfaceFlinger on dumpsys
*/
void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);
/*
* (*enableScreen)() is used to either blank (enable=0) or
* unblank (enable=1) the screen this framebuffer is attached to.
*
* Returns 0 on success or -errno on error.
*/
int (*enableScreen)(struct framebuffer_device_t* dev, int enable);
void* reserved_proc[6];
} framebuffer_device_t;
这里可以看到,该结构体中包含了(继承了)结构体struct hw_device_t。这个是之前在hardware.h中提到的的三个重要结构体之一。该结构体包含了设备的一些信息。如fb0这里就包含了width,height等信息,同时还提供了上面提到的一些“标准”的接口。
/*
* requests a specific swap-interval (same definition than EGL)
请求特定的交换间隔(与EGL相同的定义)
* Returns 0 on success or -errno on error.
*/
int (*setSwapInterval)(struct framebuffer_device_t* window,
int interval); //设置两个缓冲区交换的时间间隔
/*
这个钩子是可选的。
它是非NULL如果帧缓冲驱动程序支持“按需更新”,则给定的矩形是在(* post)()期间更新的屏幕区域。
这对于能够根据需要仅将屏幕的一部分DMA显示到显示面板的设备非常有用 - 例如,与每秒60次不断刷新面板相反。仅此矩形定义的区域保证 是有效的,也就是说,不允许司机在这个矩形之外张贴任何东西。
在(* post)()期间评估的矩形,并指定要传递的缓冲区的哪个区域(* post)()。
*
* return -EINVAL if width or height <=0, or if left or top < 0
*/
int (*setUpdateRect)(struct framebuffer_device_t* window,
int left, int top, int width, int height); //设置刷新区域,需要framebuffer驱动支持“update-on-demand”,也就是说,在这个区域外的数据很可能被认为无效
/*
将发布到显示屏上(在屏幕上显示)必须使用GRALLOC_USAGE_HW_FB使用标志分配缓冲区。 缓冲区必须与显示屏的宽度和高度相同,不得锁定。
缓冲区在下一个VSYNC期间显示。
如果再次发布相同的缓冲区(可能在一些其他缓冲区之后),post()将阻塞直到第一个帖子完成。在内部,post()应该锁定缓冲区,以便后续调用gralloc_module_t ::(* 锁定)()USAGE_RENDER或USAGE _ * _ WRITE将阻塞,直到它安全为止; 通常一旦显示此缓冲区并且已发布另一个缓冲区。
* Returns 0 on success or -errno on error.
*/
int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer); //将buffer数据post到显示屏上。要求buffer必须与屏幕尺寸一致,并且没有被locked。这样buffer内容将在下一次VSYNC中被显示出来。
这里再来分析下framebuffer_device_t中比较重要的成员变量。
变量 | 描述 |
---|---|
const uint32_t flags; | 标志位,指示framebuffer的属性配置 |
const uint32_t width;const uint32_t height; | framebuffer的宽和高,以像素为单位 |
const uint32_t flags; | 标志位,指示framebuffer的属性配置 |
const int format; | framebuffer的像素格式,比如:HAL_PIXEL_FORMAT_RGBA_8888HAL_PIXEL_FROMAT_RGBX_8888 HAL_PIXEL_FORMAT_RGB_888 HAL_PIXEL_RGB_565等 |
const float xdpi;const float ydpi; | x和y轴的密度(dot per inch) |
const float fps; | 屏幕的每秒刷新率。假如无法从设备获取这个值,Android系统会默认设置为60Hz |
const int minSwapInterval;const int maxSwapInterval; | 该framebuffer支持的最小和最大缓冲交换时间 |
刚刚在分析fb设备打开流程中有重点注释到一个函数mapFrameBuffer();这个函数即是Android系统如何打开Kernel层的fb设备以及如何对fb设备进行配置的。
源码前熟悉:
在应用程序中,操作/dev/fb的一般步骤如下:
1.打开/dev/fb设备文件。
2.用 ioctrl 操作取得当前显示屏幕的参数,如屏幕分辨率,每个像素点的比特数。根据屏幕参数可计算屏幕缓冲区的大小。
3.将屏幕缓冲区映射到用户空间(mmap)。
4.映射后就可以直接读写屏幕缓冲区,进行绘图和图片显示了。
static int mapFrameBuffer(struct private_module_t* module)
{
pthread_mutex_lock(&module->lock); //线程上锁
int err = mapFrameBufferLocked(module); //实际调用了这个
pthread_mutex_unlock(&module->lock);//线程解锁
return err;
}
int mapFrameBufferLocked(struct private_module_t* module)
{
// already initialized...
if (module->framebuffer) { //确保module buffer是否存在
return 0;
}
char const * const device_template[] = { //kernel fb设备的路径
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };
int fd = -1;
int i=0;
char name[64];
while ((fd==-1) && device_template[i]) { //循环打开device_template,即kernel中fb设备可能存在的路径
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0); //读写方式打开
i++;
}
if (fd < 0) //可能存在的路径,没有一个能打开的,直接返回
return -errno;
//FBIOGET_VSCREENINFO:获取framebuffer可变信息参数,比如屏幕分辨率,像素格式等。
//FBIOPUT_VSCREENINFO:设置framebuffer的分辨率,像素格式
//FBIOGET_FSCREENINFO:获取framebuffer固定信息参数,包括显存起始物理地址、显存大小和行间距等。
struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) //获取fb_var_screeninfo结构的信息,在linux/include/linux/fb.h定义。 存储在 finfo
return -errno;
struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) //获取fb_fix_screeninfon结构的信息。在linux/include/linux/fb.h定义。 存储在 info
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) 请求NUM_BUFFERS个屏幕(页面翻转至少2个)
*/
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
#if USE_PAN_DISPLAY //USE_PAN_DISPLAY为0
if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
ALOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
#else
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { //走这 设置framebuffer的分辨率,像素格式
ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
#endif
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
}
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) //获取fb_fix_screeninfon结构的信息。
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) */
// 请注意,info.pixclock在仿真时可能为0,因此请避免在此处进行0分频(ARM上的SIGFPE)
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
if (refreshRate == 0) { //默认刷新率为60Hz
// 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) //获取framebuffer固定信息参数,包括显存起始物理地址、显存大小和行间距等
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;
}
注意:mapFrameBuffer/mapFrameBufferLocked 除了打开fb设备和配置fb设备。还有个重要任务就是为fb设备做内存映射。
从mapFrameBufferLocked中截选
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);
由上述代码可知,映射地址保存在 module->framebuffer->base。变量module对应的是前面hw_get_module(GRALLOC_HARDWARE_MODULE_ID,&module)得到的hw_module_t(被强制类型转换为private_module_t)
即:module->framebuffer->base ==》 private_module_t->private_handle_t*->uint64_t base attribute((aligned(8)));
关于Android系统中HAL层是如何打开配置操作fb,总结下大概作了这些事。
编译生成gralloc.default.so.上层通过该库调用module必须注册的open方法进行打开操作,打开操作根据设备名判断打开gralloc(gpu0)设备还是fb设备。
gralloc(gpu0)设备中管理着图形缓冲区的分配和释放。
fb设备中对fb设备有着post、setSwapInterval、setUpdateRect等操作。
Linux的帧缓冲设备
framebuffer缓冲帧/dev/fb0学习
FBIOPAN_DISPLAY和MSMFB_DISPLAY_COMMIT刷屏流程
android display框架与数据流