内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer

【关注我,后续持续新增专题博文,谢谢!!!】

上一篇我们讲了:

这一篇我们开始讲: 内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer

目录

一、背景

二、:CmdBufferManager管理单元

2.1:CmdBufferManager初始化

2.2:CmdBufferManager获取buffer

[三、:Camx CmdBuffer模块](#三、:Camx CmdBuffer模块)

3.1:CmdBuffer初始化

[3.2 :CmdBuffer核心接口](#3.2 :CmdBuffer核心接口)

[3.3 :CmdBuffer核心接口使用方式](#3.3 :CmdBuffer核心接口使用方式)

[3.4 :CmdBuffer中sensor上电命令形式](#3.4 :CmdBuffer中sensor上电命令形式)

四、:总结


一、背景

Camx HAL层ION Buffer可以分为两类:ImageBuffer和CmdBuffer。这篇博文就CmdBuffer模块进行分析介绍。

了解过高通Camx架构,一般知道bringup的开发并非都在kernel层,chi-cdk用户态也存在大量bringup开发工作,而用户态sensor等xml配置类似内核态dts配置一样,chi-cdk用户态存在大量sensor、马达等硬件bringup代码,需要讲xml配置通过CmdBuffer的方式下发到kernel去执行最终的驱动代码。

二、:CmdBufferManager管理单元

2.1:CmdBufferManager初始化

CmdBufferManager::Initialize是对CmdBufferManager进行初始化,可以看到核心代码只有一行:可以知道最终还是同ImageBuffer一样由CSLAlloc分配ION内存。

cpp 复制代码
X:\bruce\SI\camx\src\core\camxcmdbuffermanager.cpp

CamxResult CmdBufferManager::Initialize(
    const CHAR*             pBufferManagerName,
    const ResourceParams*   pParams)
{
    {

        CAMX_ASSERT(NULL != pBufferManagerName);
        OsUtils::StrLCpy(m_pBufferManagerName, pBufferManagerName, sizeof(m_pBufferManagerName));

        m_params         = *pParams;

        result = InitializePool();
    }

    m_pLock = Mutex::Create("CmdBufferManager");

    return result;
}

CamxResult CmdBufferManager::InitializePool()
{
    CamxResult result = CamxResultSuccess;

    CAMX_ASSERT((0 != m_params.resourceSize) && (0 == (m_params.poolSize % m_params.resourceSize)));

    if ((0 == m_params.resourceSize) || (0 != (m_params.poolSize % m_params.resourceSize)))
    {
        result = CamxResultEInvalidArg;
    }
    else
    {
        SIZE_T  allocationSize  = 0;
        UINT32  flags           = m_params.memFlags;
        m_numResources          = m_params.poolSize / m_params.resourceSize;

        CSLBufferInfo*  pBufferInfo = static_cast<CSLBufferInfo*>(CAMX_CALLOC(sizeof(CSLBufferInfo)));

        if (NULL == m_pParentBufferManager)
        {
            if (NULL != pBufferInfo)
            {
                result = CSLAlloc(m_pBufferManagerName,
                                  pBufferInfo,
                                  allocationSize,
                                  m_params.alignment,
                                  flags,
                                  m_params.pDeviceIndices,
                                  m_params.numDevices);
            }
        }
}

2.2:CmdBufferManager获取buffer

  1. CmdBufferManager获取buffer主要通过GetBuffer和GetBufferForRequest两个接口,返回都是PacketResource,它对应的就是CmdBuffer中CSLBufferInfo,本质就是xml的命令配置。
  2. CmdBufferManager是管理 CmdBuffer的,CmdBufferManager中有2条链表 m_busyPool和m_freePool,其中:m_freePool中存放着空闲的Buffer,m_busyPool中存放着正在被client 使用的Buffer。
cpp 复制代码
CamxResult CmdBufferManager::GetBuffer(
    PacketResource** ppBuffer)
{
    LDLLNode* pNode = m_freePool.RemoveFromHead();

    if (NULL != pNode)
    {
        *ppBuffer = static_cast<PacketResource*>(pNode->pData);

        if (NULL == *ppBuffer)
        {
            result = CamxResultEInvalidState;
        }
        else
        {
            // Check canary
            if (TRUE == (*ppBuffer)->GetUsageFlags().batchedPacket)
            {
                BatchedPacket* pBatchedPacket = static_cast<BatchedPacket*>(*ppBuffer);
                pBatchedPacket->CheckCanary();
            }
            (*ppBuffer)->Reset();
            (*ppBuffer)->SetRequestId(CamxInvalidRequestId);
        }

        CAMX_FREE(pNode);
    }

    m_pLock->Unlock();

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CmdBufferManager::GetBufferForRequest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CmdBufferManager::GetBufferForRequest(
    UINT64           requestId,
    PacketResource** ppBuffer)
{
    CamxResult result = GetBuffer(ppBuffer);

    m_pLock->Lock();

    if (CamxResultSuccess == result)
    {
        CAMX_ASSERT(NULL != *ppBuffer);

        (*ppBuffer)->SetRequestId(requestId);

        LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));

        if (NULL != pNode)
        {
            pNode->pData = *ppBuffer;

            m_busyPool.InsertToTail(pNode);

            m_peakNumResourcesUsed = Utils::MaxUINT(m_peakNumResourcesUsed, m_busyPool.NumNodes());
        }
        else
        {
            result = CamxResultENoMemory;
        }
    }

    m_pLock->Unlock();

    return result;
}

三、:Camx CmdBuffer模块

3.1:CmdBuffer初始化

CmdBuffer初始化本质是对PacketResource进行初始化,再对CSLBufferInfo进行封装。

cpp 复制代码
X:\bruce\SI\camx\src\core\camxcmdbuffer.cpp

CamxResult CmdBuffer::Initialize(
    const CmdParams*        pParams,
    const CSLBufferInfo*    pBufferInfo,
    SIZE_T                  offset,
    SIZE_T                  size)
{
    if (NULL == pParams)
    {
        CAMX_LOG_ERROR(CamxLogGroupUtils, "Invalid input params");
        return CamxResultEInvalidPointer;
    }

    CamxResult result = PacketResource::Initialize(pBufferInfo, offset, size);

    return result;
}

CamxResult PacketResource::Initialize(
    const CSLBufferInfo*    pBufferInfo,
    SIZE_T                  offset,
    SIZE_T                  size)
{
    CamxResult result = CamxResultSuccess;

    if ((NULL == pBufferInfo) || (CSLInvalidHandle == pBufferInfo->hHandle))
    {
        result = CamxResultEInvalidArg;
        CAMX_LOG_ERROR(CamxLogGroupUtils, "Invalid packet initialization args");
    }
    else
    {
        m_bufferInfo    = *pBufferInfo;
        m_offsetInBytes = offset;
        m_sizeInBytes   = size;
        m_pUserdata     = NULL;
        m_requestId     = CamxInvalidRequestId;
    }

    return result;
}

3.2 :CmdBuffer核心接口

CmdBuffer核心接口主要是这三个:

  1. CmdBuffer::BeginCommands:CSL开始准备下发命令到kernel
  2. CmdBuffer::CommitCommands:CSL正式提交命令到kernel
  3. CmdBuffer::CancelCommands:CSL取消下发命令到kernel
cpp 复制代码
VOID* CmdBuffer::BeginCommands(
    UINT32 numDwordsToReserve)
{
    VOID* pDwords = NULL;

    if ((GetNumDwordsAvailable() >= numDwordsToReserve) && (0 != numDwordsToReserve))
    {
        pDwords = GetCurrentWriteAddr();
        m_pendingDwords = numDwordsToReserve;
        // Put a canary to check in commit for overrun
        // This requires that we allocate one extra dword for command buffers (in command buffer manager)
        *static_cast<UINT*>(Utils::VoidPtrInc(pDwords, numDwordsToReserve * sizeof(UINT32))) = CamxCanary;
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupUtils, "Failed to reserve words-Dwords needed:%d, Dwords Available:%d",
                    numDwordsToReserve,
                    GetNumDwordsAvailable());
    }

    return pDwords;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CmdBuffer::CommitCommands
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CmdBuffer::CommitCommands()
{
    CamxResult result = CamxResultSuccess;

    CAMX_ASSERT_MESSAGE(GetNumDwordsAvailable() >= m_pendingDwords,
                        "Pending dwords: %d to commit is greater than available dwords: %d",
                        m_pendingDwords, GetNumDwordsAvailable());

    if (0 >= m_pendingDwords)
    {
        CAMX_LOG_ERROR(CamxLogGroupUtils, "Invalid Command buffer state pending dwords: %d",
                       m_pendingDwords);
        result = CamxResultEInvalidState;
    }
    else
    {
        // check for overrun
        CAMX_ASSERT(CamxCanary == *static_cast<UINT*>(Utils::VoidPtrInc(GetCurrentWriteAddr(),
                                                                        m_pendingDwords * sizeof(UINT32))));

        m_resourceUsedDwords += m_pendingDwords;
        m_pendingDwords = 0;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CmdBuffer::CancelCommands
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CmdBuffer::CancelCommands()
{
    CamxResult result = CamxResultSuccess;

    m_pendingDwords = 0;

    return result;
}

3.3 :CmdBuffer核心接口使用方式

下面就是OIS和马达bingup代码通过这些接口下发xml命令到kernel

cpp 复制代码
camx/src/swl/sensor/camxois.cpp
result = m_pI2CInfoCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = m_pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = m_pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = m_pInitializeCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pCalibrateCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pOisModeCmdBuffer->CommitCommands(); in ConfigureOISMode()

camx/src/swl/sensor/camxactuator.cpp
result = pI2CInfoCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pInitializeCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pMoveFocusCmdBuffer->CommitCommands(); in MoveFocus()

camx/src/swl/sensor/camxactuator.cpp
CmdBuffer* pInitializeCmdBuffer = NULL; in CreateInitializePacket() local
pInitializeCmdBuffer = m_pParentNode->GetCmdBuffer(m_pInitializeCmdManager); in CreateInitializePacket()
(NULL == pInitializeCmdBuffer)) in CreateInitializePacket()
pInitializeCmdBuffer); in CreateInitializePacket()
pCmdBegin = pInitializeCmdBuffer->BeginCommands(initializeCmdSize / sizeof(UINT32)); in CreateInitializePacket()
result = pInitializeCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pPacket->AddCmdBufferReference(pInitializeCmdBuffer, NULL); in CreateInitializePacket()
m_pInitializeCmdManager->Recycle(pInitializeCmdBuffer); in CreateInitializePacket()

3.4 :CmdBuffer中sensor上电命令形式

以下就是imxxxx_sensor.xml配置的sensor上电的时序,最终会通过代码读取并封装到PacketResource打包成CmdBuffer,再下发大kernel。【camx chi bringup解析xml并下发kernel后面单独介绍,流程漫长】

XML 复制代码
    <powerUpSequence>
      <!--Power setting configuration
          Contains: configType, configValue and delay in milli seconds -->
      <powerSetting>
        <!--Power configuration type
            Supported types are: MCLK, VANA, VDIG, VIO, VAF, RESET, STANDBY -->
        <configType>RESET</configType>
        <!--Configuration value for the type of configuration -->
        <configValue>0</configValue>
        <!--Delay in milli seconds -->
        <delayMs>1</delayMs>
      </powerSetting>
      <!--Power setting configuration
          Contains: configType, configValue and delay in milli seconds -->
      <powerSetting>
        <configType>VANA</configType>
        <configValue>0</configValue>
        <delayMs>1</delayMs>
      </powerSetting>
      <powerSetting>
        <configType>VDIG</configType>
        <configValue>0</configValue>
        <delayMs>1</delayMs>
      </powerSetting>
      <powerSetting>
        <configType>VIO</configType>
        <configValue>0</configValue>
        <delayMs>0</delayMs>
      </powerSetting>
      <powerSetting>
        <configType>MCLK</configType>
        <configValue>24000000</configValue>
        <delayMs>1</delayMs>
      </powerSetting>
      <powerSetting>
        <configType>RESET</configType>
        <configValue>1</configValue>
        <delayMs>18</delayMs>
      </powerSetting>
    </powerUpSequence>

四、:总结

Camx CmdBufferManager和CmdBuffer之间的核心关系如上所述:CmdBufferManager通过GetBuffer的有2条链表 m_busyPool和m_freePool拿到CmdBuffer。

CmdBuffer核心接口主要是这三个:

  1. CmdBuffer::BeginCommands:CSL开始准备下发命令到kernel
  2. CmdBuffer::CommitCommands:CSL正式提交命令到kernel
  3. CmdBuffer::CancelCommands:CSL取消下发命令到kernel

【关注我,后续持续新增专题博文,谢谢!!!】

下一篇讲解:

相关推荐
baidu_2474386115 小时前
Android ViewModel定时任务
android·开发语言·javascript
有位神秘人16 小时前
Android中Notification的使用详解
android·java·javascript
·云扬·16 小时前
MySQL Binlog落盘机制深度解析:性能与安全性的平衡艺术
android·mysql·adb
独自破碎E17 小时前
【BISHI9】田忌赛马
android·java·开发语言
代码s贝多芬的音符19 小时前
android 两个人脸对比 mlkit
android
darkb1rd20 小时前
五、PHP类型转换与类型安全
android·安全·php
gjxDaniel21 小时前
Kotlin编程语言入门与常见问题
android·开发语言·kotlin
csj5021 小时前
安卓基础之《(22)—高级控件(4)碎片Fragment》
android
yunjingtianhe21 小时前
EL隐裂检测仪的优势—精准捕捉细微隐裂、微小断栅等隐蔽性极强的隐患
数码相机
峥嵘life1 天前
Android16 【CTS】CtsMediaCodecTestCases等一些列Media测试存在Failed项
android·linux·学习