Android图形显示之硬件抽象层Gralloc

蹉跎莫遣韶光老,人生唯有读书好。这篇文章主要讲述Android图形显示之硬件抽象层Gralloc相关的知识,希望能为你提供帮助。
https://blog.csdn.net/yangwen123/article/details/12192401
 
FrameBuffer驱动程序分析文中介绍了Linux系统下的显示驱动框架,每个显示屏被抽象为一个帧缓冲区,注册到FrameBuffer模块中,并在/dev/graphics目录下创建对应的fbX设备。android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。最后,用户空间中的应用程序就通过fb设备来将已经准备好了的图形缓冲区渲染到帧缓冲区中去,即将图形缓冲区的内容绘制到显示屏中去。相应地,当用户空间中的应用程序不再需要使用一块图形缓冲区的时候,就可以通过gralloc设备来释放它,并且将它从地址空间中解除映射。
 
Gralloc模块实现源码位于:hardware/libhardware/modules/gralloc
├── Android.mk
├── framebuffer.cpp
├── gralloc.cpp
├── gralloc_priv.h
├── gr.h
└── mapper.cpp
 
Android硬件抽象Hardware库加载过程源码分析介绍了Android系统中的硬件抽象层模块的加载过程,并指出每个硬件抽象层模块都必须定义HAL_MODULE_INFO_SYM符号,并且有自己唯一的ID,Gralloc也不例外,Gralloc模块ID定义为:

1 #define GRALLOC_HARDWARE_MODULE_ID "gralloc"

 
同时定义了以HAL_MODULE_INFO_SYM为符号的类型为private_module_t的结构体:
hardware\\libhardware\\modules\\gralloc\\gralloc.cpp
1 static struct hw_module_methods_t gralloc_module_methods = { 2open: gralloc_device_open 3 }; 4 struct private_module_t HAL_MODULE_INFO_SYM = { 5base: { 6common: { 7tag: HARDWARE_MODULE_TAG, 8version_major: 1, 9version_minor: 0, 10id: GRALLOC_HARDWARE_MODULE_ID, 11name: "Graphics Memory Allocator Module", 12author: "The Android Open Source Project", 13methods: & gralloc_module_methods 14}, 15registerBuffer: gralloc_register_buffer, 16unregisterBuffer: gralloc_unregister_buffer, 17lock: gralloc_lock, 18unlock: gralloc_unlock, 19}, 20framebuffer: 0, 21flags: 0, 22numBuffers: 0, 23bufferMask: 0, 24lock: PTHREAD_MUTEX_INITIALIZER, 25currentBuffer: 0, 26 };

  通过Android硬件抽象Hardware库加载过程源码分析的方法将Gralloc模块加载到内存中来之后,就可以调用函数dlsym来获得它所导出的符号HMI,得到private_module_t的首地址后,由于private_module_t的第一个成员变量的类型为gralloc_module_t,因此也是gralloc_module_t的首地址,由于gralloc_module_t的第一个成员变量类型为hw_module_t,因此也是hw_module_t的首地址,因此只要得到这三种类型中其中一种类型变量的地址,就可以相互转换为其他两种类型的指针。
 
数据结构定义在分析Gralloc模块之前,首先介绍Gralloc模块定义的一些数据结构。private_module_t用于描述Gralloc模块下的系统帧缓冲区信息
1 struct private_module_t { 2gralloc_module_t base; 3private_handle_t* framebuffer; //指向系统帧缓冲区的句柄 4uint32_t flags; //用来标志系统帧缓冲区是否支持双缓冲 5uint32_t numBuffers; //表示系统帧缓冲区包含有多少个图形缓冲区 6uint32_t bufferMask; //记录系统帧缓冲区中的图形缓冲区的使用情况 7pthread_mutex_t lock; //一个互斥锁,用来保护结构体private_module_t的并行访问 8buffer_handle_t currentBuffer; //用来描述当前正在被渲染的图形缓冲区 9int pmem_master; 10void* pmem_master_base; 11struct fb_var_screeninfo info; //保存设备显示屏的动态属性信息 12struct fb_fix_screeninfo finfo; ////保存设备显示屏的固定属性信息 13float xdpi; //描述设备显示屏在宽度 14float ydpi; //描述设备显示屏在高度 15float fps; //用来描述显示屏的刷新频率 16 };

 
  framebuffer_device_t用来描述系统帧缓冲区设备的信息
1 typedef struct framebuffer_device_t { 2struct hw_device_t common; 3const uint32_tflags; //用来记录系统帧缓冲区的标志 4const uint32_twidth; //用来描述设备显示屏的宽度 5const uint32_theight; //用来描述设备显示屏的高度 6const intstride; //用来描述设备显示屏的一行有多少个像素点 7const intformat; //用来描述系统帧缓冲区的像素格式 8const floatxdpi; //用来描述设备显示屏在宽度上的密度 9const floatydpi; //用来描述设备显示屏在高度上的密度 10const floatfps; //用来描述设备显示屏的刷新频率 11const intminSwapInterval; //用来描述帧缓冲区交换前后两个图形缓冲区的最小时间间隔 12const intmaxSwapInterval; //用来描述帧缓冲区交换前后两个图形缓冲区的最大时间间隔 13int reserved[8]; //保留 14//用来设置帧缓冲区交换前后两个图形缓冲区的最小和最大时间间隔 15int (*setSwapInterval)(struct framebuffer_device_t* window,int interval); 16//用来设置帧缓冲区的更新区域 17int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height); 18//用来将图形缓冲区buffer的内容渲染到帧缓冲区中去 19int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer); 20//用来通知fb设备,图形缓冲区的组合工作已经完成 21int (*compositionComplete)(struct framebuffer_device_t* dev); 22void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len); 23int (*enableScreen)(struct framebuffer_device_t* dev, int enable); 24//保留 25void* reserved_proc[6]; 26 } framebuffer_device_t

  gralloc_module_t用于描述gralloc模块信息
1 typedef struct gralloc_module_t { 2struct hw_module_t common; 3//映射一块图形缓冲区到一个进程的地址空间去 4int (*registerBuffer)(struct gralloc_module_t const* module,buffer_handle_t handle); 5//取消映射一块图形缓冲区到一个进程的地址空间去 6int (*unregisterBuffer)(struct gralloc_module_t const* module,buffer_handle_t handle); 7//锁定一个指定的图形缓冲区 8int (*lock)(struct gralloc_module_t const* module,buffer_handle_t handle, int usage, 9int l, int t, int w, int h,void** vaddr); 10//解锁一个指定的图形缓冲区 11int (*unlock)(struct gralloc_module_t const* module,buffer_handle_t handle); 12int (*perform)(struct gralloc_module_t const* module,int operation, ... ); 13void* reserved_proc[7]; 14 } gralloc_module_t;

alloc_device_t用于描述gralloc设备的信息
1 typedef struct alloc_device_t { 2struct hw_device_t common; 3//用于分配一块图形缓冲区 4int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride); 5//用于释放指定的图形缓冲区 6int (*free)(struct alloc_device_t* dev,buffer_handle_t handle); 7void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len); 8void* reserved_proc[7]; 9 } alloc_device_t;

 
 
Android图形显示之硬件抽象层Gralloc

文章图片
 
1 typedef struct hw_module_t { 2uint32_t tag; //标签 3uint16_t version_major; //模块主设备号 4uint16_t version_minor; //模块次设备号 5const char *id; //模块ID 6const char *name; //模块名称 7const char *author; //模块作者 8struct hw_module_methods_t* methods; //模块操作方法 9void* dso; //保存模块首地址 10uint32_t reserved[32-7]; //保留位 11 } hw_module_t;

硬件抽象层Gralloc模块定义了设备fb和设备gpu:
1 #define GRALLOC_HARDWARE_FB0 "fb0" 2 #define GRALLOC_HARDWARE_GPU0 "gpu0"

 
 
Android图形显示之硬件抽象层Gralloc

文章图片
 
设备gpu用于分配图形缓冲区,而设备fb用于渲染图形缓冲区;hw_module_t用于描述硬件抽象层Gralloc模块,而hw_device_t则用于描述硬件抽象层Gralloc设备,通过硬件抽象层设备可以找到对应的硬件抽象层模块。在Gralloc模块中,无论是定义fb设备还是gpu设备,都是用来处理图形缓冲区,以下是关于缓冲区的数据结构 定义:
 
private_handle_t用来描述一块缓冲区,Android对缓冲区的定义提供了C和C++两种方式,C语言编译器下的定义:
1 struct private_handle_t { 2struct native_handle nativeHandle; 3enum { 4PRIV_FLAGS_FRAMEBUFFER = 0x00000001 5}; 6intfd; //指向一个文件描述符,这个文件描述符要么指向帧缓冲区设备,要么指向一块匿名共享内存 7intmagic; 8intflags; //用来描述一个缓冲区的标志,当一个缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER的时候,就表示它是在帧缓冲区中分配的。 9intsize; //用来描述一个缓冲区的大小 10intoffset; //用来描述一个缓冲区的偏移地址 11intbase; //用来描述一个缓冲区的实际地址 12intpid; //用来描述一个缓冲区的创建者的PID 13 };

C++编译器下的定义:
1 struct private_handle_t : public native_handle { 2enum { 3PRIV_FLAGS_FRAMEBUFFER = 0x00000001 4}; 5intfd; //指向一个文件描述符,这个文件描述符要么指向帧缓冲区设备,要么指向一块匿名共享内存 6intmagic; //指向一个魔数,它的值由静态成员变量sMagic来指定,用来标识一个private_handle_t结构体。 7intflags; //用来描述一个缓冲区的标志,它的值要么等于0,要么等于PRIV_FLAGS_FRAMEBUFFER 8intsize; //用来描述一个缓冲区的大小。 9intoffset; //用来描述一个缓冲区的偏移地址。 10intbase; //用来描述一个缓冲区的实际地址,它是通过成员变量offset来计算得到的。 11intpid; //用来描述一个缓冲区的创建者的PID。 12static const int sNumInts = 6; //包含有6个整数 13static const int sNumFds = 1; //包含有1个文件描述符 14static const int sMagic = 0x3141592; 15 };

 
  两种编译器下的private_handle_t定义都继承于native_handle,native_handle的定义如下:
1 typedef struct native_handle 2 { 3int version; //设置为结构体native_handle_t的大小,用来标识结构体native_handle_t的版本 4int numFds; //表示结构体native_handle_t所包含的文件描述符的个数,这些文件描述符保存在成员变量data所指向的一块缓冲区中。 5int numInts; //表示结构体native_handle_t所包含的整数值的个数,这些整数保存在成员变量data所指向的一块缓冲区中。 6int data[0]; //指向的一块缓冲区中 7 } native_handle_t; 8 typedef const native_handle_t* buffer_handle_t;

 
Android图形显示之硬件抽象层Gralloc

文章图片
Gralloc模块的打开过程在Android硬件抽象Hardware库加载过程源码分析中详细分析过了,下面就分析Gralloc模块中定义了两种设备的打开过程。
 
Android图形显示之硬件抽象层Gralloc

文章图片

 
 
Fb设备打开过程fb设备的ID值定义为#defineGRALLOC_HARDWARE_FB0"fb0",fb设备使用结构体framebuffer_device_t来描述。结构体framebuffer_device_t是用来描述系统帧缓冲区的信息
  hardware\\libhardware\\include\\hardware\\fb.h
1 framebuffer_open(const struct hw_module_t* module, 2struct framebuffer_device_t** device) { 3return module-> methods-> open(module,GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device); 4 }

 
  module指向的是一个用来描述Gralloc模块的hw_module_t结构体,前面提到,它的成员变量methods所指向的一个hw_module_methods_t结构体的成员函数open指向了Gralloc模块中的函数gralloc_device_open 
 
hardware\\libhardware\\modules\\gralloc\\gralloc.cpp
gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device) { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { ... } else { status = fb_device_open(module, name, device); } return status; }

 
  gralloc_device_open函数即可以打开fb设备,也可以用于打开gpu设备,这里根据设备名来区分打开的设备,对应fb设备,则调用fb_device_open函数来完成设备打开操作。 
hardware\\libhardware\\modules\\gralloc\\framebuffer.cpp
1 int fb_device_open(hw_module_t const* module, const char* name, 2hw_device_t** device) 3 { 4int status = -EINVAL; 5//判断打开的是fb设备 6if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { 7alloc_device_t* gralloc_device; 8//打开gpu设备 9status = gralloc_open(module, & gralloc_device); 10if (status < 0) 11return status; 12//创建一个fb_context_t对象,用来描述fb设备上下文 13fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev)); 14memset(dev, 0, sizeof(*dev)); 15//初始化fb_context_t对象 16dev-> device.common.tag = HARDWARE_DEVICE_TAG; 17dev-> device.common.version = 0; 18dev-> device.common.module = const_cast< hw_module_t*> (module); 19//注册fb设备的操作函数 20dev-> device.common.close = fb_close; 21dev-> device.setSwapInterval = fb_setSwapInterval; 22dev-> device.post= fb_post; 23dev-> device.setUpdateRect = 0; 24 25private_module_t* m = (private_module_t*)module; 26//将fb映射到当前进程地址空间 27status = mapFrameBuffer(m); 28if (status > = 0) { 29int stride = m-> finfo.line_length / (m-> info.bits_per_pixel > > 3); 30int format = (m-> info.bits_per_pixel == 32) 31? HAL_PIXEL_FORMAT_RGBX_8888 32: HAL_PIXEL_FORMAT_RGB_565; 33const_cast< uint32_t& > (dev-> device.flags) = 0; 34const_cast< uint32_t& > (dev-> device.width) = m-> info.xres; 35const_cast< uint32_t& > (dev-> device.height) = m-> info.yres; 36const_cast< int& > (dev-> device.stride) = stride; 37const_cast< int& > (dev-> device.format) = format; 38const_cast< float& > (dev-> device.xdpi) = m-> xdpi; 39const_cast< float& > (dev-> device.ydpi) = m-> ydpi; 40const_cast< float& > (dev-> device.fps) = m-> fps; 41const_cast< int& > (dev-> device.minSwapInterval) = 1; 42const_cast< int& > (dev-> device.maxSwapInterval) = 1; 43*device = & dev-> device.common; 44} 45} 46return status; 47 }

这个函数主要是用来创建一个fb_context_t结构体,并且对它的成员变量device进行初始化。结构体fb_context_t的成员变量device的类型为framebuffer_device_t,它是用来描述fb设备的。fb设备主要是用来渲染图形缓冲区的,这是通过调用它的成员函数post来实现的。函数fb_device_open所打开的fb设备的成员函数post被设置为Gralloc模块中的函数fb_post。函数mapFrameBuffer除了用来获得系统帧缓冲区的信息之外,还会将系统帧缓冲区映射到当前进程的地址空间来。line_length用来描述显示屏一行像素总共所占用的字节数,bits_per_pixel用来描述显示屏每一个像素所占用的位数,bits_per_pixel的值向右移3位,就可以得到显示屏每一个像素所占用的字节数。用显示屏像素总共所占用的字节数line_length除以每一个像素所占用的字节数就可以得到显示屏一行有多少个像素点,并保存在stride中。
1 stride = line_length / ( bits_per_pixel > > 3)

1 static int mapFrameBuffer(struct private_module_t* module) 2 { 3pthread_mutex_lock(& module-> lock); 4int err = mapFrameBufferLocked(module); 5pthread_mutex_unlock(& module-> lock); 6return err; 7 }

 
 
  调用mapFrameBufferLocked函数执行映射过程,该函数在线程保护下完成。
 
【Android图形显示之硬件抽象层Gralloc】 
1 int mapFrameBufferLocked(struct private_module_t* module) 2 { 3// already initialized... 4if (module-> framebuffer) { 5return 0; 6} 7char const * const device_template[] = { 8"/dev/graphics/fb%u", 9"/dev/fb%u", 100 }; 11 12int fd = -1; 13int i=0; 14char name[64]; 15//检查是否存在设备文件/dev/graphics/fb0或者/dev/fb0。如果存在的话,那么就调用函数open来打开它,并且将得到的文件描述符保存在变量fd中 16while ((fd==-1) & & device_template[i]) { 17snprintf(name, 64, device_template[i], 0); 18fd = open(name, O_RDWR, 0); 19i++; 20} 21if (fd < 0) 22return -errno; 23//通过IO控制命令FBIOGET_FSCREENINFO来获得系统帧缓冲区的固定信息,保存在fb_fix_screeninfo结构体finfo中 24struct fb_fix_screeninfo finfo; 25if (ioctl(fd, FBIOGET_FSCREENINFO, & finfo) == -1) 26return -errno; 27//通过IO控制命令FBIOGET_VSCREENINFO来获得系统帧缓冲区的可变信息,保存在fb_var_screeninfo结构体info中 28struct fb_var_screeninfo info; 29if (ioctl(fd, FBIOGET_VSCREENINFO, & info) == -1) 30return -errno; 31//初始化info 32info.reserved[0] = 0; 33info.reserved[1] = 0; 34info.reserved[2] = 0; 35info.xoffset = 0; 36info.yoffset = 0; 37info.activate = FB_ACTIVATE_NOW; 38//fb_var_screeninfo的成员变量xres和yres用来描述显示屏的可视分辨率,而成员变量xres_virtual和yres_virtual用来描述显示屏的虚拟分辨率。 39//将虚拟分辨率的高度值设置为可视分辨率的高度值的NUM_BUFFERS倍。 40info.yres_virtual = info.yres * NUM_BUFFERS; //2 41uint32_t flags = PAGE_FLIP; 42//设置设备显示屏的虚拟分辨率 43if (ioctl(fd, FBIOPUT_VSCREENINFO, & info) == -1) { 44//设置失败,重新设置显示屏的虚拟分辨率 45info.yres_virtual = info.yres; 46flags & = ~PAGE_FLIP; 47ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported"); 48} 49if (info.yres_virtual < info.yres * 2) { 50// we need at least 2 for page-flipping 51info.yres_virtual = info.yres; 52flags & = ~PAGE_FLIP; 53ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",info.yres_virtual, info.yres*2); 54} 55//通过IO控制命令FBIOGET_VSCREENINFO来重新获得系统帧缓冲区的可变信息 56if (ioctl(fd, FBIOGET_VSCREENINFO, & info) == -1) 57return -errno; 58//计算设备显示屏的刷新频率 59uint64_trefreshQuotient = 60( 61uint64_t( info.upper_margin + info.lower_margin + info.yres )* ( info.left_margin+ info.right_margin + info.xres )* info.pixclock 62); 63//模拟器的info.pixclock=0,因此计算得到的refreshQuotient=0 64int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0; 65//如果是模拟器,设置刷新频率为60 Hz 66if (refreshRate == 0) { 67refreshRate = 60*1000;

    推荐阅读