]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/memoryallocator.cpp
Initial implementation of Vulkan backend
[libs/gl.git] / source / backends / vulkan / memoryallocator.cpp
diff --git a/source/backends/vulkan/memoryallocator.cpp b/source/backends/vulkan/memoryallocator.cpp
new file mode 100644 (file)
index 0000000..6ffcc9f
--- /dev/null
@@ -0,0 +1,136 @@
+#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