Android Display架构分析

2023-11-07

在这里插入图片描述
Fence https://www.jianshu.com/p/3c61375cc15b
android12 display分析:https://www.cnblogs.com/roger-yu/p/15641545.html
hwcomper https://blog.csdn.net/jianye33/article/details/108003293
Android Display架构分析–侧重高通平台
转 :https://www.pianshen.com/article/7993475272/

display 渲染https://www.pianshen.com/article/96762157553/
Android display架构分析(一)

http://hi.baidu.com/leowenj/blog/item/429c2dd6ac1480c851da4b95.html

性能https://blog.csdn.net/u011578734/category_7009042.html

高通7系列硬件架构分析
在这里插入图片描述

1

如上图,高通7系列 Display的硬件部分主要由下面几个部分组成:

A、MDP

高通MSM7200A内部模块,主要负责显示数据的转换和部分图像处理功能理,如YUV转RGB,放大缩小、旋转等。MDP内部的MDP DMA负责数据从DDR到MDDI Host的传输(可以完成RGB之间的转换,如RGB565转成RGB666,这个转换工能载目前的code 中没有使用)。

B、MDDI

一种采用差分信号的高速的串行数据传输总线,只负责数据传输,无其它功能;其中的MDDI Hosat提供并行数据和串行数据之间的转换和缓冲功能。由于外面是VGA的屏幕,数据量较大,为了减少对EBI2总线的影响,传输总线使用MDDI,而非之前的EBI2。

C、MDDI Bridge

由于现在采用的外接LCD并不支持MDDI接口,故需要外加MDDI转换器,即MDDI bridge,来把MDDI数据转换成RGB接口数据。这里采用的EPSON MDDIBridge还有LCD Controller功能,可以完成其它一些数据处理的功能,如数据格式转换、支持TV-OUT、PIP等;并且还可以提供一定数量的GPIO。目前我们主要用它把HOST端MDDI传递过来的显示数据和控制数据(初始化配置等)转换成并行的数据传递给LCD。

D、LCD module

主要是LCD Driver IC 和TFT Panel,负责把MDDI Bridge传来的显存中的图像示在自己的 Panel上。

Android display架构分析(二)

http://hi.baidu.com/leowenj/blog/item/3fe59f740a6fee17b051b991.html

Android display SW架构分析
在这里插入图片描述

在这里插入图片描述

下面简单介绍一下上图中的各个Layer:

*蓝色部分-用户空间应用程序

应用程序层,其中包括Android应用程序以及框架和系统运行库,和底层相关的是系统运行库,而其中和显示相关的就是Android的Surface Manager, 它负责对显示子系统的管理,并且为多个应用程序提 供了2D和3D图层的无缝融合。

*黑色部分-HAL层,在2.2.1部分会有介绍

*红色部分-Linux kernel层

Linux kernel,其中和显示部分相关的就是Linux的FrameBuffer,它是Linux系统中的显示部分驱动程序接口。Linux工作在保护模式下,User空间的应用程序无法直接调用显卡的驱动程序来直接画屏,FrameBuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过 Framebuffer的读写直接对显存进行操作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由 Framebuffer设备驱动来完成的。

*绿色部分-HW驱动层

该部分可以看作高通显卡的驱动程序,和高通显示部分硬件相关以及外围LCD相关的驱动都被定义在这边,比如上述的显卡的一些特性都是在这边被初始化的,同样MDP和MDDI相关的驱动也都定义在这里

User Space Display功能介绍

这里的User Space就是与应用程序相关的上层部分(参考上图中的蓝色部分),其中与Kernel空间交互的部分称之为HAL-HW Abstraction Layer。

HAL其实就是用户空间的驱动程序。如果想要将 Android 在某硬件平台上执行,基本上完成这些驱动程序就行了。其内定义了 Android 对各硬件装置例如显示芯片、声音、数字相机、GPS、GSM 等等的需求。

HAL存在的几个原因:

1、 并不是所有的硬件设备都有标准的linux kernel的接口。

2、 Kernel driver涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去HAL方式绕过GPL。

3、 针对某些硬件,Android有一些特殊的需求。

在display部分,HAL的实现code在copybit.c中,应用程序直接操作这些接口即可,具体的接口如下:

struct copybit_context_t *ctx = malloc(sizeof(struct copybit_context_t));
memset(ctx, 0, sizeof(*ctx));
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
ctx->device.common.version = 0;
ctx->device.common.module = module;
ctx->device.common.close = close_copybit;
ctx->device.set_parameter = set_parameter_copybit;//设置参数
ctx->device.get = get;
ctx->device.blit = blit_copybit;//传送显示数据
ctx->device.stretch = stretch_copybit;
ctx->mAlpha = MDP_ALPHA_NOP;
ctx->mFlags = 0;
ctx->mFD = open(“/dev/graphics/fb0”, O_RDWR, 0);//打开设备
Kernel Space Display功能介绍

这里的Kernel空间(与Display相关)是Linux平台下的FB设备(参考上图中的红色部分)。下面介绍一下FB设备。

Fb即FrameBuffer的简称。framebuffer 是一种能够提取图形的硬件设备,是用户进入图形界面很好的接口。有了framebuffer,用户的应用程序不需要对底层驱动有深入了解就能够做出很好的图形。对于用户而言,它和/dev 下面的其他设备没有什么区别,用户可以把

framebuffer 看成一块内存,既可以向这块内存中写入数据,也可以从这块内存中读取数据。它允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。

从用户的角度看,帧缓冲设备和其他位于/dev下面的设备类似,它是一个字符设备,通常主设备号是29,次设备号定义帧缓冲的个数。

在LINUX系统中,设备被当作文件来处理,所有的文件包括设备文件,Linux都提供了统一的操作函数接口。上面的结构体就是Linux为FB设备提供的操作函数接口。

1)、读写(read/write)接口,即读写屏幕缓冲区(应用程序不一定会调用该接口)

2)、映射(map)操作(用户空间不能直接访问显存物理空间,需map成虚拟地址后才可以)

由于Linux工作在保护模式,每个应用程序都有自己的虚拟地址空间,在应用程序中是不能直接访问物理缓冲区地址的。为此,Linux在文件操作 file_operations结构中提供了mmap函数,可将文件的内容映射到用户空间。对于帧缓冲设备,则可通过映射操作,可将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就可以通过读写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图了。实际上,使用帧缓冲设备的应用程序都是通过映射操作来显示图形的。由于映射操作都是由内核来完成,下面我们将看到,帧缓冲驱动留给开发人员的工作并不多

3)、I/O控制:对于帧缓冲设备,对设备文件的ioctl操作可读取/设置显示设备及屏幕的参数,如分辨率,显示颜色数,屏幕大小等等。ioctl的操作是由底层的驱动程序来完成

Note:上述部分请参考文件fbmem.c。

Android display架构分析(三)

http://hi.baidu.com/leowenj/blog/item/76411bf6237dc429bc31099f.html

Kernel Space Display架构介绍
在这里插入图片描述

如上图所示,除了上层的图形应用程序外,和Kernel空间有关的包括Linux FB设备层以及和具体HW相关的驱动层,对应的源文件分别是fb_mem.c、msm_fb.c、mddi_toshiba.c。下面会一一介绍。

函数和数据结构介绍
这个文件包含了Linux Fb设备的所有接口,主要函数接口和数据结构如下:

A、Fb设备的文件操作接口

在这里插入图片描述

B、3个重要的数据结构

FrameBuffer中有3个重要的结构体,fb.h中定义,如下:

1)、frame_var_screeninfo

该结构体定义了显卡的一些可变的特性,这些特性在程序运行期间可以由应用程序动态改变,比较典型的如xrex和yres表示在显示屏上显示的真实分辨率、显示的bit数等,该结构体user space可以访问。

2)、frame_fix_screeninfo

该结构体定义了显卡的一些固定的特性,这些特性在硬件初始化时就被定义了以后不可以更改。其中最重要的成员就是smem_len和smem_start,前者指示显存的大小(目前程序中定义的显存大小为整屏数据RGB565大小的2倍),后者给出了显存的物理地址。该结构体user space可以访问。

Note:smem_start是显存的物理地址,应用程序是不可以直接访问的,必须通过fb_ops中的mmp函数映射成虚拟地址后,应用程序方可访问。

3)、fb_info

FrameBuffer中最重要的结构体,它只能在内核空间内访问。内部定义了fb_ops结构体(包含一系列FrameBuffer的操作函数,Open/read/write、地址映射等).

C、其他

1)、一个重要的全局变量

struct fb_info *registered_fb[FB_MAX];

这变量记录了所有fb_info结构的实例,fb_info结构描述显卡的当前状态,所有设备对应的fb_info结构都保存在这个数组中,当一个FrameBuffer设备驱动向系统注册自己时,其对应的fb_info结构就会添加到这个结构中,同时num_registered_fb为自动加1。

2)、注册framebuffer函数

register_framebuffer(struct fb_info *fb_info);

unregister_framebuffer(struct fb_info *fb_info);

这两个是提供给下层FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情就是填充fb_info结构然后向系统注册或注销它

Android display架构分析(四)

http://hi.baidu.com/leowenj/blog/item/37e1a8521e35522842a75b99.html

函数和数据结构介绍
该文件为高通显卡的驱动文件,比较重要的函数接口和数据结构如下:

A、高通msm fb设备的文件操作函数接口

static struct fb_ops msm_fb_ops = {

.owner = THIS_MODULE,

.fb_open = msm_fb_open,

.fb_release = msm_fb_release,

.fb_read = NULL,

.fb_write = NULL,

.fb_cursor = NULL,

.fb_check_var = msm_fb_check_var, /*参数检查*/

.fb_set_par = msm_fb_set_par, /*设置显示相关参数*/

.fb_setcolreg = NULL, /* set color register */

.fb_blank = NULL, /* blank display */

.fb_pan_display = msm_fb_pan_display, /*显示*/

.fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */

.fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */

.fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */

.fb_cursor = NULL,

.fb_rotate = NULL,

.fb_sync = NULL, /* wait for blit idle, optional */

.fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */

.fb_mmap = NULL,

};

B、高通msm fb的driver接口

static struct platform_driver msm_fb_driver = {

.probe = msm_fb_probe,//驱动探测函数

.remove = msm_fb_remove,

#ifndef CONFIG_ANDROID_POWER

.suspend = msm_fb_suspend,

.suspend_late = NULL,

.resume_early = NULL,

.resume = msm_fb_resume,

#endif

.shutdown = NULL,

.driver = {

/* Driver name must match the device name added in platform.c. */

.name = "msm_fb",

},

};

C、msm_fb_init()

向系统注册msm fb的driver,初始化时会调用

D、msm_fb_add_device

向系统中添加新的lcd设备,在mddi_toshiba.c中会被调用

函数和数据结构介绍
该文件包含了所有和具体LCD(Toshiba)相关的信息和驱动,重点的数据结构和函数结构如下:

A、LCD设备相关信息

static struct platform_device this_device_0 = { p>

.name = “mddi_toshiba_vga”,

.id = TOSHIBA_VGA_PRIM,

.dev = {

.platform_data = &toshiba_panel_data0,

}

};

其中toshiba_panel_data0包含了硬件LCD的控制函数,如开关、初始化等等

B、LCD driver接口

static struct platform_driver this_driver = {

.probe = mddi_toshiba_lcd_probe,

.driver = {

.name = “mddi_toshiba_vga”,

},

};

其中mddi_toshiba_lcd_probe中会调用msm_fb_add_device接口把具体LCD添加到系统中去。

C、mddi_toshiba_lcd_init

注册LCD设备及driver到系统中去,同时也把LCD的固有信息(大小、格式、位率等)一并注册到系统中去。

D、LCD相关控制函数

toshiba_common_initial_setup():初始化MDDI bridge

toshiba_prim_start():初始化LCD

数据流分析
本部分来看一下应用层以下,显示数据的流程是怎样的。

先来分析一下传统的Linux平台下FB设备是如果调用的,如下图所示:

上层调用FB API(主要是fb_ioctl()),fb_ioctl()会调用具体显卡的驱动,这里是高通的显卡驱动,其实就是MDP DMA的驱动,通过MDP DMA把显示数据经MDDI接口送到外围LCD组件。

Note:这里的MDP DMA并不对数据进行任何处理(可以完成简单的格式转换,如RGB565->RGB666)。

在这里插入图片描述

接下来再分析一下Android平台下显示数据是如何处理的,如下图所示:

在这里插入图片描述

同样上层也是调用FB API,不过这里其实把FB bypass了,相当于直接调用的是高通MDP PPP的驱动,然后数据经PPP处理后再经MDDI接口送出到外围LCD组件。

Note:这里的MDP PPP可以完成很多显示数据处理功能,如YUV->RGB、Scale、Rotate、Blending等。

初始化过程分析
Kernel部分display的初始化包含下面几个步骤:

1)、在linux fb设备初始化时会向系统中注册msm_fb_driver。Name为msm_fb。

msm_fb_init-> msm_fb_register_driver-> platform_driver_register(&msm_fb_driver)

其中的probe函数会对msm fb进行初始化,分配显存等(见msm_fb_probe函数)。

2)、在LCD模块初始化时会先向系统中注册驱动(在mddi_toshiba_lcd_init函数中)

platform_driver_register(&this_driver);名字为mddi_toshiba_vga;

this_driver的probe函数为mddi_toshiba_lcd_probe,其内部会调用msm_fb_add_device向系统中添加MSM fb设备。

3)、调用platform_device_register(&this_device_0)向系统中注册设备,名字为mddi_toshiba_vga,其中this_device_0包含了一些操作LCD的接口,如on/off。

Note:设备和driver的name需要一致才可以绑定;另外,如果某些设备不需要让platform的总线来管理,那么只需要注册驱动即可,而无须向系统中注册device,如msm_touch。

Android display架构分析(五)

http://hi.baidu.com/leowenj/blog/item/7a12ecb77067737f8ad4b266.html

Display接口介绍

、User Space display接口
在Android平台下,应用程序面对的显示部分的接口就是HAL,参考copybit.c,具体接口如下介绍:

open_copybit

初始化相关变量,并调用open(“/dev/graphics/fb0”, O_RDWR, 0);打开fb设备。

set_parameter_copybit

设置各种操作参数,如rotate、alpha、dither等。

stretch_copybit

Copy一块数据(Rectangle)到显存,然后并命令msm_fb进行显示。

close_copybit

调用close(ctx->mFD);关闭fb设备。

Note:另外,应用程序在使用上面接口之前,需要调用mapFrameBuffer接口(EGLDisplaySurface.cpp),其功能如下:

1、初始化显示相关参数,并设置到底层。

2、映射出显存的虚拟地址。

、Kernel display接口
Kernel部分显示的接口全部都在fbmem.c中,这里详细介绍一下:

fb_open

打开Linux下fb设备。

fb_read/fb_write

读写显存中的数据

fb_ioctl

对显示设备的命令操作。如get或set一些显示参数、通知底层进行刷屏等。

在典型应用中,画屏的一般步骤如下:

1.打开/dev/fb设备文件。

2.用ioctrl操作取得当前显示屏幕的参数,如屏幕分辨率,每个像素点的比特数。根据屏幕参数可计算屏幕缓冲区的大小。

3.将屏幕缓冲区映射到用户空间。

4.映射后就可以直接读写屏幕缓冲区,进行绘图和图片显示了。

典型程序段如下:

#include

int main()

{

int fbfd = 0;

struct fb_var_screeninfo vinfo;

struct fb_fix_screeninfo finfo;

long int screensize = 0;

/打开设备文件/

fbfd = open(“/dev/fb0”, O_RDWR);

/取得屏幕相关参数/

ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo); ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);

/计算屏幕缓冲区大小/

screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

/映射屏幕缓冲区到用户地址空间/

fbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED, fbfd, 0);

/下面可通过fbp指针读写缓冲区/

}

典型应用flow分析
在不同应用程序中,上层的调用会有所不同,比如Andriod下会选择应用程序跳过Linux fb操作层,直接操作显卡驱动层,称之为BLT accelerator。

下面看一下Android平台下画屏的操作流程。

1、通过mapFrameBuffer直接把用户空间的数据映射到显存中。

2、调用HAL中的stretch函数直接命令MSM设备提取显存数据然后送入MDP PPP进行处理并经MDDI接口送到外围LCD组件。

具体的函数调用流程如下:

copybit_open();//打开BlitEngine,同时也打开fb设备

mapFrameBuffer();//设置显示参数,同时得到显存虚拟地址

copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);//通知底层去刷屏

接下的流程是:

stretch_copybit-> msm_copybit-> fb_ioctl()->msm_fb_ioctl(MSMFB_BLIT)-> msmfb_blit-> mdp_blit-> mdp_ppp_blit->mdp_start_ppp->MDP&MDDI HW operation

Android display架构分析(六)

http://hi.baidu.com/leowenj/blog/item/78c068dc443c961f48540361.html

介绍
Note:

本部分介绍的完全是用户空间显示部分的架构,与kernel并没有直接的联系,主要是JNI以下到HAL以上的部分。

、Surface manager(surface flinger)简介
Surface manager是用户空间中framework下libraries中负责显示相关的一个模块。如下:

在这里插入图片描述

当系统同时执行多个应用程序时,Surface Manager会负责管理显示与存取操作间的互动,另外也负责将2D绘图与3D绘图进行显示上的合成。

surface manager 可以准备一块 surface(可以看作一个layer),把 surface 的 fd (一块内存) 传给一个 app,让 app 可以在上面作画。典型应用如下:

在这里插入图片描述

在这里插入图片描述

2、架构分析
Android中的图形系统采用Client/Server架构,如下:

Client端:应用程序相关部分。代码分为两部分,一部分是由Java提供的供应用使用的api,另一部分则是由c++写成的底层实现。

Server端:即SurfaceFlinger,负责合成并送入buffer显示。其主要由c++代码编写而成。

Client和Server之前通过Binder的IPC方式进行通信,总体结构图如下:

如上图所示,Surface的client部分其实是提供给各应用程序进行画图操作的一个桥梁,该桥梁通过binder通向server端的Surfaceflinger,Surfaceflinger负责合成各个surface,然后把buffer传送到framebuffer端进行底层显示。其中每个surface对应2个buffer,一个front buffer, 一个back buffer,更新时,数据更新在back buffer上,需要显示时,则将back buffer和front buffer互换。

下一部分我们重点研究一下Surfaceflinger。

Android display架构分析(七-1)

http://hi.baidu.com/leowenj/blog/item/7abbe33a309367ff3b87ce6f.html

流程分析
根据前面的介绍,surfaceflinger作为一个server process,上层的应用程序(作为client)通过Binder方式与其进行通信。Surfaceflinger作为一个thread,这里把它分为3个部分,如下:
1、 Thread本身处理部分,包括初始化以及thread loop。

2、 Binder部分,负责接收上层应用的各个设置和命令,并反馈状态标志给上层。

3、 与底层的交互,负责调用底层接口(HAL)。

结构图如下:

在这里插入图片描述

注释:

a、 Binder接收到应用程序的命令(如创建surface、设置参数等),传递给flinger。

b、 Flinger完成对应命令后将相关结果状态反馈给上层。

c、 在处理上层命令过程中,根据需要设置event(主要和显示有关),通知Thread Loop进行处理。

d、 Flinger根据上层命令通知底层进行处理(主要是设置一些参数,Layer、position等)

e、 Thread Loop中进行surface的合成并通知底层进行显示(Post buffer)。

f、 DisplayHardware层根据flinger命令调用HAL进行HW的操作。

下面来具体分析一些SurfaceFlinger中重要的处理函数以及surface、Layer的属性

1)、readToRun

SurfaceFlinger thread的初始化函数,主要任务是分配内存和设置底层接口(EGL&HAL)。

status_t SurfaceFlinger::readyToRun()

mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);//为IPC分配共享内存

mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);//为flinger分配heap,大小为8M,存放具体的显示数据

{

// initialize the main display

GraphicPlane& plane(graphicPlane(dpy));

DisplayHardware* const hw = new DisplayHardware(this, dpy);

plane.setDisplayHardware(hw);//保存显示接口

}

//获取显示相关参数

const GraphicPlane& plane(graphicPlane(dpy));

const DisplayHardware& hw = plane.displayHardware();

const uint32_t w = hw.getWidth();

const uint32_t h = hw.getHeight();

const uint32_t f = hw.getFormat();

// Initialize OpenGL|ES

glActiveTexture(GL_TEXTURE0);

glBindTexture(GL_TEXTURE_2D, 0);

glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

2)、ThreadLoop

Surfaceflinger的loop函数,主要是等待其他接口发送的event,进行显示数据的合成以及显示。

bool SurfaceFlinger::threadLoop()

{

waitForEvent();//等待其他接口的signal event

// post surfaces (if needed)

handlePageFlip();//处理翻页机制

const DisplayHardware& hw(graphicPlane(0).displayHardware());

if (LIKELY(hw.canDraw()))

{

// repaint the framebuffer (if needed)

handleRepaint();//合并所有layer并填充到buffer中去

postFramebuffer();//互换front buffer和back buffer,调用EGL接口进行显示

}

}

3)、createSurface

提供给应用程序的主要接口,该接口可以创建一个surface,底层会根据参数创建layer以及分配内存,surface相关参数会反馈给上层

sp SurfaceFlinger::createSurface(ClientID clientId, int pid,

ISurfaceFlingerClient::surface_data_t* params,

DisplayID d, uint32_t w, uint32_t h, PixelFormat format,

uint32_t flags)

int32_t id = c->generateId(pid);

if (uint32_t(id) >= NUM_LAYERS_MAX) //NUM_LAYERS_MAX=31

{

LOGE(“createSurface() failed, generateId = %d”, id);

return

}

layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);//创建layer,根据参数(宽高格式)分配内存(共2个buffer:front/back buffer)

if (layer)

{

setTransactionFlags(eTransactionNeeded);

surfaceHandle = layer->getSurface();//创建surface

if (surfaceHandle != 0)

surfaceHandle->getSurfaceData(params);//创建的surface参数反馈给应用层

}

待续。。。

Android display架构分析(七-2)

http://hi.baidu.com/leowenj/blog/item/ba4c5d6378a5da48eaf8f86a.html

4)、setClientState

处理上层的各个命令,并根据flag设置event通知Threadloop进行处理

status_t SurfaceFlinger::setClientState(

ClientID cid,

int32_t count,

const layer_state_t* states)

{

Mutex::Autolock _l(mStateLock);

uint32_t flags = 0;

cid <<= 16;

for (int i=0 ; i

{

const layer_state_t& s = states[i];

LayerBaseClient* layer = getLayerUser_l(s.surface | cid);

if (layer)

{

const uint32_t what = s.what;

// 检测应用层是否设置各个标志,如果有则通知底层完成对应操作,并通知ThreadLoop做对应的处理

if (what & eDestroyed) //删除该层Layer

{

if (removeLayer_l(layer) == NO_ERROR)

{

flags |= eTransactionNeeded;

continue;

}

}

if (what & ePositionChanged) //显示位置变化

{

if (layer->setPosition(s.x, s.y))

flags |= eTraversalNeeded;

}

if (what & eLayerChanged) //Layer改变

{

if (layer->setLayer(s.z))

{

mCurrentState.layersSortedByZ.reorder(

layer, &Layer::compareCurrentStateZ);

flags |= eTransactionNeeded|eTraversalNeeded;

}

}

if (what & eSizeChanged)

{

if (layer->setSize(s.w, s.h))//设置宽高变化

flags |= eTraversalNeeded;

}

if (what & eAlphaChanged) {//设置Alpha效果

if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))

flags |= eTraversalNeeded;

}

if (what & eMatrixChanged) {//矩阵参数变化

if (layer->setMatrix(s.matrix))

flags |= eTraversalNeeded;

}

if (what & eTransparentRegionChanged) {//显示区域变化

if (layer->setTransparentRegionHint(s.transparentRegion))

flags |= eTraversalNeeded;

}

if (what & eVisibilityChanged) {//是否显示

if (layer->setFlags(s.flags, s.mask))

flags |= eTraversalNeeded;

}

}

}

if (flags)

{

setTransactionFlags(flags);//通过signal通知ThreadLoop

}

return NO_ERROR;

}

5)、composeSurfaces

该接口在Threadloop中被调用,负责将所有存在的surface进行合并,OpenGl模块负责这个部分。

6)、postFramebuffer

该接口在Threadloop中被调用,负责将合成好的数据(存于back buffer中)推入在front buffer中,然后调用HAL接口命令底层显示。

7)、从3中可知,上层每创建一个surface的时候,底层都会同时创建一个layer,下面看一下surface及layer的相关属性。

Note:code中相关结构体太大,就不全部罗列出来了

A、Surface相关属性(详细参考文件surface.h)

a1:SurfaceID:根据此ID把相关surface和layer对应起来

a2:SurfaceInfo

包括宽高格式等信息

a3:2个buffer指针、buffer索引等信息

B、Layer相关属性(详细参考文件layer.h/layerbase.h/layerbitmap.h)

包括Layer的ID、宽高、位置、layer、alpha指、前后buffer地址及索引、layer的状态信息(如eFlipRequested、eBusy、eLocked等)

Android display架构分析(八)

http://hi.baidu.com/leowenj/blog/item/03aae36137acb8d1e6113a75.html

开发的经验分享
1Display Driver的工作内容
参考上面linux下fb设备的软件架构,可以知道,要加入一个新的MDDI 接口的LCM,Driver的工作就是要提供自己的mddi_xxxx.c(在这次porting的过程中,为了节省时间,我们直接修改了mddi_toshiba.c),并且完成和这个lcd相关的HWr的初始化。主要的工作包括:

A、初始化和LCD / LCD背光相关的IO以及电源;

B、编写初始化函数 。主要是初始化LCD控制器,这个一般LCD厂商会提供;然后分配显存,这个高通release过来的code已经包含这个动作了,最后是初始化一个fb_info的结构体,在这里主要是把LCD的一些信息登记进来。

C、把LCD的设备以及驱动注册到系统中去。(这里因为是替换现有的驱动,所以相关修改的部分不多。)

上述B、C部分代码请参考kernel/drivers/video/msm/mddi_toshiba.c。

开发过程
1.2.1配置Power和IO
更改一些GPIO的配置以及一些电源的电平配置;然后通过实际测量,确保一下信号正常:

A、供给LCD以及MDDI Bridge的电源;

B、MDDI Bridge以及LCD reset信号;

C、控制背光IC的GPIO工作正常(背光不打开,无法调试LCD)。

1.2.2Porting LCD初始化序列
LCD init的code以及外围MDDI Bridge的初始化code,都可以之前Boston Windows Mobile系统的code base中获得;把这部分code移植到mddi_Toshiba.c中,并更改相应的图像格式、分辨率等配置,编译通过。LCD初始化部分就算基本完成。

1.2.3LCD初始化过程的调试
由于硬件在之前Boston load是可以工作的,可以认为硬件连接等没有问题,所以只需关注软件部分就行。

Display部分软件调试过程如下:

A、 开机后,量一下GPIO是否为code中配置预期的状态(可确保code中的

GPIO接口工作正常);

B、 量一下各个电源是否都处于Code中定义的电平值。这些都OK后,背光

是会亮的(背光的控制比较简单,一个GPIO即可);

C、 这个时候如果LCD以及MDDI Bridge有被正常初始化的话,屏幕上是会

看出来的。反之,如果屏幕没有显示,需要用JTAG跟一下mddi_Toshiba.c中的初始化函数是否在开机的时候有被调用过。

目前版本中,是根据外围MDDI Bridge中读到的的厂商号来决定加载哪个驱动模块的。在本次调试中,bootloader中可以正确读到厂商号,所以bootloader中对于LCD的初始化是有做的,所以屏幕看到的状态就是LCD初始化后的样子(花屏)。 但Kernel起来后,并没有其他显示,用JTAG跟了后发现,Kernel中MODULE INIT中读不到正确的厂商号,所以说后面的driver没有被加载。接着发现如果在bootloader中如果不做MDDI Bridge的初始化,的话后面的MODULE INIT就可正常运行,该问题目前还没有澄清(现在暂时先把bootloader中的init disable掉)。

1.2.4LCD的调整
初始化正常后,屏幕会显示UI的相关画面,但明显颜色、位置都不对。

这个可能是数据类型配置不对导致的,即MDP输出的类型、MDDI配置的类型以、LCD接收的类型不匹配导致,也有可能是RGB的顺序不对导致(可配置成BGR)。经过调试后,把MDP端输出的格式配置成RGB565,同时外围MDDI Bridge以及LCD的input格式也配置成RGB565,这时显示色彩正常了。

如果位置或者方向不对,比如说上下或是左右颠倒,可以更改LCD的配置中的扫描方向即可。

1.2.5其他
后续发现一个问题,播放video的时候颜色都是黑白的。

这个问题很容易让人误解,按照正常的理解,video decode出来的数据为YCbCr,Y为亮度信号,CbCr为色差信号,如果只有Y信号的话颜色应该就是黑白的。所以有2个怀疑点,一个是decode出来的数据有误,另一个是MDDI Bridge误把输入的YcbCr信号当作RGB信号进行出来,这个也是有可能的。但很快第二个怀疑点被排除了(因为单更改MDDI input格式后还是不能解决问题)。

后来又详细的看了显示部分的代码,并用JTAG追踪video播放的时候用的显示接口,发现目前所有的显示接口输出的格式都是RGB格式,也就是说在通过MDP之前YcbCr已经被转化过;而MDP里的转换功能并没有使用,MDP只是被当作一个DMA完成数据的直接传输,文档中叫做Bypasse。

YcbCr到RGB的转换是由Android的lib来完成。发了个SR给高通,高通的回复也确认了,在6.3.50中,Android上层缺少这个lib(copybit.default.so),6.3.60之后的版本经解决了这个问题。

高通Android平台下关于display部分的几个关键问题

http://hi.baidu.com/leowenj/blog/item/06f8c0000763b37a3812bb03.html

显示部分的几个问题这几天通过实际测试澄清了一下,主要是下图中各个模块的使用状况以及HAL层几个模块的调用流程。以问题的方式描述如下:

1、 Ap是怎么进行显示的?

Surfaceflinger负责所有上层的显示处理,对于AP(2D或是3D的应用程序)而言,只要到surfaceflinger中创建surface,设置好参数,接下来都是统一交给surfaceflinger进行处理

2、 Surface是怎么管理多个surface的?

不管有多少个surface,最终送到显示部分的只能是屏幕大小数据,surfaceflinger中利用MDP或是GPU进行多个surface的合成处理,普通的合成MDP就可完成,但如果是复杂的比如3D的应用等就必须使用GPU,最终合成的好数据会被送到framebuffer中。

3、 Framebuffer是什么?

Framebuffer是Linux中为显示数据分配的一块显存(fb设备中),通常大小是一整个屏幕数据的两倍,对于上层AP而言,只需要将要显示的数据丢到framebuffer中就OK了,但此时显示数据并未真正的被送到LCD上,而是暂存在framebuffer中而已。

4、 上层是通过什么方式将显示内容送到framebuffer的?

有2个方式(二选一,不会同时在运行):

A、 普通的显示,使用copybit(MDP)(未使用GPU)

Surfaceflinger通过copybit将要显示的数据送到framebuffer。

Note:copybit可以看做是MDP PPP的接口,它提供了MDP的功能,如多个layer合成,scale、rotate等。

其接口在:android/hardware/msm7k/libcopybit/copybit.cpp

B、 使用GPU(即使用图中的Graphics driver)

当进行复杂的显示处理时,比如3D的应用,GPU把处理好的数据直接丢到framebuffer中,和MDP没有任何关系

5、 Framebuffer中的数据是如何被送到LCD显示的?

图中的Gralloc完成的。

Gralloc有2个功能:

一个是和copybit相同的,里面有MDP PPP的接口(目前没有使用)

另一个则是刷屏(整屏刷)的接口,即将framebuffer中的数据送到lcd上,调用的是MDP DMA的接口

这部分的code在android/hardware/msm7k/libgralloc-qsd8k目录下,之前没有留意,以为没有使用。现在可以看出开机初始化后就创建了disp_loop thread,里面的操作就是调用系统接口

ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info)

将数据送到lcd

Note:送数据的时候是2个buffer切换的

另外,上层surfaceflinger也是通过Gralloc中的接口获知屏幕的大小,调用接口为

ioctl(fd, FBIOGET_VSCREENINFO, &info),info中的屏幕宽高对应的就是底层driver设置的宽高值

6、 OpenGL是什么?

它是一个图像处理引擎,当需要一些复杂的显示(2D/3D)操作时会用到它。它分为SW方案和HW方案,软件方案就是图中的libagl.so,对应到目前项目中是libGLES_android.so,它可以完成简单的2D(文字,icon等)处理,通过trace看目前大部分显示操作都是它来完成的。

Note:它是软件方案,处理好的数据是通过copybit送到framebuffer的,而不是GPU。

其接口部分参考:android/frameworks/base/opengl/libagl

HW方案就是图中的Graphics driver,它通过使用GPU硬件来完成图像处理,处理后的数据直接送到framebuffer中。其接口部分参考:android/frameworks/base/opengl/libs(有几个版本)

7、 OpenGL在项目中是如何配置的?

在android/vendor/qcom/msm7627_ffa目录下有一个egl.cfg文件,里面指定了当前版本中的OpenGL信息,目前如下:

0 0 android

0 1 adreno200

第一行代表该codebase支持SW 方案的OpenGL,是android default的

第二行代表该codebase也支持HW方案的OpenGL,是高通的adreno引擎

如果该cfg文件为空,则只支持default的SW方案。

如果2个方案都在,上层将根据实际应用自行选择使用其一。

该部分请参考:android/frameworks/base/opengl/libs/EGL/loader.cpp

63468f3ba1f59dfed4622529
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Display架构分析 的相关文章

  • 如何使用 android:layout 属性实例化自定义首选项的布局

    我可以通过以下方式设置适当的布局以供偏好android layout属性 举个例子
  • 在第一个框中输入字符后,将焦点转到下一个框

    我必须实现一个应用程序 其中我设置了较小的值edittext用于输入 PIN 码和手机号码 每个编辑文本一次包含 1 个字符 现在 当我运行这个应用程序时 我发现对于每个框 我需要将焦点放在每个框上edittext 因此 在这种情况下 是否
  • 如何使用 WifiEnterpriseConfig 设置“使用系统证书”

    我想为我的应用程序的用户配置企业 WiFi 网络 因此 用户必须输入用户名和密码 其余的由应用程序处理 身份验证由 RADIUS 服务器 FreeRadius 3 处理 该服务器使用 LetsEncrypt 颁发的证书 因此无需导入我自己的
  • 如何在Android 4.2中更改Action Bar选项菜单的背景颜色?

    我想更改 Android 4 2 中选项 溢出 菜单的背景颜色 我已经尝试了所有方法 但它仍然显示主题设置的默认颜色 我使用了以下代码和 XML 配置 MainActivity java public class MainActivity
  • 如何将Android中的cURL发送到REST服务

    我是 android 新手 我想从 REST 服务获取一些数据 但在初始化发送到 REST 服务的方法时遇到一些问题 您知道 REST 服务使用 cURL 来操作一些数据 POST PUT GET DELETE 现在如何在 android
  • 当前版本的Android Gradle插件不支持按需配置

    升级到 Android Studio 3 1 2 后 出现以下错误 当前版本的 Android Gradle 插件不支持按需配置 因为您使用的是 Gradle 4 6 或更高版本 建议 通过在 gradle properties 文件中设置
  • Android:如何让设备只运行一个应用程序?

    我有一个客户项目 我必须制作单任务 Android 设备 客户无法逃脱我公司开发的应用程序 此外 客户无法启动任何其他应用程序 而我们的应用程序会在设备启动时启动 总体而言 客户能够使用设备执行的所有操作就是运行我们的应用程序 除了 roo
  • Firebase Messaging FCM 在可配置的时间间隔内分发

    当您使用 FCM 向给定应用程序的所有设备发送推送时 这可能会导致许多用户同时打开他们的应用程序 从而导致大量服务器轮询 从而导致负载峰值 有没有一种方便的方法可以在给定的时间间隔内分发消息以进行计划推送 最后 我们找到了一种可能的方法 通
  • 地理编码 API 与地理编码器

    在我的应用程序中 我需要使用地理编码 但我不太清楚该使用哪种方法 直到昨天我在URL中添加了参数maps googleapis com maps api geocode json address myparameter sensor fal
  • 尝试获取屏幕上绘制的每个随机圆圈的 x、y 坐标

    您好 我正在制作一款游戏 该游戏将在屏幕上创建随机圆圈 随机创建的圆圈的值为红色或绿色 我的问题是 我希望不仅能够确定用户何时单击其中一个圆圈 而且还能够确定他们最终单击的圆圈 红色或绿色 下面是我的代码 我的主要问题是试图找到将要绘制的圆
  • Android WebView文件上传

    我正在开发一个 Android 应用程序 基本上它是一个WebView和一个进度条 Facebook 的移动网站 m facebook com 已加载到WebView 当我单击 选择文件 按钮上传图像时 没有任何反应 我已经尝试了所有的解决
  • Flutter - 删除 ListView 中项目之间的空间

    我正在使用 ListView builder 函数来创建项目列表 然而 iOS 中每个项目之间的空间很大 截图 你知道如何删除项目吗 看来是默认的 因为我没有添加它 code 列表显示 return Scaffold body ListVi
  • 运行 Android 应用程序时出现错误

    我已经使用 Eclipse 创建了一个 Android 应用程序 但应用程序未在 AVD 上运行 它显示 不幸的是已停止工作 日志猫消息如下 07 29 04 59 50 789 W dalvikvm 784 threadid 1 thre
  • LinearLayout:防止最后一个孩子被之前的大文本视图推出或挤压

    我有一个LinearLayout里面有两个孩子 第一个是TextView对于动态内容 第二个是一个按钮 我的问题是按钮被推出其父级或被挤压到不再可见的程度 我想要TextView认识到其父母与第二个孩子一起没有更多空间 并开始新的一行 而不
  • 如何为 flutter 绘图应用实现橡皮擦功能

    有一个关于通过 flutter 创建绘图应用程序的视频 YouTube https www youtube com watch v yyHhloFMNNA 它支持当用户点击屏幕时绘制线 点 但我找不到像 Android 本机那样擦除用户绘制
  • 如何获取小区广播消息?

    我尝试像模拟人生一样获取小区广播消息的文本 但它不起作用 public class SMSReceiver extends BroadcastReceiver Override public void onReceive Context c
  • 如何向开关对象添加/更改波纹效果

    下面是我自定义的开关 红圈是默认的波纹效果 我发现设置一个波纹可绘制作为开关的背景 控制波纹的颜色
  • 如果我的应用程序安装在 SD 卡上,私人数据也在那里吗?

    我假设应用程序的私有数据 例如 SharedPreferences 和 SQLite 数据库 位于手机的内部存储而不是 SD 卡上 即使应用程序本身安装在 SD 卡上 我在任何地方都找不到对此的简单明确的确认 有人可以确认一下吗 是的 私有
  • Android Jetpack Compose 尺寸随持续时间变化的动画

    如何在 Jetpack Compose 中添加内容大小更改动画的持续时间 尝试使用Modifier animateContentSize 并通过动画规格具有持续时间 但它只是突然进入或退出 没有观察到持续时间 Column Modifier
  • android 中的 java.net.URL ..新手问题

    我是java新手 正在尝试android开发 以下代码生成 malformedURLException 有人可以帮助我识别异常吗 任何提示都会非常有帮助 package com example helloandroid import and

随机推荐

  • PID稳压

    思路说明 我们设置一个目标值 这是我们要调节的目标 我们通过AD采样 PC3 采集到当前电压 通过减法运算我们得出当前电压与目标电压的差值 接下来我们只要发现当前电压与目标电压不同 我们就要想办法改变当前单片机的输出电压 PA8 也就是当前
  • C++学习之gcc编译四步

    C 学习之gcc编译四步 一 linux下编写Hello World 代码文件 二 gcc编译四步 1 预处理 Preprocessing 2 编译 Compilation 3 汇编 Assembly 4 链接 Linking 三 执行 四
  • 论文学习(一)——MWP-BERT: Numeracy-Augmented Pre-training for Math WordProblem Solving

    记录一下自己的第一篇论文学习 摘要 数学应用题 MWP 的求解面临着数字表示学习的困境 为了避免数字表示的问题 并且减少可行解的搜索空间 现有求解MWP的工作通常用符号占位符代替实数 以便专注于逻辑推理 然而 不同于常见的符号推理任务 如程
  • STM32——STM32F103系列学习笔记(纯干货版)

    一 RCC函数 关于RCC函数的使用配置如下 一 定时器资源分配 关于定时器资源分配如下
  • Timer源码分析

    java util Timer简介 Timer是用于管理在后台执行的延迟任务或周期性任务 其中的任务使用java util TimerTask表示 任务的执行方式有两种 按固定速率执行 即scheduleAtFixedRate的两个重载方法
  • Python入门学习01

    基础 输出 输出语句print print 输出语句 输出函数 1 在控制台输出一段文本信息 用一对英文双引号标记 print 文本信息 默认换行 2 print 文本信息 end 结尾 n 换行符 t 制表符 3 print 文本信息1
  • Thinkphp5.1开发钉钉应用:企业免登陆_PC端demo

    config gt base php
  • C语言数字炸弹

    define CRT SECURE NO WARNINGS 1 include
  • 三、Linux系统编程:进程间的通信(IPC)之消息队列

    3 IPC 进程间通信 消息队列 消息队列 Message queue 是一种进程间通信或同一进程的不同线程间的通信方式 软件的贮列用来处理一系列的输入 通常是来自用户 3 1 背景 管道和套接字比较适合两三个进程之间的通信 如果进程成倍增
  • 小米笔记本BIOS版本升级固件 小米笔记本Pro15.6【附下载地址】

    之前出厂买的bios版本太老了 个人强迫症就更新到了新版本的bios 找了三家小米官方售后部门 前两家啥技术都没 查最新的bios版本都查不到 还说我的bios就是最新的 最后一家售后才有把我升级bios 查询自己bios版本的方法 win
  • TCP报文段的首部

    TCP报文段的首部 TCP虽然是面向字节流的 但是TCP传送的数据单元是报文段 一个TCP报文段分为首部和数据两部分 TCP报文段首部的前20个字节是固定 后面有 4 n 4n 4n字节是根据需要而增加的选项 n n
  • 基于优先队列的Dijkstra算法

    前言 最短路径问题 即在给定的连接图中 求解节点之间的最短路径 Dijkstra算法是典型的单源最短路径算法 单源即只能求解某个节点到其他节点的最短路径 另外 此算法不能处理边权重为负的情况 一 最短路径问题 最短路径问题是图论的一个经典算
  • ubuntu安装ffmpeg,三行命令

    1 安装 添加ppa源 sudo add apt repository ppa djcj hybrid 更新刚才添加的源 sudo apt get update 下载ffmpeg sudo apt get install ffmpeg 遇到
  • 【React】搭建React项目

    最近自己在尝试搭建react项目 其实react项目搭建没有想象中的那么复杂 我们只需要使用一个命令把React架子搭建好 其他的依赖可以根据具体的需求去安装 比如AntDesignMobile的UI框架 执行npm install ant
  • 绿源:“老大哥”冲刺IPO,新的故事如何讲?

    又一家老牌电动两轮车企业 开 向了资本市场 11月22日 绿源集团控股 开曼 有限公司 以下简称 绿源集团 正式向港交所递交招股说明书 拟主板挂牌上市 中信建设国际担任独家保荐人 这标志着 一部车骑10年 电动车品牌绿源拉开了上市序幕 绿源
  • Android暴露组件——被忽略的组件安全

    Intent 简介 Intent 意图 负责完成Android应用 组件之间的交互与通信 常见的Activity的调用 Receiver的发送 Service的启动都需离不开Intent Intent通常包含的信息 Categpry 种类
  • springboot文件上传 MultipartFile file

    1 讲解springboot文件上传 MultipartFile file 源自SpringMVC 注意点 如果想要直接访问html页面 则需要把html放在springboot默认加载的文件夹下面 MultipartFile 对象的tra
  • Yii Framework 开发教程(28) Data Provider 简介

    这开始介绍Zii组件之前 先简要介绍一下Yii支持的数据源接口 IDataProvider IDataProvider主要功能是为UI组件如GridView ListView等提供数据源 同时也支持数据的分页和排序 下图为Yii内置的三种数
  • QQxml和json代码生成卡片的方法

    简介 最近看到qq群里总有人发一些奇怪的卡片 例如下面这个卡片 点击之后就会跳转到你自己的个人资料 是不是很神奇 其实这是依靠xml代码转成的卡片 通过一些软件对xml编译执行 可以编译xml的软件有很多 最常用的手机xml编译执行软件是华
  • Android Display架构分析

    Fence https www jianshu com p 3c61375cc15b android12 display分析 https www cnblogs com roger yu p 15641545 html hwcomper h