内存泄漏系列专题分析之三十二:高通相机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

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

下一篇讲解:

相关推荐
阿巴斯甜19 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker20 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952721 小时前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android