1 /*
2 * Copyright (c) 2018-2021, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file mos_cmdbufmgr.cpp
24 //! \brief Container class for the basic command buffer manager
25 //!
26 #include "mos_cmdbufmgr.h"
27 #include <algorithm>
28
CmdBufMgr()29 CmdBufMgr::CmdBufMgr()
30 {
31 MOS_OS_FUNCTION_ENTER;
32
33 m_availableCmdBufPool.clear();
34 m_inUseCmdBufPool.clear();
35 m_initialized = false;
36 }
37
~CmdBufMgr()38 CmdBufMgr::~CmdBufMgr()
39 {
40 MOS_OS_FUNCTION_ENTER;
41 }
42
GetObject()43 CmdBufMgr* CmdBufMgr::GetObject()
44 {
45 MOS_OS_FUNCTION_ENTER;
46 return MOS_New(CmdBufMgr);
47 }
48
Initialize(OsContext * osContext,uint32_t cmdBufSize)49 MOS_STATUS CmdBufMgr::Initialize(OsContext *osContext, uint32_t cmdBufSize)
50 {
51 MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
52
53 MOS_OS_FUNCTION_ENTER;
54 MOS_OS_CHK_NULL_RETURN(osContext);
55
56 if (!m_initialized)
57 {
58 m_osContext = osContext;
59
60 m_inUsePoolMutex = MosUtilities::MosCreateMutex();
61 MOS_OS_CHK_NULL_RETURN(m_inUsePoolMutex);
62
63 m_availablePoolMutex = MosUtilities::MosCreateMutex();
64 MOS_OS_CHK_NULL_RETURN(m_availablePoolMutex);
65
66 for (uint32_t i = 0; i < m_initBufNum; i++)
67 {
68 auto cmdBuf = CommandBuffer::CreateCmdBuf();
69 if (cmdBuf == nullptr)
70 {
71 MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
72 return MOS_STATUS_INVALID_HANDLE;
73 }
74
75 eStatus = cmdBuf->Allocate(m_osContext, cmdBufSize);
76 if (eStatus != MOS_STATUS_SUCCESS)
77 {
78 MOS_OS_ASSERTMESSAGE("Allocate CmdBuf#%d failed", i);
79 CommandBuffer::DestroyCmdBuf(cmdBuf);
80 return MOS_STATUS_INVALID_HANDLE;
81 }
82
83 MosUtilities::MosLockMutex(m_availablePoolMutex);
84 m_availableCmdBufPool.push_back(cmdBuf);
85 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
86
87 m_cmdBufTotalNum++;
88 }
89
90 m_initialized = true;
91 }
92
93 return MOS_STATUS_SUCCESS;
94 }
95
CleanUp()96 void CmdBufMgr::CleanUp()
97 {
98 MOS_OS_FUNCTION_ENTER;
99
100 if (m_initialized)
101 {
102 CommandBuffer *cmdBuf = nullptr;
103 MosUtilities::MosLockMutex(m_availablePoolMutex);
104
105 for (auto& cmdBuf : m_availableCmdBufPool)
106 {
107 if (cmdBuf != nullptr)
108 {
109 cmdBuf->Free();
110 MOS_Delete(cmdBuf);
111 }
112 else
113 {
114 MOS_OS_ASSERTMESSAGE("Unexpected, found null command buffer!");
115 }
116 }
117
118 // clear available command buffer pool
119 m_availableCmdBufPool.clear();
120 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
121 MosUtilities::MosLockMutex(m_inUsePoolMutex);
122
123 if (!m_inUseCmdBufPool.empty())
124 {
125 MOS_OS_ASSERTMESSAGE("Unexpected, inUseCmdBufPool is not empty!");
126 for (auto& cmdBuf : m_inUseCmdBufPool)
127 {
128 if (cmdBuf != nullptr)
129 {
130 cmdBuf->Free();
131 MOS_Delete(cmdBuf);
132 }
133 }
134 }
135
136 // clear in-use command buffer pool
137 m_inUseCmdBufPool.clear();
138 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
139
140 m_cmdBufTotalNum = 0;
141 m_initialized = false;
142 MosUtilities::MosDestroyMutex(m_inUsePoolMutex);
143 m_inUsePoolMutex = nullptr;
144 MosUtilities::MosDestroyMutex(m_availablePoolMutex);
145 m_availablePoolMutex = nullptr;
146 }
147 }
148
PickupOneCmdBuf(uint32_t size)149 CommandBuffer *CmdBufMgr::PickupOneCmdBuf(uint32_t size)
150 {
151 MOS_OS_FUNCTION_ENTER;
152
153 if (!m_initialized)
154 {
155 MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer picking up!");
156 return nullptr;
157 }
158
159 // lock for both in-use and available command buffer pool before pick up
160 MosUtilities::MosLockMutex(m_inUsePoolMutex);
161 MosUtilities::MosLockMutex(m_availablePoolMutex);
162
163 CommandBuffer* cmdBuf = nullptr;
164 CommandBuffer* retbuf = nullptr;
165 MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
166
167 if (!m_availableCmdBufPool.empty())
168 {
169 cmdBuf = *(m_availableCmdBufPool.begin());
170 if (cmdBuf == nullptr)
171 {
172 MOS_OS_ASSERTMESSAGE("available command buf pool is null.");
173 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
174 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
175 return nullptr;
176 }
177
178 // find available buf
179 if (size <= cmdBuf->GetCmdBufSize())
180 {
181 m_inUseCmdBufPool.push_back(cmdBuf);
182
183 m_availableCmdBufPool.erase(m_availableCmdBufPool.begin());
184
185 MOS_OS_VERBOSEMESSAGE("successfully get available buf from pool");
186 }
187 // available buf is not large enough, need reallocate
188 else
189 {
190 MOS_OS_VERBOSEMESSAGE("find available buf, but is not large enough");
191
192 cmdBuf = CommandBuffer::CreateCmdBuf();
193 if (cmdBuf == nullptr)
194 {
195 MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
196 }
197 else
198 {
199 eStatus = cmdBuf->Allocate(m_osContext, size);
200 if (eStatus != MOS_STATUS_SUCCESS)
201 {
202 MOS_OS_ASSERTMESSAGE("Allocate CmdBuf failed");
203 }
204
205 // directly push into inuse pool
206 m_inUseCmdBufPool.push_back(cmdBuf);
207 m_cmdBufTotalNum++;
208 }
209 }
210
211 retbuf = cmdBuf;
212 }
213 // no available buf in the pool, will allocate in batch
214 else
215 {
216 MOS_OS_VERBOSEMESSAGE("No more cmd buf in the pool");
217
218 if (m_cmdBufTotalNum < m_maxPoolSize)
219 {
220 MOS_OS_VERBOSEMESSAGE("Increase the cmd buf pool size by %d", m_bufIncStepSize);
221 for (uint32_t i = 0; i < m_bufIncStepSize; i++)
222 {
223 cmdBuf = CommandBuffer::CreateCmdBuf();
224 if (cmdBuf == nullptr)
225 {
226 MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
227 continue;
228 }
229
230 eStatus = cmdBuf->Allocate(m_osContext, size);
231 if (eStatus != MOS_STATUS_SUCCESS)
232 {
233 MOS_OS_ASSERTMESSAGE("Allocate CmdBuf#%d failed", i);
234 cmdBuf->Free();
235 MOS_Delete(cmdBuf);
236 continue;
237 }
238
239 if (i == 0)
240 {
241 // directly push into inuse pool
242 m_inUseCmdBufPool.push_back(cmdBuf);
243 retbuf = cmdBuf;
244 }
245 else
246 {
247 m_availableCmdBufPool.insert(m_availableCmdBufPool.begin(), cmdBuf);
248 }
249 m_cmdBufTotalNum++;
250 }
251 // sort by decent order
252 std::sort(m_availableCmdBufPool.begin(), m_availableCmdBufPool.end(), &CmdBufMgr::GreaterSizeSort);
253 }
254 else
255 {
256 MOS_OS_ASSERTMESSAGE("No availabe cmd buf in pool and the total buf num hit the ceiling, may need wait for a while.");
257 retbuf = nullptr;
258 }
259 }
260
261 // unlock after got return buffer
262 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
263 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
264
265 return retbuf;
266 }
267
UpperInsert(CommandBuffer * cmdBuf)268 void CmdBufMgr::UpperInsert(CommandBuffer *cmdBuf)
269 {
270 auto it = std::find_if(m_availableCmdBufPool.begin(), m_availableCmdBufPool.end(), [=](CommandBuffer * p1){return p1->GetCmdBufSize() < cmdBuf->GetCmdBufSize();});
271 m_availableCmdBufPool.emplace(it, cmdBuf);
272 }
273
ReleaseCmdBuf(CommandBuffer * cmdBuf)274 MOS_STATUS CmdBufMgr::ReleaseCmdBuf(CommandBuffer *cmdBuf)
275 {
276 MOS_OS_FUNCTION_ENTER;
277
278 MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
279
280 if (!m_initialized)
281 {
282 MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer release!");
283 return MOS_STATUS_NULL_POINTER;
284 }
285
286 MOS_OS_CHK_NULL_RETURN(cmdBuf);
287
288 // lock for both in-use and available command buffer pool before release
289 MosUtilities::MosLockMutex(m_inUsePoolMutex);
290 MosUtilities::MosLockMutex(m_availablePoolMutex);
291
292 bool found = false;
293 for (auto iter = m_inUseCmdBufPool.begin(); iter != m_inUseCmdBufPool.end(); iter++)
294 {
295 if (cmdBuf == *iter)
296 {
297 found = true;
298 m_inUseCmdBufPool.erase(iter);
299 break;
300 }
301 }
302
303 if (!found)
304 {
305 MOS_OS_ASSERTMESSAGE("Cannot find the specified cmdbuf in inusepool, sth must be wrong!");
306 eStatus = MOS_STATUS_UNKNOWN;
307 }
308 else
309 {
310 UpperInsert(cmdBuf);
311 }
312
313 // unlock after release buffer
314 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
315 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
316
317 return eStatus;
318 }
319
ResizeOneCmdBuf(CommandBuffer * cmdBufToResize,uint32_t newSize)320 MOS_STATUS CmdBufMgr::ResizeOneCmdBuf(CommandBuffer *cmdBufToResize, uint32_t newSize)
321 {
322 MOS_OS_FUNCTION_ENTER;
323
324 MOS_OS_CHK_NULL_RETURN(cmdBufToResize);
325
326 if (!m_initialized)
327 {
328 MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer resize!");
329 return MOS_STATUS_UNKNOWN;
330 }
331
332 return cmdBufToResize->ReSize(newSize);
333 }
334