summaryrefslogtreecommitdiff
path: root/engine/xe_image.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/xe_image.cpp')
-rw-r--r--engine/xe_image.cpp120
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