Skip to content

Commit a606451

Browse files
committed
Add mipmap
1 parent b32d4ff commit a606451

File tree

9 files changed

+2748
-14
lines changed

9 files changed

+2748
-14
lines changed

docs/codes/0700_mipmaps/main.cpp

Lines changed: 1705 additions & 0 deletions
Large diffs are not rendered by default.

docs/codes/0700_mipmaps/main.diff

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
diff --git a/src/main.cpp b/src/main.cpp
2+
index 6dabfb1..89a0f11 100644
3+
--- a/src/main.cpp
4+
+++ b/src/main.cpp
5+
@@ -85,6 +85,7 @@ private:
6+
std::vector<vk::raii::Buffer> m_uniformBuffers;
7+
std::vector<void*> m_uniformBuffersMapped;
8+
vk::raii::DeviceMemory m_textureImageMemory{ nullptr };
9+
+ uint32_t m_mipLevels;
10+
vk::raii::Image m_textureImage{ nullptr };
11+
vk::raii::ImageView m_textureImageView{ nullptr };
12+
vk::raii::Sampler m_textureSampler{ nullptr };
13+
@@ -492,7 +493,12 @@ private:
14+
m_swapChainImageViews.reserve( m_swapChainImages.size() );
15+
for (size_t i = 0; i < m_swapChainImages.size(); ++i) {
16+
m_swapChainImageViews.emplace_back(
17+
- createImageView(m_swapChainImages[i], m_swapChainImageFormat, vk::ImageAspectFlagBits::eColor)
18+
+ createImageView(
19+
+ m_swapChainImages[i],
20+
+ m_swapChainImageFormat,
21+
+ vk::ImageAspectFlagBits::eColor,
22+
+ 1
23+
+ )
24+
);
25+
}
26+
}
27+
@@ -1185,6 +1191,7 @@ private:
28+
void createImage(
29+
uint32_t width,
30+
uint32_t height,
31+
+ uint32_t mipLevels,
32+
vk::Format format,
33+
vk::ImageTiling tilling,
34+
vk::ImageUsageFlags usage,
35+
@@ -1197,7 +1204,7 @@ private:
36+
imageInfo.extent.width = width;
37+
imageInfo.extent.height = height;
38+
imageInfo.extent.depth = 1;
39+
- imageInfo.mipLevels = 1;
40+
+ imageInfo.mipLevels = mipLevels;
41+
imageInfo.arrayLayers = 1;
42+
imageInfo.format = format;
43+
imageInfo.tiling = tilling;
44+
@@ -1221,7 +1228,8 @@ private:
45+
vk::raii::Image& image,
46+
vk::Format format,
47+
vk::ImageLayout oldLayout,
48+
- vk::ImageLayout newLayout
49+
+ vk::ImageLayout newLayout,
50+
+ uint32_t mipLevels
51+
) {
52+
vk::raii::CommandBuffer commandBuffer = beginSingleTimeCommands();
53+
54+
@@ -1233,7 +1241,7 @@ private:
55+
barrier.image = image;
56+
// barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
57+
barrier.subresourceRange.baseMipLevel = 0;
58+
- barrier.subresourceRange.levelCount = 1;
59+
+ barrier.subresourceRange.levelCount = mipLevels;
60+
barrier.subresourceRange.baseArrayLayer = 0;
61+
barrier.subresourceRange.layerCount = 1;
62+
63+
@@ -1324,6 +1332,7 @@ private:
64+
throw std::runtime_error("failed to load texture image!");
65+
}
66+
vk::DeviceSize imageSize = texWidth * texHeight * 4;
67+
+ m_mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
68+
69+
vk::raii::DeviceMemory stagingBufferMemory{ nullptr };
70+
vk::raii::Buffer stagingBuffer{ nullptr };
71+
@@ -1346,8 +1355,10 @@ private:
72+
createImage(
73+
texWidth,
74+
texHeight,
75+
+ m_mipLevels,
76+
vk::Format::eR8G8B8A8Srgb,
77+
vk::ImageTiling::eOptimal,
78+
+ vk::ImageUsageFlagBits::eTransferSrc |
79+
vk::ImageUsageFlagBits::eTransferDst |
80+
vk::ImageUsageFlagBits::eSampled,
81+
vk::MemoryPropertyFlagBits::eDeviceLocal,
82+
@@ -1359,7 +1370,8 @@ private:
83+
m_textureImage,
84+
vk::Format::eR8G8B8A8Srgb,
85+
vk::ImageLayout::eUndefined,
86+
- vk::ImageLayout::eTransferDstOptimal
87+
+ vk::ImageLayout::eTransferDstOptimal,
88+
+ m_mipLevels
89+
);
90+
91+
copyBufferToImage(
92+
@@ -1369,33 +1381,52 @@ private:
93+
static_cast<uint32_t>(texHeight)
94+
);
95+
96+
- transitionImageLayout(
97+
+ generateMipmaps(
98+
m_textureImage,
99+
vk::Format::eR8G8B8A8Srgb,
100+
- vk::ImageLayout::eTransferDstOptimal,
101+
- vk::ImageLayout::eShaderReadOnlyOptimal
102+
+ texWidth,
103+
+ texHeight,
104+
+ m_mipLevels
105+
);
106+
+
107+
+ // transitionImageLayout(
108+
+ // m_textureImage,
109+
+ // vk::Format::eR8G8B8A8Srgb,
110+
+ // vk::ImageLayout::eTransferDstOptimal,
111+
+ // vk::ImageLayout::eShaderReadOnlyOptimal,
112+
+ // m_mipLevels
113+
+ // );
114+
115+
}
116+
/////////////////////////////////////////////////////////////////
117+
118+
/////////////////////////////////////////////////////////////////
119+
/// image view and sampler
120+
- vk::raii::ImageView createImageView(vk::Image image, vk::Format format, vk::ImageAspectFlags aspectFlags) {
121+
+ vk::raii::ImageView createImageView(
122+
+ vk::Image image,
123+
+ vk::Format format,
124+
+ vk::ImageAspectFlags aspectFlags,
125+
+ uint32_t mipLevels
126+
+ ) {
127+
vk::ImageViewCreateInfo viewInfo;
128+
viewInfo.image = image;
129+
viewInfo.viewType = vk::ImageViewType::e2D;
130+
viewInfo.format = format;
131+
viewInfo.subresourceRange.aspectMask = aspectFlags;
132+
viewInfo.subresourceRange.baseMipLevel = 0;
133+
- viewInfo.subresourceRange.levelCount = 1;
134+
+ viewInfo.subresourceRange.levelCount = mipLevels;
135+
viewInfo.subresourceRange.baseArrayLayer = 0;
136+
viewInfo.subresourceRange.layerCount = 1;
137+
138+
return m_device.createImageView(viewInfo);
139+
}
140+
void createTextureImageView() {
141+
- m_textureImageView = createImageView(m_textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor);
142+
+ m_textureImageView = createImageView(
143+
+ m_textureImage,
144+
+ vk::Format::eR8G8B8A8Srgb,
145+
+ vk::ImageAspectFlagBits::eColor,
146+
+ m_mipLevels
147+
+ );
148+
}
149+
void createTextureSampler() {
150+
vk::SamplerCreateInfo samplerInfo;
151+
@@ -1420,7 +1451,9 @@ private:
152+
samplerInfo.mipmapMode = vk::SamplerMipmapMode::eLinear;
153+
samplerInfo.mipLodBias = 0.0f;
154+
samplerInfo.minLod = 0.0f;
155+
- samplerInfo.maxLod = 0.0f;
156+
+ samplerInfo.maxLod = static_cast<float>(m_mipLevels);
157+
+
158+
+ // samplerInfo.minLod = static_cast<float>(m_mipLevels / 2);
159+
160+
m_textureSampler = m_device.createSampler(samplerInfo);
161+
}
162+
@@ -1466,6 +1499,7 @@ private:
163+
createImage(
164+
m_swapChainExtent.width,
165+
m_swapChainExtent.height,
166+
+ 1,
167+
depthFormat,
168+
vk::ImageTiling::eOptimal,
169+
vk::ImageUsageFlagBits::eDepthStencilAttachment,
170+
@@ -1474,13 +1508,19 @@ private:
171+
m_depthImageMemory
172+
);
173+
174+
- m_depthImageView = createImageView(m_depthImage, depthFormat, vk::ImageAspectFlagBits::eDepth);
175+
+ m_depthImageView = createImageView(
176+
+ m_depthImage,
177+
+ depthFormat,
178+
+ vk::ImageAspectFlagBits::eDepth,
179+
+ 1
180+
+ );
181+
182+
// transitionImageLayout(
183+
// m_depthImage,
184+
// depthFormat,
185+
// vk::ImageLayout::eUndefined,
186+
- // vk::ImageLayout::eDepthStencilAttachmentOptimal
187+
+ // vk::ImageLayout::eDepthStencilAttachmentOptimal,
188+
+ // 1
189+
// );
190+
}
191+
/////////////////////////////////////////////////////////////////
192+
@@ -1538,6 +1578,114 @@ private:
193+
}
194+
}
195+
/////////////////////////////////////////////////////////////////
196+
+
197+
+ /////////////////////////////////////////////////////////////////
198+
+ /// mipmaps
199+
+ void generateMipmaps(
200+
+ vk::raii::Image& image,
201+
+ vk::Format imageFormat,
202+
+ int32_t texWidth,
203+
+ int32_t texHeight,
204+
+ uint32_t mipLevels
205+
+ ) {
206+
+ // vk::FormatProperties
207+
+ auto formatProperties = m_physicalDevice.getFormatProperties(imageFormat);
208+
+
209+
+ if(!(formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear)){
210+
+ throw std::runtime_error("texture image format does not support linear blitting!");
211+
+ }
212+
+
213+
+
214+
+ auto commandBuffer = beginSingleTimeCommands();
215+
+
216+
+ vk::ImageMemoryBarrier barrier;
217+
+ barrier.image = image;
218+
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
219+
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
220+
+ barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
221+
+ barrier.subresourceRange.baseArrayLayer = 0;
222+
+ barrier.subresourceRange.layerCount = 1;
223+
+ barrier.subresourceRange.levelCount = 1;
224+
+
225+
+ int32_t mipWidth = texWidth;
226+
+ int32_t mipHeight = texHeight;
227+
+
228+
+ for (uint32_t i = 1; i < mipLevels; ++i) {
229+
+ barrier.subresourceRange.baseMipLevel = i - 1;
230+
+ barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
231+
+ barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
232+
+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
233+
+ barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
234+
+ commandBuffer.pipelineBarrier(
235+
+ vk::PipelineStageFlagBits::eTransfer,
236+
+ vk::PipelineStageFlagBits::eTransfer,
237+
+ {},
238+
+ nullptr,
239+
+ nullptr,
240+
+ barrier
241+
+ );
242+
+
243+
+ vk::ImageBlit blit;
244+
+ blit.srcOffsets[0] = vk::Offset3D{ 0, 0, 0 };
245+
+ blit.srcOffsets[1] = vk::Offset3D{ mipWidth, mipHeight, 1 };
246+
+ blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
247+
+ blit.srcSubresource.mipLevel = i - 1;
248+
+ blit.srcSubresource.baseArrayLayer = 0;
249+
+ blit.srcSubresource.layerCount = 1;
250+
+ blit.dstOffsets[0] = vk::Offset3D{ 0, 0, 0 };
251+
+ blit.dstOffsets[1] = vk::Offset3D{
252+
+ mipWidth > 1 ? mipWidth / 2 : 1,
253+
+ mipHeight > 1 ? mipHeight / 2 : 1,
254+
+ 1
255+
+ };
256+
+ blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
257+
+ blit.dstSubresource.mipLevel = i;
258+
+ blit.dstSubresource.baseArrayLayer = 0;
259+
+ blit.dstSubresource.layerCount = 1;
260+
+ commandBuffer.blitImage(
261+
+ image, vk::ImageLayout::eTransferSrcOptimal,
262+
+ image, vk::ImageLayout::eTransferDstOptimal,
263+
+ blit,
264+
+ vk::Filter::eLinear
265+
+ );
266+
+
267+
+ barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
268+
+ barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
269+
+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
270+
+ barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
271+
+ commandBuffer.pipelineBarrier(
272+
+ vk::PipelineStageFlagBits::eTransfer,
273+
+ vk::PipelineStageFlagBits::eFragmentShader,
274+
+ {},
275+
+ nullptr,
276+
+ nullptr,
277+
+ barrier
278+
+ );
279+
+
280+
+ if (mipWidth > 1) mipWidth /= 2;
281+
+ if (mipHeight > 1) mipHeight /= 2;
282+
+ }
283+
+
284+
+ barrier.subresourceRange.baseMipLevel = mipLevels - 1;
285+
+ barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
286+
+ barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
287+
+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
288+
+ barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
289+
+ commandBuffer.pipelineBarrier(
290+
+ vk::PipelineStageFlagBits::eTransfer,
291+
+ vk::PipelineStageFlagBits::eFragmentShader,
292+
+ {},
293+
+ nullptr,
294+
+ nullptr,
295+
+ barrier
296+
+ );
297+
+
298+
+ if (mipWidth > 1) mipWidth /= 2;
299+
+ if (mipHeight > 1) mipHeight /= 2;
300+
+
301+
+ endSingleTimeCommands( std::move(commandBuffer) );
302+
+ }
303+
+ /////////////////////////////////////////////////////////////////
304+
};
305+
306+

docs/images/highmipmaps.png

166 KB
Loading

docs/images/mipmaps.png

276 KB
Loading

docs/images/mipmaps_comparison.png

372 KB
Loading

docs/images/mipmaps_example.jpg

125 KB
Loading

0 commit comments

Comments
 (0)