1 /*
2 * Copyright (c) 2019, 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_next.cpp
24 //! \brief Container class for the basic command buffer manager
25 //!
26 #include "mos_cmdbufmgr_next.h"
27 #include "mos_context_next.h"
28
CmdBufMgrNext()29 CmdBufMgrNext::CmdBufMgrNext()
30 {
31 MOS_OS_FUNCTION_ENTER;
32
33 m_availableCmdBufPool.clear();
34 m_inUseCmdBufPool.clear();
35 m_initialized = false;
36 }
37
~CmdBufMgrNext()38 CmdBufMgrNext::~CmdBufMgrNext()
39 {
40 MOS_OS_FUNCTION_ENTER;
41 }
42
GetObject()43 CmdBufMgrNext* CmdBufMgrNext::GetObject()
44 {
45 MOS_OS_FUNCTION_ENTER;
46 return MOS_New(CmdBufMgrNext);
47 }
48
Initialize(OsContextNext * osContext,uint32_t cmdBufSize)49 MOS_STATUS CmdBufMgrNext::Initialize(OsContextNext *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 = CommandBufferNext::CreateCmdBuf(this);
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 cmdBuf->Free();
79 MOS_Delete(cmdBuf);
80 MOS_OS_ASSERTMESSAGE("Allocate CmdBuf#%d failed", i);
81 return MOS_STATUS_INVALID_HANDLE;
82 }
83
84 MosUtilities::MosLockMutex(m_availablePoolMutex);
85 m_availableCmdBufPool.push_back(cmdBuf);
86 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
87
88 m_cmdBufTotalNum++;
89 }
90
91 m_initialized = true;
92 }
93
94 return MOS_STATUS_SUCCESS;
95 }
96
Reset()97 MOS_STATUS CmdBufMgrNext::Reset()
98 {
99 MOS_OS_FUNCTION_ENTER;
100
101 CommandBufferNext *cmdBuf = nullptr;
102 auto gpuContextMgr = m_osContext->GetGpuContextMgr();
103 MOS_OS_CHK_NULL_RETURN(gpuContextMgr);
104 std::vector<CommandBufferNext *> tmpInUseCmdBufPool = {};
105
106 MosUtilities::MosLockMutex(m_inUsePoolMutex);
107
108 if (!m_inUseCmdBufPool.empty())
109 {
110 tmpInUseCmdBufPool = std::move(m_inUseCmdBufPool);
111 }
112
113 // clear in-use command buffer pool
114 m_inUseCmdBufPool.clear();
115 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
116
117 MosUtilities::MosLockMutex(m_availablePoolMutex);
118 if (!tmpInUseCmdBufPool.empty())
119 {
120 for (auto& cmdBuf : tmpInUseCmdBufPool)
121 {
122 UpperInsert(cmdBuf);
123 }
124 }
125
126 for (auto& cmdBuf : m_availableCmdBufPool)
127 {
128 if (cmdBuf != nullptr)
129 {
130 auto nativeGpuContext = cmdBuf->GetLastNativeGpuContext();
131 auto nativeGpuContextHandle = cmdBuf->GetLastNativeGpuContextHandle();
132 if (nativeGpuContext != nullptr && nativeGpuContext == gpuContextMgr->GetGpuContext(nativeGpuContextHandle))
133 {
134 cmdBuf->UnBindToGpuContext(true);
135 nativeGpuContext->ResetCmdBuffer();
136 }
137 cmdBuf->ResetLastNativeGpuContext();
138
139 auto gpuContext = cmdBuf->GetGpuContext();
140 auto gpuContextHandle = cmdBuf->GetGpuContextHandle();
141 if (gpuContext != nullptr && gpuContext == gpuContextMgr->GetGpuContext(gpuContextHandle))
142 {
143 cmdBuf->UnBindToGpuContext(false);
144 gpuContext->ResetCmdBuffer();
145 }
146 cmdBuf->ResetGpuContext();
147 }
148 else
149 {
150 MOS_OS_ASSERTMESSAGE("Unexpected, found null command buffer!");
151 }
152 }
153 m_cmdBufTotalNum = m_availableCmdBufPool.size();
154 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
155 return MOS_STATUS_SUCCESS;
156 }
157
CleanUp()158 void CmdBufMgrNext::CleanUp()
159 {
160 MOS_OS_FUNCTION_ENTER;
161
162 CommandBufferNext *cmdBuf = nullptr;
163 MosUtilities::MosLockMutex(m_availablePoolMutex);
164
165 for (auto& cmdBuf : m_availableCmdBufPool)
166 {
167 if (cmdBuf != nullptr)
168 {
169 auto gpuContext = cmdBuf->GetLastNativeGpuContext();
170 auto gpuContextHandle = cmdBuf->GetLastNativeGpuContextHandle();
171 auto gpuContextMgr = m_osContext->GetGpuContextMgr();
172 if (gpuContext != nullptr && gpuContextMgr && gpuContext == gpuContextMgr->GetGpuContext(gpuContextHandle))
173 {
174 cmdBuf->UnBindToGpuContext(true);
175 }
176 cmdBuf->Free();
177 MOS_Delete(cmdBuf);
178 }
179 else
180 {
181 MOS_OS_ASSERTMESSAGE("Unexpected, found null command buffer!");
182 }
183 }
184
185 // clear available command buffer pool
186 m_availableCmdBufPool.clear();
187 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
188 MosUtilities::MosLockMutex(m_inUsePoolMutex);
189
190 if (!m_inUseCmdBufPool.empty())
191 {
192 for (auto& cmdBuf : m_inUseCmdBufPool)
193 {
194 if (cmdBuf != nullptr)
195 {
196 cmdBuf->Free();
197 MOS_Delete(cmdBuf);
198 }
199 }
200 }
201
202 // clear in-use command buffer pool
203 m_inUseCmdBufPool.clear();
204 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
205
206 m_cmdBufTotalNum = 0;
207 m_initialized = false;
208 MosUtilities::MosDestroyMutex(m_inUsePoolMutex);
209 m_inUsePoolMutex = nullptr;
210 MosUtilities::MosDestroyMutex(m_availablePoolMutex);
211 m_availablePoolMutex = nullptr;
212 }
213
PickupOneCmdBuf(uint32_t size)214 CommandBufferNext *CmdBufMgrNext::PickupOneCmdBuf(uint32_t size)
215 {
216 MOS_OS_FUNCTION_ENTER;
217
218 if (!m_initialized)
219 {
220 MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer picking up!");
221 return nullptr;
222 }
223
224 // lock for both in-use and available command buffer pool before pick up
225 MosUtilities::MosLockMutex(m_inUsePoolMutex);
226 MosUtilities::MosLockMutex(m_availablePoolMutex);
227
228 CommandBufferNext* cmdBuf = nullptr;
229 CommandBufferNext* retbuf = nullptr;
230 MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
231
232 if (!m_availableCmdBufPool.empty())
233 {
234 cmdBuf = *(m_availableCmdBufPool.begin());
235 if (cmdBuf == nullptr)
236 {
237 MOS_OS_ASSERTMESSAGE("available command buf pool is null.");
238 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
239 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
240 return nullptr;
241 }
242
243 // find available buf
244 if (size <= cmdBuf->GetCmdBufSize() && !cmdBuf->IsUsedByHw() && !cmdBuf->IsInCmdList())
245 {
246 m_inUseCmdBufPool.push_back(cmdBuf);
247
248 m_availableCmdBufPool.erase(m_availableCmdBufPool.begin());
249
250 MOS_OS_VERBOSEMESSAGE("successfully get available buf from pool");
251 }
252 // available buf is not large enough, need reallocate
253 else
254 {
255 MOS_OS_VERBOSEMESSAGE("find available buf, but is not large enough or it is still used by HW");
256
257 cmdBuf = CommandBufferNext::CreateCmdBuf(this);
258 if (cmdBuf == nullptr)
259 {
260 MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
261 }
262 else
263 {
264 eStatus = cmdBuf->Allocate(m_osContext, size);
265 if (eStatus != MOS_STATUS_SUCCESS)
266 {
267 MOS_OS_ASSERTMESSAGE("Allocate CmdBuf failed");
268 }
269
270 // directly push into inuse pool
271 m_inUseCmdBufPool.push_back(cmdBuf);
272 m_cmdBufTotalNum++;
273
274 }
275 }
276
277 retbuf = cmdBuf;
278 }
279 // no available buf in the pool, will allocate in batch
280 else
281 {
282 MOS_OS_VERBOSEMESSAGE("No more cmd buf in the pool");
283
284 if (m_cmdBufTotalNum < m_maxPoolSize)
285 {
286 MOS_OS_VERBOSEMESSAGE("Increase the cmd buf pool size by %d", m_bufIncStepSize);
287 for (uint32_t i = 0; i < m_bufIncStepSize; i++)
288 {
289 cmdBuf = CommandBufferNext::CreateCmdBuf(this);
290 if (cmdBuf == nullptr)
291 {
292 MOS_OS_ASSERTMESSAGE("input nullptr returned by CommandBuffer::CreateCmdBuf.");
293 continue;
294 }
295
296 eStatus = cmdBuf->Allocate(m_osContext, size);
297 if (eStatus != MOS_STATUS_SUCCESS)
298 {
299 MOS_OS_ASSERTMESSAGE("Allocate CmdBuf#%d failed", i);
300 cmdBuf->Free();
301 MOS_Delete(cmdBuf);
302 continue;
303 }
304
305 if (i == 0)
306 {
307 // directly push into inuse pool
308 m_inUseCmdBufPool.push_back(cmdBuf);
309 retbuf = cmdBuf;
310 }
311 else
312 {
313 m_availableCmdBufPool.insert(m_availableCmdBufPool.begin(), cmdBuf);
314 }
315 m_cmdBufTotalNum++;
316 }
317
318 // sort by decent order
319 std::sort(m_availableCmdBufPool.begin(), m_availableCmdBufPool.end(), &CmdBufMgrNext::GreaterSizeSort);
320 }
321 else
322 {
323 MOS_OS_ASSERTMESSAGE("No availabe cmd buf in pool and the total buf num hit the ceiling, may need wait for a while.");
324 retbuf = nullptr;
325 }
326 }
327
328 // unlock after got return buffer
329 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
330 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
331
332 return retbuf;
333 }
334
UpperInsert(CommandBufferNext * cmdBuf)335 void CmdBufMgrNext::UpperInsert(CommandBufferNext *cmdBuf)
336 {
337 auto it = std::find_if(m_availableCmdBufPool.begin(), m_availableCmdBufPool.end(), [=](CommandBufferNext * p1){return p1->GetCmdBufSize() < cmdBuf->GetCmdBufSize();});
338 m_availableCmdBufPool.emplace(it, cmdBuf);
339 }
340
ReleaseCmdBuf(CommandBufferNext * cmdBuf)341 MOS_STATUS CmdBufMgrNext::ReleaseCmdBuf(CommandBufferNext *cmdBuf)
342 {
343 MOS_OS_FUNCTION_ENTER;
344
345 MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
346
347 if (!m_initialized)
348 {
349 MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer release!");
350 return MOS_STATUS_NULL_POINTER;
351 }
352
353 MOS_OS_CHK_NULL_RETURN(cmdBuf);
354
355 // lock for both in-use and available command buffer pool before release
356 MosUtilities::MosLockMutex(m_inUsePoolMutex);
357 MosUtilities::MosLockMutex(m_availablePoolMutex);
358
359 bool found = false;
360 for (auto iter = m_inUseCmdBufPool.begin(); iter != m_inUseCmdBufPool.end(); iter++)
361 {
362 if (cmdBuf == *iter)
363 {
364 found = true;
365 m_inUseCmdBufPool.erase(iter);
366 break;
367 }
368 }
369
370 if (!found)
371 {
372 MOS_OS_ASSERTMESSAGE("Cannot find the specified cmdbuf in inusepool, sth must be wrong!");
373 eStatus = MOS_STATUS_UNKNOWN;
374 }
375 else
376 {
377 UpperInsert(cmdBuf);
378 }
379
380 // unlock after release buffer
381 MosUtilities::MosUnlockMutex(m_availablePoolMutex);
382 MosUtilities::MosUnlockMutex(m_inUsePoolMutex);
383
384 return eStatus;
385 }
386
ResizeOneCmdBuf(CommandBufferNext * cmdBufToResize,uint32_t newSize)387 MOS_STATUS CmdBufMgrNext::ResizeOneCmdBuf(CommandBufferNext *cmdBufToResize, uint32_t newSize)
388 {
389 MOS_OS_FUNCTION_ENTER;
390
391 MOS_OS_CHK_NULL_RETURN(cmdBufToResize);
392
393 if (!m_initialized)
394 {
395 MOS_OS_ASSERTMESSAGE("cmd buf pool need be initialized before buffer resize!");
396 return MOS_STATUS_UNKNOWN;
397 }
398
399 return cmdBufToResize->ReSize(newSize);
400 }
401
402
GreaterSizeSort(CommandBufferNext * a,CommandBufferNext * b)403 bool CmdBufMgrNext::GreaterSizeSort(CommandBufferNext *a, CommandBufferNext *b)
404 {
405 return (a->GetCmdBufSize() > b->GetCmdBufSize());
406 }