--- /dev/null
+#include <msp/core/algorithm.h>
+#include <msp/graphics/vulkancontext_platform.h>
+#include "device.h"
+#include "error.h"
+#include "memoryallocator.h"
+#include "vulkan.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+MemoryAllocator::MemoryAllocator(Device &d):
+ device(d),
+ phys_device(handle_cast<VkPhysicalDevice>(device.get_context().get_private().physical_device))
+{
+ const VulkanFunctions &vk = device.get_functions();
+
+ VkPhysicalDeviceMemoryProperties mem_props;
+ vk.GetPhysicalDeviceMemoryProperties(mem_props);
+
+ const VkMemoryPropertyFlags host_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ memory_types.reserve(mem_props.memoryTypeCount);
+ for(unsigned i=0; i<mem_props.memoryTypeCount; ++i)
+ {
+ VkMemoryPropertyFlags flags = mem_props.memoryTypes[i].propertyFlags;
+ MemoryType type = UNKNOWN_MEMORY;
+ if(flags&VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
+ {
+ if((flags&host_flags)==host_flags)
+ type = STREAMING_MEMORY;
+ else
+ type = DEVICE_MEMORY;
+ }
+ else if((flags&host_flags)==host_flags)
+ type = STAGING_MEMORY;
+ memory_types.push_back(type);
+ }
+}
+
+unsigned MemoryAllocator::find_memory_type_index(unsigned mask, MemoryType type)
+{
+ for(unsigned i=0; i<memory_types.size(); ++i)
+ if((mask&(1<<i)) && memory_types[i]==type)
+ return i;
+ if(type==DEVICE_MEMORY || type==STAGING_MEMORY)
+ return find_memory_type_index(mask, STREAMING_MEMORY);
+ throw runtime_error("Unable to find suitable memory type");
+}
+
+unsigned MemoryAllocator::allocate(size_t size, unsigned type_bits, MemoryType type)
+{
+ const VulkanFunctions &vk = device.get_functions();
+
+ VkMemoryAllocateInfo alloc_info = { };
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ alloc_info.allocationSize = size;
+ alloc_info.memoryTypeIndex = find_memory_type_index(type_bits, type);
+
+ Allocation alloc;
+ vk.AllocateMemory(alloc_info, alloc.memory);
+
+ alloc.type = type;
+ alloc.size = size;
+ allocations.push_back(alloc);
+
+ return allocations.size();
+}
+
+MemoryAllocator::Allocation &MemoryAllocator::get_allocation(unsigned id)
+{
+ return allocations[id-1];
+}
+
+const MemoryAllocator::Allocation &MemoryAllocator::get_allocation(unsigned id) const
+{
+ return allocations[id-1];
+}
+
+unsigned MemoryAllocator::allocate(VkBuffer buffer, MemoryType type)
+{
+ const VulkanFunctions &vk = device.get_functions();
+
+ VkMemoryRequirements requirements;
+ vk.GetBufferMemoryRequirements(buffer, requirements);
+
+ unsigned id = allocate(requirements.size, requirements.memoryTypeBits, type);
+
+ vk.BindBufferMemory(buffer, get_allocation(id).memory, 0);
+
+ return id;
+}
+
+void MemoryAllocator::release(unsigned id)
+{
+ Allocation &alloc = get_allocation(id);
+ if(!alloc.memory)
+ throw invalid_operation("MemoryAllocator::release");
+
+ const VulkanFunctions &vk = device.get_functions();
+
+ vk.FreeMemory(alloc.memory);
+}
+
+size_t MemoryAllocator::get_allocation_size(unsigned id) const
+{
+ return get_allocation(id).size;
+}
+
+void *MemoryAllocator::map(unsigned id, size_t offset, size_t size)
+{
+ Allocation &alloc = get_allocation(id);
+ if(alloc.mapped_address)
+ throw invalid_operation("MemoryAllocator::map");
+
+ const VulkanFunctions &vk = device.get_functions();
+
+ vk.MapMemory(alloc.memory, offset, size, 0, &alloc.mapped_address);
+
+ return alloc.mapped_address;
+}
+
+void MemoryAllocator::unmap(void *ptr)
+{
+ auto i = find_member(allocations, ptr, &Allocation::mapped_address);
+ if(i==allocations.end())
+ throw invalid_operation("MemoryAllocator::unmap");
+
+ const VulkanFunctions &vk = device.get_functions();
+
+ vk.UnmapMemory(i->memory);
+ i->mapped_address = 0;
+}
+
+} // namespace GL
+} // namespace Msp