]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/memoryallocator.cpp
Initial implementation of Vulkan backend
[libs/gl.git] / source / backends / vulkan / memoryallocator.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/graphics/vulkancontext_platform.h>
3 #include "device.h"
4 #include "error.h"
5 #include "memoryallocator.h"
6 #include "vulkan.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12
13 MemoryAllocator::MemoryAllocator(Device &d):
14         device(d),
15         phys_device(handle_cast<VkPhysicalDevice>(device.get_context().get_private().physical_device))
16 {
17         const VulkanFunctions &vk = device.get_functions();
18
19         VkPhysicalDeviceMemoryProperties mem_props;
20         vk.GetPhysicalDeviceMemoryProperties(mem_props);
21
22         const VkMemoryPropertyFlags host_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
23         memory_types.reserve(mem_props.memoryTypeCount);
24         for(unsigned i=0; i<mem_props.memoryTypeCount; ++i)
25         {
26                 VkMemoryPropertyFlags flags = mem_props.memoryTypes[i].propertyFlags;
27                 MemoryType type = UNKNOWN_MEMORY;
28                 if(flags&VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
29                 {
30                         if((flags&host_flags)==host_flags)
31                                 type = STREAMING_MEMORY;
32                         else
33                                 type = DEVICE_MEMORY;
34                 }
35                 else if((flags&host_flags)==host_flags)
36                         type = STAGING_MEMORY;
37                 memory_types.push_back(type);
38         }
39 }
40
41 unsigned MemoryAllocator::find_memory_type_index(unsigned mask, MemoryType type)
42 {
43         for(unsigned i=0; i<memory_types.size(); ++i)
44                 if((mask&(1<<i)) && memory_types[i]==type)
45                         return i;
46         if(type==DEVICE_MEMORY || type==STAGING_MEMORY)
47                 return find_memory_type_index(mask, STREAMING_MEMORY);
48         throw runtime_error("Unable to find suitable memory type");
49 }
50
51 unsigned MemoryAllocator::allocate(size_t size, unsigned type_bits, MemoryType type)
52 {
53         const VulkanFunctions &vk = device.get_functions();
54
55         VkMemoryAllocateInfo alloc_info = { };
56         alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
57         alloc_info.allocationSize = size;
58         alloc_info.memoryTypeIndex = find_memory_type_index(type_bits, type);
59
60         Allocation alloc;
61         vk.AllocateMemory(alloc_info, alloc.memory);
62
63         alloc.type = type;
64         alloc.size = size;
65         allocations.push_back(alloc);
66
67         return allocations.size();
68 }
69
70 MemoryAllocator::Allocation &MemoryAllocator::get_allocation(unsigned id)
71 {
72         return allocations[id-1];
73 }
74
75 const MemoryAllocator::Allocation &MemoryAllocator::get_allocation(unsigned id) const
76 {
77         return allocations[id-1];
78 }
79
80 unsigned MemoryAllocator::allocate(VkBuffer buffer, MemoryType type)
81 {
82         const VulkanFunctions &vk = device.get_functions();
83
84         VkMemoryRequirements requirements;
85         vk.GetBufferMemoryRequirements(buffer, requirements);
86
87         unsigned id = allocate(requirements.size, requirements.memoryTypeBits, type);
88
89         vk.BindBufferMemory(buffer, get_allocation(id).memory, 0);
90
91         return id;
92 }
93
94 void MemoryAllocator::release(unsigned id)
95 {
96         Allocation &alloc = get_allocation(id);
97         if(!alloc.memory)
98                 throw invalid_operation("MemoryAllocator::release");
99
100         const VulkanFunctions &vk = device.get_functions();
101
102         vk.FreeMemory(alloc.memory);
103 }
104
105 size_t MemoryAllocator::get_allocation_size(unsigned id) const
106 {
107         return get_allocation(id).size;
108 }
109
110 void *MemoryAllocator::map(unsigned id, size_t offset, size_t size)
111 {
112         Allocation &alloc = get_allocation(id);
113         if(alloc.mapped_address)
114                 throw invalid_operation("MemoryAllocator::map");
115
116         const VulkanFunctions &vk = device.get_functions();
117
118         vk.MapMemory(alloc.memory, offset, size, 0, &alloc.mapped_address);
119
120         return alloc.mapped_address;
121 }
122
123 void MemoryAllocator::unmap(void *ptr)
124 {
125         auto i = find_member(allocations, ptr, &Allocation::mapped_address);
126         if(i==allocations.end())
127                 throw invalid_operation("MemoryAllocator::unmap");
128
129         const VulkanFunctions &vk = device.get_functions();
130
131         vk.UnmapMemory(i->memory);
132         i->mapped_address = 0;
133 }
134
135 } // namespace GL
136 } // namespace Msp