Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/metal/mtl_memory.mm
| Show All 19 Lines | |||||
| { | { | ||||
| if (!ensure_initialised_) { | if (!ensure_initialised_) { | ||||
| BLI_assert(mtl_device); | BLI_assert(mtl_device); | ||||
| ensure_initialised_ = true; | ensure_initialised_ = true; | ||||
| device_ = mtl_device; | device_ = mtl_device; | ||||
| #if MTL_DEBUG_MEMORY_STATISTICS == 1 | #if MTL_DEBUG_MEMORY_STATISTICS == 1 | ||||
| /* Debug statistics. */ | /* Debug statistics. */ | ||||
| total_allocation_bytes_ = 0; | |||||
| per_frame_allocation_count_ = 0; | per_frame_allocation_count_ = 0; | ||||
| allocations_in_pool_ = 0; | allocations_in_pool_ = 0; | ||||
| buffers_in_pool_ = 0; | buffers_in_pool_ = 0; | ||||
| #endif | #endif | ||||
| /* Free pools -- Create initial safe free pool */ | /* Free pools -- Create initial safe free pool */ | ||||
| BLI_assert(current_free_list_ == nullptr); | BLI_assert(current_free_list_ == nullptr); | ||||
| this->begin_new_safe_list(); | this->begin_new_safe_list(); | ||||
| } | } | ||||
| } | } | ||||
| MTLBufferPool::~MTLBufferPool() | MTLBufferPool::~MTLBufferPool() | ||||
| { | { | ||||
| this->free(); | this->free(); | ||||
| } | } | ||||
| void MTLBufferPool::free() | void MTLBufferPool::free() | ||||
| { | { | ||||
| buffer_pool_lock_.lock(); | |||||
| for (auto buffer : allocations_) { | for (auto buffer : allocations_) { | ||||
| BLI_assert(buffer); | BLI_assert(buffer); | ||||
| delete buffer; | delete buffer; | ||||
| } | } | ||||
| allocations_.clear(); | allocations_.clear(); | ||||
| for (std::multiset<blender::gpu::MTLBufferHandle, blender::gpu::CompareMTLBuffer> *buffer_pool : | for (std::multiset<blender::gpu::MTLBufferHandle, blender::gpu::CompareMTLBuffer> *buffer_pool : | ||||
| buffer_pools_.values()) { | buffer_pools_.values()) { | ||||
| delete buffer_pool; | delete buffer_pool; | ||||
| } | } | ||||
| buffer_pools_.clear(); | buffer_pools_.clear(); | ||||
| buffer_pool_lock_.unlock(); | |||||
| } | } | ||||
| gpu::MTLBuffer *MTLBufferPool::allocate(uint64_t size, bool cpu_visible) | gpu::MTLBuffer *MTLBufferPool::allocate(uint64_t size, bool cpu_visible) | ||||
| { | { | ||||
| /* Allocate buffer with default HW-compatible alignment of 256 bytes. | /* Allocate buffer with default HW-compatible alignment of 256 bytes. | ||||
| * See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf for more. */ | * See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf for more. */ | ||||
| return this->allocate_aligned(size, 256, cpu_visible); | return this->allocate_aligned(size, 256, cpu_visible); | ||||
| } | } | ||||
| Show All 25 Lines | options = ([device_ hasUnifiedMemory]) ? MTLResourceStorageModeShared : | ||||
| MTLResourceStorageModeManaged; | MTLResourceStorageModeManaged; | ||||
| } | } | ||||
| else { | else { | ||||
| options = MTLResourceStorageModePrivate; | options = MTLResourceStorageModePrivate; | ||||
| } | } | ||||
| /* Check if we have a suitable buffer */ | /* Check if we have a suitable buffer */ | ||||
| gpu::MTLBuffer *new_buffer = nullptr; | gpu::MTLBuffer *new_buffer = nullptr; | ||||
| buffer_pool_lock_.lock(); | |||||
| std::multiset<MTLBufferHandle, CompareMTLBuffer> **pool_search = buffer_pools_.lookup_ptr( | std::multiset<MTLBufferHandle, CompareMTLBuffer> **pool_search = buffer_pools_.lookup_ptr( | ||||
| (uint64_t)options); | (uint64_t)options); | ||||
| if (pool_search != nullptr) { | if (pool_search != nullptr) { | ||||
| std::multiset<MTLBufferHandle, CompareMTLBuffer> *pool = *pool_search; | std::multiset<MTLBufferHandle, CompareMTLBuffer> *pool = *pool_search; | ||||
| MTLBufferHandle size_compare(aligned_alloc_size); | MTLBufferHandle size_compare(aligned_alloc_size); | ||||
| auto result = pool->lower_bound(size_compare); | auto result = pool->lower_bound(size_compare); | ||||
| if (result != pool->end()) { | if (result != pool->end()) { | ||||
| Show All 30 Lines | gpu::MTLBuffer *MTLBufferPool::allocate_aligned(uint64_t size, | ||||
| } | } | ||||
| /* Allocate new buffer. */ | /* Allocate new buffer. */ | ||||
| if (new_buffer == nullptr) { | if (new_buffer == nullptr) { | ||||
| new_buffer = new gpu::MTLBuffer(device_, size, options, alignment); | new_buffer = new gpu::MTLBuffer(device_, size, options, alignment); | ||||
| /* Track allocation in context. */ | /* Track allocation in context. */ | ||||
| allocations_.append(new_buffer); | allocations_.append(new_buffer); | ||||
| #if MTL_DEBUG_MEMORY_STATISTICS == 1 | |||||
| total_allocation_bytes_ += aligned_alloc_size; | total_allocation_bytes_ += aligned_alloc_size; | ||||
| #endif | |||||
| } | } | ||||
| else { | else { | ||||
| /* Re-use suitable buffer. */ | /* Re-use suitable buffer. */ | ||||
| new_buffer->set_usage_size(aligned_alloc_size); | new_buffer->set_usage_size(aligned_alloc_size); | ||||
| #if MTL_DEBUG_MEMORY_STATISTICS == 1 | #if MTL_DEBUG_MEMORY_STATISTICS == 1 | ||||
| /* Debug. */ | /* Debug. */ | ||||
| allocations_in_pool_ -= new_buffer->get_size(); | allocations_in_pool_ -= new_buffer->get_size(); | ||||
| buffers_in_pool_--; | buffers_in_pool_--; | ||||
| BLI_assert(allocations_in_pool_ >= 0); | BLI_assert(allocations_in_pool_ >= 0); | ||||
| #endif | #endif | ||||
| /* Ensure buffer memory is correctly backed. */ | /* Ensure buffer memory is correctly backed. */ | ||||
| BLI_assert(new_buffer->get_metal_buffer()); | BLI_assert(new_buffer->get_metal_buffer()); | ||||
| } | } | ||||
| /* Flag buffer as actively in-use. */ | /* Flag buffer as actively in-use. */ | ||||
| new_buffer->flag_in_use(true); | new_buffer->flag_in_use(true); | ||||
| #if MTL_DEBUG_MEMORY_STATISTICS == 1 | #if MTL_DEBUG_MEMORY_STATISTICS == 1 | ||||
| per_frame_allocation_count_++; | per_frame_allocation_count_++; | ||||
| #endif | #endif | ||||
| /* Release lock. */ | |||||
| buffer_pool_lock_.unlock(); | |||||
| return new_buffer; | return new_buffer; | ||||
| } | } | ||||
| gpu::MTLBuffer *MTLBufferPool::allocate_aligned_with_data(uint64_t size, | gpu::MTLBuffer *MTLBufferPool::allocate_aligned_with_data(uint64_t size, | ||||
| uint32_t alignment, | uint32_t alignment, | ||||
| bool cpu_visible, | bool cpu_visible, | ||||
| const void *data) | const void *data) | ||||
| { | { | ||||
| Show All 28 Lines | bool MTLBufferPool::free_buffer(gpu::MTLBuffer *buffer) | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void MTLBufferPool::update_memory_pools() | void MTLBufferPool::update_memory_pools() | ||||
| { | { | ||||
| /* Ensure thread-safe access to `completed_safelist_queue_`, which contains | /* Ensure thread-safe access to `completed_safelist_queue_`, which contains | ||||
| * the list of MTLSafeFreeList's whose buffers are ready to be | * the list of MTLSafeFreeList's whose buffers are ready to be | ||||
| * re-inserted into the Memory Manager pools. */ | * re-inserted into the Memory Manager pools. | ||||
| * we also need to lock access to general buffer pools, to ensure allocations | |||||
| * are not simultaneously happening on background threads. */ | |||||
| safelist_lock_.lock(); | safelist_lock_.lock(); | ||||
| buffer_pool_lock_.lock(); | |||||
| #if MTL_DEBUG_MEMORY_STATISTICS == 1 | #if MTL_DEBUG_MEMORY_STATISTICS == 1 | ||||
| int num_buffers_added = 0; | int num_buffers_added = 0; | ||||
| #endif | #endif | ||||
| /* Always free oldest MTLSafeFreeList first. */ | /* Always free oldest MTLSafeFreeList first. */ | ||||
| for (int safe_pool_free_index = 0; safe_pool_free_index < completed_safelist_queue_.size(); | for (int safe_pool_free_index = 0; safe_pool_free_index < completed_safelist_queue_.size(); | ||||
| safe_pool_free_index++) { | safe_pool_free_index++) { | ||||
| ▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | while (key_iterator != buffer_pools_.keys().end()) { | ||||
| ++value_iterator; | ++value_iterator; | ||||
| } | } | ||||
| per_frame_allocation_count_ = 0; | per_frame_allocation_count_ = 0; | ||||
| #endif | #endif | ||||
| /* Clear safe pools list */ | /* Clear safe pools list */ | ||||
| completed_safelist_queue_.clear(); | completed_safelist_queue_.clear(); | ||||
| buffer_pool_lock_.unlock(); | |||||
| safelist_lock_.unlock(); | safelist_lock_.unlock(); | ||||
| } | } | ||||
| void MTLBufferPool::push_completed_safe_list(MTLSafeFreeList *safe_list) | void MTLBufferPool::push_completed_safe_list(MTLSafeFreeList *safe_list) | ||||
| { | { | ||||
| /* When an MTLSafeFreeList has been released by the GPU, and buffers are ready to | /* When an MTLSafeFreeList has been released by the GPU, and buffers are ready to | ||||
| * be re-inserted into the MemoryManager pools for future use, add the MTLSafeFreeList | * be re-inserted into the MemoryManager pools for future use, add the MTLSafeFreeList | ||||
| * to the `completed_safelist_queue_` for flushing at a controlled point in time. */ | * to the `completed_safelist_queue_` for flushing at a controlled point in time. */ | ||||
| ▲ Show 20 Lines • Show All 585 Lines • Show Last 20 Lines | |||||