1 /*
2 * Copyright (c) 2017, 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     memory_block.h
24 //! \brief    A memory block is a chunk of memory in a heap.
25 //! \details  All heap memory is described with memory blocks. Each block has a state
26 //!           which determines how it may be used and what other states it may be
27 //!           transferred to. The client has limited direct access to a memory block--
28 //!           data may be added to the memory location referred to nothing else may be
29 //!           modified.
30 //!
31 
32 #ifndef __MEMORY_BLOCK_H__
33 #define __MEMORY_BLOCK_H__
34 
35 #include <memory>
36 #include <string>
37 #include "heap.h"
38 #include "frame_tracker.h"
39 
40 //! \brief   Describes a block of memory in a heap.
41 //! \details For internal use by the MemoryBlockManager only.
42 class MemoryBlockInternal
43 {
44     friend class MemoryBlockManager;
45 
46 public:
MemoryBlockInternal()47     MemoryBlockInternal() { HEAP_FUNCTION_ENTER_VERBOSE; }
48 
~MemoryBlockInternal()49     virtual ~MemoryBlockInternal() { HEAP_FUNCTION_ENTER; }
50 
51     //!
52     //! \brief  Add data to the memory block.
53     //! \param  [in] data
54     //!         Pointer containint data to insert, must be valid
55     //! \param  [in] dataOffset
56     //!         Relative offset where the data should be inserted within the
57     //!         memory block.
58     //! \param  [in] dataSize
59     //!         Size of the data to be copied from \a data.
60     //! \param  [in] zeroBlock
61     //!         Zeros the entire block, other parameters are not considered
62     //! \return MOS_STATUS
63     //!         MOS_STATUS_SUCCESS if success, else fail reason
64     //!
65     MOS_STATUS AddData(
66         void* data,
67         uint32_t dataOffset,
68         uint32_t dataSize,
69         bool zeroBlock = false);
70 
71     //!
72     //! \brief  Read data from the memory block.
73     //! \param  [out] data
74     //!         Pointer to data returned from memory block, must be valid
75     //! \param  [in] dataOffset
76     //!         Relative offset where the data will be read from within the
77     //!         memory block.
78     //! \param  [in] dataSize
79     //!         Size of the data to be copied to \a data.
80     //! \return MOS_STATUS
81     //!         MOS_STATUS_SUCCESS if success, else fail reason
82     //!
83     MOS_STATUS ReadData(
84         void* data,
85         uint32_t dataOffset,
86         uint32_t dataSize);
87 
88     //!
89     //! \brief  Dumps the contents of this memory block
90     //! \param  [in] filename
91     //!         The file to be written, includes path
92     //! \param  [in] offset
93     //!         Additional offset to be added to this memory block's offest
94     //! \param  [in] size
95     //!         Size of the data to be dumped, cannot be greater than this memory block's size
96     //! \param  [in] dumpInBinary
97     //!         Dump the data as binary instead of 32-bit hex segments
98     //! \return MOS_STATUS
99     //!         MOS_STATUS_SUCCESS if success, else fail reason
100     //!
101     MOS_STATUS Dump(
102         std::string filename,
103         uint32_t offset = 0,
104         uint32_t size = 0,
105         bool dumpInBinary = false);
106 
107     //!
108     //! \brief  Gets the relative offset of the memory block
109     //! \return The relative offset of this block in the heap \see m_offset
110     //!
GetOffset()111     uint32_t GetOffset() { return m_offset; }
112 
113     //!
114     //! \brief  Gets the size of the memory block
115     //! \return The size of this block \see m_size
116     //!
GetSize()117     uint32_t GetSize() { return m_size; }
118 
119     //!
120     //! \brief  Gets the tracker ID
121     //! \return This block's tracker ID \see m_trackerId
122     //!
GetTrackerId()123     uint32_t GetTrackerId() { return m_trackerId; }
124 
125     //!
126     //! \brief  Gets the tracker Producer
127     //! \return This block's tracker producer \see m_trackerProducer
128     //!
GetTrackerToken()129     FrameTrackerToken *GetTrackerToken() { return &m_trackerToken; }
130 
131     //!
132     //! \brief  Indicates whether or not the memory block is static
133     //! \return If this block is static \see m_static
134     //!
IsStatic()135     bool IsStatic() { return m_static; }
136 
137     //! \brief Invalid value to be read from the tracker data \see MemoryBlockInternalManager::m_pTrackerData
138     static const uint32_t m_invalidTrackerId = 0;
139 
140 protected:
141     //! \brief Possible states of a memory block
142     //! \dot
143     //! digraph states {
144     //!     pool -> free [style = dotted];
145     //!     free -> pool [style = dotted];
146     //!     free -> allocated;
147     //!     free -> deleted;
148     //!     allocated -> submitted;
149     //!     allocated -> deleted;
150     //!     allocated -> allocated [label = "static" labeltooltip = "Static blocks are always in allocated state"];
151     //!     submitted -> allocated [label = "!static" labeltooltip = "This state change requires a refresh."];
152     //!     submitted -> free [label = "!static" labeltooltip = "This state change requires a refresh."];
153     //!     submitted -> deleted;
154     //!     deleted -> pool [style = dotted];
155     //! }
156     //! \enddot
157     enum State
158     {
159         pool = 0,   //!< Memory block is blank and ready to be used by the memory block manager
160         free,       //!< Memory block is available for use by the client
161         allocated,  //!< Space has been acquired in the heap by the client and data may be added to the memory block
162         submitted,  //!< Memory block is submitted, no further changes are permitted
163         deleted,    //!< Memory block is in the process of being freed, may not be used
164         stateCount  //!< Number of states possible for a memory block
165     };
166 
167     //!
168     //! \brief  Sets up a memory block in the specified heap
169     //! \param  [in] heap
170     //!         Heap to which this memory block blongs.
171     //! \param  [in] requestedState
172     //!         Requested state for the block.
173     //! \param  [in] prev
174     //!         Memory block which is adjacent to this new block with a lower offset.
175     //! \param  [in] offset
176     //!         Relative offset within \a heap where this memory block is located
177     //! \param  [in] size
178     //!         Size of the memory block.
179     //! \param  [in] trackerId
180     //!         TrackerId associated with this memory block
181     //! \return MOS_STATUS
182     //!         MOS_STATUS_SUCCESS if success, else fail reason
183     //!
184     MOS_STATUS Create(
185         Heap *heap,
186         State requestedState,
187         MemoryBlockInternal *prev,
188         uint32_t offset,
189         uint32_t size,
190         uint32_t trackerId);
191 
192     //!
193     //! \brief   Adjusts this block's information such that it may be combined with \a block.
194     //! \details After combining, \a block will be returned to a pool state and this block
195     //!          will have expanded forward or backward to encompass \a block.
196     //! \param   [in] block
197     //!          Must be adjacent to this block to be combined.
198     //! \return  MOS_STATUS
199     //!          MOS_STATUS_SUCCESS if success, else fail reason
200     //!
201     MOS_STATUS Combine(MemoryBlockInternal *block);
202 
203     //!
204     //! \brief  Downsizes this block to \a size, puts the remainder into a new block \a block.
205     //! \param  [in,out] block
206     //!         Must be in a pool state. Block which takes some of this blocks space.
207     //! \param  [in] size
208     //!         Size of the new block.
209     //! \return MOS_STATUS
210     //!         MOS_STATUS_SUCCESS if success, else fail reason
211     //!
212     MOS_STATUS Split(MemoryBlockInternal *block, uint32_t size);
213 
214     //!
215     //! \brief  Indicates that the block is a placeholder until its state changes
216     //! \return MOS_STATUS
217     //!         MOS_STATUS_SUCCESS if success, else fail reason
218     //!
219     MOS_STATUS Pool();
220 
221     //!
222     //! \brief  Indicates that the block is ready for re-use
223     //! \return MOS_STATUS
224     //!         MOS_STATUS_SUCCESS if success, else fail reason
225     //!
226     MOS_STATUS Free();
227 
228     //!
229     //! \brief  Indicates that the block may be edited
230     //! \return MOS_STATUS
231     //!         MOS_STATUS_SUCCESS if success, else fail reason
232     //!
233     MOS_STATUS Allocate(uint32_t trackerId);
234 
235     //!
236     //! \brief  Indicates that the block may be edited
237     //! \return MOS_STATUS
238     //!         MOS_STATUS_SUCCESS if success, else fail reason
239     //!
240     MOS_STATUS Allocate(uint32_t index, uint32_t trackerId, FrameTrackerProducer *producer = nullptr);
241 
242     //!
243     //! \brief  Indicates that the client is done editing the memory block.
244     //! \return MOS_STATUS
245     //!         MOS_STATUS_SUCCESS if success, else fail reason
246     //!
247     MOS_STATUS Submit();
248 
249     //!
250     //! \brief  Indicates that the heap is in the process of being freed.
251     //! \return MOS_STATUS
252     //!         MOS_STATUS_SUCCESS if success, else fail reason
253     //!
254     MOS_STATUS Delete();
255 
256     //!
257     //! \brief  Indicates the state of the memory block
258     //! \return This block's state \see m_state
259     //!
GetState()260     State GetState() { return m_state; }
261 
262     //!
263     //! \brief  Forces \see m_static to false
264     //!
ClearStatic()265     void ClearStatic() { m_static = false; }
266 
267     //!
268     //! \brief  Forces \see m_static to true
269     //!
SetStatic()270     void SetStatic() { m_static = true; }
271 
272     //!
273     //! \brief  Gets the previous memory block
274     //! \return The previous adjacent block \see m_prev
275     //!
GetPrev()276     MemoryBlockInternal *GetPrev() { return m_prev; }
277 
278     //!
279     //! \brief  Gets the next memory block
280     //! \return The next adjacent block \see m_next
281     //!
GetNext()282     MemoryBlockInternal *GetNext() { return m_next; }
283 
284     //!
285     //! \brief  Gets the heap of the memory block
286     //! \return The heap that this block belongs to \see m_heap
287     //!
GetHeap()288     Heap *GetHeap()
289     {
290         if (m_heap != nullptr)
291         {
292             if (!m_heap->IsValid())
293             {
294                 HEAP_ASSERTMESSAGE("Memory block does not have a valid heap to return");
295                 return nullptr;
296             }
297         }
298         return m_heap;
299     }
300 
301 private:
302     //! \brief The heap referred to by the memory block
303     Heap *m_heap = nullptr;
304     //! \brief The relative offset of the memory block within the heap.
305     uint32_t m_offset = 0;
306     //! \brief Size of the memory block.
307     uint32_t m_size = 0;
308     //! \brief State of this memory block
309     State m_state = State::pool;
310     //! \brief   Static memory blocks are controlled by the client and may not be auto-freed
311     //! \details Since the client controls static blocks, static blocks are allowed to have
312     //!          invalid tracker IDs.
313     bool m_static = false;
314     //! \brief Software tag used to determine whether or not a memory block is still in use.
315     uint32_t m_trackerId = m_invalidTrackerId;
316     //! \brief Multiple software tags used to determine whether or not a memory block is still in use.
317     FrameTrackerToken m_trackerToken;
318 
319     //! \brief   The previous block in memory, this block is adjacent in heap memory.
320     //! \details Due to the way that the memory manager handles heap memory block lists--by having
321     //!          a dummy block at the start of a heaps block list, this pointer is always expected to
322     //!          be valid for non-pool state blocks.
323     MemoryBlockInternal *m_prev = nullptr;
324     //! \brief   The next block in memory, this block is adjacent in heap memory.
325     //! \details If this block is at the end of the heap, the next block is expected to be nullptr.
326     MemoryBlockInternal *m_next = nullptr;
327 
328     //! \brief Previous sorted block, nullptr if this block is the first in the sorted list
329     MemoryBlockInternal *m_statePrev = nullptr;
330     //! \brief Next block in sorted list, nullptr if this block is last in the sorted list
331     MemoryBlockInternal *m_stateNext = nullptr;
332     //! \brief State type for the sorted list to which this block belongs, if between lists type is stateCount
333     State m_stateListType = State::stateCount;
334 };
335 
336 //! \brief Describes a block of memory in a heap.
337 class MemoryBlock
338 {
339     friend class MemoryBlockManager;
340 
341 public:
MemoryBlock()342     MemoryBlock()
343     {
344         HEAP_FUNCTION_ENTER_VERBOSE;
345         m_resource = nullptr;
346     }
347 
~MemoryBlock()348     virtual ~MemoryBlock() { HEAP_FUNCTION_ENTER_VERBOSE; }
349 
350     //!
351     //! \brief  Add data to the memory block.
352     //! \param  [in] data
353     //!         Pointer containint data to insert, must be valid
354     //! \param  [in] dataOffset
355     //!         Relative offset where the data should be inserted within the
356     //!         memory block.
357     //! \param  [in] dataSize
358     //!         Size of the data to be copied from \a data.
359     //! \param  [in] zeroBlock
360     //!         Zeros the entire block, other parameters are not considered
361     //! \return MOS_STATUS
362     //!         MOS_STATUS_SUCCESS if success, else fail reason
363     //!
364     MOS_STATUS AddData(
365         void* data,
366         uint32_t dataOffset,
367         uint32_t dataSize,
368         bool zeroBlock = false)
369     {
370         if (!m_valid || m_block == nullptr)
371         {
372             HEAP_ASSERTMESSAGE("The memory block is not valid!");
373             return MOS_STATUS_INVALID_PARAMETER;
374         }
375         return m_block->AddData(data, dataOffset, dataSize, zeroBlock);
376     }
377 
378     //!
379     //! \brief  Read data from the memory block.
380     //! \param  [out] data
381     //!         Pointer to data returned from memory block, must be valid
382     //! \param  [in] dataOffset
383     //!         Relative offset where the data will be read from within the
384     //!         memory block.
385     //! \param  [in] dataSize
386     //!         Size of the data to be copied to \a data.
387     //! \return MOS_STATUS
388     //!         MOS_STATUS_SUCCESS if success, else fail reason
389     //!
ReadData(void * data,uint32_t dataOffset,uint32_t dataSize)390     MOS_STATUS ReadData(
391         void* data,
392         uint32_t dataOffset,
393         uint32_t dataSize)
394     {
395         if (!m_valid || m_block == nullptr)
396         {
397             HEAP_ASSERTMESSAGE("The memory block is not valid!");
398             return MOS_STATUS_INVALID_PARAMETER;
399         }
400 
401         return m_block->ReadData(data, dataOffset, dataSize);
402     }
403 
404     //!
405     //! \brief  Dumps the contents of this memory block
406     //! \param  [in] filename
407     //!         The file to be written, includes path
408     //! \param  [in] offset
409     //!         Additional offset to be added to this memory block's offest
410     //! \param  [in] size
411     //!         Size of the data to be dumped, cannot be greater than this memory block's size
412     //! \param  [in] dumpInBinary
413     //!         Dump the data as binary instead of 32-bit hex segments
414     //! \return MOS_STATUS
415     //!         MOS_STATUS_SUCCESS if success, else fail reason
416     //!
417     MOS_STATUS Dump(
418         std::string filename,
419         uint32_t offset = 0,
420         uint32_t size = 0,
421         bool dumpInBinary = false)
422     {
423         if (!m_valid || m_block == nullptr)
424         {
425             HEAP_ASSERTMESSAGE("The memory block is not valid!");
426             return MOS_STATUS_INVALID_PARAMETER;
427         }
428         return m_block->Dump(filename, offset, size, dumpInBinary);
429     }
430 
431     //!
432     //! \brief  Indicates whether or not the memory block is static
433     //! \return If this block is static \see m_static
434     //!
IsValid()435     bool IsValid() { return m_valid; }
436 
437     //!
438     //! \brief  Gets the relative offset of the memory block
439     //! \return The relative offset of this block in the heap \see m_offset
440     //!
GetOffset()441     uint32_t GetOffset() { return m_offset; }
442 
443     //!
444     //! \brief  Gets the size of the memory block
445     //! \return The size of this block \see m_size
446     //!
GetSize()447     uint32_t GetSize() { return m_size; }
448 
449     //!
450     //! \brief  Gets the tracker ID
451     //! \return This block's tracker ID \see m_trackerId
452     //!
GetTrackerId()453     uint32_t GetTrackerId() { return m_trackerId; }
454 
455     //!
456     //! \brief  Indicates whether or not the memory block is static
457     //! \return If this block is static \see m_static
458     //!
IsStatic()459     bool IsStatic() { return m_static; }
460 
461     //!
462     //! \brief  Gets the heap of the memory block
463     //! \return The heap that this block belongs to \see m_heap
464     //!
GetResource()465     MOS_RESOURCE* GetResource()
466     {
467         HEAP_FUNCTION_ENTER_VERBOSE;
468         if (!m_valid)
469         {
470             HEAP_ASSERTMESSAGE("The memory block is not valid!");
471             return nullptr;
472         }
473         if (Mos_ResourceIsNull(m_resource))
474         {
475             HEAP_ASSERTMESSAGE("The heap resource is invalid");
476             return nullptr;
477         }
478         return m_resource;
479     }
480 
481     //!
482     //! \brief  Gets the size of the heap to which the memory block belongs
483     //! \return The size of the associated heap \see m_heapSize
484     //!
GetHeapSize()485     uint32_t GetHeapSize() { return m_heapSize; }
486 
487 #if (_DEBUG || _RELEASE_INTERNAL)
488     //!
489     //! \brief   Gets the locked heap
490     //! \details To be used when the memory block dump is insufficient.
491     //! \return  Pointer to the locked heap data \see m_lockedHeap
492     //!
GetHeapLockedData()493     uint8_t* GetHeapLockedData() { return m_lockedHeap; }
494 #endif
495 
496     //! \brief Invalid value to be read from the tracker data \see MemoryBlockInternalManager::m_pTrackerData
497     static const uint32_t m_invalidTrackerId = MemoryBlockInternal::m_invalidTrackerId;
498 
499 protected:
500     //!
501     //! \brief  Initializes memory block based on provided inputs
502     //! \param  [in] internalBlock
503     //!         Internal block used to initialize this memory block
504     //! \param  [in] heap
505     //!         Heap used to initialize this memory block
506     //! \return MOS_STATUS
507     //!         MOS_STATUS_SUCCESS if success, else fail reason
508     //!
CreateFromInternalBlock(MemoryBlockInternal * internalBlock,Heap * heap,uint8_t * lockedHeap)509     MOS_STATUS CreateFromInternalBlock(
510         MemoryBlockInternal *internalBlock,
511         Heap *heap,
512         uint8_t *lockedHeap)
513     {
514         HEAP_CHK_NULL(internalBlock);
515         HEAP_CHK_NULL(heap);
516         if (!heap->IsValid())
517         {
518             HEAP_ASSERTMESSAGE("Memory block does not have a valid heap to return");
519             return MOS_STATUS_INVALID_PARAMETER;
520         }
521         HEAP_CHK_NULL(m_resource = heap->GetResource());
522         m_heapSize = heap->GetSize();
523 #if (_DEBUG || _RELEASE_INTERNAL)
524         m_lockedHeap = lockedHeap;
525 #endif
526         m_offset = internalBlock->GetOffset();
527         m_size = internalBlock->GetSize();
528         m_static = internalBlock->IsStatic();
529         m_trackerId = internalBlock->GetTrackerId();
530         m_block = internalBlock;
531         m_valid = true;
532         return MOS_STATUS_SUCCESS;
533     }
534 
535     //!
536     //! \brief  Gets the internal memory block
537     //! \return The internal memory block backing up this data
538     //!
GetInternalBlock()539     MemoryBlockInternal *GetInternalBlock() { return m_block; }
540 
541 private:
542     bool m_valid = false;       //!< Memory block is valid.
543     MOS_RESOURCE *m_resource;    //!< Graphics resource for the heap
544 #if (_DEBUG || _RELEASE_INTERNAL)
545     uint8_t *m_lockedHeap = nullptr;    //!< Pointer to the locked heap data, only valid if kept locked
546 #endif
547     uint32_t m_heapSize = 0;    //!< Size of the heap
548     uint32_t m_offset = 0;      //!< relative offset of the memory block within the heap.
549     uint32_t m_size = 0;        //!< Size of the memory block.
550     //! \brief   Static memory blocks are controlled by the client and may not be auto-freed
551     //! \details Since the client controls static blocks, static blocks are allowed to have
552     //!          invalid tracker IDs.
553     bool m_static = false;
554     //! \brief Software tag used to determine whether or not a memory block is still in use.
555     uint32_t m_trackerId = m_invalidTrackerId;
556     MemoryBlockInternal *m_block = nullptr; //!< Reference to the internal memory block
557 };
558 
559 #endif // __MEMORY_BLOCK_H__