-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathvulkan_ubo.cpp
More file actions
132 lines (110 loc) · 5.3 KB
/
vulkan_ubo.cpp
File metadata and controls
132 lines (110 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* SimShip by Edouard Halbert
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License
http://creativecommons.org/licenses/by-nc-nd/4.0/ */
#include "vulkan_ubo.hpp"
VulkanUBO::VulkanUBO(shared_ptr<VulkanDevice>& vulkanDevice, VkDeviceSize size, VkBufferUsageFlags usage)
{
mVulkanDevice = vulkanDevice;
mSize = GetAlignedSize(size);
CreateBuffer(usage);
vkMapMemory(mVulkanDevice->device, memory, 0, size, 0, &data);
HasCoherentMemory();
}
VulkanUBO::~VulkanUBO()
{
if (!mVulkanDevice->device)
return;
if (data)
{
vkUnmapMemory(mVulkanDevice->device, memory);
data = nullptr;
}
vkDestroyBuffer(mVulkanDevice->device, buffer, nullptr);
vkFreeMemory(mVulkanDevice->device, memory, nullptr);
}
void VulkanUBO::Flush()
{
// Si mémoire NON cohérente ? flush manuel requis
if (!hasCoherentMemory)
{
VkMappedMemoryRange mappedRange{};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.size = mSize; // Flush toute la région
vkFlushMappedMemoryRanges(mVulkanDevice->device, 1, &mappedRange);
}
// Si hasCoherentMemory = true ? automatique, rien à faire
}
void VulkanUBO::CreateBuffer(VkBufferUsageFlags usage)
{
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = mSize;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if (vkCreateBuffer(mVulkanDevice->device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS)
throw runtime_error("Failed to create buffer!");
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(mVulkanDevice->device, buffer, &memRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = FindMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
if (vkAllocateMemory(mVulkanDevice->device, &allocInfo, nullptr, &memory) != VK_SUCCESS)
throw runtime_error("Failed to allocate buffer memory!");
vkBindBufferMemory(mVulkanDevice->device, buffer, memory, 0);
}
uint32_t VulkanUBO::FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
{
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(mVulkanDevice->physicalDevice, &memProperties);
// 1. PRIORITÉ: HOST_CACHED + HOST_VISIBLE + HOST_COHERENT (optimal)
VkMemoryPropertyFlags ideal = properties | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
if (properties & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
ideal |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & ideal) == ideal)
return i;
// 2. Fallback: HOST_VISIBLE + HOST_COHERENT (standard)
ideal = properties | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & ideal) == ideal)
return i;
// 3. ULTIME fallback (peut nécessiter flush)
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
return i;
throw runtime_error("failed to find suitable memory type!");
}
void VulkanUBO::HasCoherentMemory()
{
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(mVulkanDevice->physicalDevice, &memProperties);
uint32_t memoryTypeIndex = GetMemoryTypeIndex();
VkMemoryType& memoryType = memProperties.memoryTypes[memoryTypeIndex];
hasCoherentMemory = (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
}
uint32_t VulkanUBO::GetMemoryTypeIndex()
{
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(mVulkanDevice->device, buffer, &memRequirements);
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(mVulkanDevice->physicalDevice, &memProperties);
// Trouve l'index du type de mémoire associé à cette allocation
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
{
if ((memRequirements.memoryTypeBits & (1 << i)) != 0)
{
// Vérifie que les propriétés correspondent exactement à notre allocation
VkMemoryPropertyFlags typeProps = memProperties.memoryTypes[i].propertyFlags;
VkMemoryPropertyFlags requiredProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
if ((typeProps & requiredProps) == requiredProps)
return i;
}
}
throw runtime_error("Could not determine memory type index for existing allocation!");
}
VkDeviceSize VulkanUBO::GetAlignedSize(VkDeviceSize size)
{
return (size + mVulkanDevice->minOffsetAlignment - 1) & ~(mVulkanDevice->minOffsetAlignment - 1);
}