2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
19 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h>
20 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
21 #include <dali/graphics/vulkan/vulkan-graphics.h>
22 #include <dali/graphics/vulkan/vulkan-buffer.h>
23 #include <dali/graphics/vulkan/vulkan-image.h>
35 const uint32_t INVALID_MEMORY_INDEX = -1u;
38 * Helper function which returns GPU heap index that can be used to allocate
39 * particular type of resource
41 uint32_t GetMemoryIndex(const vk::PhysicalDeviceMemoryProperties &memoryProperties,
42 uint32_t memoryTypeBits, vk::MemoryPropertyFlags properties)
44 for(uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
46 if((memoryTypeBits & (1u << i)) &&
47 ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties))
52 return INVALID_MEMORY_INDEX;
57 * Class: GpuMemoryDefaultAllocator
59 * Non-thread safe default GPU memory allocator
60 * with simple refcounting and garbage collection on demand
62 struct GpuMemoryDefaultAllocator : public GpuMemoryAllocator
66 MemoryBlock() = default;
67 ~MemoryBlock() = default;
69 vk::MemoryRequirements requirements {};
70 vk::DeviceSize offset { 0u };
71 vk::DeviceSize size { 0u };
72 vk::DeviceSize alignment { 0u };
73 vk::DeviceMemory memory { nullptr };
76 GpuMemoryDefaultAllocator( GpuMemoryManager& manager )
77 : GpuMemoryAllocator(), mGpuManager( manager ),
78 mGraphics(manager.GetGraphics())
83 ~GpuMemoryDefaultAllocator() override = default;
86 RefCountedGpuMemoryBlock Allocate( const vk::MemoryRequirements& requirements, vk::MemoryPropertyFlags memoryProperties ) override
89 auto memoryTypeIndex = GetMemoryIndex(mGraphics.GetMemoryProperties(), requirements.memoryTypeBits,
92 auto memory = VkAssert(
94 .allocateMemory(vk::MemoryAllocateInfo{}
95 .setMemoryTypeIndex(memoryTypeIndex)
96 .setAllocationSize(requirements.size), mGraphics.GetAllocator()));
98 // add allocated memory to the heap of memories as a base handle
99 auto handle = RefCountedGpuMemoryBlock( new GpuMemoryBlock( *this, MakeUnique<MemoryBlock>() ) );
101 auto &block = *handle->GetData<MemoryBlock>();
102 block.requirements = requirements;
104 block.size = requirements.size;
105 block.alignment = requirements.alignment;
106 block.memory = memory;
108 mUniqueBlocks.emplace_back( MakeUnique<RefCountedGpuMemoryBlock>(handle) );
115 * @param memoryProperties
118 virtual RefCountedGpuMemoryBlock Allocate( const Handle<Buffer>& buffer, vk::MemoryPropertyFlags memoryProperties ) override
120 return Allocate( mGraphics.GetDevice().getBufferMemoryRequirements(buffer->GetVkHandle() ),
127 * @param memoryProperties
130 RefCountedGpuMemoryBlock Allocate( const RefCountedImage& image, vk::MemoryPropertyFlags memoryProperties ) override
132 return Allocate( mGraphics.GetDevice().getImageMemoryRequirements(image->GetVkHandle() ),
140 void Retain( GpuMemoryBlock& allocationId ) override
144 void Release( GpuMemoryBlock& block ) override
146 if( block.GetRefCount() == 1 )
156 void GC( void* userdata ) override
158 for( auto&& block : mUniqueBlocks )
160 if( block->GetRefCount() == 1 )
162 // collect and make invalid ( maybe freelist or sumtink )
163 mGraphics.GetDevice().freeMemory( (**block.get()), mGraphics.GetAllocator() );
164 block.reset( nullptr );
169 vk::DeviceMemory GetVkDeviceMemory( GpuMemoryBlock& block ) const override
171 return block.GetData<MemoryBlock>()->memory;
174 void* Map( GpuMemoryBlock& block, uint32_t offset, uint32_t size ) override
176 return VkAssert( mGraphics.GetDevice().mapMemory( block.GetData<MemoryBlock>()->memory,
177 offset, size == 0u ? VK_WHOLE_SIZE : static_cast<VkDeviceSize>(size)));
180 void Unmap( GpuMemoryBlock& block ) override
182 mGraphics.GetDevice().unmapMemory( block.GetData<MemoryBlock>()->memory );
185 void Flush( GpuMemoryBlock& allocationId ) override
190 GpuMemoryManager& mGpuManager;
193 std::vector<std::unique_ptr<RefCountedGpuMemoryBlock>> mUniqueBlocks;
196 struct GpuMemoryManager::Impl
198 Impl( Graphics& graphics, GpuMemoryManager& interface ) :
199 mGraphics( graphics ),
200 mMemoryManager( interface )
211 CreateDefaultAllocator();
215 GpuMemoryAllocator& GetDefaultAllocator() const
217 return *mDefaultAllocator;
220 void CreateDefaultAllocator()
222 mDefaultAllocator = MakeUnique<GpuMemoryDefaultAllocator>( mMemoryManager );
226 GpuMemoryManager& mMemoryManager; // interface to this implementation
227 std::unique_ptr<GpuMemoryAllocator> mDefaultAllocator; // default allocator, brute force allocation
231 * Class: GpuMemoryManager
234 std::unique_ptr<GpuMemoryManager> GpuMemoryManager::New(Graphics& graphics)
236 auto retval = std::unique_ptr<GpuMemoryManager>(new GpuMemoryManager(graphics));
237 if( retval->mImpl->Initialise() )
244 GpuMemoryManager::GpuMemoryManager() = default;
246 GpuMemoryManager::~GpuMemoryManager() = default;
248 GpuMemoryManager::GpuMemoryManager(Graphics& graphics)
250 mImpl = std::unique_ptr<Impl, std::default_delete<GpuMemoryManager::Impl>>( new Impl(graphics, *this) );
253 GpuMemoryAllocator& GpuMemoryManager::GetDefaultAllocator() const
255 return mImpl->GetDefaultAllocator();
259 GpuMemoryAllocatorUID GpuMemoryManager::RegisterAllocator( std::unique_ptr<GpuMemoryAllocator> allocator )
265 bool GpuMemoryManager::UnregisterAllocator( GpuMemoryAllocatorUID allocatorHandle )
271 Graphics& GpuMemoryManager::GetGraphics() const
273 return mImpl->mGraphics;