Skip to content

Commit dff13fe

Browse files
author
warriormaster12
committed
Mipmaps
1 parent 9dc6adb commit dff13fe

File tree

4 files changed

+111
-17
lines changed

4 files changed

+111
-17
lines changed

Include/Engine/Renderer/VkTextureManager.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ namespace VkRenderer
1414
void createTextureImage(const std::string TEXTURE_PATH, VkCommandPool& commandPool);
1515
void createTextureImageView();
1616
void createTextureSampler();
17-
VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags);
18-
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
19-
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandPool& commandPool);
17+
VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels);
18+
void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
19+
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandPool& commandPool, uint32_t mipLevels);
2020
void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, VkCommandPool& commandPool);
21+
void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels, VkCommandPool& commandPool);
2122

2223
VkSetup *setup_ref;
2324
VkBufferCreation *buffer_ref;
2425
VkMemory *memory_ref;
2526

27+
uint32_t mipLevels;
2628
VkImage textureImage;
2729
VkDeviceMemory textureImageMemory;
2830
VkImageView textureImageView;

src/Engine/Renderer/Buffers/VkDepthBuffer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ namespace VkRenderer
77
{
88
VkFormat depthFormat = findDepthFormat();
99

10-
texture_m_ref->createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);
11-
depthImageView = texture_m_ref->createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
10+
texture_m_ref->createImage(swapChainExtent.width, swapChainExtent.height, 1, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);
11+
depthImageView = texture_m_ref->createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1);
1212
}
1313
VkFormat VkDepthBuffer::findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) {
1414
for (VkFormat format : candidates) {

src/Engine/Renderer/VkSwapChain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ namespace VkRenderer
6868
swapChainImageViews.resize(swapChainImages.size());
6969

7070
for (size_t i = 0; i < swapChainImages.size(); i++) {
71-
swapChainImageViews[i] = texture_m_ref->createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
71+
swapChainImageViews[i] = texture_m_ref->createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
7272
}
7373
}
7474

src/Engine/Renderer/VkTextureManager.cpp

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace VkRenderer
99
int texWidth, texHeight, texChannels;
1010
stbi_uc* pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
1111
VkDeviceSize imageSize = texWidth * texHeight * 4;
12+
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
1213

1314
if (!pixels) {
1415
throw std::runtime_error("failed to load texture image!");
@@ -25,19 +26,21 @@ namespace VkRenderer
2526

2627
stbi_image_free(pixels);
2728

28-
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);
29+
createImage(texWidth, texHeight, mipLevels, 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);
2930

30-
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, commandPool);
31-
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight), commandPool);
32-
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, commandPool);
31+
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, commandPool,mipLevels);
32+
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight), commandPool);
33+
//transitioned to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL while generating mipmaps
3334

3435
vkDestroyBuffer(setup_ref->device, stagingBuffer, nullptr);
3536
vkFreeMemory(setup_ref->device, stagingBufferMemory, nullptr);
37+
38+
generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, texWidth, texHeight, mipLevels, commandPool);
3639
}
3740
void VkTextureManager::createTextureImageView() {
38-
textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
41+
textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, mipLevels);
3942
}
40-
VkImageView VkTextureManager::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags)
43+
VkImageView VkTextureManager::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels)
4144
{
4245
VkImageViewCreateInfo viewInfo{};
4346
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@@ -46,7 +49,7 @@ namespace VkRenderer
4649
viewInfo.format = format;
4750
viewInfo.subresourceRange.aspectMask = aspectFlags;
4851
viewInfo.subresourceRange.baseMipLevel = 0;
49-
viewInfo.subresourceRange.levelCount = 1;
52+
viewInfo.subresourceRange.levelCount = mipLevels;
5053
viewInfo.subresourceRange.baseArrayLayer = 0;
5154
viewInfo.subresourceRange.layerCount = 1;
5255

@@ -58,15 +61,15 @@ namespace VkRenderer
5861
return imageView;
5962
}
6063

61-
void VkTextureManager::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory)
64+
void VkTextureManager::createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory)
6265
{
6366
VkImageCreateInfo imageInfo{};
6467
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6568
imageInfo.imageType = VK_IMAGE_TYPE_2D;
6669
imageInfo.extent.width = width;
6770
imageInfo.extent.height = height;
6871
imageInfo.extent.depth = 1;
69-
imageInfo.mipLevels = 1;
72+
imageInfo.mipLevels = mipLevels;
7073
imageInfo.arrayLayers = 1;
7174
imageInfo.format = format;
7275
imageInfo.tiling = tiling;
@@ -109,6 +112,9 @@ namespace VkRenderer
109112
samplerInfo.compareEnable = VK_FALSE;
110113
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
111114
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
115+
samplerInfo.minLod = 0;
116+
samplerInfo.maxLod = static_cast<float>(mipLevels);
117+
samplerInfo.mipLodBias = 0.0f;
112118

113119
if (vkCreateSampler(setup_ref->device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) {
114120
throw std::runtime_error("failed to create texture sampler!");
@@ -137,8 +143,94 @@ namespace VkRenderer
137143

138144
buffer_ref->endSingleTimeCommands(commandBuffer,commandPool);
139145
}
146+
void VkTextureManager::generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels, VkCommandPool& commandPool) {
147+
// Check if image format supports linear blitting
148+
VkFormatProperties formatProperties;
149+
vkGetPhysicalDeviceFormatProperties(setup_ref->physicalDevice, imageFormat, &formatProperties);
150+
151+
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
152+
throw std::runtime_error("texture image format does not support linear blitting!");
153+
}
154+
155+
VkCommandBuffer commandBuffer = buffer_ref->beginSingleTimeCommands(commandPool);
140156

141-
void VkTextureManager::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandPool& commandPool)
157+
VkImageMemoryBarrier barrier{};
158+
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
159+
barrier.image = image;
160+
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
161+
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
162+
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
163+
barrier.subresourceRange.baseArrayLayer = 0;
164+
barrier.subresourceRange.layerCount = 1;
165+
barrier.subresourceRange.levelCount = 1;
166+
167+
int32_t mipWidth = texWidth;
168+
int32_t mipHeight = texHeight;
169+
170+
for (uint32_t i = 1; i < mipLevels; i++) {
171+
barrier.subresourceRange.baseMipLevel = i - 1;
172+
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
173+
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
174+
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
175+
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
176+
177+
vkCmdPipelineBarrier(commandBuffer,
178+
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
179+
0, nullptr,
180+
0, nullptr,
181+
1, &barrier);
182+
183+
VkImageBlit blit{};
184+
blit.srcOffsets[0] = {0, 0, 0};
185+
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
186+
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
187+
blit.srcSubresource.mipLevel = i - 1;
188+
blit.srcSubresource.baseArrayLayer = 0;
189+
blit.srcSubresource.layerCount = 1;
190+
blit.dstOffsets[0] = {0, 0, 0};
191+
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
192+
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
193+
blit.dstSubresource.mipLevel = i;
194+
blit.dstSubresource.baseArrayLayer = 0;
195+
blit.dstSubresource.layerCount = 1;
196+
197+
vkCmdBlitImage(commandBuffer,
198+
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
199+
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
200+
1, &blit,
201+
VK_FILTER_LINEAR);
202+
203+
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
204+
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
205+
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
206+
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
207+
208+
vkCmdPipelineBarrier(commandBuffer,
209+
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
210+
0, nullptr,
211+
0, nullptr,
212+
1, &barrier);
213+
214+
if (mipWidth > 1) mipWidth /= 2;
215+
if (mipHeight > 1) mipHeight /= 2;
216+
}
217+
218+
barrier.subresourceRange.baseMipLevel = mipLevels - 1;
219+
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
220+
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
221+
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
222+
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
223+
224+
vkCmdPipelineBarrier(commandBuffer,
225+
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
226+
0, nullptr,
227+
0, nullptr,
228+
1, &barrier);
229+
230+
buffer_ref->endSingleTimeCommands(commandBuffer, commandPool);
231+
}
232+
233+
void VkTextureManager::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandPool& commandPool, uint32_t mipLevels)
142234
{
143235
VkCommandBuffer commandBuffer = buffer_ref->beginSingleTimeCommands(commandPool);
144236

@@ -151,7 +243,7 @@ namespace VkRenderer
151243
barrier.image = image;
152244
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
153245
barrier.subresourceRange.baseMipLevel = 0;
154-
barrier.subresourceRange.levelCount = 1;
246+
barrier.subresourceRange.levelCount = mipLevels;
155247
barrier.subresourceRange.baseArrayLayer = 0;
156248
barrier.subresourceRange.layerCount = 1;
157249

0 commit comments

Comments
 (0)