Android 画面显示流程二

本文详细介绍了Android系统中BufferQueue如何处理应用程序与SurfaceFlinger之间的同步问题,以及Buffer状态的切换。重点讨论了BufferSlot的管理,包括不同状态的BufferSlot如何在SurfaceFlinger和应用程序之间流转。此外,还探讨了在多buffer系统中SurfaceFlinger的管理策略和Fence在异步硬件同步中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BufferQueue

BufferQueue要解决的是生产者的同步问题,应用程序生产画面,SurfaceFlinger消费画面,SurfaceFlinger生产画面而HWCService消费画面。用来存储这些画面的存储区我们称其为帧缓冲区buffer,下面我们以应用程序作为生产者,SurfaceFlinger作为消费者为例来了解一下BufferQueue的内部设计。

Buffer State的切换

在Buffer Queue的设计中,一个buffer有以下几种状态:
FREE:表示该buffer可以给到应用程序,由应用程序来绘画
Dequeued:表示该buffer的控制权已经交给到应用程序侧,这个状态下应用程序可以在上面绘图了
Queued:表示buffer已经由应用程序绘画完成,buffer的控制权已经回到SurfaceFlinger手上
QCQUIRED:表示该buffer已经交给HWC service去合成了,这时控制权已经到HWC Service了

Buffer初始态为FREE,当生产者通过dequeueBuffer来申请buffer成功时,buffer状态变成Dequeued状态,应用画图完成后通过queueBuffer将buffer状态变为了Queued状态,当SurfaceFlinger通过acquireBuffer操作将buffer拿去给HWC Service合成,这时buffer状态变为ACQUIRED状态,合成完成后通过releaseBuffer把buffer状态重新改为FREE状态。状态切换如下图所示:
在这里插入图片描述
从时间轴上来看一个buffer的状态总是这样循环变化
FREE–>DEQUEUED–>QUEUED–>FREE
应用程序在DEQUEUED状态下绘图,而HWC Service在状态为ACQUIRED状态下合成

在这里插入图片描述

BufferSlot

每一个应用程序的图层在SurfaceFlinger里称为一个Layer,而每个Layer都拥有一个独立的BufferQueue,每个BufferQueue都有多个Buffer,Android系统上目前支持每个Layer最多64个buffer,这个最大值被定义在frameworks/native/gui/BufferQueueDefs.h,每个buffer用一个结构体BufferSlot来代表。
每个BufferSlot里主要有如下重要成员:

struct BufferSlot{
   
   
    ......
    BufferState mBufferState;//代表当前Buffer的状态 FREE/DEQUEUED/QUEUED/ACQUIRED
    ....
    sp<GraphicBuffer> mGraphicBuffer;//代表了真正的buffer的存储空间
    ......
    uint64_t mFrameNumber;//表示这个slot被queued的编号,在应用调dequeueBuffer申请slot时会参考该值
    ......
    sp<Fence> mFence;//在Fence一章再来看它的作用
    .....
}

64个BufferSlot可以分成俩个部分,used Slots和Unused Slot就是使用未使用的,而Used Slots又可以分为Active Slots和UnActive Slots ,处在Dequeued,queued,ACQUIRED状态的被称为Active Slots,剩下FREE状态的称为UnActive Slots,所以所有Active Slots都是正在有人使用中的slot,使用者可能是生产者也可能是消费者。而FREE状态的Slot根据是否已经为其分配内存分为两个部分,一是已经分配过内存的,在Android源码中称mFreeBuffers,没有分配过内存的称为mFreeSlots, 所以如果我们在代码中看到是从mFreeSlots里拿出一个BufferSlot那说明这个BufferSlot是还没有配置GraphicBuffer的, 这个slot可能是第一次被使用到。其分类如下图所示:
在这里插入图片描述我们来看一下,应用上帧时SurfaceFlinger是如何管理分配这些Slot的。
应用侧对图层buffer的操作接口如下文件:
应用第一次dequeueBuffer前会通过connect接口和SurfaceFlinger建立连接

int Surface::connect(int api, const sp<IProducerListener>&listener, bool reportBufferRemoval){
   
   
    ATRACE_CALL();//应用第一次上帧前可以在trace 中看到这个
    ......
    int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);//这里通过binder调用和SurfaceFlinger建立联系
    ......
}

应用第一次dequeueBuffer时会先调用requestBuffer:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
   
   
    ATRACE_CALL();//这里可以在systrace中看到
    ......
    //这里尝试去dequeueBuffer,因为这时SurfaceFlinger对应Layer的slot还没有分配buffer,这时SurfaceFlinger会回复的flag会有BUFFER_NEEDS_REALLOCATION
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, 
                                       reqFormat, reqUsage, &mBufferAge, 
                                        enableFrameTimestamps?&frameTimestamps:nullptr);
    ......
    if((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
   
   
        ......
        //这里检查到dequeueBuffer返回的结果里带有BUFFER_NEEDS_REALLOCATION标志就会发出一次requestBuffer
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
        ......
    }
    ......
}

在SurfaceFinger这端,第一次收到DequeueBuffer时发现分配出来的slot没有Graphic,这时会去申请对应的Buffer

status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
                                            uint32_t width, uint32_t height, PixelFormat format,
                                            uint64_t usage, uint64_t* outBufferAge,
                                            FrameEventHistoryDelta* outTimestamps) {
   
   
    if ((buffer == NULL) ||
        buffer->needsReallocation(width, height
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值