안 드 로 이 드 gralloc 프로 세 스 분석 for msm 8960

원문http://blog.csdn.net/g_salamander/article/details/8424334
Gralloc 모듈 의 플랫폼 배경 과 기능 개술 부분 을 추 가 했 습 니 다.
원문 에 대해 msm 8960 android display 를 수정 하 였 습 니 다.
Surfaceflinger 가 FrameBufferNativeWindow 를 초기 화 하 는 코드 부분 이 추가 되 었 습 니 다.
플랫폼 에 ashmen, PMEM 등 다양한 메모리 유형 이 있 는데 비디오, Graphics, GPU 메모리 접근 의 수 요 를 위해 안 드 로 이 드 는 Gralloc 모듈 을 도입 하여 메모리 관 리 를 실현 합 니 다.Gralloc 는 FrameBuffer 의 배분 도 포함 시 켰 고, ION 을 Gralloc 의 비 FrameBuffer 메모리 의 분배 기로 새로 도입 했다.ION 은 커 널 상태 에 존재 하 는 사용자 프로 세 스 간 의 방문 과 하드웨어 플랫폼 모듈 간 의 데이터 유통 에 효율 적 인 해결 방안 을 제공 했다.
Android 에서 lcd 는 프레임 버퍼 장치 입 니 다. 드라이버 는 프로세서 의 lcd 컨트롤 러 를 통 해 물리 적 메모리 의 한 부분 을 디 스 플레이 로 설정 합 니 다. 이 메모리 영역 에 데 이 터 를 기록 하면 바로 lcd 에 표 시 됩 니 다.Android 는 HAL 에서 프레임 버퍼 장치 에 대한 사용자 층 의 모든 조작 인 터 페 이 스 를 봉인 하고 Surface Flinger 서 비 스 를 통 해 응용 프로그램 에 디 스 플레이 지원 을 제공 하 는 gralloc 모듈 을 제공 합 니 다.시작 과정 에서 시스템 은 gralloc 모듈 을 불 러 온 다음 프레임 버퍼 장 치 를 열 어 장치 의 각종 인 자 를 가 져 오고 gralloc 모듈 의 초기 화 를 완성 합 니 다.프로그램 이 lcd 에 내용 을 표시 하려 면 gralloc 모듈 을 통 해 그래 픽 버퍼 를 신청 한 다음 이 그래 픽 버퍼 를 자신의 주소 공간 에 표시 하고 내용 을 기록 하면 됩 니 다.프로그램 이 더 이상 이 그래 픽 버퍼 가 필요 하지 않 을 때 gralloc 모듈 을 통 해 풀 어 낸 다음 버퍼 에 대한 맵 을 해제 해 야 합 니 다.
1. 기초 데이터 구조
gralloc 모듈 통과 struct private_module_t. 이 구 조 는 다음 과 같이 정의 합 니 다.
struct private_module_t {
    gralloc_module_t base;

    private_handle_t* framebuffer;  /*            */
    uint32_t flags;                 /*                   */
    uint32_t numBuffers;            /*            */
    uint32_t bufferMask;            /*              */
    pthread_mutex_t lock;           /*      private_module_t      */
    buffer_handle_t currentBuffer;  /*                 */
    int pmem_master;                /* pmem         */
    void* pmem_master_base;         /* pmem        */

    struct fb_var_screeninfo info;  /* lcd      */
    struct fb_fix_screeninfo finfo; /* lcd      */
    float xdpi;                     /* x            */
    float ydpi;                     /* y            */
    float fps;                      /* lcd     */
    
    int orientation;                /*      */

    enum {
        PRIV_USAGE_LOCKED_FOR_POST = 0x80000000  /* flag to indicate we'll post this buffer */
    };
};

이 구조의 구성원 은 gralloc 모듈 의 각종 매개 변 수 를 기록 하 였 으 며, 주로 모듈 자체 가 사용 하 였 으 며, 응용 프로그램 이 조작 하 는 그래 픽 버퍼 의 데이터 구 조 는 struct private 이다.handle_t, 정 의 는 다음 과 같다.
#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {
    struct native_handle nativeHandle;  /*             */
#endif
    
    enum {
        PRIV_FLAGS_FRAMEBUFFER    = 0x00000001,
        PRIV_FLAGS_USES_PMEM      = 0x00000002,
        PRIV_FLAGS_USES_MMEM      = 0x00000004,
        PRIV_FLAGS_NEEDS_FLUSH    = 0x00000008,
    };

    enum {
        LOCK_STATE_WRITE     =   1<<31,
        LOCK_STATE_MAPPED    =   1<<30,
        LOCK_STATE_READ_MASK =   0x3FFFFFFF
    };

    /*          ,                 ,            
     *    private_handle_t                 ,          */
    int     fd;
    /*       ,          sMagic   ,      private_handle_t    */
    int     magic;
    /*               ,       0,    PRIV_FLAGS_FRAMEBUFFER
     *               PRIV_FLAGS_FRAMEBUFFER   ,               */
    int     flags;
    int     size;   /*              */
    int     offset; /*                */

    int     phys;   /*                  */
    int     base;   /*                  */
    int     lockState;
    int     writeOwner;
    int     pid;    /*               PID */

#ifdef __cplusplus
    static const int sNumInts = 9;  /*  9      */
    static const int sNumFds = 1;   /*  1       */
    static const int sMagic = 0x3141592;

    private_handle_t(int fd, int size, int flags) :
        fd(fd), magic(sMagic), flags(flags), size(size), offset(0),
        phys(0), base(0), lockState(0), writeOwner(0), pid(getpid())
    {
        version = sizeof(native_handle);
        numInts = sNumInts;
        numFds = sNumFds;
    }
    ~private_handle_t() {
        magic = 0;
    }

    bool usesPhysicallyContiguousMemory() {
        return (flags & PRIV_FLAGS_USES_PMEM) != 0;
    }

    /*       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) 
        {
            LOGE("invalid gralloc handle (at %p)", h);
            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
};

도형 버퍼 의 조작 인 터 페 이 스 는 구조 struct grallocmodule_t 정의:
typedef struct gralloc_module_t {
    struct hw_module_t common;

    /*          ,              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);

    /*                        
     *              ,                    
     *       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, ... );

    /* reserved for future use */
    void* reserved_proc[7];
} gralloc_module_t;

gralloc 장치 사용 구조 struct alloc_device_t. 설명 합 니 다. 그 정 의 는 다음 과 같 습 니 다.
typedef struct alloc_device_t {
    struct hw_device_t common;

    /*              */    
    int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);

    /*              */
    int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);
} alloc_device_t;

프레임 버퍼 장 치 는 구 조 를 사용한다. struct framebuffer_device_t 설명:
typedef struct framebuffer_device_t {
    struct hw_device_t common;

    const uint32_t  flags;  /*               */

    const uint32_t  width;  /* lcd          */
    const uint32_t  height;

    const int       stride; /*                   */

    /*              ,   HAL_PIXEL_FORMAT_RGBX_8888 HAL_PIXEL_FORMAT_RGB_565   */
    const int       format;

    const float     xdpi;
    const float     ydpi;
    const float     fps;              /* lcd    */
    const int       minSwapInterval;  /*               */
    const int       maxSwapInterval;  /*               */

    int reserved[8];

    /*         */
    int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);

    /*             */
    int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);

    /*         buffer            ,             */
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);

    /*     fb  device,               */
    int (*compositionComplete)(struct framebuffer_device_t* dev);

    void* reserved_proc[8];
} framebuffer_device_t;

그 중 구성원 함수 post 는 응용 프로그램 에 있어 서 가장 중요 한 인터페이스 로 데 이 터 를 메모리 에 기록 하 는 작업 을 완성 합 니 다.
2, gralloc 모듈
HAL 중 통과. hw_get_module 인터페이스 에서 지정 한 id 모듈 을 불 러 오고 하 나 를 가 져 옵 니 다. hw_module_t 구조 로 장 치 를 엽 니 다. 절 차 는 다음 과 같 습 니 다.  
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));

int hw_get_module(const char *id, const struct hw_module_t **module) 
{
    int status;
    int i;
    const struct hw_module_t *hmi = NULL;
    char prop[PATH_MAX];
    char path[PATH_MAX];

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* Loop through the configuration variants looking for a module */
    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) {  /*   variant_keys         */
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",  /*          , :/system/lib/hw/gralloc.xxx.so */
                    HAL_LIBRARY_PATH1, id, prop);
            if (access(path, R_OK) == 0) break;

            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, id, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, id);
            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(id, path, module);                 /*      */
    }

    return status;
}

이 를 통 해 알 수 있 듯 이 id 와 시스템 플랫폼 의 이름 으로 so 의 파일 이름 을 조합 하여 설정 한 디 렉 터 리 에 이 라 이브 러 리 파일 을 동적 으로 불 러 온 다음 에 특정한 기 호 를 분석 하여 hw 를 찾 습 니 다.module_t object。
함수 /시스템 / lib / hw 또는 /vendor / lib / hw 디 렉 터 리 에서 gralloc. xxx. so 파일 을 찾 으 면 load 인터페이스 로 불 러 옵 니 다.
최종 호출 gralloc_device_open gralloc 장치 구성원 초기 화 완료:
int gralloc_device_open(const hw_module_t* module, const char* name,
        hw_device_t** device)
{
98    int status = -EINVAL;
99    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
100        const private_module_t* m = reinterpret_cast<const private_module_t*>(
101            module);
102        gpu_context_t *dev;
103        IAllocController* alloc_ctrl = IAllocController::getInstance();
104        dev = new gpu_context_t(m, alloc_ctrl);
105        *device = &dev->common;
106        status = 0;
  } else {
        status = fb_device_open(module, name, device);
    }

    return status;
}

Gralloc module 에 두 개의 장치 gpu 가 있다 고 볼 수 있 습 니 다.alloc_device 와 fbdevice, 전 자 는 GPU 0 에서 사용 하 는 메모리 와 FB 메모 리 를 분배 하 는 데 사용 되 며, GPU 0 메모리 관 리 는 ION allocator 를 사용 합 니 다.후 자 는 Framebuffer Info 를 분배 하고 fb 를 조작 하 는 데 사 용 됩 니 다.
안 드 로 이 드 시스템 에서 모든 그래 픽 버퍼 는 Surface Flinger 서비스 에서 분 배 됩 니 다. 시스템 프레임 버퍼 에 분 배 된 그래 픽 버퍼 는 Surface Flinger 서비스 에서 만 사용 되 고 메모리 에 분 배 된 그래 픽 버퍼 는 Surface Flinger 서비스 에서 도 사용 할 수 있 으 며 다른 응용 프로그램 에서 도 사용 할 수 있 습 니 다.프로그램 이 Surface Flinger 서비스 에 그래 픽 버퍼 를 할당 해 달라 고 요청 할 때 두 번 의 맵 이 발생 합 니 다. 서비스 가 있 는 프로 세 스 는 먼저 신청 한 버퍼 를 서비스의 주소 공간 에 매 핑 한 다음 프로그램 이 이 그래 픽 버퍼 를 사용 할 때 프로그램의 주소 공간 에 매 핑 합 니 다.분배 함수 의 실현 은 다음 과 같다.
 
static int gralloc_alloc_framebuffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
{
    private_module_t* m = reinterpret_cast<private_module_t*>(
            dev->common.module);
    pthread_mutex_lock(&m->lock);
    int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
    pthread_mutex_unlock(&m->lock);
    return err;
}

static int gralloc_alloc_buffer(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
{
127    int err = 0;
128    int flags = 0;
129    size = roundUpToPageSize(size);
130    alloc_data data;
131    data.offset = 0;
132    data.fd = -1;
133    data.base = 0;
134    data.size = size;
135    if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)
136        data.align = 8192;
137    else
138        data.align = getpagesize();
139    data.pHandle = (unsigned int) pHandle;
140    err = mAllocCtrl->allocate(data, usage);
141
142    if (!err) {
143        /* allocate memory for enhancement data */
144        alloc_data eData;
145        eData.fd = -1;
146        eData.base = 0;
147        eData.offset = 0;
148        eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
149        eData.pHandle = data.pHandle;
150        eData.align = getpagesize();
151        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
152        int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);
153        ALOGE_IF(eDataErr, "gralloc failed for eData err=%s", strerror(-err));
154
155        if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {
156            flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
157        }
158
159        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
160            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
161            //The EXTERNAL_BLOCK flag is always an add-on
162            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {
163                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
164            }
165            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {
166                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;
167            }
168        }
169
170        flags |= data.allocType;
171        int eBaseAddr = int(eData.base) + eData.offset;
172        private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
173                bufferType, format, width, height, eData.fd, eData.offset,
174                eBaseAddr);
175
176        hnd->offset = data.offset;
177        hnd->base = int(data.base) + data.offset;
178        *pHandle = hnd;
179    }
180
181    ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
182
183    return err;    
184}

/*****************************************************************************/

static int gralloc_alloc(alloc_device_t* dev,int w, int h, int format, int usage,
                            buffer_handle_t* pHandle, int* pStride)
{
    if (!pHandle || !pStride)
        return -EINVAL;

    size_t size, stride;

    int align = 4;
    int bpp = 0;
    switch (format) {  /*             */
        case HAL_PIXEL_FORMAT_RGBA_8888:
        case HAL_PIXEL_FORMAT_RGBX_8888:
        case HAL_PIXEL_FORMAT_BGRA_8888:
            bpp = 4;
            break;
        case HAL_PIXEL_FORMAT_RGB_888:
            bpp = 3;
            break;
        case HAL_PIXEL_FORMAT_RGB_565:
        case HAL_PIXEL_FORMAT_RGBA_5551:
        case HAL_PIXEL_FORMAT_RGBA_4444:
            bpp = 2;
            break;
        default:
            return -EINVAL;
    }
    size_t bpr = (w*bpp + (align-1)) & ~(align-1);
    size = bpr * h;
    stride = bpr / bpp;

    int err;
    if (usage & GRALLOC_USAGE_HW_FB) {
        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);  /*                */
    } else {
        err = gralloc_alloc_buffer(dev, size, usage, pHandle);       /*             */
    }

    if (err < 0) {
        return err;
    }

    *pStride = stride;
    return 0;
}

3、gpu_alloc 모듈
gpu 0 메모리 즉 비 HWFB 메모 리 는 ION 분배 기 를 사용 하여 분 배 됩 니 다. 이 글 은 상세 하 게 설명 하지 않 습 니 다.
 
4. fb 모듈
... 에 있다 gralloc_device_open 에서 전달 하 는 매개 변수 에 따라 두 장 치 를 각각 초기 화 합 니 다. 정 의 는 다음 과 같 습 니 다.
#define GRALLOC_HARDWARE_FB0 "fb0"
#define GRALLOC_HARDWARE_GPU0 "gpu0"

인자 가 "gpu 0" 이 아니라면 "fb% u" 형식 이 라면 fb 를 호출 합 니 다.device_open fb 장 치 를 초기 화 합 니 다. 주요 프로 세 스 는 gralloc 를 여 는 것 과 대체적으로 일치 합 니 다. 함수 에서 mapFrameBuffer - > mapFrameBufferLocked 를 호출 하여 프레임 캐 시 장치 의 인 자 를 가 져 오고 장치 노드 를 사용자 공간 에 표시 합 니 다. 프로 세 스 는 다음 과 같 습 니 다 (대체적으로 msm 8960 플랫폼 코드 에 변화 가 있 습 니 다. msm 플랫폼 에서 fb 장치 파일 이름 은 / dev / graphics / fb% u).
int mapFrameBufferLocked(struct private_module_t* module)
{
    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;

    info.bits_per_pixel = 32;
    info.red.offset     = 16;
    info.red.length     = 8;
    info.green.offset   = 8;
    info.green.length   = 8;
    info.blue.offset    = 0;
    info.blue.length    = 8;
    info.transp.offset  = 24;
    info.transp.length  = 8;

    /*
     * 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, FBIOPAN_DISPLAY, &info) == -1) {
        info.yres_virtual = info.yres;
        flags &= ~PAGE_FLIP;
        LOGW("FBIOPAN_DISPLAY 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;
        LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
                info.yres_virtual, info.yres*2);
    }

    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
        return -errno;

    int refreshRate = 1000000000000000LLU /
    (
            uint64_t( info.upper_margin + info.lower_margin + info.yres )
            * ( info.left_margin  + info.right_margin + info.xres )
            * info.pixclock
    );  /*   lcd    */

    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;

    LOGI(   "using (fd=%d)
" "id = %s
" "xres = %d px
" "yres = %d px
" "xres_virtual = %d px
" "yres_virtual = %d px
" "bpp = %d
" "r = %2u:%u
" "g = %2u:%u
" "b = %2u:%u
", 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 ); LOGI( "width = %d mm (%f dpi)
" "height = %d mm (%f dpi)
" "refresh rate = %.2f Hz
", 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, private_handle_t::PRIV_FLAGS_USES_PMEM); module->numBuffers = info.yres_virtual / info.yres; /* */ module->bufferMask = 0; void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); /* fb */ if (vaddr == MAP_FAILED) { LOGE("Error mapping the framebuffer (%s)", strerror(errno)); return -errno; } module->framebuffer->base = intptr_t(vaddr); /* */ memset(vaddr, 0, fbSize); return 0; }

fb 장치 의 열기 와 HWFB 메모리 의 분 배 는 FrameBufferNativeWindow 의 구조 코드 에서 fb0 장 치 를 열 어 Framebuffer Info 를 가 져 온 다음 gralloc 를 사용 하여 이 FrameBufferNativeWindow 에 두 개의 HW 를 분배 하 는 것 을 볼 수 있 습 니 다.FB 메모리 즉 Framebuffer, 즉 모든 Window, double buffer 입 니 다.코드 는 다음 과 같 습 니 다:
62/*
63 * This implements the (main) framebuffer management. This class is used
64 * mostly by SurfaceFlinger, but also by command line GL application.
65 *
66 * In fact this is an implementation of ANativeWindow on top of
67 * the framebuffer.
68 *
69 * Currently it is pretty simple, it manages only two buffers (the front and
70 * back buffer).
71 *
72 */
73
74FramebufferNativeWindow::FramebufferNativeWindow()
75    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
76{
77    hw_module_t const* module;
78    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
79        int stride;
80        int err;
81        int i;
82        err = framebuffer_open(module, &fbDev);
83        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
84
85        err = gralloc_open(module, &grDev);
86        ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
87
88        // bail out if we can't initialize the modules
89        if (!fbDev || !grDev)
90            return;
91
92        mUpdateOnDemand = (fbDev->setUpdateRect != 0);
93
94        // initialize the buffer FIFO
95        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
96           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
97            mNumBuffers = fbDev->numFramebuffers;
98        } else {
99            mNumBuffers = MIN_NUM_FRAME_BUFFERS;
100        }
101        mNumFreeBuffers = mNumBuffers;
102        mBufferHead = mNumBuffers-1;
103
104        /*
105         * This does not actually change the framebuffer format. It merely
106         * fakes this format to surfaceflinger so that when it creates
107         * framebuffer surfaces it will use this format. It's really a giant
108         * HACK to allow interworking with buggy gralloc+GPU driver
109         * implementations. You should *NEVER* need to set this for shipping
110         * devices.
111         */
112#ifdef FRAMEBUFFER_FORCE_FORMAT
113        *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
114#endif
115
116        for (i = 0; i < mNumBuffers; i++)
117        {
118                buffers[i] = new NativeBuffer(
119                        fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
120        }
121
122        for (i = 0; i < mNumBuffers; i++)
123        {
124                err = grDev->alloc(grDev,
125                        fbDev->width, fbDev->height, fbDev->format,
126                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
127
128                ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
129                        i, fbDev->width, fbDev->height, strerror(-err));
130
131                if (err)
132                {
133                        mNumBuffers = i;
134                        mNumFreeBuffers = i;
135                        mBufferHead = mNumBuffers-1;
136                        break;
137                }
138        }
139
140        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
141        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
142        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
143        const_cast<int&>(ANativeWindow::minSwapInterval) =
144            fbDev->minSwapInterval;
145        const_cast<int&>(ANativeWindow::maxSwapInterval) =
146            fbDev->maxSwapInterval;
147    } else {
148        ALOGE("Couldn't get gralloc module");
149    }
150
151    ANativeWindow::setSwapInterval = setSwapInterval;
152    ANativeWindow::dequeueBuffer = dequeueBuffer;
153    ANativeWindow::lockBuffer = lockBuffer;
154    ANativeWindow::queueBuffer = queueBuffer;
155    ANativeWindow::query = query;
156    ANativeWindow::perform = perform;
157    ANativeWindow::cancelBuffer = NULL;
158}

FrameBufferNativeWindow 를 만 드 는 것 은 DisplayHardware 의 구조 후 초기 화 에서 만 발생 합 니 다. 코드 세 션 은 다음 과 같 습 니 다.
150void DisplayHardware::init(uint32_t dpy)
151{
152    mNativeWindow = new FramebufferNativeWindow();  //******
153    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
154    if (!fbDev) {
155        ALOGE("Display subsystem failed to initialize. check logs. exiting...");
156        exit(0);
157    }
158
159    int format;
160    ANativeWindow const * const window = mNativeWindow.get();
161    window->query(window, NATIVE_WINDOW_FORMAT, &format);
162    mDpiX = mNativeWindow->xdpi;
163    mDpiY = mNativeWindow->ydpi;
164    mRefreshRate = fbDev->fps;
....
}

디 스 플레이 하드웨어 의 진정한 구 조 는 Surfacelinger 가 시 작 된 후 ready ToRun 에서 만 사용 되 고 나머지 는 모두 복사 구조의 기본 적 인 Bitwise Copy 를 사용 합 니 다. 물론 이것 은 하나의 화면 을 대상 으로 하 는 것 일 뿐 현재 큰 화면 이 주류 입 니 다.관련 코드 세 션 은 다음 과 같 습 니 다.
217status_t SurfaceFlinger::readyToRun()
218{
219    ALOGI(   "SurfaceFlinger's main thread ready to run. "
220            "Initializing graphics H/W...");
221
222    // we only support one display currently
223    int dpy = 0;
224
225    {
226        // initialize the main display
227        GraphicPlane& plane(graphicPlane(dpy));
228        DisplayHardware* const hw = new DisplayHardware(this, dpy); //*******
229        plane.setDisplayHardware(hw);
230    }
231
232    // create the shared control-block
233    mServerHeap = new MemoryHeapBase(4096,
234            MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
235    ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
236
237    mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
238    ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
239
240    new(mServerCblk) surface_flinger_cblk_t;
241
242    // initialize primary screen
243    // (other display should be initialized in the same manner, but
244    // asynchronously, as they could come and go. None of this is supported
245    // yet).
246    const GraphicPlane& plane(graphicPlane(dpy));
247    const DisplayHardware& hw = plane.displayHardware();
248    const uint32_t w = hw.getWidth();
249    const uint32_t h = hw.getHeight();
250    const uint32_t f = hw.getFormat();
251    hw.makeCurrent();
.....
}

 
fb 모듈 의 가장 중요 한 작업 은 응용 프로그램 이 지정 한 내용 을 메모리 에 기록 하 는 것 입 니 다. 함 수 를 통 해 fb_post 가 완 성 된 절 차 는 다음 과 같 습 니 다 (msm 8960 코드 는 대체적으로 이와 같 지만 FBIOPUT VSCREENINFO IOCTL CODE 를 사용 합 니 다).
/*       buffer             */
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
	unsigned int phys;
	void* virt;
	int pitch;
	int format;

    /*       handle              Gralloc      */
    if (private_handle_t::validate(buffer) < 0)
        return -EINVAL;

    fb_context_t* ctx = (fb_context_t*)dev;

    private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);  /*       */
    private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);    /*      */

    if (m->currentBuffer) {  /*              */
        m->base.unlock(&m->base, m->currentBuffer);
        m->currentBuffer = 0;
    }

    if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {  /*                    */
        m->base.lock(&m->base, buffer,  /*         */
                private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
                0, 0, m->info.xres, m->info.yres, NULL);

        const size_t offset = hnd->base - m->framebuffer->base; /*                */
        /*       fb_var_screeninfo        activate    FB_ACTIVATE_VBL
         *                  ,                    
         *                ,                            */
        m->info.activate = FB_ACTIVATE_VBL;
        m->info.yoffset = offset / m->finfo.line_length;  /*          */

        if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1) {  /*        */
            LOGE("FBIOPAN_DISPLAY failed");
            m->base.unlock(&m->base, buffer); 
            return -errno;
        }

        if (UNLIKELY(mDebugFps)) {
            debugShowFPS();
        }

        m->currentBuffer = buffer;  /*           */
    return 0;
}

5、Gralloc map/unmap、register/unregister
GPU 메모리 file descriptor 가 한 프로 세 스 A 에서 다른 프로 세 스 B 로 전 달 된 후 프로 세 스 B 는 grallocregister_buffer 는 allocator 를 사용 합 니 다. 이 때 는 ION 이 이 buffer 를 이 프로 세 스에 비 추어 접근 하 는 데 사 용 됩 니 다.이 기능 들 은 gralloc 의 mapper 기능 으로 한다.
메모리 file descriptor, binder 가 이 메모리 fd 를 전달 하 는 구체 적 인 메커니즘 은 ION 의 기능 을 참조 합 니 다.

좋은 웹페이지 즐겨찾기