美文网首页
图形系统

图形系统

作者: 猫侠 | 来源:发表于2017-06-09 09:32 被阅读0次

    设计师的需求是,每个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;  // 被裁剪的矩形,即上层不透明区域
    

    相关文章

      网友评论

          本文标题:图形系统

          本文链接:https://www.haomeiwen.com/subject/fhwwtxtx.html