高通Camx-内存池架构/ImageBuffer

[复制链接]
发表于 2025-12-21 00:39:36 | 显示全部楼层 |阅读模式
一、Camx内存池架构简介

1.1内存池使用的优点

        起首,在项目中假如频仍的使用malloc申请内存空间,堆上分配和开释内存,会导致性能的丧失。由于堆空间申请的存储地点是不连续的,也会使体系中出现的大量的内存碎片,低沉内存的使用率,而内存池的使用就很好的办理了这些性能和内存上的题目。
        其次,内存池使用映射到连续物理地点的Ion Buffer(本质是linux的file文件),通过文件形貌符可以实现各个进程间数据的共享,比堆空间的使用范围大多了,能更好的link上下路各个模块间的链路。

1.2Camx内存池架构总览

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

二、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函数实现如下

  1. CamxResult ImageBufferManager::Create(
  2.     const CHAR*              pBufferManagerName,
  3.     BufferManagerCreateData* pCreateData,
  4.     ImageBufferManager**     ppImageBufferManager)
  5. {
  6.     CamxResult          result              = CamxResultSuccess;
  7.     ImageBufferManager* pImageBufferManager = NULL;
  8.     if (CamxResultSuccess == result)
  9.     {
  10.         *ppImageBufferManager = NULL;
  11.         pImageBufferManager = CAMX_NEW ImageBufferManager();
  12.     }
  13.     if (CamxResultSuccess == result)
  14.     {
  15.         // 从内存池中为ImageBufferManager分配内存
  16.         result = pImageBufferManager->Initialize(pBufferManagerName, pCreateData);
  17.         if (CamxResultSuccess == result)
  18.         {
  19.             CAMX_LOG_INFO(CamxLogGroupMemMgr, "[%s] : allocRequired=%d, immediateAllocBufferCount=%d, maxBufferCount=%d", pBufferManagerName, pCreateData->allocateBufferMemory, pCreateData->immediateAllocBufferCount, pCreateData->maxBufferCount);
  20.             // 初始化ImageBufferManager中的buffers,这里是重点
  21.             result = pImageBufferManager->InitializeBuffers(pCreateData);
  22.         }
  23.     }
  24.     if (CamxResultSuccess == result)
  25.     {
  26.         *ppImageBufferManager = pImageBufferManager;
  27.     }
  28.     return result;
复制代码
2.1.2 ImageBufferManager::InitializeBuffer实现如下

  1. CamxResult ImageBufferManager::InitializeBuffers(
  2. BufferManagerCreateData* pCreateData) {
  3.     m_createData                = *pCreateData;
  4.     m_currentFormat             = pCreateData->bufferProperties.imageFormat;
  5.     m_maxBufferCount            = pCreateData->maxBufferCount;
  6.     m_immediateAllocBufferCount = pCreateData->immediateAllocBufferCount;
  7.     // Allocate the minimum number of buffers needed immediately serially
  8.     for (UINT i = 0; i < m_immediateAllocBufferCount; i++)
  9.     {
  10.         // ①new buffer
  11.         ImageBuffer* pBuffer = CAMX_NEW ImageBuffer();
  12.         if (NULL != pBuffer)
  13.         {
  14.             // ②buffer初始化,buffer相关信息放在全局变量m_createData中
  15.             result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this,m_hMemPoolBufMgrHandle);
  16.             // ③Allocate the buffer
  17.             result = pBuffer->Allocate();
  18.             LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));
  19.             if (NULL != pNode)
  20.             {
  21.                 pNode->pData = pBuffer;
  22.                 // ④Add the buffer to the free buffer list
  23.                 m_freeBufferList.InsertToTail(pNode);
  24.             }
  25.     }
复制代码
2.1.3 ImageBufferManager::GetImageBuffer函数实现如下

①从free-list中找buffer;假如没有
②再去busy-list中找引用计数为0的buffer;照旧没有
③看看能不能自己创建buffer;假如不能创建
④超时等候n次去获取busy-list中引用计数为0的buffer
颠末上述使用,假如能获取到buffer,先添加buffer的引用计数,然后封装成node,放到busy-list链表尾
  1. ImageBuffer* ImageBufferManager::GetImageBuffer()
  2. {
  3.     // first:先从free_list的头部取出buffer节点
  4.     LDLLNode*    pNode       = m_freeBufferList.RemoveFromHead();   
  5.     ImageBuffer* pBuffer     = NULL;
  6.     // Check the free List for an available buffer
  7.     if (NULL != pNode)
  8.     {
  9.         // 取出buffer节点中的buffer
  10.         pBuffer = static_cast<ImageBuffer*>(pNode->pData);  
  11.         CAMX_FREE(pNode); // 释放该节点所占用的内存
  12.         pNode = NULL;
  13.     }
  14.     // second:如果free_list中没有可用buffer,就去busy_list中去取
  15.     if (NULL == pBuffer)
  16.     {
  17.         // 从头遍历busy_list中的节点
  18.         pNode = m_busyBufferList.Head();
  19.         while (NULL != pNode)
  20.         {
  21.             ImageBuffer* pBusyBuffer = static_cast<ImageBuffer*>(pNode->pData);  
  22.             LDLLNode*    pNext       = LightweightDoublyLinkedList::NextNode(pNode);
  23.             if (0 == pBusyBuffer->GetReferenceCount())
  24.             {
  25.                 // 如果该busy-buffer的引用计数为0,说明该buffer可以被使用
  26.                 m_busyBufferList.RemoveNode(pNode);
  27.                 // 就从busy_list中取出node,这里会先移出,然后后面会再次添加到busy-list的尾部
  28.                 if (NULL == pBuffer) {
  29.                     // We will keep this buffer
  30.                     pBuffer = pBusyBuffer;   // 将上述busy-buffer赋值给pBuffer
  31.                     CAMX_FREE(pNode);        // 释放该节点所占用的内存
  32.                     pNode = NULL;
  33.                 }
  34.                 else
  35.                 {
  36.                     // 如果从busy-list取节点时刚好发现pBuffer不为空了,而pNode都从busy-list中取出来了,这次不用就下次再用吧,将其放到free-list中
  37.                     m_freeBufferList.InsertToTail(pNode);
  38.                     
  39.                 }
  40.             }
  41.             pNode = pNext;
  42.         }
  43.     }
  44.     // third:如果free-list和busy-list中没有找到引用计数为0的buffer,看看能不能创建buffer
  45.     if (NULL == pBuffer)
  46.     {
  47.         UINT numOfFreeBuffers = m_freeBufferList.NumNodes();
  48.         UINT numOfBusyBuffers = m_busyBufferList.NumNodes();
  49.         // If no free buffers were found either in the free list or the busy list, we check to see if an additional buffer
  50.         // can be allocated immediately
  51.         if ((numOfFreeBuffers + numOfBusyBuffers) < m_maxBufferCount)
  52.         {  
  53.             // 只要没有达到创建buffer的max值,就能额外创建buffer
  54.             CamxResult result = CamxResultSuccess;
  55.             // 下面就是buffer创建三部曲
  56.             pBuffer = CAMX_NEW ImageBuffer();
  57.             if (NULL != pBuffer)
  58.             {
  59.                 result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this, m_hMemPoolBufMgrHandle);  
  60.                
  61.             }
  62.             else
  63.             {
  64.                 CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Ran out of memory to allocate", GetBufferManagerName());
  65.                 result = CamxResultENoMemory;
  66.             }
  67.             if (CamxResultSuccess == result)
  68.             {
  69.                 if ((TRUE == m_createData.allocateBufferMemory) &&
  70.                     (FALSE == m_createData.bEnableLateBinding))
  71.                 {
  72.                     // Allocate the buffer
  73.                     result = pBuffer->Allocate();
  74.                 }
  75.             }
  76.         }
  77.     }
  78.     // four:如果上面三种情况都不满足,那么就只能等待busy-list中的buffer释放了
  79.     if (NULL == pBuffer)
  80.     {   
  81.         pNode = NULL;
  82.         while (NULL == pNode)
  83.         {
  84.             // 设置超时等待,接收busy-list中的buffer释放信号         
  85.             result = m_pWaitFreeBuffer->TimedWait(m_pLock->GetNativeHandle(), BufferTimeoutMilliseconds);
  86.             pNode = m_freeBufferList.RemoveFromHead();
  87.             if (timeoutCount >= MaxTimeoutCount)
  88.             {  
  89.                 // 这里会进行几次超时等待,如果超过最大等待次数就退出循环,等不下去了,累了!!
  90.                 CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Waited %ux%u times and failed to get buffer, returning a null buffer", GetBufferManagerName(), timeoutCount, BufferTimeoutMilliseconds);
  91.                 break;
  92.             }
  93.             else if (CamxResultETimeout == result)
  94.             { // 继续超时等待,死等,还挺执着!!
  95.                 // timeout happened, print an error log and continue waiting
  96.                 timeoutCount++;
  97.                 CAMX_LOG_WARN(CamxLogGroupMemMgr, "[%s] Waiting %ux%d ms timedout, there might be a leak or performance issue", GetBufferManagerName(), timeoutCount, BufferTimeoutMilliseconds);
  98.             }
  99.             else if (CamxResultSuccess != result)
  100.             {
  101.                 // 函数执行期间遇到错误,退出循环
  102.                 timeoutCount++;
  103.                 CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Waiting %dx%d ms failed for unknown reason, result=%s",GetBufferManagerName(), timeoutCount,BufferTimeoutMilliseconds,Utils::CamxResultToString(result));
  104.                 break;
  105.             }
  106.         }
  107.         // 如果free-list中取到节点了,万事大吉,取其buffer。念念不忘,必有回响!
  108.         if (NULL != pNode)
  109.         {
  110.             pBuffer = static_cast<ImageBuffer*>(pNode->pData);
  111.             CAMX_FREE(pNode);
  112.             pNode   = NULL;
  113.             CAMX_LOG_INFO(CamxLogGroupMemMgr, "[%s] Returning a buffer [%p] from the free list after wait ended",GetBufferManagerName(), pBuffer);
  114.         }
  115.     }
  116.     // 几经波折,如果能取到buffer,会进一步处理
  117.     if (NULL != pBuffer)
  118.     {
  119.         m_pLock->Unlock();
  120.         pBuffer->AddImageReference();  // 添加buffer的引用计数
  121.         m_pLock->Lock();
  122.         pBuffer->SetBusyState(TRUE);   // 我很忙
  123.         pBuffer->ClearReferenceHolderData();
  124.         pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));
  125.         if (NULL != pNode)
  126.         {
  127.             pNode->pData = pBuffer;
  128.             m_busyBufferList.InsertToTail(pNode); // 将节点插入到busy-list的尾部
  129.             m_peakBufferHolders = Utils::MaxUINT(m_peakBufferHolders, m_busyBufferList.NumNodes());
  130.         }
  131.     }
  132.     return pBuffer;
  133. }
复制代码
2.1.4 ImageBufferManager::AddReference函数实现如下

①查察该buffer是否在free-list中,假如在则将其从free-list中移到busy-list中,并添加该buffer的引用计数;假如不在
②查察该buffer是否在busy-list中,假如在则增长该buffer的引用计数。
  1. UINT ImageBufferManager::AddReference(
  2. ImageBuffer* pImageBuffer) {
  3.     BOOL      doneFlag = FALSE;
  4.     UINT      count    = 0;   
  5.     LDLLNode* pNode;
  6.     // 看看该buffer是不是在free-list中,如果是,则将其从中移除并添加到busy-list中
  7.     pNode = m_freeBufferList.Head();
  8.     while (NULL != pNode)
  9.     {
  10.         if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData))
  11.         {
  12.             // Add reference to the image buffer
  13.             count = pImageBuffer->AddImageReference();
  14.             // Move if from free list to busy list
  15.             m_freeBufferList.RemoveNode(pNode);
  16.             pImageBuffer->SetBusyState(TRUE);
  17.             m_busyBufferList.InsertToTail(pNode);
  18.             CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] Image buffer %p in free list, reference count after adding = %d",GetBufferManagerName(), pImageBuffer, pImageBuffer->GetReferenceCount());
  19.             doneFlag = TRUE;
  20.             break;
  21.         }
  22.         pNode = LightweightDoublyLinkedList::NextNode(pNode);
  23.     }
  24.     // 添加引用的buffer不在freelist中
  25.     if (FALSE == doneFlag)
  26.     {
  27.         pNode = m_busyBufferList.Head();
  28.         // Didn't find the image buffer in free list, then search busy list
  29.         while (NULL != pNode)
  30.         {
  31.             // Found the image buffer in busy list
  32.             if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData))
  33.             {
  34.                 // Add reference to the image buffer
  35.                 count = pImageBuffer->AddImageReference();
  36.                 CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] Image buffer %p in busy list, reference count after adding = %d",GetBufferManagerName(), pImageBuffer, pImageBuffer->GetReferenceCount());
  37.                 doneFlag = TRUE;
  38.                 break;
  39.             }
  40.             pNode = LightweightDoublyLinkedList::NextNode(pNode);
  41.         }
  42.     }
  43.     if (FALSE == doneFlag)
  44.     {
  45.         CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Add reference to image buffer %p failed.",GetBufferManagerName(), pImageBuffer);
  46.     }
  47.     m_pLock->Unlock();
  48.     return count;
  49. }
  50. CAMX_INLINE UINT AddImageReference()
  51. {
  52.     UINT count = CamxAtomicIncU(&m_aReferenceCount); // 引用计数+1
  53.     return count; // 返回添加引用计数后的数值
  54. }
复制代码
2.1.5 ImageBufferManager::ReleaseReference函数实现如下

①查察该buffer是否在busy-list中;假如在
②查察将该buffer引用计数-1后的引用计数值;假如为0
③将其从busy-list移动到free-list链表中,并发送信号关照那些等候buffer的线程去取buffer(GetImageBuffer中假如取不到buffer,会设置超时等候)
  1. UINT ImageBufferManager::ReleaseReference(
  2. ImageBuffer* pImageBuffer)
  3. {
  4.     BOOL doneFlag = FALSE;
  5.     UINT count    = 0;
  6.     LDLLNode* pNode = m_busyBufferList.Head();
  7.     while (NULL != pNode)
  8.     {
  9.         // Found the image buffer in busy list,
  10.         if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData))
  11.         {
  12.             if (0 < pImageBuffer->GetReferenceCount())
  13.             {
  14.                 // count为该buffer引用计数-1后的结果
  15.                 count = pImageBuffer->ReleaseImageReference();
  16.                 if (0 == count)
  17.                 {
  18.                     // Move the buffer to the free list
  19.                     m_busyBufferList.RemoveNode(pNode);
  20.                     if ((TRUE == m_createData.bEnableLateBinding)   &&
  21.                         (TRUE == m_createData.allocateBufferMemory) &&
  22.                         (TRUE == pImageBuffer->HasBackingBuffer()))
  23.                     {
  24.                         // If late binding is enabled, release the buffer and just add the holder ImageBuffer object into
  25.                         // free list. When this ImageBuffer is acquired, explicit BindBuffer on this ImageBuffer object will be
  26.                         // called to allocate or bind the buffer back to this ImageBuffer
  27.                         pImageBuffer->Release(FALSE);
  28.                     }
  29.                     pImageBuffer->SetBusyState(FALSE);// 为即将插入到free-list中的buffer设置状态时传参false,为busy-list时传参true
  30.                     m_freeBufferList.InsertToTail(pNode);
  31.                     // 发送信号通知等待此buffer的线程,有buffer用了,不用等了
  32.                     m_pWaitFreeBuffer->Signal();
  33.                 }
  34.             }
  35.             doneFlag = TRUE;
  36.             break;
  37.         }
  38.         pNode = LightweightDoublyLinkedList::NextNode(pNode);
  39.     }
  40.     if (FALSE == doneFlag)
  41.     {
  42.         CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Didn't find the image buffer %p in busy list.",GetBufferManagerName(), pImageBuffer);
  43.     }
  44.     return count;
  45. }
复制代码
三、Camx MemPoolManager

        在对ImageBufferManager接口举行具体阐明后,对MemPoolMgr中怎样获取ImagerBufferManager所需的ImageBuffer举行了下图的关系阐明。


四、Camx ImageBuffer

         imageBuffer在pipeline中扮演着非常告急的决议,负责图像数据在node之间的流转。在pipeline中node之间的毗连是靠port来链接的,而port的毗连正是通过共享内存(一组imageBuffer)来实现的
        高通Camx架构通过一个 Import 使用,把MemPoolBuffer的bufferInfo,通报给 imagebuffer的bufferInfo。 ImageBuffer 在 pipeline node port口 之间是通过通报这个bufferInfo,把一个node 的outputport 通报给 inputport的。
        以下是简单的ImageBuffer在pipeline内里的流转表示图:

五、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博客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表