首先可以梳理出SurfaceFlinger的类图
然后可以看下这些类大致是干嘛的,梳理出主要的类
===========先看主文件夹下的类================
1.Barrier
用于控制互斥访问的
2.Colorizer
用户颜色转换
3.DisplayDevice(重要类)
显示设备类
4.DispSync(重要类)
DispSync维护了显示设备基于硬件的vsync事件的周期性模型,并用这个模型周期性的在特定的硬件vsync事件相位来执行回调
这个模型的通过addResyncSample函数连续传递硬件事件时间戳进行构造
这个模型通过addPresentFence函数使用传递到DispSync对象的Fence对象的时间戳来进行验证
这些fence时间戳应该对应硬件vsync事件,但他们不需要是连续的硬件vsync时间。如果这个函数确定当前的模型准确地反应了硬件事件的时间
那么就会返回false来表明不需要resyncchronization(通过addResyncSample)。
所以这个类就是用来判定和调节sync周期的,如果周期正确就不调节。
5.DdmConnection
只有一个start函数
6.FrameTracker
信息跟踪类,用于跟踪最近渲染的一些帧的信息,主要记录在mFrameRecords中
7.transform
是一个工具类
8.MessageQueue(重要类)
是SurfaceFlinger的基础
9.MonitoredProducer
封装了一个IGraphicBufferProducer(libgui.so中的类)用于保证当其被销毁时SurfaceFlinger会收到通知
多数是一些对GraphicBuffer的操作及断开连接操作。
10.Client(重要类)
SurfaceComposerClient的一个实现
看实现是用于操作SurfaceFlinger类来创建和销毁Surface的,并且有一个向量以wp<IBinder>为索引存储了多个wp<Layer>对象进行管理
11.SurfaceFlingerConsumer(重要类)
对GLConsumer的简单封装,我们可以看下GLConsumer这个类的注释
GLConsumer消费BufferQueue中的图形数据buffer,并使其变成texture可以被OpenGL使用
一个典型的用例模式时设置GLConsumer以期望的选项,然后在需要一个新的frame的时候调用updateTexImage()
如果这个新的frame可用,那么这个texure就被更新,如果不是,那么就会保持前面的内容。
默认情况下,texture在第一个调用updateTexImage()的线程中被绑定到一个GL_TEXTURE_EXTERNAL_OES纹理目标
GLConsumer类在先前的Android版本中是叫SurfaceTexture的(= =)
12.EventThread
事件线程
13.EventControlThread
事件管理线程
14.SurfaceFlinger(重要类)
===========然后看下RenderEngine文件夹下的类================
15.RenderEngine
看实现可以知道是对ligegl.so的一层封装,封装EGL调用的一个引擎,如上图,依赖于libegl.so
16.ProgramCache
17.Texture
纹理类
18.Program
操作GLSL脚本着色器的辅助类
19.Description
这个类持有RenderEngine的状态。这个类用于产生一个对应的GLSLprogram并且设置合适的uniform
Program和ProgramChache是其友元
20.Mesh
工具类
21.GLExtensions
工具类,将一些信息转成字符串形式方便打印
===========最后看下DisplayHardware文件夹中的类================
22.DisplaySurface(重要类)
这里关注DisplaySurface的生命周期
beginFrame在获知composition configuration之前,composition loop开始的时候被调用。DisplaySurface应该做任何需要做的事情来使HWComposer
决定如何copose一帧。我们传递mustRecompose参数,我们可以保持VirtualDisplaySurface的状态机,所以在没有任何东西被改变的时候,实际上可以不入队一个buffer
prepareFrame在composition configuration已知但合成发生之前被调用。DisplaySurface可以用composition type来决定如何管理GLES和HWC之间的这一帧的buffer流
compositioncomplete应该在composition 渲染完成的时候调用(但并不一定要调用eglSwapbuffers).部分老驱动需要这个函数来保持同步
advanceFrame通知surface 这一帧的ELES合成操作已经完成,并且surface需要保证HWComposer拥有这一帧的正确buffer。部分实现可能仅仅在GLES合成发生的时候
将新buffer push到HWComposer,其余的可能需要每一帧都push一个新的buffer。当advanceFrame可能会被再次调用的时候,其后必须跟随一个onFrameCommitted调用
onFrameCommitted在frame已经被提交给hardware composer后调用,surface回收这一帧buffer的release fence
23.FramebufferSurface(重要类)
继承了DisplaySurface的生命周期,并多了一些能力
nextBuffer等待并附着从BufferQueue中过来的下一个buffer并释放先前已经附着的buffer。新buffer会在参数'buffer'中被返回
mDisplayType必须符合HWC显示类型中的一种
mCurrentBufferSlot是当前buffer的slot index或者INVALID_BUFFER_SLOT,用来标明当前buffer是否不存在或者buffer没有关联到一个slot
mCurrentBuffer是当前buffer或者Null,用来标明当前buffer是否不存在
mHwc是一个HardwareComposer,由SurfaceFlinger拥有。
24.VirtualDisplaySurface
支持虚拟显示的一种实现,比如GLES和/或 HWC合成到一个buffer,然后传递给跑在另一个进程中的任意一个消费者
最简单的用例是当虚拟显示器不使用h/w composer -h/w composer不支持写buffer,或者有比它能够支持的更多数量的显示器。在这种情况下,GLES驱动直接工作在output buffer queue上,并且从SurfaceFlinger上直接调用虚拟显示器,DisplayHardware不做任何事情。
如果h/w composer可能会被使用,那么每一帧都会是三种配置中的一种:GLES-only,HWC-only,MIXED composition。在所有这些配置中,我们必须为HWC 的set()调用提供一个FrameBuffer和output buffer
在ELES-only合成中,GLES 驱动会从sink中给一个buffer给渲染。当GLES驱动将这些buffer以队列形式发送给VirtualDisplaySurface,VirtualdisplaySurface会持有这些buffer而非立即将其压入sink。buffer被HWC同时作为FB target和output buffer使用,尽管在这些帧上HWC没有为这个显示做任何事情,也没有写任何东西到output buffer中。在合成完成后,buffer被入队到sink中。
在HWC-only 合成中,VirturalDisplaySurface 将一个buffer 从sink中dequeue 并传递给HWC,同时作为FB target和output buffer。HWC不需要从FB target buffer中读取,单需要向output buffer中写入。在合成完成后,buffer被入队到sink中。
在MIXED frames,事情会变得更加复杂,既然一些h/w composer实现不能向同一个buffer中读和写。这个类拥有一个内部BufferQueue作为一个临时buffer 池。GLES驱动被给予一个临时buffer用来渲染。当渲染完成时,buffer入队并且立即被VirtualDisplaySurface获取。这个临时buffer然后被HWC当做FB target buffer,另一个独立的buffer从sink中出队并被当做HWC的outputbuffer。当HWC合成完成时,这个临时buffer被释放而output buffer被入队到sink中。
mapSource2ProducerSlot(Source source, int sslot)
mapProducer2SourceSlot(Source source, int pslot)
sink和临时缓冲区池都拥有各自的slot集合("source slots"或"sslot")。我们需要将这些分发到被GLES生产者使用的slot集合中("producer slots"或“pslot”),为了减小生产者slot在他们源slot集合中切换的次数,我们为每个资源将源slot的数量映射到生产者slot的数量
这用的是
uint32_t mOutputFormat;
uint32_t mOutputUsage;
为了避免重复分配buffer,我们跟踪buffer在前一帧的使用标识及格式并在新的一帧再次使用。如果合成类型改变或者GLES驱动开始请求不同的使用标识或者格式,我们就获取一个新buffer
25.HWComposer(重要类)
硬件合成类
分析完类的作用和角色,我们现在分析一下这些重要类在架构设计上的关系。
只保留了一些主要的类,总结如下:
1.三个主要的类是SurfaceFlinger HWcomposer和RenderEngine
2.部分做成员变量的类简化到了成员变量中
3.SurfaceFlingerComsumer在Layer类中被使用
4.整个SurfaceFlinger模块主要依赖外部libgui.so和libegl.so
在deleteTextureAsync的时候会调用到RenderEngine的deleteTextures函数
分析完重要类在架构上的关系之后,详细分析一下SurfaceFlinger的原理,尤其VirtualDisplaySurface的用法。
通过分析得知,最后绘制的目标为Layer类中的mTexture,参见Layer::onDraw()的实现
所以现在想办法把这个mTexture绘制到Unity中即可
mTexture来自于DisplayDevice中的mSecureLayerVisible
1.SurfaceFlinger中DisplayDevice封装了部分对EGL函数的调用,比如eglSwapBuffers
=============================实现分析=============================================
写了demo,应用可以取出SurfaceFlinger中的mTexture并绘制,但是绘制的时候会不停闪烁。
1.绘制的时候不停闪烁
2.当前是在TextureObtain中创建了一个Surface,然后取出来显示,但现在是要取到其他进程中的Surface
第一个问题继续调查,可能和刷新周期有关
第二个问题,应该可以通过更改TextureObtain的代码,改成跨进程获取。这里又有两个条件,第一是将自身应用的图像
1.任意app的图像可以通过SurfaceFlinger渲染到屏幕上
2.目标效果,要确保LauncherApp仍然正常渲染,只不过在Launcher应用中有一个线程从系统中取出系统屏幕图像来显示
这就要确保,取屏幕的线程取得图像应该不包括Launcher应用的图像,因为如果包含的话,就会出现在Launcher中显示Launcher的情况了。
所以,这个线程应该是取非Launcher的图像显示,其他什么都不动。
3.现在确认可以将SurfaceFlinger中的图像取到应用中出来显示。所以现在要考虑的是如何取到其他应用的UI画面。