架构概览:https://source.android.com/devices/graphics/arch-sh

https://developer.android.com/reference/android/graphics/SurfaceTexture
https://developer.android.com/reference/android/view/Surface
这几篇API doc一直没有中文翻译,要了解Android渲染底层部分绕不开SurfaceTexture,学习顺便翻译一下。

Surface

https://developer.android.com/reference/android/view/Surface
java层的Surface对象持有着底层由compositor管理的raw buffer句柄,也就是持有一个java的long类型属性,值为raw buffer的内存地址,就是指针。
一般来说一个Surface由image buffer的consumer创建(如SurfaceTexture、MediaRecorder、Allocation),并且由image producer(OpenGL、MediaPlayer、CameraDevice)来进行渲染。

SurfaceTexture

https://developer.android.com/reference/android/graphics/SurfaceTexture
负责从Image Stream中截取帧,并将这些帧作为OpenGL ES Texture。
Image Stream可以是从相机预览或者视频解码产生的。由SurfaceTexture创建的Surface可以作为camera2、MediaCodec、MediaPlayer、Allocation的输出目标。当调用updateTexImage时,会更新创建SurfaceTexture时所指定的那个纹理,让纹理包含image stream中最近的图像。这可能会导致image stream中的多个帧被跳过。
过去的camera包提供的API允许指定SurfaceTexture作为相机预览输出,此时相机的图像流被送到SurfaceTexture的Surface上而不是代表屏幕的Surface上。

SurfaceTexture对象使用GL_TEXTURE_EXTERNAL_OES作为Texture texture target(看起来这是一个Android推动EGL弄出来的接口,相关的概念需要先了解EGL_OES_image_base,不过EGL的规范,又是老问题了,看起来只是专门为了Android搞的,规范描述的实在是不太明确,更像是列举了一下Android大概都用了哪些东西,至于细节、使用场景、实例、demo,对不起,没有,read the fucking source code。。。真是难受,看来从文档里也看不出太多东西,还是得从源码理解)。

自己的理解

具体的Window创建过程就不再复述,之前记录过:https://www.yuque.com/gaolf/ipvf6y/mozgw7

Android中,SurfaceFlinger服务负责管理界面上显示内容。
当应用启动时,会创建一个Window对象,Window对象其实是描述窗口元数据的一个对象,负责根据这些描述创建DecorView,帮我们在ViewRootImpl之下创建一些基础的布局结构,很多时候我们都希望自己控制界面的方方面面,因为国内的App不符合Google的设计规范,因此一般我们都会想办法修改Theme让DecorView尽量不要添加太多View。
真正负责和SurfaceFlingr通信的,是一个SurfaceFlinger服务的Binder对象:Session对象,这个Session对象是由ViewRootImpl来持有的,因此ViewRootImpl才是真正负责和SurfaceFlinger沟通的类。在ViewRootImpl执行View层次的遍历时,会先确保代表当前应用窗口的Session符合当前的设置,包括窗口大小、窗口纹理的颜色格式等,如果发现这些属性和之前不一样了就会要求Session根据最新属性进行调整,在第一次渲染的场景里,调整的结果就是根据属性在WMS里创建一个SurfaceControl,这个SurfaceControl就是是由WMS跨进程调用SurfaceFlinger申请的buffer的封装,然后返回它(这是个Parcelable,因此可以跨进程传递)给ViewRootImpl,ViewRootImpl会利用它创建Surface对象。Surface对象是Android的EGL实现中规定的代表NativeWindow句柄,由此就能够创建出EGLSurface,后续ViewRootImpl会遍历View树完成测量、布局和渲染,收集好一颗抽象的渲染指令树,将这些渲染指令通过OpenGL API实现,EGL就会负责根据GL指令来完成渲染,渲染到EGLSurface上,也就是SurfaceFlinger之前所分配的那个buffer上。
在使用GL时,如果不调用EGLSwapBuffer,是不会将渲染结果显示到屏幕上的,在Android中,EGLSwapBuffer的作用是将渲染结果,也就是渲染好的buffer提交给SurfaceFlinger,并向SurfaceFlinger申请到一个新的buffer用于下以帧渲染。如果应用某一帧渲染花了太长时间,SurfaceFlinger在vsync信号到来时发现应用还没提交这一帧的渲染结果,那应用窗口就不会变化,还以之前的渲染结果来显示,也就是我们所说的卡顿(jank)。
上面说的一直是WMS管理的Surface,也就是屏幕上显示的Surface,下面聊聊SurfaceTexture。
SurfaceTexture,内部会创建Surface,这个Surface必须由Android的特定API来负责渲染(一般来说这些API的实现都是写在Framework的C++代码中的),这些API还要负责在每一帧渲染完毕后调用onFrameAvailable回调,然后我们在回调里应该使用updateTexImage来将Surface内容上传到一个特殊的EGL纹理上,至于这个纹理怎么用,得结合源码和文档一块看,因为文档没说明白。反正,这个纹理肯定是能够被作为当前激活的纹理单元使用的,可以被渲染到Framebuffer上,显示到屏幕中或者是离屏生成图片/视频。