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__