您的位置:首页 > 其它

SurfaceFlinger启动过程分析(三)

2012-04-19 13:38 393 查看
转载时请注明出处和作者

文章出处:http://danielwood.cublog.cn

作者:Daniel Wood

------------------------------------------------------------

    内存映射对于framebuffer来说非常重要,因为通常用户是不能直接操作物理地址空间的(也就是物理内存?),然而通过mmap映射之后,将framebuffer的物理地址空间映射到用户空间的一段虚拟地址中,用户就可以通过操作这段虚拟内存而间接操作framebuffer了,你在那段虚拟内存中画了图,相应的图就会显示到屏幕上。

——这段是自己的理解,有错必究!

下面是framebuffer.cpp中的mapFrameBufferLocked函数。

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;

    /*

     * Explicitly request 5/6/5

     */

    info.bits_per_pixel = 16;

    info.red.offset = 11;

    info.red.length = 5;

    info.green.offset = 5;

    info.green.length = 6;

    info.blue.offset = 0;

    info.blue.length = 5;

    info.transp.offset = 0;

    info.transp.length = 0;

    /*

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

        LOGW("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;

        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

    );

    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)\n"

            "id = %s\n"

            "xres = %d px\n"

            "yres = %d px\n"

            "xres_virtual = %d px\n"

            "yres_virtual = %d px\n"

            "bpp = %d\n"

            "r = %2u:%u\n"

            "g = %2u:%u\n"

            "b = %2u:%u\n",

            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)\n"

            "height = %d mm (%f dpi)\n"

            "refresh rate = %.2f Hz\n",

            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) {

        LOGE("Error mapping the framebuffer (%s)", strerror(errno));

        return -errno;

    }

    module->framebuffer->base = intptr_t(vaddr);

    memset(vaddr, 0, fbSize);

    return 0;
}

这个函数就是和驱动相关的调用,其实结合驱动去看代码是很有意思的,把一路都打通了。

该函数首先通过open函数打开设备结点。

"/dev/graphics/fb%u"和"/dev/fb%u",如果前一个顺利打开的话,那么就不打开第二个。我的Log显示打开的是第一个设备结点/dev/graphics/fb%u。

    然后通过ioctl读取设备的固定参数(FBIOGET_FSCREENINFO)和可变参数(FBIOGET_VSCREENINFO)。

【kernel部分的代码在drivers\video\fbmem.c中。】

    然后对可变参数进行修改,通过ioctl设置(FBIOPUT_VSCREENINFO)显示屏的可变参数。

    设置好以后再ioctl-FBIOGET_VSCREENINFO获得可变参数,然后在log上打出显示屏的各个参数设置,也就是我们开机看到的一长串log。

I/gralloc ( 1620): using (fd=8) 

I/gralloc ( 1620): id = truly-ILI9327 

I/gralloc ( 1620): xres = 240
px 

I/gralloc ( 1620): yres = 400
px 

I/gralloc ( 1620): xres_virtual = 240
px 

I/gralloc ( 1620): yres_virtual = 800
px 

I/gralloc ( 1620): bpp = 16 

I/gralloc ( 1620): r = 11:5 

I/gralloc ( 1620): g = 5:6 

I/gralloc ( 1620): b = 0:5 

I/gralloc ( 1620): width = 38
mm (160.421051 dpi) 

I/gralloc ( 1620): height = 64
mm (158.750000 dpi) 

I/gralloc ( 1620): refresh rate = 60.00
Hz

    然后通过mmap完成对显示缓存区的映射。这样mapFrameBufferLocked函数的任务算是完成了。

好了,以上所讲的只是(1)中的第一句话而已

Displayhardware.cpp中的init函数。
mNativeWindow = new FramebufferNativeWindow();

下面贴张图,直观一点。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  module video 任务