#include #include #include #define STB_IMAGE_IMPLEMENTATION #include #include using namespace std::string_literals; Texture::Texture(vkb::Device& dev, VmaAllocator& allocator, const std::string& fname) : fname(fname) { unsigned int width; unsigned int height; int n_channels; uint8_t* data = stbi_load(fname.c_str(), reinterpret_cast(&width), reinterpret_cast(&height), &n_channels, STBI_rgb_alpha); if (!data) { stbi_image_free(data); throw "Failed to load texture \""s + fname + "\": " + stbi_failure_reason(); } vk::DeviceSize image_size = width * height * sizeof(uint32_t); vk::Extent3D img_ext { .width = width, .height = height, .depth = 1, }; vk::ImageCreateInfo image_info { .imageType = vk::ImageType::e2D, .format = vk::Format::eR8G8B8A8Unorm, .extent = img_ext, .mipLevels = 1, .arrayLayers = 1, .samples = vk::SampleCountFlagBits::e1, .tiling = vk::ImageTiling::eLinear, .usage = vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, .sharingMode = vk::SharingMode::eExclusive, .initialLayout = vk::ImageLayout::eUndefined, }; VmaAllocationCreateInfo alloc_info { .usage = VMA_MEMORY_USAGE_CPU_ONLY, }; VkImage tmp_img; if (vmaCreateImage(allocator, &image_info.operator const VkImageCreateInfo & (), &alloc_info, &tmp_img, &alloc, NULL)) { throw "Failed to create image for "s + fname; } image = vk::Image(tmp_img); vk::BufferCreateInfo staging_buffer_info { .size = image_size, .usage = vk::BufferUsageFlagBits::eTransferSrc, }; vk::Buffer staging_buffer; VmaAllocation staging_alloc; VmaAllocationCreateInfo staging_alloc_info{ .usage = VMA_MEMORY_USAGE_CPU_ONLY, }; VkBuffer tmp_buff; if (vmaCreateBuffer(allocator, &staging_buffer_info.operator const VkBufferCreateInfo & (), &staging_alloc_info, &tmp_buff, &staging_alloc, NULL) != VK_SUCCESS) { throw "Failed to allocate texture staging buffer for "s + fname; } staging_buffer = vk::Buffer(tmp_buff); void* staging_data; vmaMapMemory(allocator, staging_alloc, &staging_data); std::memcpy(staging_data, data, static_cast(image_size)); vmaUnmapMemory(allocator, staging_alloc); stbi_image_free(data); vk::ImageSubresourceRange staging_range { .aspectMask = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, }; /* memory barrier for undefined->transfer optimal */ vk::ImageMemoryBarrier staging_memory_barrier { .srcAccessMask = vk::AccessFlagBits::eNone, .dstAccessMask = vk::AccessFlagBits::eTransferWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eTransferDstOptimal, .image = image, .subresourceRange = staging_range, }; vk::BufferImageCopy staging_buffer_copy { .bufferOffset = 0, .bufferRowLength = 0, .bufferImageHeight = 0, .imageSubresource = vk::ImageSubresourceLayers { .aspectMask = vk::ImageAspectFlagBits::eColor, .baseArrayLayer = 0, .layerCount = 1, }, .imageExtent = img_ext, }; /* transfer optimal -> shader optimal */ vk::ImageMemoryBarrier staging_buffer_to_shader_barrier { .srcAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eShaderRead, .oldLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .image = image, .subresourceRange = staging_range, }; CommandBuffer cmd(dev); vk::CommandBufferBeginInfo cmd_begin_info { .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit }; cmd.buffer.begin(cmd_begin_info); cmd.buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer,); /* TODO: Finish transfer */ }