source: opengl-game/vulkan-utils.cpp@ 7f60b28

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

Split VulkanUtils::querySwapChainSupport into three separate functions

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