xref: /aosp_15_r20/external/intel-media-driver/media_driver/agnostic/common/os/mos_cmdbufmgr.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
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