转载自 From LXS. http://blog.csdn.net/uiop78uiop78/
声明:本学习笔记来源是 http://blog.csdn.net/xuesen_lin/article/details/8954508 (林学森的csdn),本笔记仅供我个人总结和学习备用。
1. Gralloc与Framebuffer
Gralloc是一个模块,此模块负责gralloc和frambuffer两个设备,分别对应 gpu0和fb*,gpu0负责图形缓冲区的分配和释放,fb就是主屏幕。
frambuffer提供的设备文件节点是/gaphics/fb*,理论上支持多个屏幕显示,fb0为主显示屏。
Gralloc模块是由FramebufferNativeWindown在构造时加载的,其中 grDev和fbDev成员变量来管理gralloc和fb设备,在其构造函数中这两个设备分别用 gralloc_open(GRALLOC_HARDWARE_GPU0)和frambuffer_open(GRALLOC_HARDWARE_FB0)函数打开。然后调用到module_method的open函数来调用我们厂商根据各自平台实现的fb和gralloc的打开关闭和管理等函数指针。
static struct hw_module_methods_t gralloc_module_methods =
{
.open = gralloc_device_open //本函数内部是有厂商自己实现
};
<pre name="code" class="cpp">int gralloc_device_open(const hw_module_t* module, const char* name,hw_device_t** device)
{
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {//打开gralloc设备
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
} else{
fb_device_open(module, name, device);//否则就是fb设备
}
return status;
}
/*hardware/libhardware/modules/gralloc/Framebuffer.cpp*/
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)) {//设备名是否正确
fb_context_t *dev =(fb_context_t*)malloc(sizeof(*dev));//分配hw_device_t空间,这是一个“壳”
memset(dev, 0,sizeof(*dev));//初始化,良好的编程习惯
…
dev->device.common.close = fb_close;//这几个接口是fb设备的核心
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
…
private_module_t* m =(private_module_t*)module;
status = mapFrameBuffer(m);//内存映射,以及参数配置
if (status >= 0) {
…
*device =&dev->device.common;//“壳”和“核心”的关系
}
}
return status;
}
一个标准的fb设备通常要提供如下的函数实现:
Ø int(*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
将buffer数据post到显示屏上。要求buffer必须与屏幕尺寸一致,并且没有被locked。这样的话buffer内容将在下一次VSYNC中被显示出来
Ø int(*setSwapInterval)(struct framebuffer_device_t* window, int interval);
设置两个缓冲区交换的时间间隔
Ø int(*setUpdateRect)(struct framebuffer_device_t* window, int left, int top, int width, int height);
设置刷新区域,需要framebuffer驱动支持“update-on-demand”。也就是说在这个区域外的数据很可能被认为无效
2. Android中的本地窗口(NativeWindow)
至少需要两种本地窗口:
Ø 面向管理者(SurfaceFlinger) : FramebufferNativeWindow
既然SurfaceFlinger扮演了系统中所有UI界面的管理者,那么它需要直接或间接地持有“本地窗口”
Ø 面向应用程序 : SurfaceTextureClient
系统中存在多个应用程序时,从内存中为它们每个分配缓冲区空间,这样保证它们都获得一个本地窗口;
SufaceFlinger会手机所有程序的显示需求,然后对它们做统一的图像混合操作,再输出到自己的本地窗口(这种窗口是能直接显示在终端屏幕上的——它使用了帧缓冲区)。
这些本地窗口都可以与OPENGL ES绑定,使用OPENGL ES来完成复杂的界面渲染。
不论哪种本地窗口,都必须要与NativeWindowType保持一致,否则就无法正常使用EGL了/*frameworks/native/opengl/include/egl/Eglplatform.h*/,Android平台下使用的是ANativeWindow指针/*system/core/include/system/Window.h*/。
ANativeWindow结构体中:
setSwapInterval | 设置交换间隔时间,后面我们会讲解swap的作用 |
dequeueBuffer | EGL通过这个接口来申请一个buffer。以前面我们所举的例子来说,两个本地窗口所提供的buffer分别来自于帧缓冲区和内存空间。单词“dequeue”的字面意思是“出队列”,这从侧面告诉我们,一个Window所包含的buffer很可能不只一份 |
lockBuffer | 申请到的buffer并没有被锁定,这种情况下是不允许我们去修改其中的内容的。所以我们必须要先调用lockBuffer来获得一个锁 |
queueBuffer | 当EGL对一块buffer渲染完成后,它调用这个接口来unlock和post buffer |
query | 用于向本地窗口咨询相关信息 |
FramebufferNativeWindow继承ANativeWindow,会将其成员函数填充到ANativeWindow中的函数指针中,比如,
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
这样子OpenGL ES才能通过一个ANativeWindow来正确地与本地窗口建立连接。
FramebufferNativeWindow构造函数中grDev->alloc 申请的usage类型是GRALLOC_USAGE_HW_FB,表示缓冲区用于framebuffer设备
针对应用程序端的本地窗口是SurfaceTextureClient,和FramebufferNativeWindow一样,它必须继承ANativeWindow,SurfaceTextureClient是面向Android系统中所有UI应用程序的,也就是说它承担着单个应用进程中的UI显示需求。SurfaceTextureClient提供给上层(主要是java层)绘制图像的“画板”,然后SurfaceFlinger需要收集系统中所有应用程序绘制的图像数据,然后集中显示到物理屏幕上。
为应用程序服务的本地窗口SurfaceTextureClient在server端的实现是BufferQueue。