如果图片链接失败,请扫码查看文章详情。
Android Display Graphics系列文章-汇总
系列文章请扫关注公众号!
目录
1、Android 图形元素
不管开发的小伙伴使用系统的哪个API显示内容,最终都会将显示内容渲染到surface上。前面说了,Surface理解为存储数据的内存块,实际上Surface表示缓冲区队列BufferQueue的生产者角色,而缓冲区队列BufferQueue一般被SurfaceFlinger消费掉,也就是说SurfaceFlinger扮演的是缓冲区队列BufferQueue的消费者。
Android平台上创建的每一个窗口都由Surface提供支持的。所有被渲染的可见的Surface都被SurfaceFlinger合成并送显到Display上。
协作图如下:
上图的系统架构是生产者-消费者模式,从上到下的层次:
• 图像数据的生产者,可以是Media Player视频解码器,Camera预览,NDK调用,OpenGL ES接口。可以分为两类数据的传输,一个是真正的显示帧数据BufferData,即Surface,通过BufferQueue的方式调用libgui的接口入队。一个是窗口信息的传递WindowMetadata,即窗口的大小,位置等。
• 例如view每次执行lockCanvas->draw->unlockCanvas,会存入一帧数据进入BufferQueue中。
Native Framework
• Framework对上层提供的接口在libgui中,frameworks/native/libs/gui。在这里可以操作Surface出队入队Buffer队列BufferQueue。实现Buffer的生成和BufferQueue数据跨进程之间的传递。
WindowManager
• 计算窗口大小,位置等,并传递相应的参数到SurfaceFlinger,SurfaceFlinger根据这些Window Metadata信息,设置窗口Window的大小、z-order等。
Image Stream Consumers
• 代表的是图像数据的消费者。SurfaceFlinger消耗的是BufferQueue中visible的Surface,并使用WindowManager中的Metadata信息对这些Surface进行合成。SurfaceFlinger是可以修改显示内容的唯一服务,也是显示系统中承上启下的核心服务。
• SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface。OpenGL ES 应用也可以消耗图像流,例如相机应用会消耗相机预览图像流。非 GL 应用也可以是消费者,例如 ImageReader。
HAL 硬件混合渲染器
• 这块主要如前一节介绍的HWC,DPU相关。一块是Hardware Composer也用于合成和送显。当SurfaceFlinger中合成的图层时,会请求composer合成,因为它合成的快,功耗又低。如果合成的layer数大于composer支持的最大数了,那剩下的就让SurfaceFlinger通过GPU合成,最后统一送给HardwareComposer送显。
• SurfaceFlinger在请求HWC Composer合成时,本身充当了一个OpenGL ES的client端。
• Gralloc 是系统图像显示的内存分配器,用来分配图像生产者请求的内存。和系统的ION是有关的。
GraphicBuffer介绍
应用有显示需求时,应用会向系统申请一块GraphicBuffer内存,这块内存将会共享给GPU用于执行渲染工作,接着会同步给HWC用于合成和显示。
GraphicBuffer是Display系统中的显示内存管理类,在APP、SurfaceFlinger、HardwareComposer之间传递。渲染和合成操作都将在GraphicBuffer上进行的。
定义在/frameworks/native/libs/ui/include/ui/GraphicBuffer.h
: public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
public Flattenable<GraphicBuffer>
friend class Flattenable<GraphicBuffer>;
......
static sp<GraphicBuffer> from(ANativeWindowBuffer *);
static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*);
static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*);
AHardwareBuffer* toAHardwareBuffer();
AHardwareBuffer const* toAHardwareBuffer() const;
// Create a GraphicBuffer to be unflatten'ed into or be reallocated.
// Create a GraphicBuffer by allocating and managing a buffer internally.
// This function is privileged. See reallocate for details.
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inLayerCount, uint64_t inUsage,
std::string requestorName = "<Unknown>");
......
}
可以与ANativeWindowBuffer、AHardwareBuffer相互转换。上层JNI的调用封装在android_hardware_HardwareBuffer.cpp、android_graphics_GraphicBuffer.cpp 。
Libgui.so中有广泛使用这个对象,并将封装在一个Surface中,例如
/frameworks/native/libs/gui/Surface.cpp
Surface::attachBuffer函数将Surface与GraphicBuffer attached。
GraphicBuffer 的分配和回收由gralloc管理。
Fence机制
一个GraphicBuffer对象完整的生命周期大概是这样:
- 渲染阶段:应用有绘图需求了,由GPU分配一块内存给应用,应用调用GPU执行绘图,此时使用者是GPU
- 合成阶段:GPU渲染完成后将图层传递给sf进程,sf进程决定由谁来合成,hwc或者GPU
- 如果使用GPU合成,那么此时buffer的使用者依旧是GPU
- 如果使用hwc合成,那么此时buffer的使用者是hwc
- 显示阶段:所有的buffer在此阶段的使用者都是hwc,因为hwc控制着显示芯片
从生命周期可以看出GraphicBuffer对象在流转的过程中,会被GPU、CPU、DPU三个不同的硬件访问,此时需要一个同步机制。用来保证跨硬件访问时的数据安全。可以把Fence理解为一把硬件的互斥锁。
每个需要访问GraphicBuffer的角色,在使用前都要检查这把锁是否signaled了才能进行安全的操作,否则就要等待。
- active状态,该GraphicBuffer正在被占用
- signaled状态,表明不再控制buffer
BufferQueue
GraphicBuffer的queue队列,BufferQueue的引入是为了解决性能问题。如果只有一个Buffer,是不合理的,因为在渲染、合成、送显这个相当于线性执行,效率太低。所以就有了double和triple缓冲机制,相当于有的Buffer在渲染的同事,另外Buffer可以合成、送显。这样就提高了效率。
Surface的概念是对APP进程讲的,Layer是对系统进程讲的,例如SurfaceFlinger。
前面说的生产者-消费者模型,对于BufferQueue来说就是
这里的producer就是前面说的各app,当app create一个Surface时就向BufferQueue队列申请一个buffer,这个过程称为dequeue。当app绘制(渲染)好这个Surface后就放入BufferQueue中,这个过程称为queue。
这里的Consumer如上面说的,对于可见layer,它就是SurfaceFlinger。当buffer 放入BufferQueue后,通知SurfaceFlinger消费。SurfaceFlinger从BufferQueue拿buffer的过程称为acquire。当SurfaceFlinger合成完后,就将buffer释放并放回BufferQueue中,这个过程称为release。
声明和定义在libgui.so中 /frameworks/native/libs/gui/include/gui/BufferQueue.h
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger = false);
}
创建BufferQueue时需要传入producer和Consumer。
GraphicBuffer在producer、BufferQueue、Consumer之间传递,是有状态的。GraphicBuffer就是在不断地循环FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个过程。
数据流
Android数据流的经典图如下
重点是深刻理解这张图:
- 我们看到的手机界面一般是有4个及以上Surface组成的;例子见上篇文章GPU部分;
- 这里也是4个Surface,左侧黄色部分,layer1 Status Bar,layer2 System Bar Renderer,layer3 Background Renderer,layer4 Icons/Widgets renderer;所有layer都是通过GPU(硬件加速)渲染;
- 每个layer使用GPU渲染后将Buffer入队queue到BufferQueue,所以每个layer都有自己的BufferQueue;
- 合成时SurfaceFlinger询问HWComposer,哪些layer给它。随后将layer3,layer4给到HWComposer去合成了;
- Layer1、layer2由SurfaceFlinger合成为layer12,layer12又通过BufferQueue机制给到HWComposer;
- 最后由HWComposer统一合成到一起再送显。
详细流程可见下图:
2、Google组件库
Andorid Graphic中低级别组件库用来控制图形内存的流转、封装Buffer结构。比如CPU、GPU和HWC要共享同一块内存,需要一种格式让它们都能识别这块内存并且还要互斥访问。
Android Graphic中包含了[libui.so]和[libgui.so]两个低级别组件库。
libui.so
其中GraphicBuffer,GraphicBufferAllocator, Fence都定义在libui库中。应用开发者通常不会直接使用libui.so中的接口,因为它们比较底层。相反,这些接口被封装在更高级别的API中
libgui.so
libgui.so库在libui.so的基础上提供了更高级的图形界面功能。它主要负责图形缓冲区的管理和传输,以及与SurfaceFlinger的交互。包含:
- BufferQueue:管理图形缓冲区的生产和消费。生产者(如相机或视频解码器)生成图形数据,消费者(如SurfaceFlinger)使用这些数据进行显示。
- SurfaceComposerClient:提供与SurfaceFlinger交互的接口,允许应用程序创建和管理窗口。
- IGraphicBufferProducer和IGraphicBufferConsumer:定义了生产者和消费者之间的接口,用于图形缓冲区的传输。
- DisplayEventReceiver:处理显示事件,如VSync信号,用于同步显示更新。
开发者通常不会直接使用libgui.so中的接口,而是通过Android框架提供的更高级别的API来间接使用。例如,开发者通过SurfaceView、TextureView等类来使用这些底层功能。