diff options
Diffstat (limited to 'engine/xe_image.cpp')
-rw-r--r-- | engine/xe_image.cpp | 120 |
1 files changed, 115 insertions, 5 deletions
diff --git a/engine/xe_image.cpp b/engine/xe_image.cpp index 8b6065c..419cbdd 100644 --- a/engine/xe_image.cpp +++ b/engine/xe_image.cpp @@ -13,9 +13,11 @@ namespace xe { Image::Image(Device &xeDevice, const std::string &filename) : xeDevice{xeDevice} { createTextureImage(filename); createTextureImageView(); + createTextureSampler(); } Image::~Image() { + vkDestroySampler(xeDevice.device(), textureSampler, nullptr); vkDestroyImage(xeDevice.device(), textureImage, nullptr); vkFreeMemory(xeDevice.device(), textureImageMemory, nullptr); vkDestroyImageView(xeDevice.device(), textureImageView, nullptr); @@ -25,6 +27,7 @@ void Image::createTextureImage(const std::string &filename) { int texWidth, texHeight, texChannels; stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); VkDeviceSize imageSize = texWidth * texHeight * 4; + mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1; if (!pixels) { throw std::runtime_error("failed to load texture: " + filename); @@ -48,15 +51,17 @@ void Image::createTextureImage(const std::string &filename) { stbi_image_free(pixels); - createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory); + createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight)); - transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + // transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vkDestroyBuffer(xeDevice.device(), stagingBuffer, nullptr); vkFreeMemory(xeDevice.device(), stagingBufferMemory, nullptr); + generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, texWidth, texHeight, mipLevels); + } void Image::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { @@ -67,7 +72,7 @@ void Image::createImage(uint32_t width, uint32_t height, VkFormat format, VkImag imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; + imageInfo.mipLevels = mipLevels; imageInfo.arrayLayers = 1; imageInfo.format = format; imageInfo.tiling = tiling; @@ -107,7 +112,7 @@ void Image::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout barrier.image = image; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.levelCount = mipLevels; barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = 1; @@ -142,6 +147,86 @@ void Image::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout xeDevice.endSingleTimeCommands(commandBuffer); } +void Image::generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels) { + + VkCommandBuffer commandBuffer = xeDevice.beginSingleTimeCommands(); + + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = image; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + + int32_t mipWidth = texWidth; + int32_t mipHeight = texHeight; + + for (uint32_t i = 1; i < mipLevels; i++) { + barrier.subresourceRange.baseMipLevel = i - 1; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + VkImageBlit blit{}; + blit.srcOffsets[0] = {0, 0, 0}; + blit.srcOffsets[1] = {mipWidth, mipHeight, 1}; + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = 1; + blit.dstOffsets[0] = {0, 0, 0}; + blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 }; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = 1; + + vkCmdBlitImage(commandBuffer, + image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, + VK_FILTER_LINEAR); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + if (mipWidth > 1) mipWidth /= 2; + if (mipHeight > 1) mipHeight /= 2; + } + + barrier.subresourceRange.baseMipLevel = mipLevels - 1; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + xeDevice.endSingleTimeCommands(commandBuffer); + } + void Image::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) { VkCommandBuffer commandBuffer = xeDevice.beginSingleTimeCommands(); @@ -173,7 +258,7 @@ void Image::createTextureImageView() { viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.levelCount = mipLevels; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; @@ -182,4 +267,29 @@ void Image::createTextureImageView() { } } +void Image::createTextureSampler() { + + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = xeDevice.getProperties().limits.maxSamplerAnisotropy; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = static_cast<float>(mipLevels); + samplerInfo.mipLodBias = 0.0f; + + if (vkCreateSampler(xeDevice.device(), &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { + throw std::runtime_error("failed to create texture sampler!"); + } +} + }
\ No newline at end of file |