转android gralloc流程分析for msm8960

时间:2022-01-23 03:57:40

原文转载自http://blog.csdn.net/g_salamander/article/details/8424334

增加了Gralloc模块的平台背景和功能概述部分。

对原文针对msm8960 android display做了修正。

增加了Surfaceflinger初始化FrameBufferNativeWindow的代码部分。

平台中内存有ashmen、PMEM等多种内存类型,为了Video、Graphics、GPU内存访问的需要,android引入Gralloc模块实现内存的管理。Gralloc把FrameBuffer的分配也纳入了其中,并且新引入ION做为Gralloc的非FrameBuffer内存的分配器。ION对于内核态内存在用户进程之间的访问和硬件平台模块之间数据流转提供了高效的解决方案。

Android 中 lcd 是一个帧缓冲设备,驱动程序通过处理器的 lcd 控制器将物理内存的一段区域设置为显存,如果向这段内存区域写入数据就会马上在 lcd 上显示出来。Android 在 HAL 中提供了gralloc 模块,封装了用户层对帧缓冲设备的所有操作接口,并通过 SurfaceFlinger 服务向应用提供显示支持。在启动过程中系统会加载 gralloc 模块,然后打开帧缓冲设备,获取设备的各种参数并完成 gralloc 模块的初始化。当应用程序需要把内容显示到 lcd 上时,需要通过 gralloc 模块申请一块图形缓冲区,然后将这块图形缓冲区映射到自己的地址空间并写入内容即可。当应用程序不再需要这块图形缓冲区时需要通过 gralloc 模块释放掉,然后解除对缓冲区的映射。

1、基础数据结构

gralloc 模块通过 struct private_module_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; /* 保护结构体private_module_t的并行访问 */
buffer_handle_t currentBuffer; /* 描述当前正在被渲染的图形缓冲区 */
int pmem_master; /* pmem设备节点的描述符 */
void* pmem_master_base; /* pmem的起始虚拟地址 */

struct fb_var_screeninfo info; /* lcd的可变参数 */
struct fb_fix_screeninfo finfo; /* lcd的固定参数 */
float xdpi; /* x方向上每英寸的像素数量 */
float ydpi; /* y方向上每英寸的像素数量 */
float fps; /* lcd的刷新率 */

int orientation; /* 显示方向 */

enum {
PRIV_USAGE_LOCKED_FOR_POST = 0x80000000 /* flag to indicate we'll post this buffer */
};
};
该结构的成员记录了 gralloc 模块的各种参数,主要为模块自己使用,应用程序操作的图形缓冲区的数据结构是struct private_handle_t,定义如下:

图形缓冲区的操作接口由结构 struct gralloc_module_t 定义:

gralloc 设备则用结构 struct alloc_device_t 来描述,其定义如下:

帧缓冲设备则采用结构 struct framebuffer_device_t 描述: 其中成员函数 post对应用程序来说是最重要的接口,它将完成数据写入显存的工作。

2、gralloc 模块

HAL 中通过 hw_get_module 接口加载指定 id 的模块,并获得一个 hw_module_t 结构来打开设备,流程如下:  

可以看出,是使用id和系统平台的名字组合出so的文件名,去设定的目录动态加载该库文件然后解析特定符号,找到hw_module_t object

函数会在 /system/lib/hw 或者 /vendor/lib/hw 目录中去寻找gralloc.xxx.so 文件,如果找到了就调用load接口完成加载。

最终会调用 gralloc_device_open完成 gralloc 设备成员的初始化:

可以认为Gralloc module中有两个设备gpu_alloc_device和fb_device,前者用于分配GPU0使用的内存和FB内存,GPU0内存管理使用ION allocator;后者用于获取分配Framebuffer Info并操作fb。在 android 系统中,所有的图形缓冲区都是由 SurfaceFlinger服务分配的,在系统帧缓冲区中分配的图形缓冲区只在 SurfaceFlinger 服务中使用,而在内存中分配的图形缓冲区既可以在 SurfaceFlinger 服务中使用,也可以在其它的应用程序中使用,当应用程序请求 SurfaceFlinger 服务分配图形缓冲区时会发生两次映射:服务所在的进程首先会将申请到的缓冲区映射至服务的地址空间,然后应用程序使用这个图形缓冲时再将其映射至应用程序的地址空间。分配函数的实现如下: 3、gpu_alloc 模块gpu0内存即非HW_FB内存使用ION分配器进行分配,此文不做详述。 4、fb 模块

在 gralloc_device_open 中会根据传递的参数分别初始化两个设备,定义如下:

如果参数不是 "gpu0" ,那么是"fb%u"的形式,则会调用fb_device_open 初始化 fb 设备,主要流程和打开 gralloc 基本一致,在函数中会通过调用 mapFrameBuffer->mapFrameBufferLocked 获取帧缓存设备的参数并将其设备节点映射到用户空间,流程如下(大致如此,msm8960平台代码有所变化,msm平台上fb设备文件名是/dev/graphics/fb%u):

关于fb设备的打开和HW_FB内存的分配,是在FrameBufferNativeWindow的构造代码中,可以看到打开fb0设备获取Framebuffer Info,然后使用gralloc为该FrameBufferNativeWindow分配两个HW_FB内存即Framebuffer,即每个Window,double buffer。代码如下:

62/*
63 * This implements the (main) framebuffer management. This class is used
64 * mostly by SurfaceFlinger, but also by command line GL application.
65 *
66 * In fact this is an implementation of ANativeWindow on top of
67 * the framebuffer.
68 *
69 * Currently it is pretty simple, it manages only two buffers (the front and
70 * back buffer).
71 *
72 */
73
74FramebufferNativeWindow::FramebufferNativeWindow()
75 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
76{
77 hw_module_t const* module;
78 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
79 int stride;
80 int err;
81 int i;
82 err = framebuffer_open(module, &fbDev);
83 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
84
85 err = gralloc_open(module, &grDev);
86 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
87
88 // bail out if we can't initialize the modules
89 if (!fbDev || !grDev)
90 return;
91
92 mUpdateOnDemand = (fbDev->setUpdateRect != 0);
93
94 // initialize the buffer FIFO
95 if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
96 fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
97 mNumBuffers = fbDev->numFramebuffers;
98 } else {
99 mNumBuffers = MIN_NUM_FRAME_BUFFERS;
100 }
101 mNumFreeBuffers = mNumBuffers;
102 mBufferHead = mNumBuffers-1;
103
104 /*
105 * This does not actually change the framebuffer format. It merely
106 * fakes this format to surfaceflinger so that when it creates
107 * framebuffer surfaces it will use this format. It's really a giant
108 * HACK to allow interworking with buggy gralloc+GPU driver
109 * implementations. You should *NEVER* need to set this for shipping
110 * devices.
111 */
112#ifdef FRAMEBUFFER_FORCE_FORMAT
113 *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
114#endif
115
116 for (i = 0; i < mNumBuffers; i++)
117 {
118 buffers[i] = new NativeBuffer(
119 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
120 }
121
122 for (i = 0; i < mNumBuffers; i++)
123 {
124 err = grDev->alloc(grDev,
125 fbDev->width, fbDev->height, fbDev->format,
126 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
127
128 ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
129 i, fbDev->width, fbDev->height, strerror(-err));
130
131 if (err)
132 {
133 mNumBuffers = i;
134 mNumFreeBuffers = i;
135 mBufferHead = mNumBuffers-1;
136 break;
137 }
138 }
139
140 const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
141 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
142 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
143 const_cast<int&>(ANativeWindow::minSwapInterval) =
144 fbDev->minSwapInterval;
145 const_cast<int&>(ANativeWindow::maxSwapInterval) =
146 fbDev->maxSwapInterval;
147 } else {
148 ALOGE("Couldn't get gralloc module");
149 }
150
151 ANativeWindow::setSwapInterval = setSwapInterval;
152 ANativeWindow::dequeueBuffer = dequeueBuffer;
153 ANativeWindow::lockBuffer = lockBuffer;
154 ANativeWindow::queueBuffer = queueBuffer;
155 ANativeWindow::query = query;
156 ANativeWindow::perform = perform;
157 ANativeWindow::cancelBuffer = NULL;
158}


创建FrameBufferNativeWindow仅发生在DisplayHardware的构造后初始化中,代码片段如下:

150void DisplayHardware::init(uint32_t dpy)
151{
152 mNativeWindow = new FramebufferNativeWindow(); //******
153 framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
154 if (!fbDev) {
155 ALOGE("Display subsystem failed to initialize. check logs. exiting...");
156 exit(0);
157 }
158
159 int format;
160 ANativeWindow const * const window = mNativeWindow.get();
161 window->query(window, NATIVE_WINDOW_FORMAT, &format);
162 mDpiX = mNativeWindow->xdpi;
163 mDpiY = mNativeWindow->ydpi;
164 mRefreshRate = fbDev->fps;
....
}


而DisplayHardware的真正构造仅在Surfacelinger启动后readyToRun中,其余都是使用拷贝构造默认的Bitwise Copy,当然这仅仅是针对一块屏的情况,当前大屏主流。相关代码片段如下:

217status_t SurfaceFlinger::readyToRun()
218{
219 ALOGI( "SurfaceFlinger's main thread ready to run. "
220 "Initializing graphics H/W...");
221
222 // we only support one display currently
223 int dpy = 0;
224
225 {
226 // initialize the main display
227 GraphicPlane& plane(graphicPlane(dpy));
228 DisplayHardware* const hw = new DisplayHardware(this, dpy); //*******
229 plane.setDisplayHardware(hw);
230 }
231
232 // create the shared control-block
233 mServerHeap = new MemoryHeapBase(4096,
234 MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
235 ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
236
237 mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
238 ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
239
240 new(mServerCblk) surface_flinger_cblk_t;
241
242 // initialize primary screen
243 // (other display should be initialized in the same manner, but
244 // asynchronously, as they could come and go. None of this is supported
245 // yet).
246 const GraphicPlane& plane(graphicPlane(dpy));
247 const DisplayHardware& hw = plane.displayHardware();
248 const uint32_t w = hw.getWidth();
249 const uint32_t h = hw.getHeight();
250 const uint32_t f = hw.getFormat();
251 hw.makeCurrent();
.....
}

 

fb 模块最重要的工作就是将应用程序指定的内容写入显存中,是通过函数 fb_post完成的,流程如下(msm8960代码大致如此,不过使用的是FBIOPUT_VSCREENINFO IOCTL_CODE):

5、Gralloc map/unmap、register/unregister

当GPU内存file descriptor从一个进程A传递到另一个进程B后,进程B做gralloc_register_buffer就是使用allocator此时是ION将该buffer在本进程映射一下,用于访问。这些功能做为gralloc的mapper功能。

关于内存file descriptor、binder传递该内存fd的具体机制参见ION的功能。