#include #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #include /* externall synchonized, just writes to a command buffer, you still need to pull the trigger (allows bulk texture image preperation) */ Texture::Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer& command_buffer, const std::string& fname) : dev(dev) { Log::debug("Starting texture creation for: %s\n", fname.c_str()); int n_channels; vk::Extent3D extent; auto image_data = stbi_load(fname.c_str(), reinterpret_cast(&extent.width), reinterpret_cast(&extent.height), &n_channels, STBI_rgb_alpha); extent.depth = 1; image = std::make_unique(phys_dev, dev, extent, vk::Format::eR8G8B8A8Unorm, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); vk::DeviceSize sz = static_cast(extent.width * extent.height) * sizeof(uint32_t); /* staging buffer to hold image data from the CPU */ staging = std::make_unique(phys_dev, dev, sz, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); staging->upload(image_data); stbi_image_free(image_data); /* pipeline memory barrier ensures this doesn't get reordered wrong */ auto staging_buffer_trans_barrier = vk::ImageMemoryBarrier { .srcAccessMask = vk::AccessFlagBits(0), .dstAccessMask = vk::AccessFlagBits::eTransferWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eTransferDstOptimal, .image = *image, .subresourceRange = vk::ImageSubresourceRange { .aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1, }, }; /* transfer optimal --> shader optimal */ auto shader_barrier = vk::ImageMemoryBarrier{ .srcAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eShaderRead, .oldLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .image = *image, .subresourceRange = vk::ImageSubresourceRange { .aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1, }, }; command_buffer.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits(0), nullptr, nullptr, staging_buffer_trans_barrier); command_buffer.copy(*staging, *image); command_buffer.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, vk::DependencyFlagBits(0), nullptr, nullptr, shader_barrier); } void Texture::finishCreation() { view = dev.createImageView(vk::ImageViewCreateInfo { .image = *image, .viewType = vk::ImageViewType::e2D, .format = vk::Format::eR8G8B8A8Unorm, .subresourceRange = vk::ImageSubresourceRange{ .aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1, }, }); sampler = dev.createSampler(vk::SamplerCreateInfo { .magFilter = vk::Filter::eLinear, .minFilter = vk::Filter::eLinear, .mipmapMode = vk::SamplerMipmapMode::eLinear, .addressModeU = vk::SamplerAddressMode::eClampToEdge, .addressModeV = vk::SamplerAddressMode::eClampToEdge, .addressModeW = vk::SamplerAddressMode::eClampToEdge, .mipLodBias = 0.0, .anisotropyEnable = vk::False, .maxAnisotropy = 0.0, .compareEnable = vk::False, .compareOp = vk::CompareOp::eAlways, .minLod = 0.0, .maxLod = 0.0, .borderColor = vk::BorderColor::eIntOpaqueBlack, .unnormalizedCoordinates = vk::False, }); } void Texture::cleanup() { staging.reset(); image->cleanup(); dev.destroyImageView(view); dev.destroySampler(sampler); }