SurfaceFlinger学习之路(三)BufferQueue原理


本文参考很多资料和源码,每一小结附上参考资源。

组件介绍

  • SurfaceFlinger:系统服务,接收多个源的数据,对它们进行合成,然后发送到显示设备进行显示。
  • HWComposer:在没有HWComposer之前,SurfaceFlinger将各个Layer的内容用OpenGL渲染到暂存缓冲区中,最后将暂存缓冲区传送到显示硬件。HWComposer是硬件合成器,帮助GPU做一些工作,SurfaceFlinger把多个Surface输出给hwc, hwc按照Surface的属性, 把多个Surface混合成一个Surface, 最后输出到Display。
  • Gralloc:层中提供了一个Gralloc模块,Hgralloc库负责了申请图形缓冲区的所有工作,用户空间中的进程申请图形缓冲区,可以是普通的缓存区,也可以是显存缓冲区,并且将缓冲区映射到应用程序的地址空间。

GraphicBuffer

GraphicBuffer是图形内存块,是UI绘制的缓存数据。Surface向GraphicBufferProducer申请一个GraphicBuffer,再绘制到GraphicBuffer中,提供给SurfaceFlinger进行消费合成。

那么GraphicBuffer是什么?

// GraphicBuffer.h
GraphicBufferMapper& mBufferMapper; // 辅助类
ssize_t mInitCheck; // 记录图形缓冲区的状态
sp<ANativeWindowBuffer> mWrappedBuffer; // 描述Native Buffer
uint64_t mId; // 图形缓冲区的标识
sp<IBinder> mBufferRef;
uint32_t mGenerationNumber; // 记录 generation number

其中,GraphicBufferAllocator 负责GraphicBuffer创建和释放工作;

GraphicBufferMapper负责lock和unlock操作,lock 操作将图形内存块映射到应用程序进程的虚拟地址空间内。而unlock就是归还内存。

struct ANativeWindowBuffer
{
   
    int width;
    int height ;
     .....
    buffer_handle_t handle ; // 硬件驱动层生成的图像缓存句柄
}

更多GraphicBuffer可以参考:
https://www.wolfcstech.com/2017/09/20/android_graphics_bufferalloc/

GraphicBufferAllocator

GraphicBufferAllocator 管理分配显示的内存,提供了申请和释放图像内存块的方法:

status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, PixelFormat  format, uint32_t usage, buffer_handle_t* handle, uint32_t* stride);
status_t GraphicBufferAllocator::free(buffer_handle_t handle);

GraphicBufferAllocator是单例模式,每个进程只有一个GraphicBufferAllocator对象;

GraphicBufferAllocator对接了gralloc,而gralloc模块是Android硬件抽象层提供的一个操作帧缓冲区的模块。

gralloc 提供了两种缓存区:

  • FrameBuffer帧缓冲区,映射到用户空间,应用进程可以操作FrameBuffer,来让显示设备显示;
  • 普通的数据缓冲区,内核中创建一块匿名共享内存,映射到用户空间。
// gralloc
gralloc_alloc(){
    if ( usage & GRALLOC_USAGE_HW_FB ) {
   
       err = gralloc_alloc_framebuffer (dev, size, usage , pHandle);
    } else {
   
        err = gralloc_alloc_buffer (dev, size, usage , pHandle);
    }

GraphicBufferAllocator::get() 提供获取GraphicBufferAllocator的方法

GraphicBufferAllocator分配缓存Buffer,GraphicBufferMapper mmap映射到应用程序的进程

更多Gralloc参考:
https://blog.csdn.net/fu_shuwu/article/details/53048047

共享内存

由上面我们可以知道,GraphicBuffer指向的是一个图像缓存区,而应用程序执行draw动作的时候,将一帧帧的数据通过Surface写入到GraphicBuffer,等到vsync信号来了,GraphicBuffer被SurfaceFlinger消费,通过某种手段混合生成最后的帧数据,写入FrameBuffer交由显示设备显示。

其中应用进程、SurfaceFlinger都是在不同的进程,binder通信不适传递大量的图像数据,因此采用了匿名共享内存的IPC手段,在tmpfs临时文件系统中创建一个临时文件。

参考:
https://www.jianshu.com/p/d9bc9c668ba6

GraphicBuffer和FrameBuffer的关系

二者之间其实没有很直接的关系,但是自己的学习过程中,一直搞不懂之间的猫腻。

GraphicBuffer
GraphicBuffer继承自ANativeWindowBuffer,Surface继承自ANativeWindow
BufferQueue操作的具体对象,表示图像缓冲区,Surface可能包含申请多个GraphicBuffer;

FrameBuffer
帧缓冲是Linux 系统为显示设备提供的一个接口,每个显示设备被抽象为一个帧缓冲区,注册到FrameBuffer模块中,并在/dev/graphics目录下创建对应的fbX设备。屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。

http://blog.csdn.net/ear5cm/article/details/45458683

BufferQueue

GraphicBuffer是表示基本的显示内存单元,而GraphicBufferAllocator负责真正的申请和释放内存,那BufferQueue就是管理GraphicBuffer的管理者。

SurfaceFlinger在Surface创建的时候,对应创建了Layer,Layer会创建BufferQueue。
BufferQueue的原理很简单:

  1. 生产者(Producer)向BufferQueue申请出队(dequeue) GraphicBuffer,生产者向GraphicBuffer中填充图形数据后,然后将GraphicBuffer入队(queue)到BufferQueue;
  2. GraphicBuffer入队BufferQueue时,BufferQueue会通知消费者,新的图形数据生产了;
  3. 消费者(Consumer)向BufferQueue获取(acquire) GraphicBuffer,消费者消费图形数据,然后将GraphicBuffer释放交回(release)给BufferQueue;
  4. 空的GraphicBuffer交回给BufferQueue,BufferQueue又会通知到生产者有新的可利用的GraphicBuffer。
    在这里插入图片描述

BufferQueueCore

BufferQueue 内部有一个重要的变量BufferQueueCore。BufferQueue中用BufferSlot来存储GraphicBuffer,使用数组来存储一系列BufferSlot,数组默认大小为64。

  • mSlots
    定义了64个BufferSlot, BufferSlot直接持有GraphicBuffer
  • std::set mFreeSlots
    mFreeSlots里面的slot值表明当前slot的BufferSlot是FREE状态, 并且没有GraphicBuffer
  • std::list mUnusedSlots
    mSlots的大小是64个,而mUnusedSlots就是除掉mFreeSlots剩下的BufferSlot
  • std::list mFreeBuffers
    mFreeBuffers里面的slot表明当前slot对应的BufferSlot是FREE状态,并且有GraphicBuffer
  • std::set mActiveBuffers
    mActiveBuffers里面的slot表明当前slot对应的BufferSlot都有GraphicBuffer,并且是NON FREE状态

GraphicBuffer用BufferState来表示其状态,有以下状态:

  • FREE:表示该Buffer当前可用,允许被dequeued,此时Buffer属于BufferQueue;
  • DEQUEUED:表示该Buffer被生产者获取了,属于生产者,BufferQueue不可以对这块缓冲区进行操作;
  • QUEUED:表示该Buffer被生产者填充了数据,并且入队到BufferQueue了,该Buffer的所有权属于BufferQueue
  • ACQUIRED:表示该Buffer被消费者获取了,该Buffer的所有权属于消费者

BufferQueueCore

BufferQueue创建

BufferQueue是由BufferLayer创建,而BufferLayer是在SurfaceFlinger创建,BufferQueue为BufferLayer管理GrapicBuffer。

void bufferqueue::createbufferqueue(sp<igraphicbufferproducer>* outproducer,
        sp<igraphicbufferconsumer>* outconsumer,
        const sp<igraphicbufferalloc>& allocator) {
   //allocator == null
    ...
    //创建bufferqueuecore
    sp<bufferqueuecore> core(new bufferqueuecore(allocator));
    ...
    //创建生产者
    sp<igraphicbufferproducer> producer(new bufferqueueproducer(core));
    ...
    //创建消费者
    sp<igraphicbufferconsumer> consumer(new bufferqueueconsumer(core));
    ...
    *outproducer = producer;
    *outconsumer = consumer;
}

BufferQueueProducer

BufferQueue 创建了生产者BufferQueueProducer,并赋给外部的IGraphicBufferProducer,供外部调用。

来看一下BufferQueueProducer,他继承自了BnGraphicBufferProducer,是一个binder的服务端,接收来自客户端的消息。

status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence, uint32_t width,
         uint32_t height, PixelFormat format, uint64_t usage,
         uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps);
                                   
status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output);
status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);

参考:https://zhuanlan.zhihu.com/p/62813895

BufferQueueConsumer

BufferQueue 创建了消费者者BufferQueueConsumer,并赋给外部的IGraphicBufferConsumer,供外部调用。

同样,BufferQueueConsumer也继承了BnGraphicBufferConsumer,同样也是个binder的服务端。

status_t acquireBuffer(BufferItem* outBuffer,nsecs_t expectedPresent, uint64_t maxFrameNumber = 0);
status_t releaseBuffer(int slot, uint64_t frameNumber, const sp<Fence>& releaseFence, 
        EGLDisplay display, EGLSyncKHR fence);

更多参考:
https://www.jianshu.com/p/af5858c06d5d
https://blog.csdn.net/yangwen123/article/details/12234931

Surface 生产数据

Surface生产数据经历的流程:

  1. allocateBuffer
  2. dequeueBuffer
  3. queueBuffer

                
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值