4.3 重要的数据结构
根据HAL层加载库的规定,加载的时候,从HAL_MODULE_INFO_SYM模块地址开始。
Galloc模块的HAL_MODULE_INFO_SYM定义如下:
// HAL module initialize struct private_module_t HAL_MODULE_INFO_SYM = { base: { common: { tag: HARDWARE_MODULE_TAG, module_api_version: GRALLOC_MODULE_API_VERSION_0_2, hal_api_version: 0, id: GRALLOC_HARDWARE_MODULE_ID, name: "Graphics Memory Allocator Module", author: "The Android Open Source Project", methods: &gralloc_module_methods, dso: 0, }, registerBuffer: gralloc_register_buffer, unregisterBuffer: gralloc_unregister_buffer, lock: gralloc_lock, unlock: gralloc_unlock, perform: gralloc_perform, lock_ycbcr: gralloc_lock_ycbcr, }, framebuffer: 0, fbFormat: 0, flags: 0, numBuffers: 0, bufferMask: 0, lock: PTHREAD_MUTEX_INITIALIZER, currentBuffer: 0, }; |
可是每一个HAL模块必须具备HAL_MODULE_INFO_SYM结构体,而这个结构体必须以hw_module_t作为开头,现在Gralloc是不是存在特殊之处?
4.3.1 结构体private_module_t
结构体private_module_t定义在文件hardware/hardware/qcom/display/msm8974/libgralloc/fb_priv.h中,它主要是用来描述Gralloc模块的属性,包括通过alloc device申请到的FrameBuffer,使用private_handle_t来描述,以及alloc device和fb0 device等。
struct private_module_t { gralloc_module_t base;
// 成员变量framebuffer的类型为private_handle_t,它是一个指向系统帧缓冲区的句柄 struct private_handle_t* framebuffer;
uint32_t fbFormat;
// flags用来标志系统帧缓冲区是否支持双缓冲。如果支持的话,那么它的PAGE_FLIP位就等于1,否则的话,就等于0。 uint32_t flags;
// numBuffers表示系统帧缓冲区包含有多少个图形缓冲区。一个帧缓冲区包含有多少个图形缓冲区是与它的可视分辨率以及虚拟分辨率的大小有关的。例如,如果一个帧缓冲区的可视分辨率为800 x 600,而虚拟分辨率为1600 x 600,那么这个帧缓冲区就可以包含有两个图形缓冲区。 uint32_t numBuffers;
// 成员变量bufferMask用来记录系统帧缓冲区中的图形缓冲区的使用情况。例如,假设系统帧缓冲区有两个图形缓冲区,这时候成员变量bufferMask就有四种取值,分别是二进制的00、01、10和11,其中,00分别表示两个图缓冲区都是空闲的,01表示第1个图形缓冲区已经分配出去,而第2个图形缓冲区是空闲的,10表示第1个图形缓冲区是空闲的,而第2个图形缓冲区已经分配出去,11表示两个图缓冲区都已经分配出去。 uint32_t bufferMask;
// lock是一个互斥锁,用来保护结构体private_module_t的并行访问。 pthread_mutex_t lock;
// currentBuffer的类型为buffer_handle_t,用来描述当前正在被渲染的图形缓冲区, private_handle_t *currentBuffer;
// 成员变量info和finfo的类型分别为fb_var_screeninfo和fb_fix_screeninfo,它们用来保存设备显示屏的属性信息,其中,成员变量var_info保存的属性信息是可以动态设置的,而成员变量fx_info保存的属性信息是只读的。这两个成员变量的值可以通过IO控制命令FBIOGET_VSCREENINFO和FBIOGET_FSCREENINFO来从帧缓冲区驱动模块中获得。 struct fb_var_screeninfo info; struct mdp_display_commit commit; struct fb_fix_screeninfo finfo;
// 成员变量xdpi和ydpi分别用来描述设备显示屏在宽度和高度上的密度,即每英寸有多少个像素点 float xdpi; float ydpi;
// fps用来描述显示屏的刷新频率,它的单位的fps,即每秒帧数。 float fps; uint32_t swapInterval; uint32_t currentOffset; };
|
4.3.2 结构体gralloc_module_t
结构体gralloc_module_t定义在文件hardware/libhardware/include/hardware/gralloc.h中,继承了hw_module_t,并主要是定义了四个用来操作图形缓冲区的成员函数:
/** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ typedef struct gralloc_module_t { struct hw_module_t common;
// 成员函数registerBuffer和unregisterBuffer分别用来注册和注销一个指定的图形缓冲区,这个指定的图形缓冲区使用一个buffer_handle_t句柄来描述。所谓注册图形缓冲区,实际上就是将一块图形缓冲区映射到一个进程的地址空间去,而注销图形缓冲区就是执行相反的操作。 int (*registerBuffer)(struct gralloc_module_t const* module, buffer_handle_t handle); int (*unregisterBuffer)(struct gralloc_module_t const* module, buffer_handle_t handle);
// 成员函数lock和unlock分别用来锁定和解锁一个指定的图形缓冲区,这个指定的图形缓冲区同样是使用一个buffer_handle_t句柄来描述。在访问一块图形缓冲区的时候,例如,向一块图形缓冲写入内容的时候,需要将该图形缓冲区锁定,用来避免访问冲突。在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小,这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置,而参数w和h指定的是要访问的图形缓冲区的宽度和长度。锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中。另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定。 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, ... );
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; |
4.3.3 结构体hw_module_t
接下来来看下hw_module_t的结构体定义,这个其实是Android HAL层的标准定义,我们在HAL介绍的时候会重点关注:
/** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; uint16_t module_api_version; #define version_major module_api_version uint16_t hal_api_version; #define version_minor hal_api_version
const char *id;
/** Name of this module */ const char *name;
/** Author/owner/implementor of the module */ const char *author;
/** Modules methods */ struct hw_module_methods_t* methods;
/** module's dso */ 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结构体有一个重要的成员变量methods,它的类型为hw_module_methods_t,它用来描述一个HAL模块的操作方法列表。结构体hw_module_methods_t只定义有一个操作方法open,用来打开一个指定的设备。
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; |
4.3.4结构体private_handle_t
我们还要看看一个重要的数据结构:private_handle_t,定义在hardware/hardware/qcom/display/msm8974/libgralloc/gralloc_priv.h中,用来描述一块图形缓冲区,这块图形缓冲区可能是在帧缓冲区中分配的,也可能是在内存中分配的,视具体情况而定。
#ifdef __cplusplus struct private_handle_t : public native_handle { #else struct private_handle_t { native_handle_t nativeHandle; #endif enum { PRIV_FLAGS_FRAMEBUFFER = 0x00000001, PRIV_FLAGS_USES_PMEM = 0x00000002, PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004, PRIV_FLAGS_USES_ION = 0x00000008, PRIV_FLAGS_USES_ASHMEM = 0x00000010, PRIV_FLAGS_NEEDS_FLUSH = 0x00000020, PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040, PRIV_FLAGS_SW_LOCK = 0x00000080, PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100, // Set by HWC when storing the handle PRIV_FLAGS_HWC_LOCK = 0x00000200, PRIV_FLAGS_SECURE_BUFFER = 0x00000400, // For explicit synchronization PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800, // Not mapped in userspace PRIV_FLAGS_NOT_MAPPED = 0x00001000, // Display on external only PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, // Display only this buffer on external PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, // Display this buffer on external as close caption PRIV_FLAGS_EXTERNAL_CC = 0x00008000, PRIV_FLAGS_VIDEO_ENCODER = 0x00010000, PRIV_FLAGS_CAMERA_WRITE = 0x00020000, PRIV_FLAGS_CAMERA_READ = 0x00040000, PRIV_FLAGS_HW_COMPOSER = 0x00080000, PRIV_FLAGS_HW_TEXTURE = 0x00100000, PRIV_FLAGS_ITU_R_601 = 0x00200000, PRIV_FLAGS_ITU_R_601_FR = 0x00400000, PRIV_FLAGS_ITU_R_709 = 0x00800000, PRIV_FLAGS_L3_SECURE_BUFFER = 0x01000000, }; // 成员变量fd指向一个文件描述符,这个文件描述符要么指向帧缓冲区设备,要么指向一块匿名共享内存,取决于它的宿主结构体private_handle_t描述的一个图形缓冲区是在帧缓冲区分配的,还是在内存中分配的。 // file-descriptors int fd; int fd_metadata; // fd for the meta-data // ints
//成员变量magic指向一个魔数,它的值由静态成员变量sMagic来指定,用来标识一个private_handle_t结构体。 int magic;
// 成员变量flags用来描述一个图形缓冲区的标志,它的值要么等于0,要么等于PRIV_FLAGS_FRAMEBUFFER。当一个图形缓冲区的标志值等于PRIV_FLAGS_FRAMEBUFFER的时候,就表示它是在帧缓冲区中分配的。 int flags;
//成员变量size用来描述一个图形缓冲区的大小。 int size;
//成员变量offset用来描述一个图形缓冲区的偏移地址。例如,当一个图形缓冲区是在一块内存中分块的时候,假设这块内存的地址为start,那么这个图形缓冲区的起始地址就为start + offset。 int offset; int bufferType;
//成员变量base用来描述一个图形缓冲区的实际地址,它是通过成员变量offset来计算得到的。例如,上面计算得到的start + offset的值就保存在成员变量base中。 int base; int offset_metadata; // The gpu address mapped into the mmu. int gpuaddr; int format; int width; int height; int base_metadata;
#ifdef __cplusplus static const int sNumInts = 12; static const int sNumFds = 2; static const int sMagic = 'gmsm';
private_handle_t(int fd, int size, int flags, int bufferType, int format,int width, int height, int eFd = -1, int eOffset = 0, int eBase = 0) : fd(fd), fd_metadata(eFd), magic(sMagic), flags(flags), size(size), offset(0), bufferType(bufferType), base(0), offset_metadata(eOffset), gpuaddr(0), format(format), width(width), height(height), base_metadata(eBase) { version = sizeof(native_handle); numInts = sNumInts; numFds = sNumFds; } ~private_handle_t() { magic = 0; }
bool usesPhysicallyContiguousMemory() { return (flags & PRIV_FLAGS_USES_PMEM) != 0; }
// 静态成员函数validate,用来验证一个native_handle_t指针是否指向了一个private_handle_t结构体 static int validate(const native_handle* h) { const private_handle_t* hnd = (const private_handle_t*)h; if (!h || h->version != sizeof(native_handle) || h->numInts != sNumInts || h->numFds != sNumFds || hnd->magic != sMagic) { ALOGD("Invalid gralloc handle (at %p): " "ver(%d/%d) ints(%d/%d) fds(%d/%d) magic(%c%c%c%c/%c%c%c%c)", h, h ? h->version : -1, sizeof(native_handle), h ? h->numInts : -1, sNumInts, h ? h->numFds : -1, sNumFds, hnd ? (((hnd->magic >> 24) & 0xFF)? ((hnd->magic >> 24) & 0xFF) : '-') : '?', hnd ? (((hnd->magic >> 16) & 0xFF)? ((hnd->magic >> 16) & 0xFF) : '-') : '?', hnd ? (((hnd->magic >> 8) & 0xFF)? ((hnd->magic >> 8) & 0xFF) : '-') : '?', hnd ? (((hnd->magic >> 0) & 0xFF)? ((hnd->magic >> 0) & 0xFF) : '-') : '?', (sMagic >> 24) & 0xFF, (sMagic >> 16) & 0xFF, (sMagic >> 8) & 0xFF, (sMagic >> 0) & 0xFF); return -EINVAL; } return 0; }
static private_handle_t* dynamicCast(const native_handle* in) { if (validate(in) == 0) { return (private_handle_t*) in; } return NULL; } #endif }; |
结构体native_handle_t用来描述一个本地句柄值,它定义在系统运行时层的文件system/core/include/cutils/native_handle.h文件中。
typedef struct native_handle { // version的大小被设置为结构体native_handle_t的大小,用来标识结构体native_handle_t的版本。 int version; /* sizeof(native_handle_t) */
// 成员变量numFds和numInts表示结构体native_handle_t所包含的文件描述符以及整数值的个数,这些文件描述符和整数保存在成员变量data所指向的一块缓冲区中。 int numFds; /* number of file-descriptors at &data[0] */ int numInts; /* number of ints at &data[numFds] */ int data[0]; /* numFds + numInts ints */ } native_handle_t; |
4.3.5 结构体alloc_device_t
Gralloc设备通过alloc_device_t结构体来描述,定义在文件hardware/libhardware/include/hardware/gralloc.h中,alloc设备是提供对于F0设备的操作接口。
typedef struct alloc_device_t { struct hw_device_t common;
/* * (*alloc)() Allocates a buffer in graphic memory with the requested * parameters and returns a buffer_handle_t and the stride in pixels to * allow the implementation to satisfy hardware constraints on the width * of a pixmap (eg: it may have to be multiple of 8 pixels). * The CALLER TAKES OWNERSHIP of the buffer_handle_t. * * If format is HAL_PIXEL_FORMAT_YCbCr_420_888, the returned stride must be * 0, since the actual strides are available from the android_ycbcr * structure. * * Returns 0 on success or -errno on error. */
int (*alloc)(struct alloc_device_t* dev, int w, int h, int format, int usage, buffer_handle_t* handle, int* stride);
/* * (*free)() Frees a previously allocated buffer. * Behavior is undefined if the buffer is still mapped in any process, * but shall not result in termination of the program or security breaches * (allowing a process to get access to another process' buffers). * THIS FUNCTION TAKES OWNERSHIP of the buffer_handle_t which becomes * invalid after the call. * * Returns 0 on success or -errno on error. */ int (*free)(struct alloc_device_t* dev, buffer_handle_t handle);
/* This hook is OPTIONAL. * * If non NULL it will be caused by SurfaceFlingeron dumpsys */ void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len);
void* reserved_proc[7]; } alloc_device_t; |
4.3.7 结构体fb_var_screeninfo
中间由xres和yres组成的区域即为显示屏的图形绘制区,在绘制区的上、下、左和右分别有四个边距upper_margin、lower_margin、left_margin和right_margin。此外,在显示屏的最右边以及最下边还有一个水平同步区域hsync_len和一个垂直同步区域vsync_len。电子枪按照从左到右、从上到下的顺序来显示屏中打点,从而可以将要渲染的图形显示在屏幕中。前面所提到的区域信息分别保存在fb_var_screnninfo结构体info的成员变量xres、yres、upper_margin、lower_margin、left_margin、right_margin、hsync_len和vsync_len。
电子枪每在xres和yres所组成的区域中打一个点所花费的时间记录在fb_var_screnninfo结构体info的成员变量pixclock,单位为pico seconds,即10E-12秒。
电子枪从左到右扫描完成一行之后,都会处理关闭状态,并且会重新折回到左边去。由于电子枪在从右到左折回的过程中不需要打点,因此,这个过程会比从左到右扫描屏幕的过程要快,这个折回的时间大概就等于在xres和yres所组成的区域扫描(left_margin+right_margin)个点的时间。这样,我们就可以认为每渲染一行需要的时间为(xres +left_margin + right_margin)* pixclock。
同样,电子枪从上到下扫描完成显示屏之后,需要从右下角折回到左上角去,折回的时间大概等于在xres和yres所组成的区域中扫描(upper_margin +lower_margin)行所需要的时间。这样,我们就可以认为每渲染一屏图形所需要的时间等于在xres和yres所组成的区域中扫描(yres + upper_margin +lower_margin)行所需要的时间。由于在xres和yres所组成的区域中扫描一行所需要的时间为(xres + left_margin + right_margin)* pixclock,因此,每渲染一屏图形所需要的总时间就等于(yres + upper_margin + lower_margin)* (xres +left_margin + right_margin)* pixclock。
每渲染一屏图形需要的总时间经过计算之后,就保存在变量refreshQuotient中。注意,变量refreshQuotient所描述的时间的单位为1E-12秒。这样,将变量refreshQuotient的值倒过来,就可以得到设备显示屏的刷新频率。将这个频率值乘以10E15次方之后,就得到一个单位为10E-3 HZ的刷新频率,保存在变量refreshRate中。
当Android系统在模拟器运行的时候,保存在fb_var_screnninfo结构体info的成员变量pixclock中的值可能等于0。在这种情况下,前面计算得到的变量refreshRate的值就会等于0。在这种情况下,接下来的代码会将变量refreshRate的值设置为60 * 1000 * 10E-3 HZ,即将显示屏的刷新频率设置为60HZ。
4.3.6结构体fb_context_t
Fb0设备通过fb_context_t结构体来描述,定义在文件hardware/libhardware/qcom/display/msm8974/libgralloc/framebuffer.cpp中。但是fb_context_t本质上就是对应framebuffer_device_t结构体的再次封装。Framebuffer_device_t定义在hardware/libhardware/include/hardware/fb.h
typedef struct framebuffer_device_t { /** * Common methods of the framebuffer device. This *must* be the first member of * framebuffer_device_t as users of this structure will cast a hw_device_t to * framebuffer_device_t pointer in contexts where it's known the hw_device_t references a * framebuffer_device_t. */ struct hw_device_t common;
/* flags describing some attributes of the framebuffer */ const uint32_t flags;
/* dimensions of the framebuffer in pixels */ const uint32_t width; const uint32_t height;
/* frambuffer stride in pixels */ // 一行占据的点数,与宽度的差别就在于前者对齐到4字节边界,后者是调用者传进来的,不一定是对齐到4字节边界的。 const int stride;
/* framebuffer pixel format */ const int format;
/* resolution of the framebuffer's display panel in pixel per inch*/ const float xdpi; const float ydpi;
/* framebuffer's display panel refresh rate in frames per second */ const float fps;
/* min swap interval supported by this framebuffer */ const int minSwapInterval;
/* max swap interval supported by this framebuffer */ const int maxSwapInterval;
/* Number of framebuffers supported*/ const int numFramebuffers;
int reserved[7];
/* * requests a specific swap-interval (same definition than EGL) * * Returns 0 on success or -errno on error. */ int (*setSwapInterval)(struct framebuffer_device_t* window, int interval);
/* * This hook is OPTIONAL. * * It is non NULL If the framebuffer driver supports "update-on-demand" * and the given rectangle is the area of the screen that gets * updated during (*post)(). * * This is useful on devices that are able to DMA only a portion of * the screen to the display panel, upon demand -- as opposed to * constantly refreshing the panel 60 times per second, for instance. * * Only the area defined by this rectangle is guaranteed to be valid, that * is, the driver is not allowed to post anything outside of this * rectangle. * * The rectangle evaluated during (*post)() and specifies which area * of the buffer passed in (*post)() shall to be posted. * * return -EINVAL if width or height <=0, or if left or top < 0 */ int (*setUpdateRect)(struct framebuffer_device_t* window, int left, int top, int width, int height);
/* * Post <buffer> to the display (display it on the screen) * The buffer must have been allocated with the * GRALLOC_USAGE_HW_FB usage flag. * buffer must be the same width and height as the display and must NOT * be locked. * * The buffer is shown during the next VSYNC. * * If the same buffer is posted again (possibly after some other buffer), * post() will block until the the first post is completed. * * Internally, post() is expected to lock the buffer so that a * subsequent call to gralloc_module_t::(*lock)() with USAGE_RENDER or * USAGE_*_WRITE will block until it is safe; that is typically once this * buffer is shown and another buffer has been posted. * * Returns 0 on success or -errno on error. */ int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);
/* * The (*compositionComplete)() method must be called after the * compositor has finished issuing GL commands for client buffers. */
int (*compositionComplete)(struct framebuffer_device_t* dev);
/* * This hook is OPTIONAL. * * If non NULL it will be caused by SurfaceFlingeron dumpsys */ void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);
/* * (*enableScreen)() is used to either blank (enable=0) or * unblank (enable=1) the screen this framebuffer is attached to. * * Returns 0 on success or -errno on error. */ int (*enableScreen)(struct framebuffer_device_t* dev, int enable);
void* reserved_proc[6];
} framebuffer_device_t; |
4.3.7 几个结构体之间的关系
我们用一个图来清楚描述下这些结构体的关系:
结构体private_module_t的第一个成员变量base指向一个gralloc_module_t结构体,而gralloc_module_t结构体的第一个成员变量common又指向了一个hw_module_t结构体,这意味着,指向一个private_module_t结构体的指针同时可以用作一个gralloc_module_t或者hw_module_t结构体提针来使用。事实上,这是使用C语言来实现的一种继承关系,等价于结构体private_module_t继承结构体gralloc_module_t,而结构体gralloc_module_t继承hw_module_t结构体。
这样,我们就可以把在Gralloc模块中定义的符号HAL_MODULE_INFO_SYM看作是一个hw_module_t结构体。从而解答了本节开头中提到的疑问。
几个重要概念及其数据结构之间的对应关系。
l Fb_device: fb_context_t & framebuffer_device_t
l Alloce_device: alloc_device_t
l Gralloc_module: private_module_t & gralloc_module_t
l Framebuffer: private_handle_t
版权所有,转载请注明出处:http://www.junsion.icoc.bz/ by 小丑