Android GraphicBuffer是系统什么buffer及其分配过程

本文首先研究以下GraphicBuffer到底是什么buffer,然后分析下android GraphicBuffer的分配过程。
先贴上几篇我学习的好文章

  1. Android P 图像显示系统(二)GraphicBuffer和Gralloc分析
  2. Android图形缓冲区分配过程源码分析

Android P 图像显示系统(二)GraphicBuffer和Gralloc分析主要对Android P及以后的版本的GraphicBuffer的分配进行了研究
Android图形缓冲区分配过程源码分析主要对Android P以前的版本的GraphicBuffer的分配进行了研究。

首先从宏观上了解下GraphicBuffer具体是什么buffer。
通过高通关于GPU Memory Management的文档中的示意图,如下:
在这里插入图片描述

可以清楚的看到:
Android GraphicBuffer是通过ION 在不同heap上分配的内存,其可以通过内存映射实现和GPU共享内存
文档描述如下:

在这里插入图片描述
可以比较详细的了解到:
GraphicBuffer是通过ION在不同heap上分配的内存,其需要通过
内存映射(IOCTL_KGSL_MAP_USER_MEM)映射到GPU,GPU就可以获取该buffer

另外还可以了解到,GPU的command buffer、texture、vertex buffer是通过IOCTL_KGSL_GPUMEM_ALLOC在GPU上分配的内存,只了解一下,不做详细研究了。

下边从代码上了解下GraphicBuffer的定义及具体分配过程,
GraphicBuffer其实是一个ANativeWindowBuffer型buffer,类定义如下:

//frameworks\native\libs\ui\include\ui\GraphicBuffer.h
class GraphicBuffer
    : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
      public Flattenable<GraphicBuffer>

GraphicBuffer分配发生在Surface::dequeueBuffer,在满足条件时Surface会去申请分配一份新的GraphicBuffer

//frameworks\native\libs\gui
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    
    
    ..
    status_t result = mGraphicBufferProducer->dequeueBuffer(...)
}

其中mGraphicBufferProducer是BpGraphicBufferProducer代理对象,其对应的本地对象BnGraphicBufferProducer在SurfaceFlinger服务端,实现类为BufferQueueProducer

//frameworks\native\libs\gui\BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(.....) {
    
    
....
    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
    
    
        BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                width, height, format, BQ_LAYER_COUNT, usage,
                {
    
    mConsumerName.string(), mConsumerName.size()});
....
}

在BufferQueueProducer的returnFlags为BUFFER_NEEDS_REALLOCATION会创建一个新的GraphicBuffer对象

GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
    : GraphicBuffer()
{
    
    
    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
            usage, std::move(requestorName));
}

创建新的GraphicBuffer时,通过GraphicBuffer::initWithSize中会向[email protected]服务申请GraphicBuffer申请,中间详细过程不再分析了,只列出三个主要函数
第一步,申请入口

status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
        std::string requestorName)
{
    
    
    GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    uint32_t outStride = 0;
    status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
            inUsage, &handle, &outStride, mId,
            std::move(requestorName));
    ...
}

第二步,通过mMapper创建buffer的descriptor,然后继续发起申请

//frameworks\native\libs\ui\include\ui\Gralloc2.h
    Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t count,
            uint32_t* outStride, buffer_handle_t* outBufferHandles) const
    {
    
    
        BufferDescriptor descriptor;
        Error error = mMapper.createDescriptor(descriptorInfo, &descriptor);
        error = allocate(descriptor, count, outStride, outBufferHandles);
    }

第三步,通过Allocator::allocate向[email protected]服务发起申请,然后将申请到的内存通过mMapper.importBuffer方法映射到SurfaceFlinger进程

//frameworks\native\libs\ui\Gralloc2.cpp
Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count,
        uint32_t* outStride, buffer_handle_t* outBufferHandles) const
{
    
    
...
    auto ret = mAllocator->allocate(descriptor, count,
            [&](const auto& tmpError, const auto& tmpStride,
                const auto& tmpBuffers) {
    
    
                // import buffers
                for (uint32_t i = 0; i < count; i++) {
    
    
                   ...
                   //mMapper又是一个代理对象,对应的服务启动比较贴别
                   //代码在frameworks\native\libs\ui\Gralloc2.cpp
                    error = mMapper.importBuffer(tmpBuffers[i], &outBufferHandles[i]);
                }
            });
....
}

[email protected]服务中对的的allocate方法为Gralloc1Allocator::allocate
进程入口:

//hardware\interfaces\graphics\allocator\2.0\default\Gralloc1Allocator.cpp
Return<void> Gralloc1Allocator::allocate(const BufferDescriptor& descriptor,
                                         uint32_t count, allocate_cb hidl_cb){
    
    
}

Gralloc1Allocator会通过gralloc HAL来完成GraphicBuffer的分配,gralloc HAL定义在

//hardware\qcom\display\libgralloc1\gr_device_impl.cpp
struct gralloc_module_t HAL_MODULE_INFO_SYM = {
    
    
  .common = {
    
    
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = GRALLOC_MODULE_API_VERSION_1_0,
    .hal_api_version    = HARDWARE_HAL_API_VERSION,
    .id = GRALLOC_HARDWARE_MODULE_ID,
    .name = "Graphics Memory Module",
    .author = "Code Aurora Forum",
    .methods = &gralloc_module_methods,
    .dso = 0,
    .reserved = {
    
    0},
  },
};

gralloc HAL对应Gralloc1Allocator::allocate的接口为

//hardware\qcom\display\libgralloc1\gr_device_impl.cpp
gralloc1_error_t GrallocImpl::AllocateBuffers(gralloc1_device_t *device, uint32_t num_descriptors,
                                              const gralloc1_buffer_descriptor_t *descriptors,
                                              buffer_handle_t *out_buffers) {
    
    
  ...
  gralloc1_error_t status = dev->buf_mgr_->AllocateBuffers(num_descriptors, descriptors,
                                                           out_buffers);
  return status;
}

gralloc HAL最终是使用ION分配GraphicBuffer的,代码如下

//hardware\qcom\display\libgralloc1\gr_ion_alloc.cpp
int IonAlloc::AllocBuffer(AllocData *data) {
    
    
  ATRACE_CALL();
  int err = 0;
  struct ion_handle_data handle_data;
  struct ion_fd_data fd_data;
  struct ion_allocation_data ion_alloc_data;

  ion_alloc_data.len = data->size;
  ion_alloc_data.align = data->align;
  ion_alloc_data.heap_id_mask = data->heap_id;//不同heap
  ion_alloc_data.flags = data->flags;//
  ion_alloc_data.flags |= data->uncached ? 0 : ION_FLAG_CACHED;
  std::string tag_name{
    
    };
  if (ATRACE_ENABLED()) {
    
    
    tag_name = "ION_IOC_ALLOC size: " + std::to_string(data->size);
  }

  ATRACE_BEGIN(tag_name.c_str());
  if (ioctl(ion_dev_fd_, INT(ION_IOC_ALLOC), &ion_alloc_data)) {
    
    
    err = -errno;
    ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno));
    return err;
  }
  ATRACE_END();

  fd_data.handle = ion_alloc_data.handle;
  handle_data.handle = ion_alloc_data.handle;
  ATRACE_BEGIN("ION_IOC_MAP");
  if (ioctl(ion_dev_fd_, INT(ION_IOC_MAP), &fd_data)) {
    
    
    err = -errno;
    ALOGE("%s: ION_IOC_MAP failed with error - %s", __FUNCTION__, strerror(errno));
    ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data);
    return err;
  }
  ATRACE_END();

  data->fd = fd_data.fd;
  data->ion_handle = handle_data.handle;
  ALOGD_IF(DEBUG, "ion: Allocated buffer size:%zu fd:%d handle:0x%x",
          ion_alloc_data.len, data->fd, data->ion_handle);

  return 0;
}

另外,最新发现一个完整的Graphicbuffer分配的demo,感觉比较好,记录下

//\chi-cdk\test\camx-hal3-test
int BufferManager::AllocateOneBuffer(
    uint32_t           width,
    uint32_t           height,
    uint32_t           format,
    uint64_t           producerUsageFlags,
    uint64_t           consumerUsageFlags,
    buffer_handle_t*   pAllocatedBuffer,
    uint32_t*          pStride,
    uint32_t           index)
{
    
    
    int32_t result =  0;
#ifdef USE_GRALLOC1
    result = GRALLOC1_ERROR_NONE;
    gralloc1_buffer_descriptor_t gralloc1BufferDescriptor;

    result = mGrallocInterface.CreateDescriptor(mGralloc1Device, &gralloc1BufferDescriptor);

    if (GRALLOC1_ERROR_NONE == result)
    {
    
    
        result = mGrallocInterface.SetDimensions(mGralloc1Device, gralloc1BufferDescriptor, width, height);
    }

    if (GRALLOC1_ERROR_NONE == result)
    {
    
    
        result = mGrallocInterface.SetFormat(mGralloc1Device, gralloc1BufferDescriptor, format);
    }

    if (GRALLOC1_ERROR_NONE == result)
    {
    
    
        result = mGrallocInterface.SetProducerUsage(mGralloc1Device, gralloc1BufferDescriptor, producerUsageFlags);
    }

    if (GRALLOC1_ERROR_NONE == result)
    {
    
    
        result = mGrallocInterface.SetConsumerUsage(mGralloc1Device, gralloc1BufferDescriptor, consumerUsageFlags);
    }

    if (GRALLOC1_ERROR_NONE == result)
    {
    
    
        result = mGrallocInterface.Allocate(mGralloc1Device, 1, &gralloc1BufferDescriptor, &pAllocatedBuffer[0]);
    }

    if (GRALLOC1_ERROR_NONE == result)
    {
    
    
        result = mGrallocInterface.GetStride(mGralloc1Device, *pAllocatedBuffer, pStride);
    }

    if (GRALLOC1_ERROR_NONE != result)
    {
    
    
        ALOGE("allocate buffer failed\n");
        return result;
    }

    private_handle_t *hnl = ((private_handle_t *)(*pAllocatedBuffer));
    mBufferinfo[index].vaddr= mmap(NULL, hnl->size, PROT_READ  | PROT_WRITE, MAP_SHARED, hnl->fd, 0);
    mBufferinfo[index].size = hnl->size;
    ALOGE("vaddr: %p fd: %d", mBufferinfo[index].vaddr, ((private_handle_t *)(*pAllocatedBuffer))->fd);

    mGrallocInterface.DestroyDescriptor(mGralloc1Device, gralloc1BufferDescriptor);
#else
    struct ion_allocation_data alloc;
    struct ion_fd_data ion_info_fd;
    struct ion_fd_data data2;
    native_handle_t* nh = nullptr;
    int rc;
    size_t buf_size;
    if (mIonFd <= 0) {
    
    
        mIonFd = open("/dev/ion", O_RDONLY);
    }
    if (mIonFd <= 0) {
    
    
        ALOGE("Ion dev open failed %s\n", strerror(errno));
        return NULL;
    }
    memset(&alloc, 0, sizeof(alloc));
    if (height == 1) {
    
    
        // Blob
        buf_size = (size_t)width;
    } else {
    
    
        buf_size = (size_t)(width * height * 2);
    }

    alloc.len = (size_t)(buf_size);
    alloc.len = (alloc.len + 4095U) & (~4095U);
    alloc.align = 4096;
    alloc.flags = ION_FLAG_CACHED;
    alloc.heap_id_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
    rc = ioctl(mIonFd, ION_IOC_ALLOC, &alloc);
    if (rc < 0) {
    
    
        ALOGE("ION allocation failed %s with rc = %d fd:%d\n", strerror(errno), rc, mIonFd);
        return NULL;
    }
    memset(&ion_info_fd, 0, sizeof(ion_info_fd));
    ion_info_fd.handle = alloc.handle;
    rc = ioctl(mIonFd, ION_IOC_SHARE, &ion_info_fd);
    if (rc < 0) {
    
    
        ALOGE("ION map failed %s\n", strerror(errno));
        return NULL;
    }
    ALOGD("%s ION FD %d len %d\n", __func__, ion_info_fd.fd, alloc.len);
    if (!mIsMetaBuf) {
    
    
        *pAllocatedBuffer = native_handle_create(2, 4);
        nh = (native_handle_t*)(*pAllocatedBuffer);
        (nh)->data[0] = ion_info_fd.fd;
        (nh)->data[1] = 0;
        (nh)->data[2] = 0;
        (nh)->data[3] = 0;
        (nh)->data[4] = alloc.len;
        (nh)->data[5] = 0;
    } else {
    
    
        /*alloc private handle_t */

        /*(buffer_handler_t **)*/
        if (!mIsUBWC) {
    
    
            *pAllocatedBuffer = native_handle_create(1, 2);
            nh = (native_handle_t*)(*pAllocatedBuffer);
            (nh)->data[0] = ion_info_fd.fd;
            (nh)->data[1] = 0;
            (nh)->data[2] = alloc.len;
        } else {
    
    
            /*UBWC Mode*/
            #if 0
            private_handle_t *pnh = new private_handle_t(ion_info_fd.fd,
                alloc.len,
                0,
                0,
                0,
                width,
                height);
            *pAllocatedBuffer = (native_handle_t *)pnh;
            pnh->flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
            pnh->width = width;
            pnh->height = height;
            pnh->size = alloc.len;
            pnh->unaligned_width = width;
            pnh->unaligned_height = height;
            pnh->fd = ion_info_fd.fd;
            pnh->format = format;
            #endif
        }
    }

    data2.handle = ion_info_fd.handle;
    rc = ioctl(mIonFd, ION_IOC_MAP, &data2);
    if (rc) {
    
    
        ALOGE("ION MAP failed %s\n", strerror(errno));
        return NULL;
    }
    mBufferinfo[index].vaddr = mmap(NULL, alloc.len, PROT_READ  | PROT_WRITE, MAP_SHARED, data2.fd, 0);
    ALOGI("Alloc buffer fd:%d len:%d vaddr:%p\n",data2.fd,alloc.len,mBufferinfo[index].vaddr);
    mBufferinfo[index].size = alloc.len;
    mBufferinfo[index].allocData = alloc;
    mBufferinfo[index].fd = ion_info_fd.fd;
#endif
    return result;
}

/************************************************************************
* name : FreeAllBuffers
* function: free buffers
************************************************************************/
void BufferManager::FreeAllBuffers()
{
    
    
    for (uint32_t i = 0; i < mNumBuffers; i++)
    {
    
    
        if (NULL != mBuffers[i])
        {
    
    
            munmap(mBufferinfo[i].vaddr, mBufferinfo[i].size);
#ifdef USE_GRALLOC1
            mGrallocInterface.Release(mGralloc1Device, mBuffers[i]);
#else
            ioctl(mIonFd, ION_IOC_FREE,mBufferinfo[i].allocData.handle);
            close(mBufferinfo[i].fd);
            native_handle_close((native_handle_t *)mBuffers[i]);
            native_handle_delete((native_handle_t *)mBuffers[i]);
#endif
            mBuffers[i] = NULL;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/u010116586/article/details/101532079