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 }