source: opengl-game/vulkan-utils.cpp@ c205c3a

feature/imgui-sdl
Last change on this file since c205c3a was c205c3a, checked in by Dmitry Portnoy <dportnoy@…>, 3 years ago

In VulkanSFMLReference, use the Vulkan SDK version of vulkan.h instead of the one from the SFML repo, switch to the newer debugUtilsMessengerEXT for debugging, and add resources the example code needs for rendering

  • Property mode set to 100644
File size: 21.3 KB
Line 
1#include "vulkan-utils.hpp"
2
3#include <algorithm>
4#include <set>
5#include <stdexcept>
6
7#define STB_IMAGE_IMPLEMENTATION
8#include "stb_image.h" // TODO: Probably switch to SDL_image
9
10// TODO: Remove all instances of auto
11
12bool VulkanUtils::checkValidationLayerSupport(const vector<const char*> &validationLayers) {
13 uint32_t layerCount;
14 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
15
16 vector<VkLayerProperties> availableLayers(layerCount);
17 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
18
19 for (const char* layerName : validationLayers) {
20 bool layerFound = false;
21
22 for (const auto& layerProperties : availableLayers) {
23 if (strcmp(layerName, layerProperties.layerName) == 0) {
24 layerFound = true;
25 break;
26 }
27 }
28
29 if (!layerFound) {
30 return false;
31 }
32 }
33
34 return true;
35}
36
37VkResult VulkanUtils::createDebugUtilsMessengerEXT(VkInstance instance,
38 const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
39 const VkAllocationCallbacks* pAllocator,
40 VkDebugUtilsMessengerEXT* pDebugMessenger) {
41 PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
42 "vkCreateDebugUtilsMessengerEXT");
43
44 if (func != nullptr) {
45 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
46 } else {
47 return VK_ERROR_EXTENSION_NOT_PRESENT;
48 }
49}
50
51void VulkanUtils::destroyDebugUtilsMessengerEXT(VkInstance instance,
52 VkDebugUtilsMessengerEXT debugMessenger,
53 const VkAllocationCallbacks* pAllocator) {
54 PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
55 "vkDestroyDebugUtilsMessengerEXT");
56
57 if (func != nullptr) {
58 func(instance, debugMessenger, pAllocator);
59 }
60}
61
62QueueFamilyIndices VulkanUtils::findQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
63 QueueFamilyIndices indices;
64
65 uint32_t queueFamilyCount = 0;
66 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
67
68 vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
69 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data());
70
71 int i = 0;
72 for (const auto& queueFamily : queueFamilies) {
73 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
74 indices.graphicsFamily = i;
75 }
76
77 VkBool32 presentSupport = false;
78 vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &presentSupport);
79
80 if (queueFamily.queueCount > 0 && presentSupport) {
81 indices.presentFamily = i;
82 }
83
84 if (indices.isComplete()) {
85 break;
86 }
87
88 i++;
89 }
90
91 return indices;
92}
93
94bool VulkanUtils::checkDeviceExtensionSupport(VkPhysicalDevice physicalDevice, const vector<const char*>& deviceExtensions) {
95 uint32_t extensionCount;
96 vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
97
98 vector<VkExtensionProperties> availableExtensions(extensionCount);
99 vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data());
100
101 set<string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
102
103 for (const auto& extension : availableExtensions) {
104 requiredExtensions.erase(extension.extensionName);
105 }
106
107 return requiredExtensions.empty();
108}
109
110SwapChainSupportDetails VulkanUtils::querySwapChainSupport(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
111 SwapChainSupportDetails details;
112
113 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &details.capabilities);
114
115 uint32_t formatCount;
116 vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
117
118 if (formatCount != 0) {
119 details.formats.resize(formatCount);
120 vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, details.formats.data());
121 }
122
123 uint32_t presentModeCount;
124 vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
125
126 if (presentModeCount != 0) {
127 details.presentModes.resize(presentModeCount);
128 vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, details.presentModes.data());
129 }
130
131 return details;
132}
133
134VkSurfaceFormatKHR VulkanUtils::chooseSwapSurfaceFormat(const vector<VkSurfaceFormatKHR>& availableFormats) {
135 for (const auto& availableFormat : availableFormats) {
136 if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
137 return availableFormat;
138 }
139 }
140
141 return availableFormats[0];
142}
143
144VkPresentModeKHR VulkanUtils::chooseSwapPresentMode(const vector<VkPresentModeKHR>& availablePresentModes) {
145 VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
146
147 for (const auto& availablePresentMode : availablePresentModes) {
148 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
149 return availablePresentMode;
150 }
151 else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
152 bestMode = availablePresentMode;
153 }
154 }
155
156 return bestMode;
157}
158
159VkExtent2D VulkanUtils::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, int width, int height) {
160 if (capabilities.currentExtent.width != numeric_limits<uint32_t>::max()) {
161 return capabilities.currentExtent;
162 } else {
163 VkExtent2D actualExtent = {
164 static_cast<uint32_t>(width),
165 static_cast<uint32_t>(height)
166 };
167
168 actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
169 actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
170
171 return actualExtent;
172 }
173}
174
175VkImageView VulkanUtils::createImageView(VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) {
176 VkImageViewCreateInfo viewInfo = {};
177 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
178 viewInfo.image = image;
179 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
180 viewInfo.format = format;
181
182 viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
183 viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
184 viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
185 viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
186
187 viewInfo.subresourceRange.aspectMask = aspectFlags;
188 viewInfo.subresourceRange.baseMipLevel = 0;
189 viewInfo.subresourceRange.levelCount = 1;
190 viewInfo.subresourceRange.baseArrayLayer = 0;
191 viewInfo.subresourceRange.layerCount = 1;
192
193 VkImageView imageView;
194 if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {
195 throw runtime_error("failed to create image view!");
196 }
197
198 return imageView;
199}
200
201VkFormat VulkanUtils::findSupportedFormat(VkPhysicalDevice physicalDevice, const vector<VkFormat>& candidates,
202 VkImageTiling tiling, VkFormatFeatureFlags features) {
203 for (VkFormat format : candidates) {
204 VkFormatProperties props;
205 vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
206
207 if (tiling == VK_IMAGE_TILING_LINEAR &&
208 (props.linearTilingFeatures & features) == features) {
209 return format;
210 } else if (tiling == VK_IMAGE_TILING_OPTIMAL &&
211 (props.optimalTilingFeatures & features) == features) {
212 return format;
213 }
214 }
215
216 throw runtime_error("failed to find supported format!");
217}
218
219void VulkanUtils::createBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage,
220 VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
221 VkBufferCreateInfo bufferInfo = {};
222 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
223 bufferInfo.size = size;
224 bufferInfo.usage = usage;
225 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
226
227 if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
228 throw runtime_error("failed to create buffer!");
229 }
230
231 VkMemoryRequirements memRequirements;
232 vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
233
234 VkMemoryAllocateInfo allocInfo = {};
235 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
236 allocInfo.allocationSize = memRequirements.size;
237 allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties);
238
239 if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
240 throw runtime_error("failed to allocate buffer memory!");
241 }
242
243 vkBindBufferMemory(device, buffer, bufferMemory, 0);
244}
245
246uint32_t VulkanUtils::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) {
247 VkPhysicalDeviceMemoryProperties memProperties;
248 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
249
250 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
251 if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
252 return i;
253 }
254 }
255
256 throw runtime_error("failed to find suitable memory type!");
257}
258
259void VulkanUtils::createVulkanImageFromFile(VkDevice device, VkPhysicalDevice physicalDevice,
260 VkCommandPool commandPool, string filename, VulkanImage& image, VkQueue graphicsQueue) {
261 // TODO: Since the image loaded here will be used as a texture, display a warning if it has
262 // non power-of-two dimensions
263 int texWidth, texHeight, texChannels;
264
265 stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
266 VkDeviceSize imageSize = texWidth * texHeight * 4;
267
268 if (!pixels) {
269 throw runtime_error("failed to load texture image!");
270 }
271
272 VkBuffer stagingBuffer;
273 VkDeviceMemory stagingBufferMemory;
274
275 createBuffer(device, physicalDevice, imageSize,
276 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
277 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
278 stagingBuffer, stagingBufferMemory);
279
280 void* data;
281
282 vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
283 memcpy(data, pixels, static_cast<size_t>(imageSize));
284 vkUnmapMemory(device, stagingBufferMemory);
285
286 stbi_image_free(pixels);
287
288 createImage(device, physicalDevice, texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL,
289 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image);
290
291 transitionImageLayout(device, commandPool, image.image, VK_FORMAT_R8G8B8A8_UNORM,
292 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, graphicsQueue);
293 copyBufferToImage(device, commandPool, stagingBuffer, image.image,
294 static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight), graphicsQueue);
295 transitionImageLayout(device, commandPool, image.image, VK_FORMAT_R8G8B8A8_UNORM,
296 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, graphicsQueue);
297
298 vkDestroyBuffer(device, stagingBuffer, nullptr);
299 vkFreeMemory(device, stagingBufferMemory, nullptr);
300
301 image.imageView = createImageView(device, image.image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
302}
303
304void VulkanUtils::createVulkanImageFromSDLTexture(VkDevice device, VkPhysicalDevice physicalDevice,
305 SDL_Texture* texture, VulkanImage& image) {
306 int a, w, h;
307
308 // I only need this here for the width and height, which are constants, so just use those instead
309 SDL_QueryTexture(texture, nullptr, &a, &w, &h);
310
311 createImage(device, physicalDevice, w, h, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL,
312 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image);
313
314 image.imageView = createImageView(device, image.image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
315}
316
317void VulkanUtils::populateVulkanImageFromSDLTexture(VkDevice device, VkPhysicalDevice physicalDevice,
318 VkCommandPool commandPool, SDL_Texture* texture, SDL_Renderer* renderer, VulkanImage& image,
319 VkQueue graphicsQueue) {
320 int a, w, h;
321
322 SDL_QueryTexture(texture, nullptr, &a, &w, &h);
323
324 VkDeviceSize imageSize = w * h * 4;
325 unsigned char* pixels = new unsigned char[imageSize];
326
327 SDL_RenderReadPixels(renderer, nullptr, SDL_PIXELFORMAT_ABGR8888, pixels, w * 4);
328
329 VkBuffer stagingBuffer;
330 VkDeviceMemory stagingBufferMemory;
331
332 createBuffer(device, physicalDevice, imageSize,
333 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
334 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
335 stagingBuffer, stagingBufferMemory);
336
337 void* data;
338
339 vkMapMemory(device, stagingBufferMemory, 0, VK_WHOLE_SIZE, 0, &data);
340 memcpy(data, pixels, static_cast<size_t>(imageSize));
341
342 VkMappedMemoryRange mappedMemoryRange = {};
343 mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
344 mappedMemoryRange.memory = stagingBufferMemory;
345 mappedMemoryRange.offset = 0;
346 mappedMemoryRange.size = VK_WHOLE_SIZE;
347
348 // TODO: Should probably check that the function succeeded
349 vkFlushMappedMemoryRanges(device, 1, &mappedMemoryRange);
350 vkUnmapMemory(device, stagingBufferMemory);
351
352 delete[] pixels;
353
354 transitionImageLayout(device, commandPool, image.image, VK_FORMAT_R8G8B8A8_UNORM,
355 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, graphicsQueue);
356 copyBufferToImage(device, commandPool, stagingBuffer, image.image,
357 static_cast<uint32_t>(w), static_cast<uint32_t>(h), graphicsQueue);
358 transitionImageLayout(device, commandPool, image.image, VK_FORMAT_R8G8B8A8_UNORM,
359 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, graphicsQueue);
360
361 vkDestroyBuffer(device, stagingBuffer, nullptr);
362 vkFreeMemory(device, stagingBufferMemory, nullptr);
363}
364
365void VulkanUtils::createDepthImage(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool,
366 VkFormat depthFormat, VkExtent2D extent, VulkanImage& image, VkQueue graphicsQueue) {
367 createImage(device, physicalDevice, extent.width, extent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL,
368 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image);
369 image.imageView = createImageView(device, image.image, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
370
371 transitionImageLayout(device, commandPool, image.image, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED,
372 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, graphicsQueue);
373}
374
375void VulkanUtils::createImage(VkDevice device, VkPhysicalDevice physicalDevice, uint32_t width, uint32_t height,
376 VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties,
377 VulkanImage& image) {
378 VkImageCreateInfo imageInfo = {};
379 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
380 imageInfo.imageType = VK_IMAGE_TYPE_2D;
381 imageInfo.extent.width = width;
382 imageInfo.extent.height = height;
383 imageInfo.extent.depth = 1;
384 imageInfo.mipLevels = 1;
385 imageInfo.arrayLayers = 1;
386 imageInfo.format = format;
387 imageInfo.tiling = tiling;
388 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
389 imageInfo.usage = usage;
390 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
391 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
392
393 if (vkCreateImage(device, &imageInfo, nullptr, &image.image) != VK_SUCCESS) {
394 throw runtime_error("failed to create image!");
395 }
396
397 VkMemoryRequirements memRequirements;
398 vkGetImageMemoryRequirements(device, image.image, &memRequirements);
399
400 VkMemoryAllocateInfo allocInfo = {};
401 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
402 allocInfo.allocationSize = memRequirements.size;
403 allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties);
404
405 if (vkAllocateMemory(device, &allocInfo, nullptr, &image.imageMemory) != VK_SUCCESS) {
406 throw runtime_error("failed to allocate image memory!");
407 }
408
409 vkBindImageMemory(device, image.image, image.imageMemory, 0);
410}
411
412void VulkanUtils::transitionImageLayout(VkDevice device, VkCommandPool commandPool, VkImage image,
413 VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkQueue graphicsQueue) {
414 VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
415
416 VkImageMemoryBarrier barrier = {};
417 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
418 barrier.oldLayout = oldLayout;
419 barrier.newLayout = newLayout;
420 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
421 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
422 barrier.image = image;
423
424 if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
425 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
426
427 if (hasStencilComponent(format)) {
428 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
429 }
430 } else {
431 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
432 }
433
434 barrier.subresourceRange.baseMipLevel = 0;
435 barrier.subresourceRange.levelCount = 1;
436 barrier.subresourceRange.baseArrayLayer = 0;
437 barrier.subresourceRange.layerCount = 1;
438
439 VkPipelineStageFlags sourceStage;
440 VkPipelineStageFlags destinationStage;
441
442 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
443 barrier.srcAccessMask = 0;
444 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
445
446 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
447 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
448 } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
449 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
450 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
451
452 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
453 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
454 } else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
455 barrier.srcAccessMask = 0;
456 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
457
458 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
459 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
460 } else {
461 throw invalid_argument("unsupported layout transition!");
462 }
463
464 vkCmdPipelineBarrier(
465 commandBuffer,
466 sourceStage, destinationStage,
467 0,
468 0, nullptr,
469 0, nullptr,
470 1, &barrier
471 );
472
473 endSingleTimeCommands(device, commandPool, commandBuffer, graphicsQueue);
474}
475
476VkCommandBuffer VulkanUtils::beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool) {
477 VkCommandBufferAllocateInfo allocInfo = {};
478 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
479 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
480 allocInfo.commandPool = commandPool;
481 allocInfo.commandBufferCount = 1;
482
483 VkCommandBuffer commandBuffer;
484 vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
485
486 VkCommandBufferBeginInfo beginInfo = {};
487 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
488 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
489
490 vkBeginCommandBuffer(commandBuffer, &beginInfo);
491
492 return commandBuffer;
493}
494
495void VulkanUtils::endSingleTimeCommands(VkDevice device, VkCommandPool commandPool,
496 VkCommandBuffer commandBuffer, VkQueue graphicsQueue) {
497 vkEndCommandBuffer(commandBuffer);
498
499 VkSubmitInfo submitInfo = {};
500 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
501 submitInfo.commandBufferCount = 1;
502 submitInfo.pCommandBuffers = &commandBuffer;
503
504 vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
505 vkQueueWaitIdle(graphicsQueue);
506
507 vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
508}
509
510void VulkanUtils::copyBufferToImage(VkDevice device, VkCommandPool commandPool, VkBuffer buffer,
511 VkImage image, uint32_t width, uint32_t height, VkQueue graphicsQueue) {
512 VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
513
514 VkBufferImageCopy region = {};
515 region.bufferOffset = 0;
516 region.bufferRowLength = 0;
517 region.bufferImageHeight = 0;
518 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
519 region.imageSubresource.mipLevel = 0;
520 region.imageSubresource.baseArrayLayer = 0;
521 region.imageSubresource.layerCount = 1;
522 region.imageOffset = { 0, 0, 0 };
523 region.imageExtent = { width, height, 1 };
524
525 vkCmdCopyBufferToImage(
526 commandBuffer,
527 buffer,
528 image,
529 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
530 1,
531 &region
532 );
533
534 endSingleTimeCommands(device, commandPool, commandBuffer, graphicsQueue);
535}
536
537void VulkanUtils::copyBuffer(VkDevice device, VkCommandPool commandPool, VkBuffer srcBuffer,
538 VkBuffer dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size,
539 VkQueue graphicsQueue) {
540 VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
541
542 VkBufferCopy copyRegion = { srcOffset, dstOffset, size };
543 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
544
545 endSingleTimeCommands(device, commandPool, commandBuffer, graphicsQueue);
546}
547
548bool VulkanUtils::hasStencilComponent(VkFormat format) {
549 return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
550}
551
552void VulkanUtils::destroyVulkanImage(VkDevice& device, VulkanImage& image) {
553 vkDestroyImageView(device, image.imageView, nullptr);
554 vkDestroyImage(device, image.image, nullptr);
555 vkFreeMemory(device, image.imageMemory, nullptr);
556}
Note: See TracBrowser for help on using the repository browser.