Changeset b794178 in opengl-game for vulkan-utils.cpp


Ignore:
Timestamp:
Oct 17, 2019, 9:30:18 PM (5 years ago)
Author:
Dmitry Portnoy <dmitry.portnoy@…>
Branches:
feature/imgui-sdl, master, points-test
Children:
e83b155
Parents:
771b33a
Message:

In vulkangame, add the ability to create vulkan resoirces and descriptor sets for shader uniforms (images and ubos)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vulkan-utils.cpp

    r771b33a rb794178  
    44#include <set>
    55#include <stdexcept>
    6 #include <string>
     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
    711
    812bool VulkanUtils::checkValidationLayerSupport(const vector<const char*> &validationLayers) {
     
    210214   throw runtime_error("failed to find supported format!");
    211215}
     216
     217void VulkanUtils::createBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage,
     218      VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
     219   VkBufferCreateInfo bufferInfo = {};
     220   bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
     221   bufferInfo.size = size;
     222   bufferInfo.usage = usage;
     223   bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
     224
     225   if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
     226      throw runtime_error("failed to create buffer!");
     227   }
     228
     229   VkMemoryRequirements memRequirements;
     230   vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
     231
     232   VkMemoryAllocateInfo allocInfo = {};
     233   allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
     234   allocInfo.allocationSize = memRequirements.size;
     235   allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties);
     236
     237   if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
     238      throw runtime_error("failed to allocate buffer memory!");
     239   }
     240
     241   vkBindBufferMemory(device, buffer, bufferMemory, 0);
     242}
     243
     244uint32_t VulkanUtils::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) {
     245   VkPhysicalDeviceMemoryProperties memProperties;
     246   vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
     247
     248   for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
     249      if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
     250         return i;
     251      }
     252   }
     253
     254   throw runtime_error("failed to find suitable memory type!");
     255}
     256
     257void VulkanUtils::createVulkanImageFromFile(VkDevice device, VkPhysicalDevice physicalDevice,
     258      VkCommandPool commandPool, string filename, VulkanImage& image, VkQueue graphicsQueue) {
     259   int texWidth, texHeight, texChannels;
     260
     261   stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
     262   VkDeviceSize imageSize = texWidth * texHeight * 4;
     263
     264   if (!pixels) {
     265      throw runtime_error("failed to load texture image!");
     266   }
     267
     268   VkBuffer stagingBuffer;
     269   VkDeviceMemory stagingBufferMemory;
     270
     271   createBuffer(device, physicalDevice, imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
     272      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     273      stagingBuffer, stagingBufferMemory);
     274
     275   void* data;
     276
     277   vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
     278   memcpy(data, pixels, static_cast<size_t>(imageSize));
     279   vkUnmapMemory(device, stagingBufferMemory);
     280
     281   stbi_image_free(pixels);
     282
     283   createImage(device, physicalDevice, texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL,
     284      VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image);
     285
     286   transitionImageLayout(device, commandPool, image.image, VK_FORMAT_R8G8B8A8_UNORM,
     287      VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, graphicsQueue);
     288   copyBufferToImage(device, commandPool, stagingBuffer, image.image,
     289      static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight), graphicsQueue);
     290   transitionImageLayout(device, commandPool, image.image, VK_FORMAT_R8G8B8A8_UNORM,
     291      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, graphicsQueue);
     292
     293   vkDestroyBuffer(device, stagingBuffer, nullptr);
     294   vkFreeMemory(device, stagingBufferMemory, nullptr);
     295
     296   image.imageView = createImageView(device, image.image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
     297}
     298
     299void VulkanUtils::createVulkanImageFromSDLTexture(VkDevice device, VkPhysicalDevice physicalDevice,
     300      SDL_Texture* texture, VulkanImage& image) {
     301   int a, w, h;
     302
     303   // I only need this here for the width and height, which are constants, so just use those instead
     304   SDL_QueryTexture(texture, nullptr, &a, &w, &h);
     305
     306   createImage(device, physicalDevice, w, h, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL,
     307      VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image);
     308
     309   image.imageView = createImageView(device, image.image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
     310}
     311
     312void VulkanUtils::createImage(VkDevice device, VkPhysicalDevice physicalDevice, uint32_t width, uint32_t height,
     313      VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties,
     314      VulkanImage& image) {
     315   VkImageCreateInfo imageInfo = {};
     316   imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
     317   imageInfo.imageType = VK_IMAGE_TYPE_2D;
     318   imageInfo.extent.width = width;
     319   imageInfo.extent.height = height;
     320   imageInfo.extent.depth = 1;
     321   imageInfo.mipLevels = 1;
     322   imageInfo.arrayLayers = 1;
     323   imageInfo.format = format;
     324   imageInfo.tiling = tiling;
     325   imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     326   imageInfo.usage = usage;
     327   imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
     328   imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
     329
     330   if (vkCreateImage(device, &imageInfo, nullptr, &image.image) != VK_SUCCESS) {
     331      throw runtime_error("failed to create image!");
     332   }
     333
     334   VkMemoryRequirements memRequirements;
     335   vkGetImageMemoryRequirements(device, image.image, &memRequirements);
     336
     337   VkMemoryAllocateInfo allocInfo = {};
     338   allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
     339   allocInfo.allocationSize = memRequirements.size;
     340   allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties);
     341
     342   if (vkAllocateMemory(device, &allocInfo, nullptr, &image.imageMemory) != VK_SUCCESS) {
     343      throw runtime_error("failed to allocate image memory!");
     344   }
     345
     346   vkBindImageMemory(device, image.image, image.imageMemory, 0);
     347}
     348
     349void VulkanUtils::transitionImageLayout(VkDevice device, VkCommandPool commandPool, VkImage image,
     350      VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkQueue graphicsQueue) {
     351   VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
     352
     353   VkImageMemoryBarrier barrier = {};
     354   barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
     355   barrier.oldLayout = oldLayout;
     356   barrier.newLayout = newLayout;
     357   barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     358   barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     359   barrier.image = image;
     360
     361   if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
     362      barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
     363
     364      if (hasStencilComponent(format)) {
     365         barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
     366      }
     367   } else {
     368      barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     369   }
     370
     371   barrier.subresourceRange.baseMipLevel = 0;
     372   barrier.subresourceRange.levelCount = 1;
     373   barrier.subresourceRange.baseArrayLayer = 0;
     374   barrier.subresourceRange.layerCount = 1;
     375
     376   VkPipelineStageFlags sourceStage;
     377   VkPipelineStageFlags destinationStage;
     378
     379   if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
     380      barrier.srcAccessMask = 0;
     381      barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
     382
     383      sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
     384      destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
     385   } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
     386      barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
     387      barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
     388
     389      sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
     390      destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
     391   } else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
     392      barrier.srcAccessMask = 0;
     393      barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
     394
     395      sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
     396      destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
     397   } else {
     398      throw invalid_argument("unsupported layout transition!");
     399   }
     400
     401   vkCmdPipelineBarrier(
     402      commandBuffer,
     403      sourceStage, destinationStage,
     404      0,
     405      0, nullptr,
     406      0, nullptr,
     407      1, &barrier
     408   );
     409
     410   endSingleTimeCommands(device, commandPool, commandBuffer, graphicsQueue);
     411}
     412
     413VkCommandBuffer VulkanUtils::beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool) {
     414   VkCommandBufferAllocateInfo allocInfo = {};
     415   allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
     416   allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
     417   allocInfo.commandPool = commandPool;
     418   allocInfo.commandBufferCount = 1;
     419
     420   VkCommandBuffer commandBuffer;
     421   vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
     422
     423   VkCommandBufferBeginInfo beginInfo = {};
     424   beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
     425   beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
     426
     427   vkBeginCommandBuffer(commandBuffer, &beginInfo);
     428
     429   return commandBuffer;
     430}
     431
     432void VulkanUtils::endSingleTimeCommands(VkDevice device, VkCommandPool commandPool,
     433      VkCommandBuffer commandBuffer, VkQueue graphicsQueue) {
     434   vkEndCommandBuffer(commandBuffer);
     435
     436   VkSubmitInfo submitInfo = {};
     437   submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
     438   submitInfo.commandBufferCount = 1;
     439   submitInfo.pCommandBuffers = &commandBuffer;
     440
     441   vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
     442   vkQueueWaitIdle(graphicsQueue);
     443
     444   vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
     445}
     446
     447void VulkanUtils::copyBufferToImage(VkDevice device, VkCommandPool commandPool, VkBuffer buffer,
     448      VkImage image, uint32_t width, uint32_t height, VkQueue graphicsQueue) {
     449   VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
     450
     451   VkBufferImageCopy region = {};
     452   region.bufferOffset = 0;
     453   region.bufferRowLength = 0;
     454   region.bufferImageHeight = 0;
     455   region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     456   region.imageSubresource.mipLevel = 0;
     457   region.imageSubresource.baseArrayLayer = 0;
     458   region.imageSubresource.layerCount = 1;
     459   region.imageOffset = { 0, 0, 0 };
     460   region.imageExtent = { width, height, 1 };
     461
     462   vkCmdCopyBufferToImage(
     463      commandBuffer,
     464      buffer,
     465      image,
     466      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
     467      1,
     468      &region
     469   );
     470
     471   endSingleTimeCommands(device, commandPool, commandBuffer, graphicsQueue);
     472}
     473
     474bool VulkanUtils::hasStencilComponent(VkFormat format) {
     475   return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
     476}
Note: See TracChangeset for help on using the changeset viewer.