fa23ccf247b07f8176ea70d09aebea8dbf41e936
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / gpu-memory / vulkan-gpu-memory-manager.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
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>
24 #include <atomic>
25 namespace Dali
26 {
27 namespace Graphics
28 {
29 namespace Vulkan
30 {
31
32 namespace
33 {
34
35 const uint32_t INVALID_MEMORY_INDEX = -1u;
36
37 /**
38  * Helper function which returns GPU heap index that can be used to allocate
39  * particular type of resource
40  */
41 uint32_t GetMemoryIndex(const vk::PhysicalDeviceMemoryProperties &memoryProperties,
42                         uint32_t memoryTypeBits, vk::MemoryPropertyFlags properties)
43 {
44   for(uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
45   {
46     if((memoryTypeBits & (1u << i)) &&
47        ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties))
48     {
49       return i;
50     }
51   }
52   return INVALID_MEMORY_INDEX;
53 }
54 }
55
56 /**
57  * Class: GpuMemoryDefaultAllocator
58  *
59  * Non-thread safe default GPU memory allocator
60  * with simple refcounting and garbage collection on demand
61  */
62 struct GpuMemoryDefaultAllocator : public GpuMemoryAllocator
63 {
64   struct MemoryBlock
65   {
66     MemoryBlock() = default;
67     ~MemoryBlock() = default;
68
69     vk::MemoryRequirements  requirements {};
70     vk::DeviceSize          offset { 0u };
71     vk::DeviceSize          size { 0u };
72     vk::DeviceSize          alignment { 0u };
73     vk::DeviceMemory        memory { nullptr };
74   };
75
76   GpuMemoryDefaultAllocator( GpuMemoryManager& manager )
77     : GpuMemoryAllocator(), mGpuManager( manager ),
78       mGraphics(manager.GetGraphics())
79   {
80
81   }
82
83   ~GpuMemoryDefaultAllocator() override = default;
84
85
86   RefCountedGpuMemoryBlock Allocate( const vk::MemoryRequirements& requirements, vk::MemoryPropertyFlags memoryProperties ) override
87   {
88
89     auto memoryTypeIndex = GetMemoryIndex(mGraphics.GetMemoryProperties(), requirements.memoryTypeBits,
90                                           memoryProperties);
91
92     auto memory = VkAssert(
93       mGraphics.GetDevice()
94                .allocateMemory(vk::MemoryAllocateInfo{}
95                                  .setMemoryTypeIndex(memoryTypeIndex)
96                                  .setAllocationSize(requirements.size), mGraphics.GetAllocator()));
97
98     // add allocated memory to the heap of memories as a base handle
99     auto handle = RefCountedGpuMemoryBlock( new GpuMemoryBlock( *this, MakeUnique<MemoryBlock>() ) );
100
101     auto &block = *handle->GetData<MemoryBlock>();
102     block.requirements = requirements;
103     block.offset       = 0u;
104     block.size         = requirements.size;
105     block.alignment    = requirements.alignment;
106     block.memory       = memory;
107
108     mUniqueBlocks.emplace_back( MakeUnique<RefCountedGpuMemoryBlock>(handle) );
109     return handle;
110   }
111
112   /**
113    *
114    * @param buffer
115    * @param memoryProperties
116    * @return
117    */
118   virtual RefCountedGpuMemoryBlock Allocate( const Handle<Buffer>& buffer, vk::MemoryPropertyFlags memoryProperties ) override
119   {
120     return Allocate( mGraphics.GetDevice().getBufferMemoryRequirements(buffer->GetVkHandle() ),
121                      memoryProperties );
122   }
123
124   /**
125    *
126    * @param buffer
127    * @param memoryProperties
128    * @return
129    */
130   RefCountedGpuMemoryBlock Allocate( const RefCountedImage& image, vk::MemoryPropertyFlags memoryProperties ) override
131   {
132     return Allocate( mGraphics.GetDevice().getImageMemoryRequirements(image->GetVkHandle() ),
133                                memoryProperties );
134   }
135
136   /**
137    *
138    * Reference counting
139    */
140   void Retain( GpuMemoryBlock& allocationId ) override
141   {
142   }
143
144   void Release( GpuMemoryBlock& block ) override
145   {
146     if( block.GetRefCount() == 1 )
147     {
148       GC(nullptr);
149     }
150   }
151
152   /**
153    *
154    * Garbage collection
155    */
156   void GC( void* userdata ) override
157   {
158     for( auto&& block : mUniqueBlocks )
159     {
160       if( block->GetRefCount() == 1 )
161       {
162         // collect and make invalid ( maybe freelist or sumtink )
163         mGraphics.GetDevice().freeMemory( (**block.get()), mGraphics.GetAllocator() );
164         block.reset( nullptr );
165       }
166     }
167   }
168
169   vk::DeviceMemory GetVkDeviceMemory( GpuMemoryBlock& block ) const override
170   {
171     return block.GetData<MemoryBlock>()->memory;
172   }
173
174   void* Map( GpuMemoryBlock& block, uint32_t offset, uint32_t size ) override
175   {
176     return VkAssert( mGraphics.GetDevice().mapMemory( block.GetData<MemoryBlock>()->memory,
177                                 offset, size == 0u ? VK_WHOLE_SIZE : static_cast<VkDeviceSize>(size)));
178   }
179
180   void Unmap( GpuMemoryBlock& block ) override
181   {
182     mGraphics.GetDevice().unmapMemory( block.GetData<MemoryBlock>()->memory );
183   }
184
185   void Flush( GpuMemoryBlock& allocationId ) override
186   {
187     NotImplemented();
188   }
189
190   GpuMemoryManager& mGpuManager;
191   Graphics& mGraphics;
192
193   std::vector<std::unique_ptr<RefCountedGpuMemoryBlock>> mUniqueBlocks;
194 };
195
196 struct GpuMemoryManager::Impl
197 {
198   Impl( Graphics& graphics, GpuMemoryManager& interface ) :
199     mGraphics( graphics ),
200     mMemoryManager( interface )
201   {
202
203   }
204
205   ~Impl()
206   {
207   }
208
209   bool Initialise()
210   {
211     CreateDefaultAllocator();
212     return true;
213   }
214
215   GpuMemoryAllocator& GetDefaultAllocator() const
216   {
217     return *mDefaultAllocator;
218   }
219
220   void CreateDefaultAllocator()
221   {
222     mDefaultAllocator = MakeUnique<GpuMemoryDefaultAllocator>( mMemoryManager );
223   }
224
225   Graphics& mGraphics;
226   GpuMemoryManager& mMemoryManager; // interface to this implementation
227   std::unique_ptr<GpuMemoryAllocator> mDefaultAllocator; // default allocator, brute force allocation
228 };
229
230 /**
231  * Class: GpuMemoryManager
232  */
233
234 std::unique_ptr<GpuMemoryManager> GpuMemoryManager::New(Graphics& graphics)
235 {
236   auto retval = std::unique_ptr<GpuMemoryManager>(new GpuMemoryManager(graphics));
237   if( retval->mImpl->Initialise() )
238   {
239     return retval;
240   }
241   return nullptr;
242 }
243
244 GpuMemoryManager::GpuMemoryManager() = default;
245
246 GpuMemoryManager::~GpuMemoryManager() = default;
247
248 GpuMemoryManager::GpuMemoryManager(Graphics& graphics)
249 {
250   mImpl = std::unique_ptr<Impl, std::default_delete<GpuMemoryManager::Impl>>( new Impl(graphics, *this) );
251 }
252
253 GpuMemoryAllocator& GpuMemoryManager::GetDefaultAllocator() const
254 {
255   return mImpl->GetDefaultAllocator();
256 }
257
258
259 GpuMemoryAllocatorUID GpuMemoryManager::RegisterAllocator( std::unique_ptr<GpuMemoryAllocator> allocator )
260 {
261   NotImplemented();
262   return 0;
263 }
264
265 bool GpuMemoryManager::UnregisterAllocator( GpuMemoryAllocatorUID allocatorHandle )
266 {
267   NotImplemented();
268   return false;
269 }
270
271 Graphics& GpuMemoryManager::GetGraphics() const
272 {
273   return mImpl->mGraphics;
274 }
275
276 }
277
278 }
279
280 }