1. 程式人生 > 其它 >【android開發】Android GUI系統學習1:Gralloc

【android開發】Android GUI系統學習1:Gralloc

Gralloc模組是從Android Eclair(android 2.1)開始加入的一個HAL模組,Gralloc的含義為是Graphics Alloc(圖形分配)。他對上為libui提供服務,為其分配視訊記憶體,重新整理顯示等。對下對framebuffer進行管理。

gralloc程式碼通常位於hardware/libhardware/modules/gralloc目錄下。包含以下幾個檔案:

Android.mk framebuffer.cpp gralloc.cpp gralloc_priv.h gr.h mapper.cpp

另外,與其相關的標頭檔案位於hardware/libhardware/include/hardware,涉及fb.h和gralloc.h。

下面從gralloc的呼叫開始學習gralloc的程式碼。程式碼基於android4.4。

gralloc的呼叫是從FramebufferNativeWindow.cpp的建構函式開始的。FramebufferNativeWindow實現FrameBuffer的管理,它主要被SurfaceFlinger使用,也可以被OpenGL Native程式使用。在本質上,它在Framebuffer之上實現了一個ANativeWindow,目前它只管理兩個buffers:front and back buffer。

如下所示(FramebufferNativeWindow.cpp):

FramebufferNativeWindow::FramebufferNativeWindow()
 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
 {
 hw_module_t const* module;
 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
 int stride;
 int err;
 int i;
 err = framebuffer_open(module, &fbDev);
 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));

err = gralloc_open(module, &grDev);
 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));

// bail out if we can't initialize the modules
 if (!fbDev || !grDev)
 return;

mUpdateOnDemand = (fbDev->setUpdateRect != 0);

// initialize the buffer FIFO
 if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
 fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){ mNumBuffers = fbDev->numFramebuffers;
 } else {
 mNumBuffers = MIN_NUM_FRAME_BUFFERS;
 }
 mNumFreeBuffers = mNumBuffers;
 mBufferHead = mNumBuffers-1;

/*
 * This does not actually change the framebuffer format. It merely
 * fakes this format to surfaceflinger so that when it creates
 * framebuffer surfaces it will use this format. It's really a giant
 * HACK to allow interworking with buggy gralloc+GPU driver
 * implementations. You should *NEVER* need to set this for shipping
 * devices.
 */
 #ifdef FRAMEBUFFER_FORCE_FORMAT
 *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
 #endif

for (i = 0; i < mNumBuffers; i++) { buffers[i] = new NativeBuffer( fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
 }

for (i = 0; i < mNumBuffers; i++) { err = grDev->alloc(grDev,
 fbDev->width, fbDev->height, fbDev->format,
 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);

ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
 i, fbDev->width, fbDev->height, strerror(-err));

if (err)
 {
 mNumBuffers = i;
 mNumFreeBuffers = i;
 mBufferHead = mNumBuffers-1;
 break;
 }
 }

const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
 const_cast<int&>(ANativeWindow::minSwapInterval) =
 fbDev->minSwapInterval;
 const_cast<int&>(ANativeWindow::maxSwapInterval) =
 fbDev->maxSwapInterval;
 } else {
 ALOGE("Couldn't get gralloc module");
 }

ANativeWindow::setSwapInterval = setSwapInterval;
 ANativeWindow::dequeueBuffer = dequeueBuffer;
 ANativeWindow::queueBuffer = queueBuffer;
 ANativeWindow::query = query;
 ANativeWindow::perform = perform;

ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
 ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
 ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
 }

這裡會先根據gralloc的module ID來得到hw_module_t結構。hw_get_module->hw_get_module_by_class。在hw_get_module_by_class裡面,首先根據平臺配置找到gralloc動態庫的位置,預設使用gralloc.default.so。 參見以下程式碼(hardware.c):

 for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, name, prop);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH2, name);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, name);
            if (access(path, R_OK) == 0) break;
        }
    }
 status = -ENOENT;
 if (i < HAL_VARIANT_KEYS_COUNT+1) {
 /* load the module, if this fails, we're doomed, and we should not try
 * to load a different variant. */
 status = load(class_id, path, module);
 }

找到gralloc庫的路徑後,會呼叫load函式,在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 結構是一個全域性結構,在gralloc.cpp中已經得到初始化了。這也是為什麼每一個HAL模組都要定義並初始化一個名字為HAL_MODULE_INFO_SYM的hw_module_t結構

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,
};

回過頭,回到FramebufferNativeWindow的構造函數出,接下來呼叫了err = framebuffer_open(module, &fbDev);framebuffer_open定義在fb.h中,是一個inline函式,其實最終呼叫了就是上面結構體中初始化的open函式,open函式指向gralloc_device_open,其實現為(gralloc.cpp):

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;
}

fb_device_open的定義如下所示(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)) {
        /* initialize our state here */
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
        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 = fb_close;
        dev->device.setSwapInterval = fb_setSwapInterval;
        dev->device.post            = fb_post;
        dev->device.setUpdateRect = 0;

        private_module_t* m = (private_module_t*)module;
        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)
                         ? 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;
}

接下來的gralloc_open也是呼叫了gralloc_device_open,只不過name引數一個是GRALLOC_HARDWARE_GPU0,而另外一個是GRALLOC_HARDWARE_FB0,這兩個函式分別得到alloc_device_t 和 framebuffer_device_t結構。到現在為止,gralloc模組的三個主要結構體,gralloc_module_t,alloc_device_t,framebuffer_device_t都已經獲取到了。其中在fb_device_open函式中會獲取實際的framebuffer裝置(通常是/dev/graphics/fb0)的一些重要引數以及能力,比如解析度資訊以及支援多少個緩衝等,另外會把framebuffer對映到內測的地址儲存到alloc_module_t中。android一般使用的都是雙緩衝機制。具體程式碼如下(framebuffer.cpp),其中涉及到對private_module_t中一些成員的完善,涉及到gralloc_module_t以及private_handle_t等,其定義在gralloc_priv.h中,這兩個結構中都儲存了framebuffer的一些私有資訊。

int mapFrameBufferLocked(struct private_module_t* module)
{
// already initialized...
if (module->framebuffer) {
return 0;
}

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;

struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;

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;

/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
}

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;

ALOGI( "using (fd=%d)n"
"id = %sn"
"xres = %d pxn"
"yres = %d pxn"
"xres_virtual = %d pxn"
"yres_virtual = %d pxn"
"bpp = %dn"
"r = %2u:%un"
"g = %2u:%un"
"b = %2u:%un",
fd,
finfo.id,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length
);

ALOGI( "width = %d mm (%f dpi)n"
"height = %d mm (%f dpi)n"
"refresh rate = %.2f Hzn",
info.width, xdpi,
info.height, ydpi,
fps
);
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;

if (finfo.smem_len <= 0)
return -errno;
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;

/*
* map the framebuffer
*/

int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);

module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;

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;
}
module->framebuffer->base = intptr_t(vaddr);
memset(vaddr, 0, fbSize);
return 0;
}

由上面函式看出,mapFrameBufferLocked主要做了下面幾件事情: 1. 開啟framebuffer裝置

2. 獲取 fb_fix_screeninfo and fb_var_screeninfo

3. refill fb_var_screeninfo

4. 判斷是否支援PAGE_FLIP

5. 計算重新整理率

6. 列印gralloc資訊

7. 填充private_module_t

8. mmap the framebuffer

由於篇幅限制,這裡暫時說道這裡,如要檢視後續內容請檢視原文:http://www.coderonline.net/android-gui%e7%b3%bb%e7%bb%9f%e5%ad%a6%e4%b9%a01%ef%bc%9agralloc.html