Android显示系统 SurfaceFlinger内部机制 4 AP申请buffer的过程,lock

韦东山 笔记

 

04, AP申请buffer的过程,lock

AP显示界面需要用到SF的服务,

1,SF端用client表示要使用界面的APP,

2,AP端创建Surface,SF端对应Layer,Layer有生产者和消费者,

Surface里有mGraphicBufferProducer,它是一个代理类,指向SF端的Layer的生产者,所以AP端可以使用生产者的所有函数

Surface里还有mSlots,Layer的生产者也有个mCore和mSlots[64],它是BufferSlot类型

3,要获得Surface中的Buffer,才可以填数据,

 

猜想,AP如何获得Surface中的buffer?

1,AP端查看mSlots是否有空余项目,(其实并没做这个步骤)

2,没有的话,向SF端生产者申请,在SF端:

生产者也要查看自己的mSlots中有无空余项,

若没有就向Gralloc HAL申请,就是向Ashmem申请得到一个fd,返回给AP,

3,通过binder,AP端获得fd',mmap获得地址(通过Gralloc HAL来mmap)

 

做了图,在create_client的A4步骤

这节分析surface->lock();

 

关键点:

1,SF端分配buffer,

2,SF端返回fd

3,AP端mmap

 

看代码,慕课网讲过这里

Surface->lock(&outBuffer, NULL);

//framewok/native/libs/gui/Surface.cpp
status_t Surface::lock(
    ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
    ANativeWindowBuffer* out;
    int fenceFd = -1;
    //取出的buffer放在out里面
    status_t err = dequeueBuffer(&out, &fenceFd);
    //记得慕课网讲过,GraphicBuffer继承自ANativeWindowBuffer所以可以这么用
    //backBuffer是绘制的那个buffer,准备好后提交,它就变为frontBuffer了
    sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
    
    status res = backBuffer->lockAsync(GRALLOC_YSAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, ..,&vaddr, fenceFd);
    
    mLockedBuffer = backBuffer;
    outBuffer->format = backBuffer->format;
    //Surface_test就是往这里面写
    outBuffer->bits = vaddr;
}

看看DequeueBuffer的实现
//framewok/native/libs/gui/Surface.cpp
int Surface::dequeueBuffer(android_natgive_buffer_t** buffer, int* fenceFd) {
    int buf = -1;
    //buf是int型,这里dequeue返回的是数组的下标:mSlots[],表明这个数组项对应的GraphicBuffer已经被分配,
    
    //使用mGraphicBufferProducer代理类发起跨进程binder远程调用,
    //1,向SF发出buffer申请,导致对方allocate buffer=
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth,...,reqFormat, reqUsage);
    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
    
    if((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
        //,2,向SF请求返回fd,然后在AP端mmap
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
    }
    *buffer = gbuf.get();
}

 

下节分析SurfaceFlinger端,native服务端的代码

 

==============================

05,surface->lock过程,分配buffer

AP调用lock,发起mGraphicBufferProducer->dequeueBuffer,然后发起binder远程调用,所以它并没有查看自己的mSlots有无空余项,

 

反查IGraphicBufferProducer,

好像接口写在AP端,和代理类在一起?看到BnGraphicBuuferProducer也在这里,

//framework/natvei/libs/gui/IGraphicBufferProducer.cpp
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t with, PixelFormat format, uint32_t usage) {
        Parcel data, reply;
        data.writeInterfaceToken();
        data.writeUint32(width);
        ....
        data.writeUint32(usage);
        //填好Parcel的data,发起binder远程调用,
        status_t result = remote()->trasact(DEQUEUE_BUFFER, data, &reply);
        *buf = reply.readInt32();
        *fence = new Fence();
        reply.read(**fence);
        result = reply.readInt32();
    }
}

//framework/natvei/libs/gui/IGraphicBufferProducer.cpp
status_t BnGraphicBufferProducer::onTransact(uint32_t code, const Parcel& data, ....)
{
    switch(code) {
        uint32_t width = data.readUint32();
        ....
        int buf = 0;
        sp<Fence> fence;
        //是派生类BufferQueueProducer的函数
        int result = dequeueBuffer(&buf, &fence, width, ...);
        reply->writeInt32(bif);
        reply->write(*fence);
        reply->writeInt32(result);
    }
}

为什么派生类是BufferQueueProducer?
//naitve/include/gui/BufferQueueProducer.h
class BufferQueueProducer : public BnGraphicBufferProducer,...

//native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp<Android::Fence> *outFence, ...) {
    while(found == BufferItem::INVALID_BUFFER_SLOT) {
        //1,等待空闲slot,然后relock,也就是看看有没有空闲的slot,
        status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, &found);
    }
    const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
    
    //,2,检查是否需要重新alloc,比如第一次申请buffer时slots的第0项一定是空闲的,而且没有被分配buffer,
    if( (buffer == NULL) || buffer->needsReallocation(width, heifth, foramt, usage))
    {
        mCore->mBufferAge = 0;
        returnFlags |= BUFFER_NEEDS_REALLCATION;
    } else {
        //we add 1 because that will be the frame number when this buffer is queued
        mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
    }
    
    BQ_LOGV("dequeueBuffer: setting buffer age to %"PRIu64, mCore->mBufferAge);
    
    if(returnFlags & BUFFER_NEEDS_REALLOCATION) {
        BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
        //,3,分配buffer,mCore是BufferQueueCore,生产者和消费者都会指向同一个mCore,
        //mAllocator是谁?
        sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
            width, height, foramt, suage,
            {mConsumerName.string(), mConsumerName.size()}, &error));
        {
            
        }    
    }
}

mAllocator是谁?在前面看BufferQueueCore的时候看过:
1,看看BufferQueueCore
//framework/native/libs/gui/BufferQueueCore.cpp
BufferQueueCore::BufferQueueCore(const sp<IGraphicBuferAlloc>& allocator) :
    mAllocator(allocator),
     mBufferAge(0),
     ....
{
    if(allocator == NULL) {
        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
        //后面分析buffer的分配的时候再看它
        //sp<IGraphicBufferAlloc> mAllocator
        mAllocator = composer->createGraphicBufferAlloc();
    }
}        

看看mCore->mAllocator->createGraphicBuffer(),
IGraphicBufferAlloc.cpp的BpGraphicBufferAlloc的createGraphicBuffer填parcel,
然后remote->onTransact发起binder调用,
BnGraphicBufferAlloc的onTransact接收到,通过code调用派生类的createGraphicBuffer,


//native/include/gui/GraphicBufferAlloc.h
class GraphicBufferAlloc : public BnGraphicBufferAlloc {
    
}

//native/libs/gui/GraphicBufferAlloc.cpp
sp<GraphicBuffer> GraphicBufferAlooc::createGraphicBuffer(uint32_t w,...usage, *error) {
    sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h ,foramt, usage));
}

看看new GraphicBuffer做了什么
//framework/native/libs/ui/GraphicBuffer.cpp
GraphicBufer::GraphicBuffer(uint inWidth,....,inUsage, std::string requestorName)
{
    mInitCheck = initSize(inWidth, inHeigth, inFormat, inUsage, std::move(requestorName));
}

//framework/native/libs/ui/GraphicBuffer.cpp
status_t GraphicBuffer::initSize(uint32_t inWidth,...)
{
    //这里是GraphicBufferAllocator,前面是GraphicBufferAlloc
    //这个构造函数打开gralloc
    GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    //这里就是通过gralloc分配内存的地方
    status_t err = allocator.allocate(inWidth, inHeight,...., &handle, &outStride, ...);
}

 

看看哪里用了hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);

cnw_init in cnativewindow.c (E:\p4vcode\sw\s3gdrv\code\s3driverSDK\libhardware\tests\hwc) : 	if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
cnw_init in cnativewindow.c (libhardware\tests\hwc) : 	if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
arc::GrallocFrameBuffer::GrallocFrameBuffer in frame_buffer.cpp (libhardware\modules\camera\3_4\arc) :   int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);

android::Gralloc1::Loader::Loader in Gralloc1.cpp (E:\p4vcode\sw\s3gdrv\code\s3driverSDK\native\libs\ui) :     int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);

hwc_s3g_init in hwc_s3g.c (E:\p4vcode\sw\s3gdrv\code\s3driverSDK\hwcomposer) :     if(hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &gralloc) == 0)
hwc_s3g_init in hwc_s3g.c (hwcomposer) :     if(hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &gralloc) == 0)

 

视频里面说是GraphicBufferAllocator的构造函数做的,这里没做,可能是ZX改的?还是Android版本问题?

接着看看GraphicBufferAllocator::allocate

//native/libs/ui/GraphicBufferAllocator.cpp
status_t GraphicBufferAllocator::allocate(uint32_t width...., buffer_handle_t *handle, ...., uint64_t graphicBufferid,..)
{
    auto descriptor = mDevice->createDescriptor();
    error = mDevice->allocate(descriptor, graphicBufferId, handle);
}

然后会进入Gralloc.cpp,我们是gralloc_s3g.c
//gralloc/gralloc_s3g.c
static struct hw_module_methods_t gralloc_module_methods = {
      .open = grallc_device_open  
};

static int gralloc_device_open(const hw_module_t* module, const char* name, hw_devic_t** device)
{
    gralloc_s3g_t *s3g = (gralloc_s3g_t *)module;
    
    gralloc_info("Load Module gralloc: %02d.%02d.%02d%s\n",DRIVER_MAJOR, DRIVER_MINOR, DRIVER_PATCHLEVEL, DRIVER_BRANCH);
    
    if(!strcmp(name, GRALLOC_HARDWARE_GPU0))
    {
        alloc_dev_s3g_t *s3g_dev = calloc(1, sizeof(*s3g_dev));
        
        s3g_dev->base.alloc = gralloc_alloc;
        //这里拿了s3g,它是在gralloc_s3g_init()填的,
        //里面填了s3g->base.common,还有s3g->base.registerBuffer\lock等
        s3g_dev->s3g = s3g;
        *device = &s3g_dev->base.common;
    }
}

//看看gralloc_alloc
static int gralloc_alloc(alloc_device_t* dev, int w, h,format,usage, buffer_handle_t* pHandle, int* pStride)
{
    alloc_dev_s3g_t *s3g_dev = (alloc_dev_s3g_t *)dev;
    gralloc_s3g_t *s3g = s3g_dev->s3g;
    native_buffer_s3g_t *buf = NULL;
    
    {
        s3g_create_allocation_t create;
        memset(&create, 0, sizeof(create));
        format = SelectHALFormat(format, usage);
        create.device = s3g->device;
        create.format = HALFormat2S3GFormat(format);
        create.usage_mask = Usage2S3GUsage(usage, create.format);
        create.tiled = 1; //default try to enable tile, krnl will enable/disable tile accord HW&usage&access_hint;
        create.secured = NeedSecured(s3g, usage);
        create.scramble = NeedScramble(s3g, usage);
        create.fence_sync = NeedFenceSync(s3g. usage);
        create.need_hdr = NeedHDR(s3g, usage);
        create.lossy_compress = NeedLossyCompress(s3g, usage, w, h, create.format);
        create.need_fd = 1;
        
        status = s3gCreateAllocation(s3g->fd, &create);
        
        buf = calloc(1, sizeof(*buf));
        buf->fd = create.buffer_fd;
        buf->device = create.device;
        buf->allocation = crerate.allocation;
        buf->format = create.format;
        buf->hw_foramt = create_foramt;
        buf->gbd = create.gdb;
        buf->gvirt_addr = create.gpu_virt_addr;
        buf->unpageble = create.unpagable;
        buf->fence_addr = create.fence_addr;
        buf->sync_obj = create.sync_obj;
        .....
        
    }
    
    //buf转换成pHandle返回了出去
    *pHandle = (buffer_handle_t)buf;
}

 

另外看到了gralloc_register_buffer,它是一次s3gOpenAllocation(s3g->fd, &open);

gralloc_lock则对应s3gLockAllocation(s3g->fd, &lock);

 

回头看android framework,

//native/libs/ui/GraphicBufferAllocator.cpp
GraphicBufferAllocator::GraphicBufferAllocator()
    : mLoader(std::make_unique<Gralloc1::Loader>()),
    mDevice(mLoader->getDevice()){}
    
//native/include/ui/GraphicBuferAllocator.h
class GraphicBufferAllocator : public Singleton<GrahpicBufferAllocator>
{
private:
    std::unique_ptr<Gralloc1::loader> mloader;
    std::unique_ptr<Gralloc1::Device> mDevice;    
}    

看看Loader的构造函数
//native/libs/ui/Gralloc1.cpp
Loader::Loader()
    : mDevice(nullptr)
{
    hw_module_t const* module;
    //得到module
    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    gralloc1_device_t* device = nullptr;
    mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
    device = mAdapter->getDevice();
    mDevice = std::make_unique<Gralloc1::Device>(device);
} 

 

这里GraphicBufferAllocator在构造函数确实拿到了Hwc,叫做mDevice,但是是怎么拿到的?

另外GraphicBufferAllocator::allocate在调用mDevice->allocate(),与graloc_s3g里面的alloc的函数名和参数个数都对不上,这是同一个函数吗?怎么调过去的?

 

继续看韦东山的视频,它看的是/libhardware/modules/gralloc/Gralloc.cpp
gralloc_alloc里面会根据 usage&GRALLOC_USAGE_HW_FB选择走
gralloc_alloc_framrbuffer()还是
gralloc_alloc_buffer(),与深入理解Android内核思想里面写的一样。
而gralloc_alloc_buffer中:
{
    fd = ashmem_create_region(size) //分配size大小的内存,得到文件句柄
    private_handle_t* hnd = new private_handle_t(fd, size, 0); //使用文件句柄fd构造handle,
    gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(dev->common.module);
    mapBuffer(module, hnd);
    *pHandle = hnd;
}

mapBuffer() => gralloc_map(module, hnd, &vaddr)  => 
void* mappedAddress = mmap(); *vaddr = (void*)hnd->base; //hnd->base就是用mappedAddress算出来的,

所以通过mmap,就得到了应用空间里,可以供CPU使用的virtual addr,

 

如果通过硬件加速,应该不需要拿到virtual addr?只需要handle就行了?

另外hwui是什么?

https://www.jianshu.com/p/824a9ddf68b9

这个讲了android p的知识,里面有hwc和hwui,优先看

 

https://blog.csdn.net/lewif/article/details/50526494

这个是旧一些的android现实系统,次之,

 

重新看韦东山,

总结:

SurfaceTest,调用surface->lock(&outBuffer)获得buffer,outBuffer是ANativeWIndow_Buffer类型,

lock调用Surface.cpp的mGraphicBufferProducer->dequeueBuffer(&buf, w, h, format, usage,);,这是生产者的代理类,会发起binder远程调用,

SF端的dequeueBuffer被调用:BufferQueueProducer::dequeueBuffer

当有NEED_REALLOCATION时,它通过mCore->mAllocator->createGraphicBuffer()分配内存,

里面allocator.alloc(w,h,foramt,usage,&handle,..)通过gralloc做事情:

通过Ashmem分配buffer,得到fd,

使用fd构造handle,

mmap得到vaddr供SurfaceFlinger自己使用。

 

看看申请内存后,数据结构的变化

在mGraphicBufferProducer,

生产者有mCore和mSlots[],分配内存就是选择某个空余的slots,然后构造它。

 

看看mSlots是什么,在BufferQueueProducer.h

//native/include/gui/BufferQueueProducer.h
class BufferQueueProducer : public BnGraphicBuferProducer {
    sp<BufferQueueCore> mCore;
    //typedef BufferSlots SlotsType[NUM_BUFFER_SLOTS];
    BufferQueueDefs::SlotsType& mSlots;  //是一个数组的引用
}

看看每项BufferSlots里面有什么东西
他是一个结构体,含有sp<GraphicBuffer> mGraphicBuffer

那么mGraphicBuffer有什么?
它继承自Flattenable
//native/include/ui/GraphicBuffer.h
class GraphicBuffer
    : public ANativeObjectBase< ANativeWidnowBuffer, GraphicBuffer, RefBase >,
    public Flattenable<GgrahpicBuffer>
{
    friend class Flattenable<GraphicBuffer>;
}    

GraphicBuffer里面有handle,handle里面有fd,gralloc进行mmap后把地址放到了handle->base里面

所以handle有fd,有base,

 

而以上都是在SF端,AP不能使用,需要传回去,

AP端的Surface同样有一个mSlots[],也是一个BufferSlot,里面也有GraphicBuffer,GraphicBuffer里也有handle,handle里有fd和base,

 

现在要构造AP端的某个mSlots,使用result = mGraphicBufferProducer->dequeueBuffer(&buf)这个buf,它是一个下标

这个result等于SF端的BufferQueueProducer的returnFlags,

AP端判断这个result是否有BUFFER_NEEDS_REALLOCATION,

如果有,则使用mGraphicBuferProducer->requestBuffer(buf, &gbuf)远程调用,来获得SF端的slot信息,然后构造自的slot

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值