Sunxi Framebuffer框架
Framebuffer的总体架构如下图所示:
在V833 Tina SDK上,framebuffer的实现基于Display Engine的channel 2 的第 0 个图层.
在framebuffer架构的实现中,struct fb_info *info中的成员info->screen_base起者至关重要的作用,它即是framebuffer,也是DE中对应的图层,所对应的真实的内核虚拟地址,显示的最终目的,就是将这片的buffer在DE中生效.
info->screen_base的分配:
fb_read的实现,直接读取info->screen_base的内容:
fb_write的实现,直接写到screen_base中.
用户态怎么写这个图层呢?当然是通过mmap来实现:
可以看到,fb_mmap的本质仍然是将info->screen_base的地址映射到用户空间去.
所以,可以看到,通过内核,DE硬件以及用户态指针都可以访问到fb这个图层,framebuffer的工作原理就是通过修改完图层之后,在刷新率中断作用下,将framebuffer中的内容显示出来。
Framebuffer的申请大小:
从上面的fb_map_video_memory函数实现中可以看出,framebuffer 的大小保存在变量smem_len中,它的而初始化很有意思,按照ARGB8888像素格式计算,它的大小计算公式为:
xres_virtual * 4 * yres_virtual * 2
重点是为何最后要乘以2,其实这是FrameBuffer实现的双Buffer机制(也叫乒乓buffer),为了防止画面被撕裂,原理如下:
为了避免画面撕裂的情况, 绝不应该在当前显示的画面上绘图,所以,为了满足这种需求,framebuffer在申请的时候,一共申请了两张,一张用于前景显示,另一张则作为后背可编辑画面,配合VSYNC(刷新帧率)中断,就可以避免撕裂的情况发生。
以本例中的640*480的屏为例,每张framebuffer 的大小是:
sizeof(framebuffer) = 640 * 480 * 4 = 0x12C000
两个framebuffer就是640 * 480 * 4 * 2 = 0x12C000 * 2 = 0x258000
所以就是如下图的情况:
调试调用堆栈观察buffer的使用情况:
开启设置buffer地址的打印LOG
LOG如下:
看起来有两个像是地址的东西0x42c000和0x300000,我们姑且先不去追究其来源,it is a long story,我们姑且认为它就是framebuffer对应的物理地址(实际上确实是).这里的理解是错误的,这两个地址不同,实际上由于要做旋转操作,0x42c000和0x300000是G2D分配的旋转buffer.而info->screen_base是用于做旋转中转,不不是最终的硬件图层。
layer:ch2, layer0, format=0, size=<480,640>, crop=<0,0,480,640>,frame=<480,640>, en=1 addr[0x42c000,0x0,0x0> alpha=<0,255>
layer:ch2, layer0, format=0, size=<480,640>, crop=<0,0,480,640>,frame=<480,640>, en=1 addr[0x300000,0x0,0x0> alpha=<0,255>
可以看到第一个framebuffer的地址是0x300000,第二个是0x42c000(忽略后面的两个0,0,其对用的是YUV图的U,V分量地址,ARGB没有UV分量)
可以看到0x42c000-0x300000 = 0x12C000,恰好符合一个framebuffer的大小,所以示意图如下:
DS5调试现场:
这个和RTOS上播放视频时的调用堆栈如出一辙,都是通过set config接口将存储当前帧数据的物理地址设置给DE的对应图层,然后等待下次的VSYNC(刷新率)中断过来生效这个地址的当前帧。
地址的魔法:
上面提到的两个地址0x42c000和0x300000怎么看也不像虚拟地址,我们找到它的虚拟地址,实际上,虚拟地址存储在info->screen_base中
图中有两个指针指向framebuffer,一个是screen_buffer,另一个是screen_base,可是,寻遍代码也只找到对screen_base赋值的地方,没有找到对screen_buffer赋值的地方,为何两个同时改变呢?原因是他们竟然是一个联合体,具有共同的地址:
猜的没错的话,0xD1001000即是framebuffer对应的内核虚拟地址,而0x300000是其对应的物理地址。
怎么证明我们的猜想呢?使用HACK MMU的方法!
我们将MMU关闭,让物理地址显露真身,如果他们两个地址的内容完全一样,就能说明他们是同一个地址了。
试验失败!!!因为使用了IOMMU.
设置图层物理地址的地方:
de_rtmx_set_lay_laddr,可以看到,和上面的调用是同一个堆栈.
实际上,代码中得到上述两个物理地址的地方在这里
终于找到了config.info.fb.addr[0]的初始化地方了,令人意外的是,它竟然是在G2D的调用中:
关于pan_display时候乒乓buffer的切换,找到了这个点,在fb_g2d_rot_apply函数中
一下是LOG输出,可以看到fb addr整个过程中不会发生变化,而地址会在ODD/EVEN中不断地切换。
我们终于从上面地LOG中,找到了0x30000和0x42c000地来历地线索.
地址地分配和大小:
下面是fb_g2d_rot_create接口中一小段实现,它创建了两个framebuffer作为乒乓buffer,分配的地址即使物理地址。
添加LOG:
得到的LOG如下:
rotate操作定义
根据以上LOG,得到一下几个重要信息:
- 由于使用的是竖屏,所以画面投到framebuffer要做rotate 270度的操作.
- rotate操作是通过G2D完成的,具体的讲是通过调用g2d的API g2d_blit_h完成的。
- 源地址来源于上面讲的info->screen_base/info->screen_buffer对应的物理地址,目的物理地址则是上面给G2D分配的target buffer, 也就是最终用于显示的图层0x30000和0x42c000.
- pan buffer的乒乓实现是通过yoffset的偏移来计算的,比如第一次yoffset=0,下一次则为480,在下次又是0.
- smem_start为0并不奇怪,0是有效地址,否则无法解释这里log中用laddr=0 作为G2D的SRC地址,更进一步,出现物理地址为0很可能是因为使用IOMMU的缘故,由于DEMO起来后,framebuffer很可能是使用IOMMU的第一个IP,所以0地址分配隔了smem_start。
追本溯源,这个rotate和旋转角度从何而来呢?
从以上截图可以看到,disp_rotation_used和degree%d两个变量均来自于外部配置文件,在tina中,所有的配置参数最终都来源于devicetree,我们在devictree中看一下是否能找到两个变量:
在tina-v83x/out/v833-perf1/image/.sunxi.dts 中,我们找到了反编译后的devicetree文本文件,可以看到,这里明显给出了关于旋转参数的配置数据.
加上旋转后,整个过程图解如下:
所以,包括旋转用到的两个framebuffer, 实际上分配了四张buffer.
fbtest用例:
tina 集成了fbtest工具用来对/dev/fb0节点进行基本功能的验证,正确配置后fbtest工具会被打包进rootfs中:
编译后烧录,控制台执行命令fbtest,即可在LCD屏上看到测试效果。
总结:
1./dev/fbX节点对应某片叫做framebuffer的内存空间,这片内存空间同时对应到DE 多个UI图层中的某一个图层。
2.DE的作用是将各个图层送来的显示数据进行混合后送给TCON去显示,TCON驱动外设接口,比如HDMI,CVBS等将混合好的图层输出到屏幕上。
结束!
相关文章
- 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问
- Python twisted框架使用解析
- Pytest测试框架一键动态切换环境思路及方案
- 日志框架到底是Logback 还是 Log4j2
- kali中浏览器攻击框架BeEF的使用
- 【渗透测试框架】Metasploit-Framework(MSF)安装与使用
- 基于Java(SSH框架)+MySQL 实现(Web)公司通用门户(CMS)网站【100010223】
- Qt编写气体安全管理系统2-界面框架
- [Web]如何利用Boostrap框架搭建一个还可以的静态网站
- java beanUtils框架
- 跨平台开发之阿里Weex框架环境搭建(二)
- Python爬虫练习四-scrapy框架练手
- 【spring框架】spring框架学习目录
- 也谈设计模式,架构,框架和类库的区别
- 首次披露!拍立淘技术框架及核心算法,日均UV超千万
- 针对Vue框架渗透测试-未授权访问目录漏洞【渗透实战+工具开发】