图形系统

设计师的需求是,每个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;  // 被裁剪的矩形,即上层不透明区域
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容