高通Camx-内存池架构/ImageBuffer

高通Camx-内存池架构/ImageBuffer首先 在项目中如果频繁的使用 malloc 申请内存空间 堆上分配和释放内存 会导致性能的损失

大家好,欢迎来到IT知识分享网。

一、Camx内存池架构简介

1.1内存池使用的好处

        首先,在项目中如果频繁的使用malloc申请内存空间,堆上分配和释放内存,会导致性能的损失。由于堆空间申请的存储地址是不连续的,也会使系统中出现的大量的内存碎片,降低内存的利用率,而内存池的使用就很好的解决了这些性能和内存上的问题。

        其次,内存池使用映射到连续物理地址的Ion Buffer(本质是linux的file文件),通过文件描述符可以实现各个进程间数据的共享,比堆空间的使用范围大多了,能更好的link上下路各个模块间的链路。

高通Camx-内存池架构/ImageBuffer

1.2Camx内存池架构总览

        高通Camx架构中的imageBuffer在pipeline的流转中扮演着重要的作用,而管理imagerBuffer的ImageBufferManager与MemPool Manager共同承担起高通Camx架构中的内存池的调度角色,下图简单绘制了一下相互的调用关系。

高通Camx-内存池架构/ImageBuffer

二、Camx ImageBufferManager

代码路径:vendor\qcom\proprietary\camx\src\core\camximagebuffermanager.cpp

                  vendor\qcom\proprietary\camx\src\core\camximagebuffer.cpp

2.1 ImageBufferManager相关函数解析

2.1.1 ImageBufferManager::Create函数实现如下

CamxResult ImageBufferManager::Create( const CHAR* pBufferManagerName, BufferManagerCreateData* pCreateData, ImageBufferManager ppImageBufferManager) { CamxResult result = CamxResultSuccess; ImageBufferManager* pImageBufferManager = NULL; if (CamxResultSuccess == result) { *ppImageBufferManager = NULL; pImageBufferManager = CAMX_NEW ImageBufferManager(); } if (CamxResultSuccess == result) { // 从内存池中为ImageBufferManager分配内存 result = pImageBufferManager->Initialize(pBufferManagerName, pCreateData); if (CamxResultSuccess == result) { CAMX_LOG_INFO(CamxLogGroupMemMgr, "[%s] : allocRequired=%d, immediateAllocBufferCount=%d, maxBufferCount=%d", pBufferManagerName, pCreateData->allocateBufferMemory, pCreateData->immediateAllocBufferCount, pCreateData->maxBufferCount); // 初始化ImageBufferManager中的buffers,这里是重点 result = pImageBufferManager->InitializeBuffers(pCreateData); } } if (CamxResultSuccess == result) { *ppImageBufferManager = pImageBufferManager; } return result;

2.1.2 ImageBufferManager::InitializeBuffer实现如下

CamxResult ImageBufferManager::InitializeBuffers( BufferManagerCreateData* pCreateData) { m_createData = *pCreateData; m_currentFormat = pCreateData->bufferProperties.imageFormat; m_maxBufferCount = pCreateData->maxBufferCount; m_immediateAllocBufferCount = pCreateData->immediateAllocBufferCount; // Allocate the minimum number of buffers needed immediately serially for (UINT i = 0; i < m_immediateAllocBufferCount; i++) { // ①new buffer ImageBuffer* pBuffer = CAMX_NEW ImageBuffer(); if (NULL != pBuffer) { // ②buffer初始化,buffer相关信息放在全局变量m_createData中 result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this,m_hMemPoolBufMgrHandle); // ③Allocate the buffer result = pBuffer->Allocate(); LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode))); if (NULL != pNode) { pNode->pData = pBuffer; // ④Add the buffer to the free buffer list m_freeBufferList.InsertToTail(pNode); } }

2.1.3 ImageBufferManager::GetImageBuffer函数实现如下

①从free-list中找buffer;如果没有
②再去busy-list中找引用计数为0的buffer;还是没有
③看看能不能自己创建buffer;如果不能创建
④超时等待n次去获取busy-list中引用计数为0的buffer
经过上述操作,如果能获取到buffer,先添加buffer的引用计数,然后封装成node,放到busy-list链表尾



 ImageBuffer* ImageBufferManager::GetImageBuffer() { // first:先从free_list的头部取出buffer节点 LDLLNode* pNode = m_freeBufferList.RemoveFromHead(); ImageBuffer* pBuffer = NULL; // Check the free List for an available buffer if (NULL != pNode) { // 取出buffer节点中的buffer pBuffer = static_cast<ImageBuffer*>(pNode->pData); CAMX_FREE(pNode); // 释放该节点所占用的内存 pNode = NULL; } // second:如果free_list中没有可用buffer,就去busy_list中去取 if (NULL == pBuffer) { // 从头遍历busy_list中的节点 pNode = m_busyBufferList.Head(); while (NULL != pNode) { ImageBuffer* pBusyBuffer = static_cast<ImageBuffer*>(pNode->pData); LDLLNode* pNext = LightweightDoublyLinkedList::NextNode(pNode); if (0 == pBusyBuffer->GetReferenceCount()) { // 如果该busy-buffer的引用计数为0,说明该buffer可以被使用 m_busyBufferList.RemoveNode(pNode); // 就从busy_list中取出node,这里会先移出,然后后面会再次添加到busy-list的尾部 if (NULL == pBuffer) { // We will keep this buffer pBuffer = pBusyBuffer; // 将上述busy-buffer赋值给pBuffer CAMX_FREE(pNode); // 释放该节点所占用的内存 pNode = NULL; } else { // 如果从busy-list取节点时刚好发现pBuffer不为空了,而pNode都从busy-list中取出来了,这次不用就下次再用吧,将其放到free-list中 m_freeBufferList.InsertToTail(pNode); } } pNode = pNext; } } // third:如果free-list和busy-list中没有找到引用计数为0的buffer,看看能不能创建buffer if (NULL == pBuffer) { UINT numOfFreeBuffers = m_freeBufferList.NumNodes(); UINT numOfBusyBuffers = m_busyBufferList.NumNodes(); // If no free buffers were found either in the free list or the busy list, we check to see if an additional buffer // can be allocated immediately if ((numOfFreeBuffers + numOfBusyBuffers) < m_maxBufferCount) { // 只要没有达到创建buffer的max值,就能额外创建buffer CamxResult result = CamxResultSuccess; // 下面就是buffer创建三部曲 pBuffer = CAMX_NEW ImageBuffer(); if (NULL != pBuffer) { result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this, m_hMemPoolBufMgrHandle); } else { CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Ran out of memory to allocate", GetBufferManagerName()); result = CamxResultENoMemory; } if (CamxResultSuccess == result) { if ((TRUE == m_createData.allocateBufferMemory) && (FALSE == m_createData.bEnableLateBinding)) { // Allocate the buffer result = pBuffer->Allocate(); } } } } // four:如果上面三种情况都不满足,那么就只能等待busy-list中的buffer释放了 if (NULL == pBuffer) { pNode = NULL; while (NULL == pNode) { // 设置超时等待,接收busy-list中的buffer释放信号 result = m_pWaitFreeBuffer->TimedWait(m_pLock->GetNativeHandle(), BufferTimeoutMilliseconds); pNode = m_freeBufferList.RemoveFromHead(); if (timeoutCount >= MaxTimeoutCount) { // 这里会进行几次超时等待,如果超过最大等待次数就退出循环,等不下去了,累了!! CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Waited %ux%u times and failed to get buffer, returning a null buffer", GetBufferManagerName(), timeoutCount, BufferTimeoutMilliseconds); break; } else if (CamxResultETimeout == result) { // 继续超时等待,死等,还挺执着!! // timeout happened, print an error log and continue waiting timeoutCount++; CAMX_LOG_WARN(CamxLogGroupMemMgr, "[%s] Waiting %ux%d ms timedout, there might be a leak or performance issue", GetBufferManagerName(), timeoutCount, BufferTimeoutMilliseconds); } else if (CamxResultSuccess != result) { // 函数执行期间遇到错误,退出循环 timeoutCount++; CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Waiting %dx%d ms failed for unknown reason, result=%s",GetBufferManagerName(), timeoutCount,BufferTimeoutMilliseconds,Utils::CamxResultToString(result)); break; } } // 如果free-list中取到节点了,万事大吉,取其buffer。念念不忘,必有回响! if (NULL != pNode) { pBuffer = static_cast<ImageBuffer*>(pNode->pData); CAMX_FREE(pNode); pNode = NULL; CAMX_LOG_INFO(CamxLogGroupMemMgr, "[%s] Returning a buffer [%p] from the free list after wait ended",GetBufferManagerName(), pBuffer); } } // 几经波折,如果能取到buffer,会进一步处理 if (NULL != pBuffer) { m_pLock->Unlock(); pBuffer->AddImageReference(); // 添加buffer的引用计数 m_pLock->Lock(); pBuffer->SetBusyState(TRUE); // 我很忙 pBuffer->ClearReferenceHolderData(); pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode))); if (NULL != pNode) { pNode->pData = pBuffer; m_busyBufferList.InsertToTail(pNode); // 将节点插入到busy-list的尾部 m_peakBufferHolders = Utils::MaxUINT(m_peakBufferHolders, m_busyBufferList.NumNodes()); } } return pBuffer; }

2.1.4 ImageBufferManager::AddReference函数实现如下

①查看该buffer是否在free-list中,如果在则将其从free-list中移到busy-list中,并添加该buffer的引用计数;如果不在
②查看该buffer是否在busy-list中,如果在则增加该buffer的引用计数。

UINT ImageBufferManager::AddReference( ImageBuffer* pImageBuffer) { BOOL doneFlag = FALSE; UINT count = 0; LDLLNode* pNode; // 看看该buffer是不是在free-list中,如果是,则将其从中移除并添加到busy-list中 pNode = m_freeBufferList.Head(); while (NULL != pNode) { if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData)) { // Add reference to the image buffer count = pImageBuffer->AddImageReference(); // Move if from free list to busy list m_freeBufferList.RemoveNode(pNode); pImageBuffer->SetBusyState(TRUE); m_busyBufferList.InsertToTail(pNode); CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] Image buffer %p in free list, reference count after adding = %d",GetBufferManagerName(), pImageBuffer, pImageBuffer->GetReferenceCount()); doneFlag = TRUE; break; } pNode = LightweightDoublyLinkedList::NextNode(pNode); } // 添加引用的buffer不在freelist中 if (FALSE == doneFlag) { pNode = m_busyBufferList.Head(); // Didn't find the image buffer in free list, then search busy list while (NULL != pNode) { // Found the image buffer in busy list if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData)) { // Add reference to the image buffer count = pImageBuffer->AddImageReference(); CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] Image buffer %p in busy list, reference count after adding = %d",GetBufferManagerName(), pImageBuffer, pImageBuffer->GetReferenceCount()); doneFlag = TRUE; break; } pNode = LightweightDoublyLinkedList::NextNode(pNode); } } if (FALSE == doneFlag) { CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Add reference to image buffer %p failed.",GetBufferManagerName(), pImageBuffer); } m_pLock->Unlock(); return count; } CAMX_INLINE UINT AddImageReference() { UINT count = CamxAtomicIncU(&m_aReferenceCount); // 引用计数+1 return count; // 返回添加引用计数后的数值 } 

2.1.5 ImageBufferManager::ReleaseReference函数实现如下

①查看该buffer是否在busy-list中;如果在

②查看将该buffer引用计数-1后的引用计数值;如果为0

③将其从busy-list移动到free-list链表中,并发送信号通知那些等待buffer的线程去取buffer(GetImageBuffer中如果取不到buffer,会设置超时等待)

UINT ImageBufferManager::ReleaseReference( ImageBuffer* pImageBuffer) { BOOL doneFlag = FALSE; UINT count = 0; LDLLNode* pNode = m_busyBufferList.Head(); while (NULL != pNode) { // Found the image buffer in busy list, if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData)) { if (0 < pImageBuffer->GetReferenceCount()) { // count为该buffer引用计数-1后的结果 count = pImageBuffer->ReleaseImageReference(); if (0 == count) { // Move the buffer to the free list m_busyBufferList.RemoveNode(pNode); if ((TRUE == m_createData.bEnableLateBinding) && (TRUE == m_createData.allocateBufferMemory) && (TRUE == pImageBuffer->HasBackingBuffer())) { // If late binding is enabled, release the buffer and just add the holder ImageBuffer object into // free list. When this ImageBuffer is acquired, explicit BindBuffer on this ImageBuffer object will be // called to allocate or bind the buffer back to this ImageBuffer pImageBuffer->Release(FALSE); } pImageBuffer->SetBusyState(FALSE);// 为即将插入到free-list中的buffer设置状态时传参false,为busy-list时传参true m_freeBufferList.InsertToTail(pNode); // 发送信号通知等待此buffer的线程,有buffer用了,不用等了 m_pWaitFreeBuffer->Signal(); } } doneFlag = TRUE; break; } pNode = LightweightDoublyLinkedList::NextNode(pNode); } if (FALSE == doneFlag) { CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Didn't find the image buffer %p in busy list.",GetBufferManagerName(), pImageBuffer); } return count; }

三、Camx MemPoolManager

        在对ImageBufferManager接口进行详细说明后,对MemPoolMgr中如何获取ImagerBufferManager所需的ImageBuffer进行了下图的关系说明。

高通Camx-内存池架构/ImageBuffer

四、Camx ImageBuffer

         imageBuffer在pipeline中扮演着非常重要的决策,负责图像数据在node之间的流转。在pipeline中node之间的连接是靠port来链接的,而port的连接正是通过共享内存(一组imageBuffer)来实现的

        高通Camx架构通过一个 Import 操作,把MemPoolBufferbufferInfo,传递给 imagebufferbufferInfo ImageBuffer pipeline node port口 之间是通过传递这个bufferInfo,把一个node outputport 传递给 inputport的。

        以下是简单的ImageBuffer在pipeline里面的流转示意图:

高通Camx-内存池架构/ImageBuffer

五、Ending

        本博文主要对一些文章中高通内存池架构/ImageBuffer进行拆分进行框架上的梳理,很多具体的各个模块细节可参考以下博文:

        1.ImageBufferManager具体在整个流程中的调用以及ImgeBuffer在pipeline之间的流转:ImageBufferManager介绍-CSDN博客

DMABuffer剖析_dma buffer-CSDN博客

        2.MemPoolMgr与ImageBufferManager之间更详细的link以及更深层次的涉及理解:DMABuffer剖析_dma buffer-CSDN博客

        3.关于ION buffer本质与mmap映射使用更详细的说明:

Android ION 相关信息查看方法_kernel查看ion-CSDN博客

ION基本概念介绍和原理分析_ion buffer-CSDN博客

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/116948.html

(0)
上一篇 2025-11-25 07:33
下一篇 2025-11-25 08:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信