欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Android14 DMA-BUF heap

Android14 DMA-BUF heap

2025/2/21 3:35:13 来源:https://blog.csdn.net/hongyeying/article/details/143886167  浏览:    关键词:Android14 DMA-BUF heap

背景介绍:

Android Camera系统经常需要一块空间来存放图像数据。从连续性来说内存有连续和非连续之分,从内存的来源来说内存可以从系统分配也可以从设备分配,从V4L2框架向用户空间暴露内存的类型来说有MMAP、USERPTR、DMABUF三种。

Android12之前Camera HAL用来存放图像的buffer通常是通过ION分配的,Android12 GKI 2.0将ION分配器替换为DMA-BUF heap。

接下来,主要介绍如何使用DMA-BUF heap模块的接口分配buffer,用于Camera HAL图像处理。

内容介绍:

DMA-BUF heap内存分配/释放接口

DMA-BUF heap内存分配器的实现

DMA-BUF heap使用的例子


  • DMA-BUF heap内存分配/释放接口
  • DMA-BUF heap内存分配器的实现
  • DMA-BUF heap使用的例子

DMA-BUF heap内存分配/释放接口

Android14 BufferAllocator是对DMA-BUF heap分配器的抽象, 通过BufferAllocator类可以从系统dma heap分配一块buffer,buffer可以是连续的也可以是不连续的。通过heap名子区分这块buffer是连续的还是不连续的,是不连续的buffer是带cache还是不带cache。/dev/dma_heap路径下的节点名即heap名:

  • linux,cma  连续内存
  • system 非连续内存
  • system-uncached 非连续不带cache

BufferAllocator提供的接口可以分为三个部分:

  • 分配器相关的接口
//获取系统提供的DMA-BUF heap列表。即/dev/dma_heap路径下的节点
static std::unordered_set<std::string> GetDmabufHeapList()
//给dmabuf_fd对应的buffer设置一个名字
static int DmabufSetName(unsigned int dmabuf_fd, const std::string& name)//创建一个BufferAllocator对象,后续buffer通过这个分配器分配。BufferAllocator对象不支持copy和move操作。
BufferAllocator()
  • Buffer分配相关的接口
//从指定名字的heap分配,返回dmabuf_fd. heap_name对应/dev/dma_heap路径下的文件名
int Alloc(const std::string& heap_name, size_t len, unsigned int heap_flags = 0,size_t legacy_align = 0)
//从system heap (cached/uncached)分配,并返回dmabuf fd
int AllocSystem(bool cpu_access, size_t len, unsigned int heap_flags = 0,size_t legacy_align = 0);
  • cache一致性相关接口
//CPU访问分配的这块内存前必需调用CpuSyncStart,
int CpuSyncStart(unsigned int dmabuf_fd, SyncType sync_type = kSyncRead,const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync = nullptr,void *legacy_ion_custom_data = nullptr)
//一旦CPU完成对这块内存的访问,必需调用CpuSyncEnd
int CpuSyncEnd(unsigned int dmabuf_fd, SyncType sync_type = kSyncRead,const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync = nullptr,void* legacy_ion_custom_data = nullptr);

DMA-BUF heap内存分配器的实现

DMA-BUF heap内存分配器实现是直接操作节点。系统将一块空间通过设备节点的方式暴露给用户空间,BufferAllocator中通过这些暴露的设备节点完成buffer的分配释放,以及一致性操作。

BufferAllocator实现有一个重要的对象属性dmabuf_heap_fds_用于记录打开的dmabuf_heap的句柄, 定义:

std::unordered_map<std::string, android::bases::unique_fd> dmabuf_heap_fds_

当调用Alloc()从DMA-BUF heap分配一块空间时,BufferAllocator首先会从dmabuf_heap_fds_表查找这个heap节点是不是已经打开。第一次从这个heap分配空间时会先打开这个heap节点,即/dev/dmabuf_heap/路径下的设备节点,得到文件句柄,并记录到dmabuf_heap_fds, 后续再从这个heap分配的时候就可以直接调用系统ioctl()从核态分配一块buffer。

BufferAllocator的结构比较简单:

DMA-BUF heap使用的例子

以下代码实现一个内存分配器,分配一块空间送驱动获取图像。

#define IMAGE_MAX_PLANES 2struct ImagePlane
{unsigned int bytesused;unsigned int length;unsigned int mem_offset;void* userptr;unsigned int dma_fd;unsigned int data_offset;
};struct ImageBuffer
{unsigned int fourcc;  //image fourcc, eg: V4L2_PIX_FMT_NV12unsigned int width;   //image widthunsigned int height;  //image heightunsigned int np;      //number of planesunsigned int state;   //revert for import bufferstruct ImagePlane planes[IMAGE_MAX_PLANES];
};class Allocator
{
private:static Allocator instance;std::shared_ptr<BufferAllocator> alloc;Allocator() { alloc = std::make_shared<BufferAllocator>(); }public:Allocator(const Allocator&) = delete;Allocator& operator=(const Allocator&) = delete;static Allocator& getInstance() { return instance; }BufferAllocator* GetAllocator() { return alloc.get(); }int AllocateBuffer(struct ImageBuffer* frame);int ReleaseBuffer(struct ImageBuffer* frame);
};
int Allocator::AllocateBuffer(struct ImageBuffer* frame)
{int i = 0;if (frame == NULL)return -1;for (i = 0; i < static_cast<int>(frame->np); i++) {frame->planes[i].dma_fd = alloc->Alloc("system", frame->planes[i].bytesused);if (frame->planes[i].dma_fd < 0) {ALOGE("Allocate buffer failed.");goto alloc_fail;}frame->planes[i].userptr = (unsigned char*)mmap(NULL, frame->planes[i].bytesused,PROT_READ|PROT_WRITE, MAP_SHARED,frame->planes[i].dma_fd, 0);if (frame->planes[i].userptr == MAP_FAILED) {ALOGE("Map buffer failed.");goto map_fail;}ALOGD("frame planes[%d] dma_fd %d userptr %p", i, frame->planes[i].dam_fd,frame->planes[i].userptr);}return 0;map_fail:close(frame->planes[i].dma_fd);
alloc_fail:for (int k = 0; k < i; k++) {munmap(frame->planes[k].userptr, frame->planes[k].bytesused);close(frame->planes[i].dma_fd);}return -1;
}int Allocator::ReleasesBuffer(struct ImageBuffer* frame)
{int i = 0;if (frame == NULL)return -1;for (i = 0; i < static_cast<int>(frame->np); i++) {munmap(frame->planes[i].userptr, frame->planes[i].bytesused);close(frame->planes[i].dma_fd);}return 0;
}
Allocator Allocator::instance;

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词