| /* |
| * 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()); |
| } |