设计师的需求是,每个window可以当作独立的模块设计;需要一种方式表达window中的树结构、每个节点在屏幕上的大小位置及纹理。
系统要解决的事情是,设计师设计的window树结构可以被识别,并调用OpenGL的API绘制出来;众多window合成一副图画显示在屏幕上。
描述surface的数据结构是BufferData。BufferData记录世界坐标系中的window的大小位置。
描述texture的类是GraphicBuffer。GraphicBuffer记录模型坐标系中texture的大小、图像格式。
struct BufferData {
FlatRegion dirtyRegion; // 需要重新绘制的区域
SmallRect crop; // 纹理坐标
uint8_t transform; // 从模型坐标系到世界坐标系
uint8_t reserved[3];
};
加入多重缓冲技术。用SharedBufferStack作为BufferData的缓冲区,用BufferQueue作为GraphicBuffer的缓冲区。
class SharedBufferStack {
volatile int32_t head; // server's current front buffer
volatile int32_t available; // number of dequeue-able buffers
volatile int32_t queued; // number of buffers waiting for post
volatile int8_t index[NUM_BUFFER_MAX];
BufferData buffers[NUM_BUFFER_MAX];
int8_t headBuf;
};
可以看出SharedBufferStack实际是一个BufferData的队列,用三个指针进行入队出队操作。那么需要封装:分配SharedBufferStack所需内存的工具类、入队出队工具类。
相应的,GraphicBuffer有GraphicBufferProducer、GrapgicBufferConsumer、SurfaceFlingerConsumer。
一个APP内最多同时存在31个surface,对应31个SharedBufferStack。这些SharedBufferStack及操作方法封装为SharedClient。
调用链为new SurfaceClient() ->SurfaceFlinger::createClientConnection() -> new UserClient() -> new SharedClient()
为了方便APP创建surface,封装一个类SurfaceControl,APP启动时创建new SurfaceClient() -> new SurfaceControl()
APP调用SurfaceControl::getSurface()即可创建surface。创建surface的同时创建对应的SharedBufferStack、APP侧入队出队工具类SharedBufferClient,系统侧入队出队工具类SharedBufferServer。
调用链为SurfaceControl::getSurface() -> new Surface() -> Surface::init() -> UserClient::getTokenForSurface() -> Layer::setToken() -> new SharedBufferServer() -> new SharedBufferClient()
上面的调用链中有一步创建的Surface,封装有OpenGL的API供java层的Canvas调用。于是可以与View的绘制联系起来。View.onDraw(Canvas canvas) -> Canvas.drawXX方法 -> Surface::XXX方法 -> OpenGL.API。
APP侧操作即new View()/View.invalidate() -> onMeasure/onLayout -> SharedBufferClient::Dequeue()如果序列有空闲,把序列中第一个BufferData出栈给APP -> APP向BufferData写入数据 -> SharedBufferClient::Queue()把这个BufferData入栈到待渲染序列 -> 创建GraphicBuffer -> onDraw向GraphicBuffer写入数据 -> SurfaceClient::signalServer()通知系统更新屏幕。
系统侧操作是Looper操作,即接收到APP侧发来的通知,开始循环检测SharedBufferStack,如果有待渲染的BufferData就取出来渲染屏幕,直到没有待渲染的BufferData停止循环,等待下一条APP发来的通知。每个循环有16ms的间隔。这个Looper线程即SurfaceFlinger::threadLoop()。
在一个循环中需要做几个工作:
handlePageFlip()
handleRepaint()
postFramebuffer()
前两步的真正执行是Layer类。
Layer中有两个变量mCurrentState/mDrawingState,也就是双缓冲。PageFlip的意思就是交换这两个变量,把front page变成back page接收数据,把back page变成front page用于显示。
Layer计算matrix和mesh -> 把matrix施加给texture -> RenderEngin根据texture和mesh绘制。
注意这个遍历,根据Z-order从最上层的Layer遍历到最下层。最上层计算出的mesh是原本的整个矩形(因为没有遮挡),第二层计算出的mesh只有可见区域visiableRegion,包括被上层透明区域覆盖的部分。visiableRegion可以由原本的矩形和上层不透明区域相减得到,那么描述visiableRegion的数据结构就是这样的:
struct Geometry{
uint32_t w; // 原本的矩形的宽
uint32_t h; // 原本的矩形的高
Rect crop; // 被裁剪的矩形,即上层不透明区域