blob: 7ebcdecc3bff5b7b77c0000b96851de544e6ee3a [file] [log] [blame]
/*
* Copyright (c) 2019, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file mos_cmdbufmgr_next.cpp
//! \brief Container class for the basic command buffer manager
//!
#include "mos_cmdbufmgr_next.h"
#include <algorithm>
CmdBufMgrNext::CmdBufMgrNext()
{
MOS_OS_FUNCTION_ENTER;
m_availableCmdBufPool.clear();
m_inUseCmdBufPool.clear();
m_initialized = false;
}
CmdBufMgrNext::~CmdBufMgrNext()
{
MOS_OS_FUNCTION_ENTER;
}
CmdBufMgrNext* CmdBufMgrNext::GetObject()
{
MOS_OS_FUNCTION_ENTER;
return MOS_New(CmdBufMgrNext);
}
MOS_STATUS CmdBufMgrNext::Initialize(OsContextNext *osContext, uint32_t cmdBufSize)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
MOS_OS_FUNCTION_ENTER;
MOS_OS_CHK_NULL_RETURN(osContext);
if (!m_initialized)
{
m_osContext = osContext;
m_inUsePoolMutex = MosUtilities::MosCreateMutex();
MOS_OS_CHK_NULL_RETURN(m_inUsePoolMutex);
m_availablePoolMutex = MosUtilities::MosCreateMutex();
MOS_OS_CHK_NULL_RETURN(m_availablePoolMutex);
for (uint32_t i = 0; i < m_initBufNum; i++)
{
auto cmdBuf = CommandBufferNext::CreateCmdBuf(this);
if (cmdBuf == nullptr)
{
MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
return MOS_STATUS_INVALID_HANDLE;
}
eStatus = cmdBuf->Allocate(m_osContext, cmdBufSize);
if (eStatus != MOS_STATUS_SUCCESS)
{
cmdBuf->Free();
MOS_Delete(cmdBuf);
MOS_OS_ASSERTMESSAGE("Allocate CmdBuf#%d failed", i);
return MOS_STATUS_INVALID_HANDLE;
}
MosUtilities::MosLockMutex(m_availablePoolMutex);
m_availableCmdBufPool.push_back(cmdBuf);
MosUtilities::MosUnlockMutex(m_availablePoolMutex);
m_cmdBufTotalNum++;
}
m_initialized = true;
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS CmdBufMgrNext::Reset()
{
MOS_OS_FUNCTION_ENTER;
CommandBufferNext *cmdBuf = nullptr;
auto gpuContextMgr = m_osContext->GetGpuContextMgr();
MOS_OS_CHK_NULL_RETURN(gpuContextMgr);
MosUtilities::MosLockMutex(m_availablePoolMutex);
MosUtilities::MosLockMutex(m_inUsePoolMutex);
if (!m_inUseCmdBufPool.empty())
{
for (auto& cmdBuf : m_inUseCmdBufPool)
{
UpperInsert(cmdBuf);
}
}
// clear in-use command buffer pool
m_inUseCmdBufPool.clear();
MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
for (auto& cmdBuf : m_availableCmdBufPool)
{
if (cmdBuf != nullptr)
{
auto nativeGpuContext = cmdBuf->GetLastNativeGpuContext();
auto nativeGpuContextHandle = cmdBuf->GetLastNativeGpuContextHandle();
if (nativeGpuContext != nullptr && nativeGpuContext == gpuContextMgr->GetGpuContext(nativeGpuContextHandle))
{
cmdBuf->UnBindToGpuContext(true);
nativeGpuContext->ResetCmdBuffer();
}
cmdBuf->ResetLastNativeGpuContext();
auto gpuContext = cmdBuf->GetGpuContext();
auto gpuContextHandle = cmdBuf->GetGpuContextHandle();
if (gpuContext != nullptr && gpuContext == gpuContextMgr->GetGpuContext(gpuContextHandle))
{
cmdBuf->UnBindToGpuContext(false);
gpuContext->ResetCmdBuffer();
}
cmdBuf->ResetGpuContext();
}
else
{
MOS_OS_ASSERTMESSAGE("Unexpected, found null command buffer!");
}
}
m_cmdBufTotalNum = m_availableCmdBufPool.size();
MosUtilities::MosUnlockMutex(m_availablePoolMutex);
return MOS_STATUS_SUCCESS;
}
void CmdBufMgrNext::CleanUp()
{
MOS_OS_FUNCTION_ENTER;
CommandBufferNext *cmdBuf = nullptr;
MosUtilities::MosLockMutex(m_availablePoolMutex);
for (auto& cmdBuf : m_availableCmdBufPool)
{
if (cmdBuf != nullptr)
{
auto gpuContext = cmdBuf->GetLastNativeGpuContext();
auto gpuContextHandle = cmdBuf->GetLastNativeGpuContextHandle();
auto gpuContextMgr = m_osContext->GetGpuContextMgr();
if (gpuContext != nullptr && gpuContextMgr && gpuContext == gpuContextMgr->GetGpuContext(gpuContextHandle))
{
cmdBuf->UnBindToGpuContext(true);
}
cmdBuf->Free();
MOS_Delete(cmdBuf);
}
else
{
MOS_OS_ASSERTMESSAGE("Unexpected, found null command buffer!");
}
}
// clear available command buffer pool
m_availableCmdBufPool.clear();
MosUtilities::MosUnlockMutex(m_availablePoolMutex);
MosUtilities::MosLockMutex(m_inUsePoolMutex);
if (!m_inUseCmdBufPool.empty())
{
for (auto& cmdBuf : m_inUseCmdBufPool)
{
if (cmdBuf != nullptr)
{
cmdBuf->Free();
MOS_Delete(cmdBuf);
}
}
}
// clear in-use command buffer pool
m_inUseCmdBufPool.clear();
MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
m_cmdBufTotalNum = 0;
m_initialized = false;
MosUtilities::MosDestroyMutex(m_inUsePoolMutex);
m_inUsePoolMutex = nullptr;
MosUtilities::MosDestroyMutex(m_availablePoolMutex);
m_availablePoolMutex = nullptr;
}
CommandBufferNext *CmdBufMgrNext::PickupOneCmdBuf(uint32_t size)
{
MOS_OS_FUNCTION_ENTER;
if (!m_initialized)
{
MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer picking up!");
return nullptr;
}
// lock for both in-use and available command buffer pool before pick up
MosUtilities::MosLockMutex(m_inUsePoolMutex);
MosUtilities::MosLockMutex(m_availablePoolMutex);
CommandBufferNext* cmdBuf = nullptr;
CommandBufferNext* retbuf = nullptr;
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
if (!m_availableCmdBufPool.empty())
{
cmdBuf = *(m_availableCmdBufPool.begin());
if (cmdBuf == nullptr)
{
MOS_OS_ASSERTMESSAGE("available command buf pool is null.");
MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
MosUtilities::MosUnlockMutex(m_availablePoolMutex);
return nullptr;
}
// find available buf
if (size <= cmdBuf->GetCmdBufSize() && !cmdBuf->IsUsedByHw() && !cmdBuf->IsInCmdList())
{
m_inUseCmdBufPool.push_back(cmdBuf);
m_availableCmdBufPool.erase(m_availableCmdBufPool.begin());
MOS_OS_VERBOSEMESSAGE("successfully get available buf from pool");
}
// available buf is not large enough, need reallocate
else
{
MOS_OS_VERBOSEMESSAGE("find available buf, but is not large enough or it is still used by HW");
cmdBuf = CommandBufferNext::CreateCmdBuf(this);
if (cmdBuf == nullptr)
{
MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
}
else
{
eStatus = cmdBuf->Allocate(m_osContext, size);
if (eStatus != MOS_STATUS_SUCCESS)
{
MOS_OS_ASSERTMESSAGE("Allocate CmdBuf failed");
}
// directly push into inuse pool
m_inUseCmdBufPool.push_back(cmdBuf);
m_cmdBufTotalNum++;
}
}
retbuf = cmdBuf;
}
// no available buf in the pool, will allocate in batch
else
{
MOS_OS_VERBOSEMESSAGE("No more cmd buf in the pool");
if (m_cmdBufTotalNum < m_maxPoolSize)
{
MOS_OS_VERBOSEMESSAGE("Increase the cmd buf pool size by %d", m_bufIncStepSize);
for (uint32_t i = 0; i < m_bufIncStepSize; i++)
{
cmdBuf = CommandBufferNext::CreateCmdBuf(this);
if (cmdBuf == nullptr)
{
MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
continue;
}
eStatus = cmdBuf->Allocate(m_osContext, size);
if (eStatus != MOS_STATUS_SUCCESS)
{
MOS_OS_ASSERTMESSAGE("Allocate CmdBuf#%d failed", i);
cmdBuf->Free();
MOS_Delete(cmdBuf);
continue;
}
if (i == 0)
{
// directly push into inuse pool
m_inUseCmdBufPool.push_back(cmdBuf);
retbuf = cmdBuf;
}
else
{
m_availableCmdBufPool.insert(m_availableCmdBufPool.begin(), cmdBuf);
}
m_cmdBufTotalNum++;
}
// sort by decent order
std::sort(m_availableCmdBufPool.begin(), m_availableCmdBufPool.end(), &CmdBufMgrNext::GreaterSizeSort);
}
else
{
MOS_OS_ASSERTMESSAGE("No availabe cmd buf in pool and the total buf num hit the ceiling, may need wait for a while.");
retbuf = nullptr;
}
}
// unlock after got return buffer
MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
MosUtilities::MosUnlockMutex(m_availablePoolMutex);
return retbuf;
}
void CmdBufMgrNext::UpperInsert(CommandBufferNext *cmdBuf)
{
auto it = std::find_if(m_availableCmdBufPool.begin(), m_availableCmdBufPool.end(), [=](CommandBufferNext * p1){return p1->GetCmdBufSize() < cmdBuf->GetCmdBufSize();});
m_availableCmdBufPool.emplace(it, cmdBuf);
}
MOS_STATUS CmdBufMgrNext::ReleaseCmdBuf(CommandBufferNext *cmdBuf)
{
MOS_OS_FUNCTION_ENTER;
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
if (!m_initialized)
{
MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer release!");
return MOS_STATUS_NULL_POINTER;
}
MOS_OS_CHK_NULL_RETURN(cmdBuf);
// lock for both in-use and available command buffer pool before release
MosUtilities::MosLockMutex(m_inUsePoolMutex);
MosUtilities::MosLockMutex(m_availablePoolMutex);
bool found = false;
for (auto iter = m_inUseCmdBufPool.begin(); iter != m_inUseCmdBufPool.end(); iter++)
{
if (cmdBuf == *iter)
{
found = true;
m_inUseCmdBufPool.erase(iter);
break;
}
}
if (!found)
{
MOS_OS_ASSERTMESSAGE("Cannot find the specified cmdbuf in inusepool, sth must be wrong!");
eStatus = MOS_STATUS_UNKNOWN;
}
else
{
UpperInsert(cmdBuf);
}
// unlock after release buffer
MosUtilities::MosUnlockMutex(m_availablePoolMutex);
MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
return eStatus;
}
MOS_STATUS CmdBufMgrNext::ResizeOneCmdBuf(CommandBufferNext *cmdBufToResize, uint32_t newSize)
{
MOS_OS_FUNCTION_ENTER;
MOS_OS_CHK_NULL_RETURN(cmdBufToResize);
if (!m_initialized)
{
MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer resize!");
return MOS_STATUS_UNKNOWN;
}
return cmdBufToResize->ReSize(newSize);
}
bool CmdBufMgrNext::GreaterSizeSort(CommandBufferNext *a, CommandBufferNext *b)
{
return (a->GetCmdBufSize() > b->GetCmdBufSize());
}