2012年8月2日 星期四

探討 Android gralloc HAL – part 1


整個 Android 2.2的圖型模組, 不論是 2D, 3D應用程式運行, 只要是圖形相關的應用, 都需要配置 graphic buffer, 在 Android 中負責這工作的模組就是 gralloc HAL(gralloc 硬體抽象層).

Gralloc HAL 的程式碼在 /hardware/libhardware/modules/gralloc/Gralloc.cpp
動態連結庫 gralloc.default.so 位置在系統路徑 /system/lib/hw/





請看到 /frameworks/base/libs/SurfaceFlinger.cpp 的 readyToRun() 函式, Android SurfaceFlinger在這個函式裡初始化繪圖硬體. 在 readyToRun() 生成 DisplayHardware 物件時, DisplayHardware 的建構式會調用 Init() 函式, Init() 會生成FramebufferNativeWindow 物件, class FramebufferNativeWindow 的程式碼位於 :
/frameworks/base/libs/ui/FramebufferNativeWindow.cpp
/frameworks/base/include/ui/FramebufferNativeWindow.h

FramebufferNativeWindow物件的建構式做了幾件事情:

1. 調用 hw_get_module (GRALLOC_HARDWARE_MODULE_ID, &module)函式

    在 hw_get_module()中調用dlopen()打開 gralloc.default.so並調用 dlsym()取得
     gralloc 模組的資訊(HMI), 此資訊用 hw_module_t 結構體存放:
     hw_module_t 定義在 /hardware/libhardware/include/hardware/Hardware.h Source2.cpp
01 typedef struct hw_module_t {
02 /** tag must be initialized to HARDWARE_MODULE_TAG */
03 uint32_t tag;
04 /** major version number for the module */
05 uint16_t version_major;
06 /** minor version number of the module */
07 uint16_t version_minor;
08 /** Identifier of module */
09 const char *id;
10 /** Name of this module */
11 const char *name;
12 /** Author/owner/implementor of the module */
13 const char *author;
14 /** Modules methods */
15 struct hw_module_methods_t* methods;
16 /** module's dso */
17 void* dso;
18 
19 /** padding to 128 bytes, reserved for future use */
20 uint32_t reserved[32-7];
21 } hw_module_t;
    其中比較關鍵的是第  15 行 的  struct hw_module_methods_t* methods; hw_module_methods_t 的
    定義如下
01 typedef struct hw_module_methods_t {
02 /** Open a specific device */
03 int (*open)(const struct hw_module_t* module, const char* id,
04 struct hw_device_t** device);
05 
06 } hw_module_methods_t;
    只有一個叫做 open 的函式指標, 此函式指標會對應到 Gralloc.cpp 中的 gralloc_device_open()函式.

2.調用  framebuffer_open(module, &fbDev) 以及 gralloc_open(module, &grDev)

   調用完 hw_get_module() 之後, FramebufferNativeWindow 建構式接下來會分別調用
   framebuffer_open(module, &fbDev) 以及 gralloc_open(module, &grDev):  這兩個函式定義在
   /hardware/libhardware/include/hardware/Gralloc.h, 以下是程式片段:
01 // framebuffer_open
02 static inline int framebuffer_open(const struct hw_module_t* module,
03 struct framebuffer_device_t** device) {
04 return module->methods->open(module,
05 GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
06 }
07 // gralloc_open
08 static inline int gralloc_open(const struct hw_module_t* module,
09 struct alloc_device_t** device) {
10 return module->methods->open(module,
11 GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device);
12 }
  參數 GRALLOC_HARDWARE_FB0 以及 GRALLOC_HARDWARE_GPU0 定義在 Gralloc.h: Source3.cpp
01 #define GRALLOC_HARDWARE_FB0 "fb0"
02 #define GRALLOC_HARDWARE_GPU0 "gpu0"
  從定義中看出兩者都會調用同一個函式 open(),但是傳入open()的第二個參數不同, 前
  面提到過 open 是函式指標且對應Gralloc.cpp 中的gralloc_device_open(), 因此調
  用 open() 其實是調用到gralloc_device_open(): Source3.cpp
01 int gralloc_device_open(const hw_module_t* module, const char* name,
02 hw_device_t** device)
03 {
04 int status = -EINVAL;
05 if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
06   gralloc_context_t *dev;
07   dev = (gralloc_context_t*)malloc(sizeof(*dev));
08 
09   /* initialize our state here */
10   memset(dev, 0, sizeof(*dev));
11 
12   /* initialize the procs */
13   dev->device.common.tag = HARDWARE_DEVICE_TAG;
14   dev->device.common.version = 0;
15   dev->device.common.module = const_cast<hw_module_t*>(module);
16   dev->device.common.close = gralloc_close;
17 
18   dev->device.alloc = gralloc_alloc;
19   dev->device.free = gralloc_free;
20 
21   *device = &dev->device.common;
22   status = 0;
23 } else {
24   status = fb_device_open(module, name, device);
25 }
26 return status;
27 
28 }
  gralloc_open(module, &grDev) 調用 gralloc_device_open時
  第二個參數傳入的是GRALLOC_HARDWARE_GPU0, 此時 gralloc_device_open()的
  任務是填充結構體grDev. 以及18,19 行的函式指標 int(*alloc)對應到 gralloc_alloc()以
  及 int(*free) 對應到 gralloc_free(). gralloc_open() 第二個參數 grDev 是 alloc_device_t 結構體 Source3.cpp
01 typedef struct alloc_device_t {
02   struct hw_device_t common;
03   int (*alloc)(struct alloc_device_t* dev,
04   int w, int h, int format, int usage,
05   buffer_handle_t* handle, int* stride);
06   int (*free)(struct alloc_device_t* dev,
07   buffer_handle_t handle);
08 
09 } alloc_device_t;

  framebuffer_open(module, &fbDev) 調用 gralloc_device_open時第二個參數傳入
  GRALLOC_HARDWARE_FB0, 因此gralloc_device_open()會調用 fb_device_open(),
  fb_device_open()除了填充結構體fbDev之外, 會調用 mapFrameBuffer() , mapFrameBuffer()會再調
 用 mapFrameBufferLocked().
 mapFrameBufferLocked()定義在 /hardware/libhardware/modules/gralloc/Framebuffer.cpp, 此函式會開
 啟 framebuffer device, 並且調用 ioctl取得 framebuffer device的資訊.
 參考 mapFrameBufferLocked() 函式片段如下:Source3.cpp
01 // already initialized...
02 if (module->framebuffer) {
03 return 0;
04 }
05 char const * const device_template[] = {
06 "/dev/graphics/fb%u",
07 "/dev/fb%u",
08 0 };
09 
10 int fd = -1;
11 int i=0;
12 char name[64];
13 
14 while ((fd==-1) && device_template[i]) {
15 snprintf(name, 64, device_template[i], 0);
16 fd = open(name, O_RDWR, 0); //¶}±Ò framebuffer device
17 i++;
18 }
19 if (fd < 0)
20 return -errno;
21 
22 struct fb_fix_screeninfo finfo;
23 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
24 return -errno;
25 
26 struct fb_var_screeninfo info;
27 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
28 return -errno;
  比較關鍵的是 mapFrameBufferLocked() 以 page alignment計算出 framebuffer 的大小, 並透過
   mmap()獲取 framebuffer的 virtual address. 程式片段如下:
01 int err;
02 size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual); //page
03 alignment
04 module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);
05 
06 module->numBuffers = info.yres_virtual / info.yres;
07 module->bufferMask = 0;
08 
09 void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
10 if (vaddr == MAP_FAILED) {
11 LOGE("Error mapping the framebuffer (%s)", strerror(errno));
12 return -errno;
13 }
14 module->framebuffer->base = intptr_t(vaddr);
15 module->framebuffer->phys_base = finfo.smem_start ;
16 LOGI("framebuffer->base=%x\n", module->framebuffer->base );
17 LOGI("framebuffer->phys_base=%x\n", module->framebuffer->phys_base );
18 memset(vaddr, 0, fbSize);
19 return 0;

3.FramebufferNativeWindow 物件建構式調用 gralloc_alloc()函式 配置 framebuffer:

   Android 2.2 使用 double-buffer, 這部份的程式片段如下: Source3.cpp
01 mNumBuffers = 2;
02 mNumFreeBuffers = 2;
03 mBufferHead = mNumBuffers-1;
04 buffers[0] = new NativeBuffer( fbDev->width, fbDev->height, 
05                            fbDev->format, GRALLOC_USAGE_HW_FB);
06 buffers[1] = new NativeBuffer( fbDev->width, fbDev->height, 
07                            fbDev->format, GRALLOC_USAGE_HW_FB);
08         ¡@
09 err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format, 
10                    GRALLOC_USAGE_HW_FB, &buffers[0]->handle, 
11         &buffers[0]->stride);  //調用 gralloc_alloc 函式 
12 
13 LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s",
14                 fbDev->width, fbDev->height, strerror(-err));
15 
16 err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format, 
17                    GRALLOC_USAGE_HW_FB, &buffers[1]->handle, 
18         &buffers[1]->stride);  //調用 gralloc_alloc 函式
19 
20 
21 LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
22                 fbDev->width, fbDev->height, strerror(-err));


10 則留言: