术语
- hwc-hal。HAL中的hwcomposer模块。专门命名的目的是为和surfaceflinger中的HWComposer类做区分
- workList。hwc-hal中的接口函数prepare和set,都须要个“hwc_display_contents_1_t**”类型的参数,称这参数为workList。workList中的一个单元对应一个显示器。一个显示器有多个图层,hwc_layer_1_t表示一个图层,其中buffer_handle_t类型的handle指向了存储该层数据的图形缓冲区。
- opengl合成。向hwc-hal调用set时,hwc-hal能接受的两种合成方法之一,有的地方称GPU合成、Client合成。其合成方法是,将各个Layer的内容用GPU渲染到暂存缓冲区中,最后将暂存缓冲区传送到显示硬件。这个暂存缓冲区称为fbTarget,每个显示设备有各自的fbTarget。这种合成方法目前使用的是opengles技术。
- hwc硬件合成。向hwc-hal调用set时,hwc-hal接受的两种合成方法之一。hwc-hal用专门的硬件合成器进行合成,它的合成能力就取决于硬件的实现。其合成方法是将各个Layer的数据全部传给显示硬件,并告知它从不同的缓冲区读取屏幕不同部分的数据。
- fbTarget。opengl合成时,将各个Layer的内容用GPU渲染到暂存缓冲区中,最后将暂存缓冲区传送到显示硬件,这个暂存缓冲区称为fbTarget,每个显示设备有各自的fbTarget。fbTarget的类型是hwc_layer_1_t。
SurfaceFlinger接收Vsync目的是为处理图像,处理图像可分为两部分,分别对应收到INVALIDATE、REFRESH消息后的行为,一是各图层从各自的Buffer Queue取出新到Buffer,二是合成各图层的图像,形成workList,把它送到hwc-hal。
surfaceflinger如何处理图像,网上不乏函数注解详细的文章,像“Android P图形显示系统(六) SurfaceFlinger合成流程(一)[1]”、“Android P图形显示系统(七) SurfaceFlinger合成流程(二)[2]“、Android P图形显示系统(八) SurfaceFlinger合成流程(三)[3]”。它们是Android P,想看低版本的,像Android 7.1,有“显示HWC合成(hwc_display_contents_1_t,hwc_layer_1_t数据结构关系)[4]”、“Android6.0 图像合成过程详解(二) doComposition函数[5]”。
这里不做具体函数注解了,给出用图描述的图像处理流程。图1分三部分,上半部是函数调用关系。左下角是“图像数据(buffer_handle_t handle)处理流程”,小结要得到各个hwc_layer_1的handle,大概分哪些步骤。右下角是“BufferItem中一些字段的流动过程”。
本文讨论的图像流程从BufferQueueProducer::queueBuffer开始。
注1。Layer::onFrameAvailable
新收到的item放入mQueueItems。放入后mLastFrameNumberReceived指示此item的mFrameNumber。由于mFrameNumber肯定是连续的,所以onFrameAvailable的下一item的mFrameNumber必须是mLastFrameNumberReceived+1。疑问:1)mQueuedFrames,mQueueItems的长度,为什么不用mQueueItems.size()?2)onFrameAvailable到达的item的mFrameNumber可能是乱序的?
注2。SurfaceFlinger::handleMessageInvalidate
如果此次有Layer要显示,并且用latchBuffer成功取出了buffer,返回true。由于有新数据,有Layer极可能要脏了,意味着须重新合成图像,handleMessageInvalidate会紧接调用SurfaceFlinger::signalRefresh。此时不须要下一个Vsync就能让SurfaceFlinger收到REFRESH,从而调用handleMessageRefresh。
注3。SurfaceFlingerConsumer::updateTexImage
输出[OUT]参数queuedBuffer。此值来自于刚从Buffer Queue取出item的mQueuedBuffer字段。一旦是true,调用它的latchBuffer会把相对应的BufferItem从Layer.mQueueItems删除
注4。opengl合成
- 创建RenderEngine。RenderEngine 是在SurfaceFlinger初始化时,创建的。
- 各DisplayDevice创建私有EGLSurface。在RenderEngine创建时,初始化了EGLDisplay、EGLConfig和EGLContext。这些都是所有DisplayDevice共用的,但是EGLSurface是每个DisplayDevice自己的。在DisplayDevice创建时,创建对应的EGLSurface。通过ANativeWindow,Surface就和DisplayDevice的BufferQueue建立了联系。
- 各Layer创建私有texture。Layer创建时,会调用glGenTextures创建一个texture。mTexName是标识该texture的纹理ID。
- Layer合成(1/3)切换私有EGLSurface为当前EGL窗口。合成是在SurfaceFlinger的doComposeSurfaces中进行,首先DisplayDevice::makeCurrent。每个DisplayDevice有自己的EGLSurface,所以,每个DisplayDevice做具体合成时,需要给RenderEngine指定EGLSurface,视窗,投影矩阵等,告诉RenderEngine合成到哪个EGLSurface上。切换当前EGL窗口的函数是eglMakeCurrent。
- Layer合成(2/3)绑定Texture。合成时,每个DisplayDevice的每个Layer都合为绘制到DisplayDevice对应的EGLSurface上。Layer首先须要把图形缓冲区数据如何绑定到纹理。GLConsumer::bindTextureImageLocked执行和绑定相关的绝大部分工作。1)创建EGLImageKHR类型的mEglImage。在该Layer私有的GLConsumer中,mCurrentTextureImage->createIfNeeded创建出mEglImage。具体用的api是eglCreateImageKHR。调用eglCreateImageKHR时须要个类型“EGLClientBuffer”的参数,它来自于GraphicBuffer的getNativeBuffer()方法。2)加载mEglImage数据到mTexName这个纹理。
- Layer合成(3/3)用opengles绘制。主要通过各Layer分别调用drawWithOpenGL函数完成。
- 交换Buffer。eglSwapBuffers 将交换GPU处理的Buffer,处理完的Buffer,也就是包含Layer合成数据后的Buffer将被queue到BufferQueue中。
调用eglCreateImageKHR创建mEglImage
------
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
在这是里参数buffer来自于GraphicBuffer的getNativeBuffer()方法。
EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer();
加载mEglImage数据到mTexName这个纹理
------
// 把mTexName作为mTextTarget这个纹理目标的纹理
glBindTexture(mTexTarget, mTexName);
// 加载mEglImage数据到mTexName这个纹理,相当于一般情况下的glTexImage2D的效果。
glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
参考
- ^Android P图形显示系统(六) SurfaceFlinger合成流程(一) https://www.jianshu.com/p/fa115146949f
- ^Android P图形显示系统(七) SurfaceFlinger合成流程(二) https://www.jianshu.com/p/fd16dcb4dfb6
- ^Android P图形显示系统(八) SurfaceFlinger合成流程(三) https://www.jianshu.com/p/cf4455021fd5
- ^显示HWC合成(hwc_display_contents_1_t,hwc_layer_1_t数据结构关系) https://blog.csdn.net/kc58236582/article/details/70146317
- ^Android6.0 图像合成过程详解(二) doComposition函数 https://blog.csdn.net/kc58236582/article/details/52868973