Android Framebuff 分析

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

声明:本博文原型来自CSDNMAXLENG

LinuxFramebuffer用于实现对不同框架显示控制器进行抽象,对用户进程而言复杂的显示过程被简化成了写显存。Framebuffer的第二功能是对输出到屏上的数据进行缓冲,将待显示的数据写入至备用显示buffer,最后执行显存地址切换输出下一帧数据。Android帧缓冲流程框图如下:

SurfaceFlinger将自己的“Surface”投掷到屏幕缓冲区,Surface的最小单位为window,在结构框图中我们称为后台窗口。后台待显示窗口通过Blit(区块搬移)到备用显示缓冲区,然后在通过Framebuffer驱动Post到显示屏幕上,完成窗口的输出工作。

从最根源的硬件帧缓冲机制我们知道显示FrameBuffer在系统中就是一段内存,界面显示的工作就是把需要输出的内容放入到该段内存的某个位置。我们将从基本的点(像素点)和基本的缓冲区操作开始研究。


一、Framebuffer数据格式与操作


1.像素点的格式

对于不同的显示设备来讲FrameBuffer存储一个像素点二进制格式各不相同,我们一般通过单个像素点使用存储单元数目、单元存储单元内部颜色分量排列关系与颜色空间等加以描述。

1)点色彩深度:通常将Depth,即表示多少位表示一个点。

1位表示一个点(单色)

2位表示一个点

16位表示一个点

32位表示一个点(Alpha通道)

2)点内格式:RGB分量分布表示。

下图我们常用的16位表示一个像素点内部颜色分量的几种存储方式:

3)色彩空间:颜色表示方法

RGB色彩空间表示法

YUV色彩空间表示法


2.数据输出到物理设备


屏幕输出实际上是通过硬件加速将显存数据映射到物理设备的过程。我们的硬件必输完成下面工作:

RGBYUV色彩空间相互转换

输出帧数据同步

内存高速数据到低速显示设备的数据DMA支持与缓冲

柔性的多样显示设备硬件支持

源显示数据内容可能为单色位图或彩色位图,但对于具体的目标显示设备来讲,我们的目标格式可能就是一种,例如16位(5/6/5)格式。但是,设计图形显示接口的基本要求为良好的可移植性好,所以我们还是必须考虑对于不同点格式LCD之间的转换操作。


3. 数据搬移


我们在显示缓冲区上做的最多的操作就是区块搬运(Blit)。由此,很多的应用处理器使用了硬件图形加速器来完成区域搬运。从我们的主要操作的对象来看,可以分为以下几个方向:

1)内存区域到屏幕区域

2)屏幕区域到屏幕区域

3)屏幕区域到内存区域

4)内存区域到内存区域

应用处理器都可能带有图形加速器,对于不同的应用处理器对其图形加速器可能有不同的处理方式,对于2D加速来讲,都可归结为Blit。多为数据的搬运,放大缩小,旋转等。

在这里我们需要特别提出的是,由于在Linux不同进程之间的内存不能自由的访问,使得我们的每个Android应用对于内存区域和屏幕缓冲区的使用变得很复杂。在Android的设计中,在屏幕缓冲区和显示内存缓冲区的管理分类很多的层次,最上层的对象是可以在进程间自由传递,但是对于缓冲区内容则使用共享内存的机制。

基于以上的基础知识,我们可以知道:

  1. 代码中需要Config像素点Format的原因

  2. 不同图像采集单元输出的图像格式各不相同(模拟电视信号采用YUVLCD则采用RGB方式)

  3. 图像处理过程必须以像素点为单位,我们必须通过约定的Fomat得到单次处理的像素点数量,采用合适的像素表示方式可节约内存占用,并同时减少数据传输对总线带宽的占用。

    4.所有屏幕上图形的移动都是显示缓冲区搬运的结果。


二、Android的缓冲区抽象定义


·不同的硬件有不同的硬件图形加速设备和缓冲内存实现方法。AndroidGralloc动态库抽象的任务就是消除不同的设备之间的差别,在上层看来都是同样的方法和对象。在Moudle层隐藏缓冲区操作细节。Android使用了动态链接库gralloc.xxx.so,来完成底层细节的封装。

1.关于动态库

动态库实现位置:

hardware/libhandware/modules/gralloc

上层调用:

frameworks/base/services/surfaceflinger/LayerBuffer.cpp

frameworks/base/libs/ui/FramebufferNativeWindow.cpp

frameworks/base/libs/ui/GraphicBufferAllocator.cpp

frameworks/base/opengl/libagl/texture.cpp

frameworks/base/opengl/libagl/egl.cpp

封装与引用:

对于动态库的使用与封装Android使用了统一的调用符号接口HAL_MODULE_INFO_SYM,代码位置如下:

hardware/libhardware

从数据关系上我们来考察动态链接库的抽象行为:在层次HAL代码实现中对动态链接库中的内容作了全新的包装。最终编译得到带HAL_MODULE_INFO_SYM符号数据接口动态库文件(/system/lib/hw/gralloc.xxx.so)。上层引用调用hw_get_modulegralloc.xxx.so提取了HAL_MODULE_INFO_SYMSYM变量)

我们在Gralloc.cpp需要完成这样的布局:

staticstruct hw_module_methods_t gralloc_module_methods = {

open:gralloc_device_open

};

structprivate_module_t HAL_MODULE_INFO_SYM = {

base:{

       common: {

           tag:HARDWARE_MODULE_TAG,

            …

           id:GRALLOC_HARDWARE_MODULE_ID,

           name:"Graphics Memory Allocator Module",

           author:"The Android Open Source Project",

           methods:&gralloc_module_methods

        },

registerBuffer:gralloc_register_buffer,

unregisterBuffer:gralloc_unregister_buffer,

lock: gralloc_lock,

unlock: gralloc_unlock,

   },

    framebuffer:0,

    flags:0,

    numBuffers:0,

    bufferMask:0,

};

引用片段

if(hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {

intstride;

interr;

inti;

err= framebuffer_open(module, &fbDev);

LOGE_IF(err,"couldn't open framebuffer HAL (%s)", strerror(-err));

err= gralloc_open(module, &grDev);

LOGE_IF(err,"couldn't open gralloc HAL (%s)", strerror(-err));

//bail out if we can't initialize the modules

if(!fbDev || !grDev)

return;

…………………

}

我们建立了什么对象来支撑缓冲区的操作?

buffer_handle_t:外部接口。

methods.openregisterBufferunregisterBufferlockunlock

下面是外部接口和内部对象的结构关系,该类型的结构充分利用C Struct的数据排列特性:基本结构体放置在最前面,本地私有放置在后面,满足了抽象的需要。

typedefconst native_handle* buffer_handle_t;

private_module_t HAL_MODULE_INFO_SYM向往暴露的动态链接库接口,通过该接口,我们直接可以使用该对象。

动态库需要完成的工作:

根据帧缓冲HAL层名称Gralloc,可知该部分涉及最多的将是图形内存的管理与分配工作。

1)硬件图形加速器的抽象:BlitEngineCopyBit的加速操作。

2)硬件FrameBuffer内存管理

3)共享缓存管理


几个接口函数的解释:

(1)fb_post

对于帧缓冲区实际地址并不需要向上层报告,所有的操作都是通过fb_post了完成。

fp_post的任务就是将一个Buffer的内容传递到硬件缓冲区。其实现方式有两种:

(方式1)无需拷贝动作,是把Framebuffer的后buffer切为前buffer,然后通过IOCTRL机制告诉FB驱动切换DMA源地地址。这个实现方式的前提是Linux内核必须分配至少两个缓冲区大小的物理内存和实现切换的ioctrol,这个实现快速切换。

(方式2)利用Copy的方式。不修改内核,则在适配层利用从拷贝的方式进行,但是这个是费时了。

(2)gralloc的主要功能是要完成:

     1)打开屏幕设备"/dev/fb0",,并映射硬件显示缓冲区。

     2)提供分配共享显示缓存的接口

    3)提供BiltEngine接口(完成硬件加速器的包装)

3gralloc_alloc输出buffer_handle_t句柄。

    这个句柄是共享的基本依据,其基本原理在后面的章节有详细描述。


三、共享缓冲


1. native_handle_tprivate_handle_t的包裹

 private_handle_tgralloc.so使用的本地缓冲区私有的数据结构,而Native_handle_t是上层抽象的可以在进程间传递的数据结构。在客户端是如何还原所传递的数据结构呢?首先看看native_handle_tprivate_handle_t的抽象包装


numFds=sNumFds=1;

numInts=sNumInts=8;

这个是Parcel中描述句柄的抽象模式。实际上是指的Native_handle所指向句柄对象的具体内容:

numFds=1表示有一个文件句柄:fd/

numInts=8表示后面跟了8INT型的数据:magic,flags,size,offset,base,lockState,writeOwner,pid;

由于在上层系统不要关心buffer_handle_tdata的具体内容。在进程间传递buffer_handle_t(native_handle_t)句柄是其实是将这个句柄内容传递到Client端。在客户端通过Binder读取readNativeHandle@Parcel.cpp新生成一个native_handle

native_handle*Parcel::readNativeHandle() const

{

native_handle*h = native_handle_create(numFds, numInts);

    for(int i=0 ; err==NO_ERROR && i<="" font="">

       h->data[i]= dup(readFileDescriptor());

        if(h->data[i] < 0) err = BAD_VALUE;

    }

    err= read(h->data + numFds, sizeof(int)*numInts);

    ….

returnh;

}

    这里需要提到的是为在构造客户端的native_handle时,对于对方传递过来的文件句柄的处理。由于不是在同一个进程中,所以需要dup(…)一下为客户端使用。这样就将Native_handle句柄中的,客户端感兴趣的从服务端复制过来。这样就将Private_native_t的数据:magic,flags,size,offset,base,lockState,writeOwner,pid;复制到了客户端。

    客户端利用这个新的Native_bufferMapper传回到gralloc.xxx.so中,获取到native_handle关联的共享缓冲区映射地址,从而获取到了该缓冲区的控制权,达到了客服端和Server间的内存共享。从SurfaceFlinger来看就是作图区域的共享。

2.Graphic Mapper是干什么的?

   服务端(SurfaceFlinger)分配了一段内存作为Surface的作图缓冲,客户端怎样在这个作图缓冲区上工作呢?这个就是Mapper(GraphicBufferMapper)要干的事情。两个进程间如何共享内存,如何获取到共享内存?Mapper就是干这个得。需要利用到两个信息:共享缓冲区设备句柄,分配时的偏移量。Mapper利用这样的原理:

   客户端只有lock,unlock,实质上就是mmapummap的操作。对于同样一个共享缓冲区,偏移量才是总要的,起始地址不重要。实际上他们操作了同一物理地址的内存块。我们在上面讨论了native_handle_tprivate_handle_t的包裹过程,从中知道服务端给客户端传递了什么东西。

       进程1在共享内存设备上预分配了8M的内存。以后所有的分配都是在这个8M的空间进行。对以该文件设备来讲,8M物理内存提交后,就实实在在的占用了8M内存。每个每个进程都可以同个该内存设备共享该8M的内存,他们使用的工具就会mmap。由于在mmap都是用0开始获取映射地址,所以所有的客户端进程都是有了同一个物理起始地址,所以此时偏移量和size就可以标识一段内存。而这个偏移量和size是个数值,从服务进程传递到客户端直接就可以使用。

3. GraphicBuffer(缓冲区代理对象)

typedefstruct android_native_buffer_t

{

    structandroid_native_base_t common;

    intwidth;

    intheight;

    intstride;

    intformat;

    intusage;

     …

    buffer_handle_thandle;

     …

}android_native_buffer_t;

关系图表:

GraphicBuffer:EGLNativeBase :android_native_buffer_t

GraphicBuffer(parcel&)建立本地的GraphicBuffer的数据native_buffer_t。在通过接收对方的传递的native_buffer_t构建GraphicBuffer。我们来看看在客户端Surface::lock获取操作缓冲区的函数调用:

Surface::lock(SurfaceInfo*other, Region* dirtyIn, bool blocking)

     {intSurface::dequeueBuffer(android_native_buffer_t** buffer)Surface

       {status_tSurface::getBufferLocked(int index, int usage)

         {

              sp buffer= s->requestBuffer(index, usage);

          {

virtualsp requestBuffer(int bufferIdx, int usage)

{  remote()->transact(REQUEST_BUFFER, data, &reply);

   spbuffer = new GraphicBuffer(reply);

Surface::Lock建立一个在Client端建立了一个新的GraphicBuffer对象,该对象通过(1)描述的原理将SurfaceFlingerbuffer_handle_t相关数据构成新的客户端buffer_handle_t数据。在客户端的Surface对象就可以使用GraphicMapper对客户端buffer_handle_t进行mmap从而获取到共享缓冲区的开始地址了。

总结

gralloc.xxx.so是跟硬件体系相关的一个动态链接库,为AndroidFrambuffer硬件抽象层。他实现了Android的硬件抽象接口标准,提供显示内存的分配机制和Frambuffer数据输出显示功能。而如何具体实现这些功能,则跟硬件平台的配备有关系,所以我们看到了对于与不同的硬件架构,有不同的配置关系。Android在该节使用了共享内存的方式来管理与显示相关的缓冲区,他设计成了两层,上层是缓冲区管理的代理机构GraphicBuffer,及其相关的native_buffer_t,下层是具体的缓冲区的分配管理及其缓冲区本身。上层的对象是可以在经常间通过Binder传递的,而在进程间并不是传递缓冲区本身,而是使用mmap来获取指向共同物理内存的映射地址。

Android平台截图研究 FrameBuffer(/dev/graphics/fb0) 文件内容研究!(含源码工程) 1. FrameBuffer文件介绍 FrameBuffer 文件是 Linux (Android是基于Linux的) 对显示设备的一种抽象设备,相当于显存。Android 的 SurfaceFlinger 想更新屏幕的时候,就会把相应的改变写入到FrameBuffer里。Android 2.x 的时代,显示开机画面的功能也是通过把图像数据写入到FrameBuf... 阅读详情

相关推荐

Android图形系统分析与移植 -- 五、Android FrameBuffer

最近在研究LCD显示部分, AndroidFrameBuffer驱动的使用方式是标准的,在Android的GUI系统中,通过调用FrameBuffer驱动的标准接口,实现显示设备的抽象。 FrameBuffer驱动是Android中的标准设备,但是路径稍有不同,如下所示: /dev/graphics/fb0;         Android中直接使用标准飞FrameB

麒麟菜籽的专栏 2256

android多媒体框架介绍(三)显示图形系统之framebuffer

FrameBuffer是linux提供的显存驱动,在android环境设备节点是/dev/graphics/fb*(支持多个屏幕显示,第一个fb0是主显示屏幕,在linux下一般是/dev/fb*)。FrameBuffer的目的就是通过对硬件的封装抽象,让上层通过设备节点文件的方式,操作硬件去显示某个内存的内容。 文章目录一、framebuffer模块定义与规格场景分析模块定义:fb的本质就是把 指定内存 的 内容显示到屏上framebuffer常见的设计规格二、framebuffer主要流程与原理分析1、

runafterhit的博客 4956

Android2.3 中如何使用GPU硬件加速

Android2.3 中如何使用GPU硬件加速 Android2.3 中如何使用GPU硬件加速   1.名词解释 GPU:Graphic Processing Unit (图形处理器) OpenGL:Open Graphic Library 定义了一个跨编程语言、跨平台的编程接口的规格,不同厂商会有不同的实现方法,它主要用于三维图象(二维的亦可)绘制。 Su

小向的专栏 2351

[置顶] Android L SurfaceFlinger dump信息全解(1)

http://demo.netfoucs.com/lee_3do/article/details/43016299 [置顶] Android L SurfaceFlinger dump信息全解(1) 分类: Android Graphic |2015-01-22 11:22 |2178人阅读 SurfaceFlinger的dump信息详解 对于很多An

xiayu98020214的专栏 5708

高通Android平台-应用空间操作framebuffer dump LCD总结

高通Android平台 dump LCD总结 转载请注明出处,谢谢! 项目终于到一个比较奇葩的客户,希望可以中断Android系统界面,显示发送过来的图片。想在高通msm8937平台,720x1280 HD 显示屏上dump点东西,

Eliot_shao的专栏 3687

android 抓屏工具,在Android中加入抓屏软件fbdump.

目标:将fbdump-0.4.2放到andrioid中运行,能够抓framebuff中的桌面。方法:1 将fbdump解压缩到externel目录,创建编译文件:external/fbdump-0.4.2/Android.mk内容如下:LOCAL_PATH :=$(call my-dir)include $(CLEAR_VARS)charge_local_path := $(LOCAL_PATH)...

weixin_39642998的博客 220

Android的BUG(五)- Android跨进程使用GraphicBuffer的野指针问题

之前在调试flash 11在ICS上的使用效果时(这个版本使用的是surfaceView,市场上下的,基本上都是用nativeWindow了),发现一个bug,bug的现象如图1所示(访问http://www.qiaqiafood.com,页面主体是一个flash): 图1:错误的图片 图2:正常的图片 Webpage加载时,没有问题,但当将网页上下拖动后,就出现如图1所示的

freshui的专栏 7909

Android OpenGL/Gralloc到framebuffer和LCD流程(六)

一、OpenGL ES与EGL   Android的GUI系统是基于OpenGL/EGL来实现的。 由于OpenGL是通用函数库,在不同平台系统上需要被“本土化”——把它与具体平台的窗口系统建立起关联,FramebufferNativeWindow是负责OpenGL ES在Android平台上本地化的中介之一。为OpenGL ES配置本地窗口的是EGL,EGL介于本地窗口系统和Rendering API(即OPenGL ES)之间的一层接口。 与OpenGL相关的模块可分为: (1)配置类...

Android系统攻城狮 1838

5.7.6.framebuffer驱动框架分析1

http://www.mamicode.com/info-detail-1209620.html 5.7.6.1、fbmem_init函数[driver/video/fbmem.c] (1)#ifdef MODULE (2)fb_proc_fops和fb在proc文件系统中的表现 (3)register_chrdev注册fb设备 (4)class_create创建graphics类 (5)fbme...

weixin_30872499的博客 218

Android Framebuffer介绍及使用

作者: Aaron 主页: http://www.wxtlife.com/2017/06/07/Android-framebuffer/ 欢迎订阅我的公众号 FrameBuffer 介绍FrameBuffer中文译名为帧缓冲驱动,它是出现在2.2.xx内核中的一种驱动程序接口。主设备号为29,次设备号递增。 Linux抽象出FrameBuffer这个设备来供用户态进程实现直接

技术特工队 4700

android下操作FrameBuffer

一、framebuffer使用基础: 1. Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏, Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。对于用户而言,framebuffer和/dev下面的其他设备没有 什么区别,用户可以把framebuffer 看成一块内存,既可以向这块内存中写入数据,也可以从这块内存...

wwater的专栏 597

Android中的FrameBuffer

<br /> <br />转载时请注明出处和作者联系方式<br />文章出处:http://www.limodev.cn/blog<br />作者联系方式:李先静 <xianjimli@gmail.com><br /> <br />FrameBuffer 在Android中并不像在其它GUI那样直观,抽象的层次比较多,加上GUI的更新是通过OpenGLES来做的。所以让人很难搞清GUI更新的整个流程,最近要准备一个讲稿,所以花了一些去研究,这里做点笔记供大家参考,源代码是基于高通平台的,这些代码在网上都可以

dinuliang的专栏 2969

安卓 OpenGL ES 2.0 完全入门(二):矩形、图片、读取显存等

https://blog.piasy.com/2016/06/14/Open-gl-es-android-2-part-2/   本文是 Piasy 原创,发表于 https://blog.piasy.com,请阅读原文支持原创 https://blog.piasy.com/2016/06/14/Open-gl-es-android-2-part-2/ 在安卓 OpenGL ES 2.0 完...

u010029439的博客 674

Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析

前面在介绍Android系统的开机画面时提到,Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序的用户界面的。Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。本文将详细分析Gralloc模块的实现,为后续分析SurfaceFlinger服务的实现打下...

duoerbasilu 649

OpenGLES FBO-BlitFramebuffer MSAA 抗锯齿的实现

OpenGLES FBO-BlitFramebuffer MSAA 抗锯齿的实现不太好用的FBO-Blit MSAA昨天写了一篇 OpenGLES 在几种情况下的 MSAA(Multisample Anti-aliasing)抗锯齿,其中唯独没有提到一种利用 FBO-Blit 的抗锯齿方法,那是因为我没能实现。我对 OpenGL MSAA 的大部分代码的了解都是根据 关于支持多重采样的FBO和Tex

我是一只小小小小鸟 5162

Android图形系统分析与移植--六、framebuffer研究

1  FrameBuffer的发展历史 计算机研究者从很早开始已经开始讨论理论上FrameBuffer的优点,但却一直苦于没有能力生产一台拥有足够内存的计算机。1969年,贝尔实验室的JoanMiller试验了第一个已知的FrameBuffer。该设备显示了一幅3位

七夜雪主 1万+

Android图形系统的分析与移植--七、双缓冲framebuffer的实现

1  实现原理在基本的FrameBuffer已经实现的基础上,需要实现的是与Android原本模拟器所使用的goldfish FrameBuffer之间的区别。比较一下不难发现,从以下及方面着手:1.                  修改初始化FrameBuffer信息;2.

七夜雪主 1万+

Android OpenGL ES Frame Buffer Object

Android OpenGL ES Frame Buffer Object

bcghgfr的博客 453
上一篇: iMX53 IPU 图解之概述篇
下一篇: 嵌入式Wi-Fi处理器的无线系统设计
chychc
博客等级 码龄17年 26粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值