Linux內核提供了統一的framebuffer顯示驅動夺鲜。Framebuffer是內核系統提供的圖形硬件的抽象描述,稱為buffer是因為它也占用了系統存儲空間的一部分乔夯,是一塊包含屏幕顯示信息的緩沖區(qū)休玩。Framebuffer借助于Linux文件系統向上層應用提供了統一而高效的操作接口他匪,讓用戶空間運行的程序比較容易地適配多種顯示設備。
Android系統中却盘,每個顯示屏被抽象為一個幀緩沖區(qū)狰域,注冊到FrameBuffer模塊中,并在/dev/graphics目錄下創(chuàng)建對應的fbX設備黄橘,framebuffer提供的設備節(jié)點為/dev/graphics/fb或者/dev/fb兆览,Android系統在硬件抽象層中提供了一個Gralloc模塊,封裝了對幀緩沖區(qū)的所有訪問操作塞关。用戶空間的應用程序在使用幀緩沖區(qū)之間抬探,首先要加載Gralloc模塊,并且獲得一個gralloc設備和一個fb設備描孟。有了gralloc設備之后驶睦,用戶空間中的應用程序就可以申請分配一塊圖形緩沖區(qū),并且將這塊圖形緩沖區(qū)映射到應用程序的地址空間來匿醒,以便可以向里面寫入要繪制的畫面的內容场航。
Android 硬件抽象庫的加載簡介
Android系統,為了隱藏各廠家自身特定硬件驅動實現細節(jié)廉羔,在用戶空間定義了一套硬件抽象層溉痢,各廠商在Android的硬件抽象層實現特定硬件的操作細節(jié),編譯成動態(tài)庫憋他,以庫的形式提供給用戶使用孩饼。
hardware/libhardware/include/hardware/hardware.h 頭文件中定義一個代表模塊的結構體 (hw_module_t),其中包含模塊的版本竹挡、名稱和作者等元數據镀娶。Android系統 會根據這些元數據來找到并正確加載 HAL 模塊。
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
uint16_t module_api_version;
uint16_t hal_api_version;
const char *id;
const char *name;
const char *author;
struct hw_module_methods_t* methods;
void* dso;
#ifdef __LP64__
uint64_t reserved[32-7];
#else
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
#endif
} hw_module_t;
hw_module_t 結構體還包含指向另一個結構體 hw_module_methods_t 的指針揪罕,后面這個結構體包含指向相應模塊的 open 函數的指針梯码。此 open 函數用于與相關硬件(此 HAL 是其抽象形式)建立通信宝泵。每個硬件專用 HAL 通常都會使用該特定硬件的附加信息來擴展通用的 hw_module_t 結構體。例如轩娶,在相機 HAL 中儿奶,camera_module_t 結構體包含一個 hw_module_t 結構體以及相機專用的其他函數指針:
typedef struct camera_module {
hw_module_t common;
int (*get_number_of_cameras)(void);
int (*get_camera_info)(int camera_id, struct camera_info *info);
} camera_module_t;
實現 HAL 并創(chuàng)建模塊結構體時,您必須將其命名為 HAL_MODULE_INFO_SYM鳄抒,以下是 Nexus 9 音頻 HAL 的示例:
struct audio_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = AUDIO_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = AUDIO_HARDWARE_MODULE_ID,
.name = "NVIDIA Tegra Audio HAL",
.author = "The Android Open Source Project",
.methods = &hal_module_methods,
},
};
HAL 設備
設備是產品硬件的抽象表示闯捎。例如,一個音頻模塊可能包含主音頻設備许溅、USB 音頻設備或藍牙 A2DP 音頻設備瓤鼻。
設備由 hw_device_t 結構體表示。與模塊類似闹司,每類設備都定義了一個通用 hw_device_t 的詳細版本娱仔,其中包含指向特定硬件功能的函數指針。例如游桩,audio_hw_device_t 結構體類型會包含指向音頻設備操作的函數指針:
struct audio_hw_device {
struct hw_device_t common;
/**
* used by audio flinger to enumerate what devices are supported by
* each audio_hw_device implementation.
*
* Return value is a bitmask of 1 or more values of audio_devices_t
*/
uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);
...
};
typedef struct audio_hw_device audio_hw_device_t;
如何加載硬件抽象層的動態(tài)庫?
int hw_get_module(const char *id, const struct hw_module_t **module)
{
return hw_get_module_by_class(id, NULL, module);
}
參數為模塊的ID耐朴,最終會返回一個hw_module_t的結構體保存在參數module中借卧。
每個硬件抽象層模塊都必須定義HAL_MODULE_INFO_SYM符號,并且有自己唯一的ID筛峭。
hw_get_module會遍歷規(guī)定的幾個目錄來查找名稱對應的動態(tài)庫铐刘,找到庫的路徑后,會調用load函數使用dlopen打開找到的庫影晓,并依據HAL_MODULE_INFO_SYM_AS_STR(其值為HMI)獲取到hw_module_t(即HAL_MODULE_INFO_SYM)結構體指針镰吵。以及把dlopen返回的handle保存在hw_module_t中,而hw_module_t HMI 結構是一個全局結構挂签。
每個硬件抽象層必須有自己的ID以及HAL_MODULE_INFO_SYM符號疤祭,Gralloc也不例外
/**
* The id of this module
*/
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
struct private_module_t HAL_MODULE_INFO_SYM = {
.base = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = GRALLOC_HARDWARE_MODULE_ID,
.name = "Graphics Memory Allocator Module",
.author = "The Android Open Source Project",
.methods = &gralloc_module_methods
},
.registerBuffer = gralloc_register_buffer,
.unregisterBuffer = gralloc_unregister_buffer,
.lock = gralloc_lock,
.unlock = gralloc_unlock,
},
.framebuffer = 0,
.flags = 0,
.numBuffers = 0,
.bufferMask = 0,
.lock = PTHREAD_MUTEX_INITIALIZER,
.currentBuffer = 0,
};
hw_get_module硬件加載方法根據gralloc的ID, 查找到gralloc模塊定義的HAL_MODULE_INFO_SYM并返回給hw_module_t結構,但是HAL_MODULE_INFO_SYM是private_module_t結構類型饵婆,如何賦值呢勺馆?
Gralloc模塊數據結構分析
struct private_module_t {
gralloc_module_t base;
private_handle_t* framebuffer; //指向系統幀緩沖區(qū)的句柄
uint32_t flags; //用來標志系統幀緩沖區(qū)是否支持雙緩沖
uint32_t numBuffers; //表示系統幀緩沖區(qū)包含有多少個圖形緩沖區(qū)
uint32_t bufferMask; //記錄系統幀緩沖區(qū)中的圖形緩沖區(qū)的使用情況
pthread_mutex_t lock; //一個互斥鎖,用來保護結構體private_module_t的并行訪問
buffer_handle_t currentBuffer; //用來描述當前正在被渲染的圖形緩沖區(qū)
int pmem_master;
void* pmem_master_base;
struct fb_var_screeninfo info; //保存設備顯示屏的動態(tài)屬性信息
struct fb_fix_screeninfo finfo; //保存設備顯示屏的固定屬性信息
float xdpi; //描述設備顯示屏在寬度
float ydpi; //描述設備顯示屏在高度
float fps; //用來描述顯示屏的刷新頻率
};
private_module_t負責管理顯示驅動framebuffer相關的信息侨核,包括framebuffer的fd, 有多少個緩存草穆,系統幀緩沖區(qū)使用情況,動態(tài)可變的信息搓译,固定屬性的信息悲柱,顯示屏的寬高,刷新率等信息些己。
private_module_t 第一個變量是gralloc_module_t結構豌鸡。
typedef struct gralloc_module_t {
struct hw_module_t common;
//映射一塊圖形緩沖區(qū)到一個進程的地址空間去
int (*registerBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
//取消映射到一個進程的地址空間去的圖形緩沖區(qū)
int (*unregisterBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
//鎖定一個指定的圖形緩沖區(qū)
int (*lock)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
//解鎖一個指定的圖形緩沖區(qū)
int (*unlock)(struct gralloc_module_t const* module,
buffer_handle_t handle);
int (*perform)(struct gralloc_module_t const* module,
int operation, ... );
int (*lock_ycbcr)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
struct android_ycbcr *ycbcr);
int (*lockAsync)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr, int fenceFd);
int (*unlockAsync)(struct gralloc_module_t const* module,
buffer_handle_t handle, int* fenceFd);
int (*lockAsync_ycbcr)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
struct android_ycbcr *ycbcr, int fenceFd);
/* reserved for future use */
void* reserved_proc[3];
} gralloc_module_t;
gralloc_module_t 負責管理gralloc模塊相關的操作跑芳,其第一個是屬性是硬件抽象層規(guī)定的hw_module_t結構,其他都是關于gralloc模塊圖像buffer處理的相關操作方法直颅。
hw_module_t結構如下:
/**
* 任何一個硬件模塊都必須有一個名稱為 HAL_MODULE_INFO_SYM的數據結構
* 并且這個數據結構必須以hw_module_t為第一個元素博个,其后再跟隨這個模塊特有的信息
*/
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag; //標簽
uint16_t module_api_version; //模塊主設備號
uint16_t hal_api_version; //模塊從設備號
const char *id; //模塊ID
const char *name; //名稱
const char *author; //作者
struct hw_module_methods_t* methods; //操作模塊的方法
void* dso; //模塊首地址
uint64_t reserved[32-7]; //保留信息
} hw_module_t;
typedef struct hw_module_methods_t {
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
硬件抽象層hw_module_t結構描述了硬件抽象層庫相關的信息。如版本號功偿,id, 名稱盆佣,相關的操作方法等。
其中還定義了模塊的打開模塊的操作方法open.
根據以上的三個結構我們可以畫出結構圖如下:
回到上面問題械荷,為什么private_module_t可以賦值給hw_module_t呢共耍?這樣看就很簡單了,private_module_t的第一個變量就是gralloc_module_t, 而gralloc_module_t的數據第一個元素就是hw_module_t吨瞎。private_module_t的首地址和hw_module_t的首地址是一樣的痹兜,所以可以直接賦值過去。
除了hw_module_t的數據結構外颤诀,gralloc模塊還定義了兩種設備相關的數據結構:
1: framebuffer_device_t 用來描述系統幀緩沖區(qū)的信息
typedef struct framebuffer_device_t {
struct hw_device_t common;
const uint32_t flags;//用來記錄系統幀緩沖區(qū)的標志
const uint32_t width;//用來描述設備顯示屏的寬度
const uint32_t height;//用來描述設備顯示屏的高度
const int stride;//用來描述設備顯示屏的一行有多少個像素點
const int format;//用來描述系統幀緩沖區(qū)的像素格式
const float xdpi;//用來描述設備顯示屏在寬度上的密度
const float ydpi;//用來描述設備顯示屏在高度上的密度
const float fps;//用來描述設備顯示屏的刷新頻率
const int minSwapInterval;//用來描述幀緩沖區(qū)交換前后兩個圖形緩沖區(qū)的最小時間間隔
const int maxSwapInterval;//用來描述幀緩沖區(qū)交換前后兩個圖形緩沖區(qū)的最大時間間隔
int reserved[8];//保留
//用來設置幀緩沖區(qū)交換前后兩個圖形緩沖區(qū)的最小和最大時間間隔
int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);
//用來設置幀緩沖區(qū)的更新區(qū)域
int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);
//用來將圖形緩沖區(qū)buffer的內容渲染到幀緩沖區(qū)中去
int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
//用來通知fb設備字旭,圖形緩沖區(qū)的組合工作已經完成
int (*compositionComplete)(struct framebuffer_device_t* dev);
void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);
int (*enableScreen)(struct framebuffer_device_t* dev, int enable);
//保留
void* reserved_proc[6];
2:alloc_device_t 用于描述圖像分配相關的信息
typedef struct alloc_device_t {
struct hw_device_t common;
//用于分配一塊圖形緩沖區(qū)
int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);
//用于釋放指定的圖形緩沖區(qū)
int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);
void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len);
void* reserved_proc[7];
} alloc_device_t;
Gralloc設備打開過程分析
從上一節(jié)數據結構分析的過程中可知,設備打開的方法是在hw_module_t結構中定義的崖叫,定義打開的方法為
struct private_module_t HAL_MODULE_INFO_SYM = {
.base = {
.common = {
...
.methods = &gralloc_module_methods
},
....
},
...
};
static struct hw_module_methods_t gralloc_module_methods = {
.open = gralloc_device_open
};
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));
/* initialize our state here */
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
*device = &dev->device.common;
status = 0;
} else {
status = fb_device_open(module, name, device);
}
return status;
}
gralloc_device_open方法用來打開設備
參數hw_module_t為硬件抽象層加載得到的結構體
name 為打開目標設備的類型遗淳,分為兩種
- 1:GRALLOC_HARDWARE_FB0 "fb0"
打開framebuffer_device_t, 負責將圖像緩沖區(qū)的內容渲染到幀緩沖區(qū)心傀,顯示到屏幕上 - 2:GRALLOC_HARDWARE_GPU0 "gpu0"
打開alloc_device_t屈暗,負責圖像緩沖區(qū)的分配和釋放
參數hw_device_t為打開的設備保存的結構,返回給調用者
分別分析下打開兩種設備的過程
1:打開GRALLOC_HARDWARE_FB0的過程
gralloc_device_open根據參數的不同來打開不同的設備脂男,打開設備GRALLOC_HARDWARE_FB0养叛,調用了fb_device_open方法
struct fb_context_t {
framebuffer_device_t device;
};
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
//判斷設備名稱是否是GRALLOC_HARDWARE_FB0,如果不是的直接返回打開失敗
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
//初始化設備framebuffer的上下文結構
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
//初始化設備相關的變量
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
//初始化fb相關的操作函數
dev->device.common.close = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = 0;
private_module_t* m = (private_module_t*)module;
//將fb映射到當前進程的地址空間
status = mapFrameBuffer(m);
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
int format = (m->info.bits_per_pixel == 32)
? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888)
: HAL_PIXEL_FORMAT_RGB_565;
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common;
}
}
return status;
}
這個函數創(chuàng)建了一個fb_context_t的數據結構宰翅, 并對其進行初始化弃甥,fb_context_t的device變量就是framebuffer_device_t,用來描述fb設備的堕油。
同時還注冊了操作fb設備的幾個函數, 其中fb_post函數比較關鍵潘飘,負責將圖形緩沖區(qū)的內容渲染到Framebuffer的顯存中。
然后使用mapFrameBuffer函數來獲取幀緩沖區(qū)的信息掉缺,然后將信息保存到framebuffer_device_t結構中卜录,并將fb設備映射到當前進程。
再看下mapFrameBuffer做了什么操作眶明?
int mapFrameBufferLocked(struct private_module_t* module)
{
// framebuffer設備已經初始化則直接返回
if (module->framebuffer) {
return 0;
}
//從"/dev/graphics/和/dev/目錄查找fb設備艰毒,并打開
char const * const device_template[] = {
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };
int fd = -1;
int i=0;
char name[64];
while ((fd==-1) && device_template[i]) {
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
i++;
}
if (fd < 0)
return -errno;
//獲取framebuffer設備的不可變的信息
struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
//獲取framebuffer設備的可變信息
struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
//fb_var_screeninfo的成員變量xres和yres用來描述顯示屏的可視分辨率,而成員變量xres_virtual和
yres_virtual用來描述顯示屏的虛擬分辨率搜囱。
//將虛擬分辨率的高度值設置為可視分辨率的高度值的NUM_BUFFERS倍
//當前聲明為雙緩存
info.yres_virtual = info.yres * NUM_BUFFERS;
//默認為雙緩沖丑瞧,如果不支持柑土,則移除雙緩沖的標志flag
uint32_t flags = PAGE_FLIP;
#if USE_PAN_DISPLAY
if (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {
ALOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
#else
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
#endif
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
}
if (info.yres_virtual < info.yres * 2) {
// we need at least 2 for page-flipping
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
info.yres_virtual, info.yres*2);
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
//計算屏幕刷新頻率
uint64_t refreshQuotient =
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);
/* Beware, info.pixclock might be 0 under emulation, so avoid a
* division-by-0 here (SIGFPE on ARM) */
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
//計算顯示器像素密度
if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}
float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;
//再次通過IO控制命令FBIOGET_FSCREENINFO來獲得系統幀緩沖區(qū)的固定信息
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
if (finfo.smem_len <= 0)
return -errno;
//得到的系統幀緩沖區(qū)的其它信息來初始化參數module所描述的一個private_module_t結構體
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;
//整個系統幀緩沖區(qū)的大小=虛擬分辨率的高度值info.yres_virtual * 每一行所占用的字節(jié)數finfo.line_length,并將整個系統幀緩沖區(qū)的大小對齊到頁面邊界
int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
//創(chuàng)建一個private_handle_t,用來描述整個系統幀緩沖區(qū)的信息
module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);
//計算整個系統幀緩沖區(qū)可以劃分為多少個圖形緩沖區(qū)來使用
module->numBuffers = info.yres_virtual / info.yres;
//初始化所有緩沖區(qū)為空閑狀態(tài)
module->bufferMask = 0;
//將幀緩沖區(qū)映射到當前進程地址空間中
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
//系統幀緩沖區(qū)在當前進程的地址空間中的起始地址保存到private_handle_t的域base中
module->framebuffer->base = intptr_t(vaddr);
//清空緩沖區(qū)的內存空間
memset(vaddr, 0, fbSize);
return 0;
}
mapFrameBuffer函數做了幾件事情
1:打開fb設備绊汹,獲取fb驅動的相關信息
2:設置fb的 yres_virtual為雙緩沖大小
3:計算像素密度
4:計算雙緩沖大小稽屏,并將其映射到當前進程,將緩沖區(qū)起始地址寶尊在framebuffer_device_t的base屬性中西乖。
至此FB設備打開過程就分析完了狐榔,FB設備打開過程做了什么事情?
打開fb設備获雕,根據fb設備初始化相關的顯示信息薄腻,并把fb設備顯存映射到當前進程方便訪問,同時還注冊了幾個操作fb設備的方法届案。
打開GRALLOC_HARDWARE_GPU0的過程
gralloc設備使用結構體alloc_device_t來描述庵楷。結構體alloc_device_t有兩個成員函數alloc和free,分別用來分配和釋放圖形緩沖區(qū)楣颠。
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));
/* initialize our state here */
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
*device = &dev->device.common;
status = 0;
}
首先創(chuàng)建了一個gralloc_context_t的上下文尽纽,gralloc_context_t的device就是alloc_device_t, 對其進行初始化 ,同時注冊了幾個操作alloc_device_t設備的函數球碉, gralloc_alloc和gralloc_free用于分配和釋放圖形緩沖區(qū)蜓斧。
什么地方打開了這兩種設備?
分析了兩種設備打開的過程睁冬, 但是什么時候會打開這兩種設備呢?
1:FB設備打開時機
// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
int HWComposer::loadFbHalModule()
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err != 0) {
ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
return err;
}
return framebuffer_open(module, &mFbDev);
}
FB設備打開時機實在HWCompser構造函數中打開的看疙,說明HWCompser會操作fb設備豆拨,渲染圖像緩沖區(qū)到顯示緩沖區(qū), 具體在分析HWCompser的時候在進行分析能庆。
2:gralloc設備打開時機
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
gralloc_open(module, &mAllocDev);
}
}
gralloc設備用于管理GraphicBuffer圖形緩沖區(qū)施禾,是在GraphicBufferAllocator中打開的,GraphicBufferAllocator負責圖形緩沖區(qū)的分配和釋放搁胆。后續(xù)在做詳細分析
文章參考:Android圖形顯示之硬件抽象層Gralloc