source: opengl-game/vulkan-utils.cpp

feature/imgui-sdl
Last change on this file was 8b823e7, checked in by Dmitry Portnoy <dportnoy@…>, 17 months ago

Create an error-checking macro to check Vulkan function results, which will print a custom message, the error code, and the line number for all results besides VK_SUCCESS, and update the imgui error-checking callback with similar functionality.

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