您的位置:首页 > 其它

SurfaceFlinger启动过程分析(三)

2011-08-19 14:10 323 查看
文章出处: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)中的第一句话而已

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