Gralloc模塊分析

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.

根據以上的三個結構我們可以畫出結構圖如下:


gralloc數據結構

回到上面問題械荷,為什么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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末弥搞,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子渠旁,更是在濱河造成了極大的恐慌攀例,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顾腊,死亡現場離奇詭異粤铭,居然都是意外死亡,警方通過查閱死者的電腦和手機杂靶,發(fā)現死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門梆惯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酱鸭,“玉大人,你說我怎么就攤上這事垛吗“妓瑁” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵怯屉,是天一觀的道長蔚舀。 經常有香客問我,道長蚀之,這世上最難降的妖魔是什么蝗敢? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮足删,結果婚禮上寿谴,老公的妹妹穿的比我還像新娘。我一直安慰自己失受,他們只是感情好讶泰,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拂到,像睡著了一般痪署。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兄旬,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天狼犯,我揣著相機與錄音,去河邊找鬼领铐。 笑死悯森,一個胖子當著我的面吹牛,可吹牛的內容都是我干的绪撵。 我是一名探鬼主播瓢姻,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼音诈!你這毒婦竟也來了幻碱?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤细溅,失蹤者是張志新(化名)和其女友劉穎褥傍,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體谒兄,經...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡摔桦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邻耕。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸥咖,死狀恐怖,靈堂內的尸體忽然破棺而出兄世,到底是詐尸還是另有隱情啼辣,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布御滩,位于F島的核電站鸥拧,受9級特大地震影響,放射性物質發(fā)生泄漏削解。R本人自食惡果不足惜富弦,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氛驮。 院中可真熱鬧腕柜,春花似錦、人聲如沸矫废。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓖扑。三九已至唉铜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間律杠,已是汗流浹背潭流。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柜去,地道東北人幻枉。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像诡蜓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子胰挑,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,696評論 0 3
  • 本文涉及的源代碼基于 Android-7.1.1r蔓罚。 一、Android GUI 框架 SurfaceFlinge...
    seraphzxz閱讀 4,114評論 1 59
  • Android系統對硬件設備的支持是分兩層的瞻颂。一層實現在內核空間中(只有內核空間才有特權操作硬件設備)豺谈,另一層實現...
    passerbywhu閱讀 658評論 0 0
  • 小記 本書的六篇序言里,各位大咖都從自己獨特的視角出發(fā)贡这,結合自己的人生體驗茬末,將書中的思想加以內化和理解,我想這本身...
    雕兄_KYP閱讀 665評論 0 0
  • 兩個同樣溫和的人在一起很是默契,結婚多年丽惭,生活如每日都喝的玉米粥击奶,平淡卻養(yǎng)胃。 有一天责掏,她翻看舊物柜砾,看到他大學里讀...
    故事匯閱讀 295評論 0 0