vk_texture.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #include "vk_texture.h"
  2. #include <iostream>
  3. #include "vk_initializers.h"
  4. #define STB_IMAGE_IMPLEMENTATION
  5. #include <stb_image.h>
  6. bool vkutil::load_image_from_file(VulkanEngine& engine, const char* file, AllocatedImage& outImage)
  7. {
  8. int tex_width, tex_height, tex_channels;
  9. stbi_uc* img{ stbi_load(file, &tex_width, &tex_height, &tex_channels, STBI_rgb_alpha) };
  10. if (!img)
  11. {
  12. std::cout << "Failed to load texture file " << file << std::endl;
  13. return false;
  14. }
  15. void* pPixels{ img };
  16. VkDeviceSize img_size{ static_cast<uint64_t>(tex_width * tex_height * 4) };
  17. // This format must match with the format loaded from stb_image
  18. VkFormat img_format{ VK_FORMAT_R8G8B8A8_SRGB };
  19. // Holds texture data to upload to GPU
  20. AllocatedBuffer staging_buffer{ engine.create_buffer(img_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) };
  21. // Copy data to buffer
  22. void* data;
  23. vmaMapMemory(engine.m_Allocator, staging_buffer.allocation, &data);
  24. memcpy(data, pPixels, static_cast<size_t>(img_size));
  25. vmaUnmapMemory(engine.m_Allocator, staging_buffer.allocation);
  26. // Free the pixels
  27. stbi_image_free(img);
  28. VkExtent3D img_extent;
  29. img_extent.width = static_cast<uint32_t>(tex_width);
  30. img_extent.height = static_cast<uint32_t>(tex_height);
  31. img_extent.depth = 1;
  32. VkImageCreateInfo image_ci{ vkinit::image_ci(img_format, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, img_extent) };
  33. AllocatedImage new_img;
  34. VmaAllocationCreateInfo image_ai{};
  35. image_ai.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  36. vmaCreateImage(engine.m_Allocator, &image_ci, &image_ai,
  37. &new_img.image, &new_img.allocation, nullptr);
  38. engine.immediate_submit([&](VkCommandBuffer cmd)
  39. {
  40. VkImageSubresourceRange range{};
  41. range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  42. range.baseMipLevel = 0;
  43. range.levelCount = 1;
  44. range.baseArrayLayer = 0;
  45. range.layerCount = 1;
  46. VkImageMemoryBarrier transfer_img_barrier{};
  47. transfer_img_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  48. transfer_img_barrier.pNext = nullptr;
  49. // Defines the pipeline layout before and after this barrier
  50. transfer_img_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  51. transfer_img_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  52. transfer_img_barrier.image = new_img.image;
  53. transfer_img_barrier.subresourceRange = range;
  54. transfer_img_barrier.srcAccessMask = 0;
  55. transfer_img_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  56. // Barrier the image into the transfer layout
  57. vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
  58. 0, 0, nullptr, 0, nullptr, 1, &transfer_img_barrier);
  59. // Image is ready to receive pixel data at this point
  60. VkBufferImageCopy copy_region{};
  61. copy_region.bufferOffset = 0;
  62. copy_region.bufferRowLength = 0;
  63. copy_region.bufferImageHeight = 0;
  64. copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  65. copy_region.imageSubresource.mipLevel = 0;
  66. copy_region.imageSubresource.baseArrayLayer = 0;
  67. copy_region.imageSubresource.layerCount = 1;
  68. copy_region.imageExtent = img_extent;
  69. // Copy buffer to image
  70. vkCmdCopyBufferToImage(cmd, staging_buffer.buffer, new_img.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
  71. // Turn image into shader readable layout
  72. VkImageMemoryBarrier readable_img_barrier{ transfer_img_barrier };
  73. readable_img_barrier.oldLayout = transfer_img_barrier.newLayout;
  74. readable_img_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  75. readable_img_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  76. readable_img_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  77. // Barrier the image into the readable layout
  78. vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  79. 0, 0, nullptr, 0, nullptr, 1, &readable_img_barrier);
  80. });
  81. engine.m_MainDeletionQueue.deletors.emplace_back([=]()
  82. {
  83. vmaDestroyImage(engine.m_Allocator, new_img.image, new_img.allocation);
  84. });
  85. vmaDestroyBuffer(engine.m_Allocator, staging_buffer.buffer, staging_buffer.allocation);
  86. std::cout << "Texture loaded successfully " << file << std::endl;
  87. outImage = new_img;
  88. return true;
  89. }