- Android板级支持与硬件相关子系统
- 韩超等
- 2271字
- 2020-08-28 12:21:34
4.3 显示BSP的结构
Android显示部分的BSP支持,主要是硬件抽象层的grallloc模块和内核中的Framebuffer等驱动程序。
gralloc的含义为Graphics Allocation(图形分配),它位于框架层的通用部分和显示设备的驱动程序之间,作为显示硬件部分对上层的唯一接口。
gralloc有一个不同于其他硬件模块的地方,系统中必须有一个grallloc,否则系统无法正常启动。Android开源代码中已经实现的默认的gralloc模块名称为gralloc.default.so。它不仅是仿真器的实现,也适用于使用标准Framebuffer驱动的平台。
在某个硬件平台上,如果实现特定gralloc模块,其下层的显示设备就可以是各种类型的驱动程序。例如,对一个标准Framebuffer驱动程序实现带有优化的改动,增加一些ioctl命令来获得额外的控制;通过Android的pmem驱动等方式获得加速的效果。
↘4.3.1 Framebuffer驱动程序
在Linux中,Framebuffer驱动是标准的显示设备的驱动;对于PC系统,Framebuffer驱动是显卡的驱动;对于嵌入式系统的SOC处理器,Framebuffer通常作为其LCD控制器或者其他显示设备的驱动。
Framebuffer驱动是一个字符设备,这个驱动在文件系统中的设备节点通常是/dev/fbX。每个系统可以有多个显示设备,使用/dev/fb0、/dev/fb1等来表示。
提示:在Android中,Framebuffer驱动的设备节点在/dev/graphics目录中。
Framebuffer驱动是一个字符设备,主设备号为29,次设备号递增生成(由每个Framebuffer程序的注册顺序决定)。
Framebuffer显示驱动的架构如图4-2所示。
图4-2 Framebuffer显示驱动的架构
Framebuffer驱动在用户空间大多使用ioctl、mmap等文件系统的接口进行操作,ioctl用于获得和设置信息,mmap可以将Framebuffer的内存映射到用户空间。Framebuffer驱动也可以直接支持write操作,直接用写的方式输出显示内容。
Framebuffer驱动的主要头文件:include/linux/fb.h。
Framebuffer驱动核心实现:drivers/video/fbmem.c。
Framebuffer驱动中核心的数据接口是fb_info,在fb.h中定义:
struct fb_info { int node; int flags; struct fb_var_screeninfo var; // 显示屏变的信息 struct fb_fix_screeninfo fix; // 显示屏固定信息 // 省略部分成员 struct fb_ops *fbops; // framebuffer的操作指针集合 // 省略部分成员 };
struct fb_info包含了Framebuffer驱动的主要信息,struct fb_var_screeninfo和struct fb_fix_screeninfo是两个相关的数据结构。通常对应FBIOGET_VSCREENINFO和FBIOGET_FSCREENINFO这两个ioctl命令从用户空间获得的显示信息。fb_ops表示对Framebuffer的操作,由一系列函数指针组成。
在具体的Framebuffer驱动的实现中,通常通过以下函数进行注册和注销:
extern int register_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info);
Framebuffer的ioctl命令在include/linux/目录的fb.h文件中定义,如下所示:
#define FBIOGET_VSCREENINFO 0x4600 // 获得变化屏幕信息 #define FBIOPUT_VSCREENINFO 0x460l // 设置变化屏幕信息 #define FBIOGET_FSCREENINFO 0x4602 // 获得固定屏幕信息 #define FBIOGETCMAP 0x4604 // 获得映射内容 #define FBIOPUTCMAP 0x4605 // 设置映射内容 #define FBIOPAN_DISPLAY 0x4606 // 调整显示区域(虚拟显示-实际显示)
具体的Framebuffer驱动需要定义一个实现fb_info结构、实现fb_ops中的各个函数指针。从驱动程序的用户空间进行ioctl调用时,会转换成调用其中的函数。具体的Framebuffer驱动注册后,将会自动递增获得一个次设备号。
在配置Linux系统时,Framebuffer驱动的配置选项是:Device Drivers=>Graphics support。Framebuffer驱动中也包含了文本模式、控制台、启动图标(Bootup Logo)等子选项支持,具体的Framebuffer驱动由每一个平台支持。
Framebuffer驱动程序通常也支持用户空间的写操作,在系统中调试Framebuffer驱动程序,可以使用直接写驱动程序设备节点的方式,这样可以改变基本的显示情况。
例如,在Android中,可以使用如下的方式在Framebuffer中获得输出效果:
# cat init > /dev/graphics/fb0
如果屏幕大小是QVGA(640×480)的,按照以上操作,由于init文件的大小大约占到一个屏幕的显示缓冲的1/3,而init文件中的内容对于显示是杂乱的,因此可以观察到屏幕上1/3的花屏区域。
提示:如果当前Framebuffer驱动程序使用双缓冲显示方式,将会看到屏幕中交替显示的带有花屏和不带有花屏的内容,交替时间就是双缓冲刷新间隔时间。
进一步还可以使用dd命令进行指定大小的操作,如下所示:
# dd if=/dev/zero of=/dev/graphics/fb0 count=l bs=256k
命令表示向/dev/graphics/fb0设备中写入256k字节为0x0的内容,使用这个命令可以看到屏幕中的部分黑屏。
↘4.3.2 gralloc硬件抽象层
gralloc模块作为显示系统硬件抽象层,其接口的内容在gralloc.h文件中定义。此内容由实际的硬件抽象层实现,由UI库调用。
gralloc.h首先定义了一个硬件模块和两个子设备的名称,内容如下所示:
#define GRALLOC_HARDWARE_MODULE_ID "gralloc" // 硬件模块的名称 #define GRALLOC_HARDWARE_FB0 "fb0" // framebuffer设备和 #define GRALLOC_HARDWARE_GPU0 "gpu0" // GPU设备
其中,“gralloc”为这个硬件模块的名称,“fb0”和“gpu0”分别表示Framebuffer设备和GPU(Graphics Process Unit,图形处理单元)硬件设备。
gralloc硬件模块是扩展定义hw_module_t来完成的,定义如下所示:
typedef struct gralloc_module_t { struct hw_module_t common; int (*registerBuffer)(struct gralloc_module_t const* module, buffer_handle_t handle); int (*unregisterBuffer)(struct gralloc_module_t const* module, buffer_handle_t handle); int (*lock)(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr); int (*unlock)(struct gralloc_module_t const* module, buffer_handle_t handle); int (*perform)(struct gralloc_module_t const* module, int operation, ... ); void* reserved_proc[7]; } gralloc_module_t;
gralloc_module_t是模块的核心,其中的几个函数指针的功能如下所示。
·registerBuffer需要在alloc_device_t::alloc之前被调用,其参数类型buffer_handle_t是内存指针;unregisterBuffer用于注销此内存。
·lock用于访问特定访问缓冲区,在调用这个接口时,硬件设备需要结束渲染或者完成同步,其参数指定一个区域。unlock用于所有buffer改变之后被调用。
·perform用于可扩展的功能,Surflinger会调用它,但是其实现是可选的。
gralloc和Framebuffer两种设备的打开和关闭使用几个静态函数表示,如下所示:
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 gralloc_close(struct alloc_device_t* device) { return device->common.close(&device->common); } 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); } static inline int framebuffer_close(struct framebuffer_device_t* device) { return device->common.close(&device->common); }
gralloc_open()、gralloc_close ()、framebuffer_open ()和framebuffer_close ()这4个函数是gralloc模块特定的API。调用它们分别用于打开和关闭GRALLOC_HARDWARE_GPU0和GRALLOC_HARDWARE_FB0这两个设备。前者对应的设备为alloc_device_t结构体,后者对应的设备为framebuffer_device_t结构体。它们都“继承自”hw_device_t结构体。
alloc_device_t设备的定义如下所示:
typedef struct alloc_device_t { struct hw_device_t common; int (*alloc)(struct alloc_device_t* dev, // 分配,以宽、高、颜色格式为参数 int w, int h, int format, int usage, buffer_handle_t* handle, int* stride); int (*free)(struct alloc_device_t* dev, // 释放 buffer_handle_t handle); } alloc_device_t;
alloc函数指针用于分配一块显示内存,其参数包括宽、高、颜色格式和buffer_handle_t类型的句柄,free函数指针用于释放显示内存。
framebuffer_device_t结构的定义如下所示:
typedef struct framebuffer_device_t { struct hw_device_t common; const uint32_t flags; const uint32_t width; // 宽 const uint32_t height; // 高 const int stride; // 每行内容 const int format; // 颜色格式 const float xdpi; // X方向像素密度 const float ydpi; // Y方向像素密度 const float fps; // 帧率 const int minSwapInterval; const int maxSwapInterval; int reserved[8]; int (*setSwapInterval)(struct framebuffer_device_t* window, int interval); int (*setUpdateRect)(struct framebuffer_device_t* window, int left, int top, int width, int height); int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer); int (*compositionComplete)(struct framebuffer_device_t* dev); void* reserved_proc[8]; } framebuffer_device_t;
framebuffer_device_t设备中定义了几个通用的显示内存描述和几个函数指针,setSwapInterval用于交换显示区域;setUpdateRect用于更新指定的区域,这个函数是可选的;post用于发送某一个Buffer到屏幕上。