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