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 //!
24 //! \file encode_buffer_tracker.cpp
25 //! \brief Defines the interface for buffer tracker
26 //! \details The tracker manages the buffers with different type
27 //!
28
29 #include "encode_tracked_buffer.h"
30 #include <iterator>
31 #include <utility>
32 #include "encode_tracked_buffer_slot.h"
33 #include "mos_utilities.h"
34
35 namespace encode {
36 constexpr MapBufferResourceType TrackedBuffer::m_mapBufferResourceType[];
TrackedBuffer(EncodeAllocator * allocator,uint8_t maxRefCnt,uint8_t maxNonRefCnt)37 TrackedBuffer::TrackedBuffer(EncodeAllocator *allocator, uint8_t maxRefCnt, uint8_t maxNonRefCnt)
38 : m_maxRefSlotCnt(maxRefCnt),
39 m_maxNonRefSlotCnt(maxNonRefCnt),
40 m_allocator(allocator)
41 {
42 m_maxSlotCnt = m_maxRefSlotCnt + m_maxNonRefSlotCnt;
43 for (uint8_t i = 0; i < m_maxSlotCnt; i++)
44 {
45 m_bufferSlots.push_back(MOS_New(BufferSlot, this));
46 }
47
48 m_mutex = MosUtilities::MosCreateMutex();
49 }
50
~TrackedBuffer()51 TrackedBuffer::~TrackedBuffer()
52 {
53 for (auto it = m_bufferSlots.begin(); it != m_bufferSlots.end(); it++)
54 {
55 (*it)->Reset();
56 MOS_Delete(*it);
57 }
58 m_bufferQueue.clear();
59 m_oldQueue.clear();
60
61 MosUtilities::MosDestroyMutex(m_mutex);
62 }
63
RegisterParam(BufferType type,MOS_ALLOC_GFXRES_PARAMS param)64 MOS_STATUS TrackedBuffer::RegisterParam(BufferType type, MOS_ALLOC_GFXRES_PARAMS param)
65 {
66 auto iter = m_allocParams.find(type);
67 if (iter == m_allocParams.end())
68 {
69 m_allocParams.insert(std::make_pair(type, param));
70 }
71 else
72 {
73 // erase the older param and insert new one when resultion change happens
74 m_allocParams.erase(iter);
75 m_allocParams.insert(std::make_pair(type, param));
76 }
77 return MOS_STATUS_SUCCESS;
78 }
79
ReleaseUnusedSlots(CODEC_REF_LIST * refList,bool lazyRelease)80 MOS_STATUS TrackedBuffer::ReleaseUnusedSlots(
81 CODEC_REF_LIST* refList,
82 bool lazyRelease)
83 {
84 ENCODE_CHK_NULL_RETURN(refList);
85
86 if (!refList->bUsedAsRef)
87 {
88 return MOS_STATUS_SUCCESS;
89 }
90
91 if (lazyRelease && m_bufferSlots.size() < m_maxSlotCnt)
92 {
93 return MOS_STATUS_SUCCESS;
94 }
95
96 // find all the slots which are not used by current reflist
97 uint8_t refIndex = 0;
98
99 for (uint8_t slotIndex = 0; slotIndex < m_maxSlotCnt; slotIndex++)
100 {
101 for (refIndex = 0; refIndex < refList->ucNumRef; refIndex++)
102 {
103 CODEC_PICTURE currRef = refList->RefList[refIndex];
104
105 if (currRef.FrameIdx == m_bufferSlots[slotIndex]->GetFrameIdx())
106 {
107 break;
108 }
109 }
110
111 if (refIndex == refList->ucNumRef)
112 {
113 ENCODE_CHK_STATUS_RETURN(m_bufferSlots[slotIndex]->Reset());
114
115 if (lazyRelease)
116 {
117 break;
118 }
119 }
120 }
121
122 return MOS_STATUS_SUCCESS;
123
124 }
125
Acquire(CODEC_REF_LIST * refList,bool isIdrFrame,bool lazyRelease)126 MOS_STATUS TrackedBuffer::Acquire(
127 CODEC_REF_LIST* refList,
128 bool isIdrFrame,
129 bool lazyRelease)
130 {
131 ENCODE_CHK_NULL_RETURN(refList);
132 AutoLock lock(m_mutex);
133
134 //if encouter Idr frame, need to clear the reference slots
135 if (isIdrFrame)
136 {
137 for (auto it = m_bufferSlots.begin(); it != m_bufferSlots.end(); it++)
138 {
139 (*it)->Reset();
140 }
141 }
142
143 ENCODE_CHK_STATUS_RETURN(ReleaseUnusedSlots(refList, lazyRelease));
144
145 // get current free slot index
146 refList->ucScalingIdx = m_currSlotIndex = 0XFF;
147 for (uint8_t i = 0; i < m_maxSlotCnt; i++)
148 {
149 BufferSlot *slot = m_bufferSlots[i];
150 if (slot->IsFree())
151 {
152 m_currSlotIndex = i;
153 slot->SetBusy();
154 slot->SetFrameIdx(refList->RefPic.FrameIdx);
155 break;
156 }
157 }
158
159 //if not found, wait for previous slot returned
160 if (m_currSlotIndex == 0XFF)
161 {
162 MOS_STATUS status = m_condition.Wait(m_mutex);
163 if (status != MOS_STATUS_SUCCESS || m_currSlotIndex == 0XFF)
164 {
165 return MOS_STATUS_UNKNOWN;
166 }
167
168 ENCODE_ASSERT(m_currSlotIndex != 0XFF);
169
170 BufferSlot *slot = m_bufferSlots[m_currSlotIndex];
171 ENCODE_CHK_NULL_RETURN(slot);
172 slot->SetBusy();
173 slot->SetFrameIdx(refList->RefPic.FrameIdx);
174 }
175
176 refList->ucScalingIdx = m_currSlotIndex;
177
178 return MOS_STATUS_SUCCESS;
179 }
180
Release(CODEC_REF_LIST * refList)181 MOS_STATUS TrackedBuffer::Release(CODEC_REF_LIST* refList)
182 {
183 ENCODE_CHK_NULL_RETURN(refList);
184 AutoLock lock(m_mutex);
185
186 uint8_t slotIndex = refList->ucScalingIdx;
187 if (slotIndex >= m_maxSlotCnt)
188 {
189 return MOS_STATUS_SUCCESS;
190 }
191
192 //if the condition variable is waiting, assign the returned slot to m_currSlotIndex
193 //and signal the waiting condition
194 if (m_currSlotIndex == 0XFF && !refList->bUsedAsRef)
195 {
196 ENCODE_CHK_STATUS_RETURN(m_bufferSlots[slotIndex]->Reset());
197
198 m_currSlotIndex = slotIndex;
199 m_condition.Signal();
200 }
201
202 if (!m_oldQueue.empty())
203 {
204 for (auto iter = m_oldQueue.begin(); iter != m_oldQueue.end();)
205 {
206 if (iter->second->SafeToDestory())
207 {
208 iter = m_oldQueue.erase(iter);
209 }
210 else
211 {
212 iter++;
213 }
214 }
215 }
216
217 return MOS_STATUS_SUCCESS;
218 }
219
OnSizeChange()220 MOS_STATUS TrackedBuffer::OnSizeChange()
221 {
222 for (auto iter = m_bufferQueue.begin(); iter != m_bufferQueue.end();)
223 {
224 if (iter->second->SafeToDestory())
225 {
226 iter = m_bufferQueue.erase(iter);
227 }
228 else
229 {
230 iter++;
231 }
232 }
233
234 if (!m_bufferQueue.empty())
235 {
236 m_oldQueue.insert(std::make_move_iterator(m_bufferQueue.begin()),
237 std::make_move_iterator(m_bufferQueue.end()));
238 m_bufferQueue.clear();
239 }
240
241 return MOS_STATUS_SUCCESS;
242 }
243
GetSurface(BufferType type,uint32_t index)244 MOS_SURFACE *TrackedBuffer::GetSurface(BufferType type, uint32_t index)
245 {
246 ResourceType resType = GetResourceType(type);
247
248 if (index > m_maxSlotCnt || resType != ResourceType::surfaceResource)
249 {
250 return nullptr;
251 }
252
253 return (MOS_SURFACE *)m_bufferSlots[index]->GetResource(type);
254 }
255
GetBuffer(BufferType type,uint32_t index)256 MOS_RESOURCE *TrackedBuffer::GetBuffer(BufferType type, uint32_t index)
257 {
258 ResourceType resType = GetResourceType(type);
259 if (index > m_maxSlotCnt || resType != ResourceType::bufferResource)
260 {
261 return nullptr;
262 }
263
264 return (MOS_RESOURCE *)m_bufferSlots[index]->GetResource(type);
265 }
266
GetBufferQueue(BufferType type)267 std::shared_ptr<BufferQueue> TrackedBuffer::GetBufferQueue(BufferType type)
268 {
269 auto iter = m_bufferQueue.find(type);
270 if (iter == m_bufferQueue.end())
271 {
272 auto param = m_allocParams.find(type);
273 if (param == m_allocParams.end())
274 {
275 return nullptr;
276 }
277
278 ResourceType resType = GetResourceType(type);
279
280 auto alloc = std::make_shared<BufferQueue>(m_allocator, param->second, m_maxSlotCnt);
281 alloc->SetResourceType(resType);
282 m_bufferQueue.insert(std::make_pair(type, alloc));
283 return alloc;
284 }
285 else
286 {
287 return iter->second;
288 }
289 }
290
291 }