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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
#include "VulkanDevice.hpp"
vke::VulkanDevice::VulkanDevice(vkPhyInfo phyInfos, const std::vector<const char*>& devLayers)
{
phy = phyInfos.phy;
properties = phyInfos.properties;
memoryProperties = phyInfos.memProps;
features = phyInfos.features;
//affect priorities to qcis from vector
for (uint i=0; i<phyInfos.pQueueInfos.size(); i++)
phyInfos.pQueueInfos[i].pQueuePriorities = phyInfos.qPriorities[i].data();
std::vector<const char*> devExtentions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
VkDeviceCreateInfo devInfo = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
devInfo.queueCreateInfoCount = (uint32_t)phyInfos.pQueueInfos.size();
devInfo.pQueueCreateInfos = phyInfos.pQueueInfos.data();
devInfo.enabledExtensionCount = (uint32_t)devExtentions.size();
devInfo.ppEnabledExtensionNames = devExtentions.data();
devInfo.enabledLayerCount = (uint32_t)devLayers.size();
devInfo.ppEnabledLayerNames = devLayers.data();
devInfo.pEnabledFeatures = &enabledFeatures;
VK_CHECK_RESULT(vkCreateDevice (phyInfos.phy, &devInfo, nullptr, &dev));
commandPool = createCommandPool (phyInfos.gQueues[0]);
vkGetDeviceQueue(dev, phyInfos.gQueues[0], 0, &queue);
//reload pipeline cache if it exists
std::ifstream is ("pipeline.cache", std::ifstream::binary);
char* buffer = nullptr;
int length = 0;
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO};
if (is) {
is.seekg (0, is.end);
length = is.tellg();
if (length > 0) {
is.seekg (0, is.beg);
buffer = new char [length];
is.read (buffer,length);
}
is.close();
pipelineCacheCreateInfo.initialDataSize = length;
pipelineCacheCreateInfo.pInitialData = buffer;
}
VK_CHECK_RESULT(vkCreatePipelineCache (dev, &pipelineCacheCreateInfo, nullptr, &pipelineCache));
delete[] buffer;
}
vke::VulkanDevice::~VulkanDevice()
{
if (pipelineCache){
if (savePLCache){
std::ofstream os("pipeline.cache", std::ofstream::binary);
size_t plCacheSize = 0;
char* plCache = nullptr;
VK_CHECK_RESULT(vkGetPipelineCacheData(dev, pipelineCache, &plCacheSize, nullptr));
plCache = new char [plCacheSize];
VK_CHECK_RESULT(vkGetPipelineCacheData(dev, pipelineCache, &plCacheSize, plCache));
os.write (plCache, plCacheSize);
os.close();
delete[] plCache;
}
vkDestroyPipelineCache(dev, pipelineCache, nullptr);
}
if (commandPool)
vkDestroyCommandPool(dev, commandPool, nullptr);
if (dev)
vkDestroyDevice(dev, nullptr);
}
uint32_t vke::VulkanDevice::getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound)
{
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
if ((typeBits & 1) == 1) {
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
if (memTypeFound) {
*memTypeFound = true;
}
return i;
}
}
typeBits >>= 1;
}
if (memTypeFound) {
*memTypeFound = false;
return 0;
} else {
throw std::runtime_error("Could not find a matching memory type");
}
}
VkFormat vke::VulkanDevice::getSuitableDepthFormat () {
std::vector<VkFormat> depthFormats = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D16_UNORM };
for (auto& format : depthFormats) {
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(phy, format, &formatProps);
if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
return format;
}
std::cerr << "No suitable depth format found" << std::endl;
exit(-1);
}
uint32_t vke::VulkanDevice::getQueueFamilyIndex(VkQueueFlagBits queueFlags)
{
// Dedicated queue for compute
// Try to find a queue family index that supports compute but not graphics
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
{
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) {
if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
return i;
break;
}
}
}
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) {
if (queueFamilyProperties[i].queueFlags & queueFlags) {
return i;
break;
}
}
throw std::runtime_error("Could not find a matching queue family index");
}
VkCommandPool vke::VulkanDevice::createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags)
{
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
cmdPoolInfo.flags = createFlags;
VkCommandPool cmdPool;
VK_CHECK_RESULT(vkCreateCommandPool(dev, &cmdPoolInfo, nullptr, &cmdPool));
return cmdPool;
}
VkCommandBuffer vke::VulkanDevice::createCommandBuffer(VkCommandBufferLevel level, bool begin, bool oneTime)
{
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdBufAllocateInfo.commandPool = commandPool;
cmdBufAllocateInfo.level = level;
cmdBufAllocateInfo.commandBufferCount = 1;
VkCommandBuffer cmdBuffer;
VK_CHECK_RESULT(vkAllocateCommandBuffers(dev, &cmdBufAllocateInfo, &cmdBuffer));
// If requested, also start recording for the new command buffer
if (begin) {
VkCommandBufferBeginInfo cmdBufInfo{};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.flags = oneTime ? VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT : 0;
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
}
return cmdBuffer;
}
void vke::VulkanDevice::flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free)
{
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
// Create fence to ensure that the command buffer has finished executing
VkFenceCreateInfo fenceInfo{};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(dev, &fenceInfo, nullptr, &fence));
// Submit to the queue
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
// Wait for the fence to signal that command buffer has finished executing
VK_CHECK_RESULT(vkWaitForFences(dev, 1, &fence, VK_TRUE, 100000000000));
vkDestroyFence(dev, fence, nullptr);
if (free) {
vkFreeCommandBuffers(dev, commandPool, 1, &commandBuffer);
}
}
VkSemaphore vke::VulkanDevice::createSemaphore ()
{
VkSemaphore sema = VK_NULL_HANDLE;
VkSemaphoreCreateInfo semaphoreCreateInfo {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
VK_CHECK_RESULT(vkCreateSemaphore (dev, &semaphoreCreateInfo, nullptr, &sema));
return sema;
}
VkFence vke::VulkanDevice::createFence (bool signaled) {
VkFence fence = VK_NULL_HANDLE;
VkFenceCreateInfo fenceCreateInfo {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, VK_NULL_HANDLE,
signaled ? VK_FENCE_CREATE_SIGNALED_BIT : (VkFenceCreateFlags)0};
VK_CHECK_RESULT(vkCreateFence (dev, &fenceCreateInfo, nullptr, &fence));
return fence;
}
void vke::VulkanDevice::destroyFence (VkFence fence) {
vkDestroyFence (dev, fence, VK_NULL_HANDLE);
}
void vke::VulkanDevice::destroySemaphore (VkSemaphore semaphore) {
vkDestroySemaphore (dev, semaphore, VK_NULL_HANDLE);
}
|