您的位置:首页 > 其它

SurfaceFlinger启动过程分析(三)

2012-01-15 11:13 183 查看
转载时请注明出处和作者
文章出处: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();

下面贴张图,直观一点。

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