Mipmaps
This commit is contained in:
parent
8285b60211
commit
8bb2fafe01
143
src/main.cpp
143
src/main.cpp
|
@ -124,6 +124,7 @@ class VulkanApp {
|
|||
vk::UniqueDeviceMemory mDepthImageMemory;
|
||||
vk::UniqueImageView mDepthImageView;
|
||||
|
||||
u32 mMipLevels;
|
||||
vk::UniqueImage mTextureImage;
|
||||
vk::UniqueDeviceMemory mTextureImageMemory;
|
||||
vk::UniqueImageView mTextureImageView;
|
||||
|
@ -439,7 +440,7 @@ class VulkanApp {
|
|||
|
||||
for (u32 i = 0; i < mSwapChainImages.size(); i++)
|
||||
mSwapChainImageViews[i] =
|
||||
createImageView(mSwapChainImages[i], mSwapChainImageFormat, vk::ImageAspectFlagBits::eColor);
|
||||
createImageView(mSwapChainImages[i], mSwapChainImageFormat, vk::ImageAspectFlagBits::eColor, 1);
|
||||
}
|
||||
|
||||
fn createRenderPass() -> void {
|
||||
|
@ -663,6 +664,7 @@ class VulkanApp {
|
|||
createImage(
|
||||
mSwapChainExtent.width,
|
||||
mSwapChainExtent.height,
|
||||
1,
|
||||
depthFormat,
|
||||
vk::ImageTiling::eOptimal,
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||
|
@ -671,7 +673,7 @@ class VulkanApp {
|
|||
mDepthImageMemory
|
||||
);
|
||||
|
||||
mDepthImageView = createImageView(mDepthImage.get(), depthFormat, vk::ImageAspectFlagBits::eDepth);
|
||||
mDepthImageView = createImageView(mDepthImage.get(), depthFormat, vk::ImageAspectFlagBits::eDepth, 1);
|
||||
}
|
||||
|
||||
fn findSupportedFormat(
|
||||
|
@ -704,11 +706,14 @@ class VulkanApp {
|
|||
|
||||
fn createTextureImage() -> void {
|
||||
i32 texWidth = 0, texHeight = 0, texChannels = 0;
|
||||
|
||||
u8* pixels = stbi_load(TEXTURE_PATH, &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
vk::DeviceSize imageSize =
|
||||
static_cast<vk::DeviceSize>(texWidth) * static_cast<vk::DeviceSize>(texHeight) * 4;
|
||||
|
||||
mMipLevels = static_cast<u32>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
|
||||
|
||||
if (!pixels)
|
||||
throw std::runtime_error("Failed to load texture image!");
|
||||
|
||||
|
@ -730,36 +735,131 @@ class VulkanApp {
|
|||
createImage(
|
||||
static_cast<u32>(texWidth),
|
||||
static_cast<u32>(texHeight),
|
||||
mMipLevels,
|
||||
vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageTiling::eOptimal,
|
||||
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
|
||||
vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst |
|
||||
vk::ImageUsageFlagBits::eSampled,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
mTextureImage,
|
||||
mTextureImageMemory
|
||||
);
|
||||
|
||||
transitionImageLayout(
|
||||
mTextureImage.get(),
|
||||
vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eTransferDstOptimal
|
||||
mTextureImage.get(), vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, mMipLevels
|
||||
);
|
||||
|
||||
copyBufferToImage(
|
||||
stagingBuffer.get(), mTextureImage.get(), static_cast<u32>(texWidth), static_cast<u32>(texHeight)
|
||||
);
|
||||
|
||||
transitionImageLayout(
|
||||
mTextureImage.get(),
|
||||
vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageLayout::eTransferDstOptimal,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal
|
||||
generateMipmaps(mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, texWidth, texHeight, mMipLevels);
|
||||
}
|
||||
|
||||
fn generateMipmaps(vk::Image image, vk::Format imageFormat, i32 texWidth, i32 texHeight, u32 mipLevels)
|
||||
-> void {
|
||||
vk::FormatProperties formatProperties = mPhysicalDevice.getFormatProperties(imageFormat);
|
||||
|
||||
if (!(formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear))
|
||||
throw std::runtime_error("Texture image format does not support linear blitting!");
|
||||
|
||||
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
vk::ImageMemoryBarrier barrier {
|
||||
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||
.image = image,
|
||||
.subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1 }
|
||||
};
|
||||
|
||||
i32 mipWidth = texWidth;
|
||||
i32 mipHeight = texHeight;
|
||||
|
||||
for (u32 i = 1; i < mipLevels; i++) {
|
||||
barrier.subresourceRange.baseMipLevel = i - 1;
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
|
||||
|
||||
commandBuffer->pipelineBarrier(
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
barrier
|
||||
);
|
||||
|
||||
vk::ImageBlit blit {
|
||||
.srcSubresource = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = i - 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1 },
|
||||
.srcOffsets = std::array<vk::Offset3D, 2> { { { 0, 0, 0 }, { mipWidth, mipHeight, 1 } } },
|
||||
.dstSubresource = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = i,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1 },
|
||||
.dstOffsets =
|
||||
std::array<vk::Offset3D, 2> {
|
||||
{ { 0, 0, 0 }, { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 } } }
|
||||
};
|
||||
|
||||
commandBuffer->blitImage(
|
||||
image,
|
||||
vk::ImageLayout::eTransferSrcOptimal,
|
||||
image,
|
||||
vk::ImageLayout::eTransferDstOptimal,
|
||||
blit,
|
||||
vk::Filter::eLinear
|
||||
);
|
||||
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
|
||||
commandBuffer->pipelineBarrier(
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
barrier
|
||||
);
|
||||
|
||||
if (mipWidth > 1)
|
||||
mipWidth /= 2;
|
||||
if (mipHeight > 1)
|
||||
mipHeight /= 2;
|
||||
}
|
||||
|
||||
barrier.subresourceRange.baseMipLevel = mMipLevels - 1;
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
|
||||
commandBuffer->pipelineBarrier(
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
barrier
|
||||
);
|
||||
|
||||
endSingleTimeCommands(std::move(commandBuffer));
|
||||
}
|
||||
|
||||
fn createTextureImageView() -> void {
|
||||
mTextureImageView =
|
||||
createImageView(mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor);
|
||||
mTextureImageView = createImageView(
|
||||
mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor, mMipLevels
|
||||
);
|
||||
}
|
||||
|
||||
fn createTextureSampler() -> void {
|
||||
|
@ -778,7 +878,7 @@ class VulkanApp {
|
|||
.compareEnable = vk::False,
|
||||
.compareOp = vk::CompareOp::eAlways,
|
||||
.minLod = 0.0F,
|
||||
.maxLod = 0.0F,
|
||||
.maxLod = static_cast<f32>(mMipLevels),
|
||||
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
||||
.unnormalizedCoordinates = vk::False,
|
||||
};
|
||||
|
@ -786,13 +886,13 @@ class VulkanApp {
|
|||
mTextureSampler = mDevice->createSamplerUnique(samplerInfo);
|
||||
}
|
||||
|
||||
fn createImageView(vk::Image image, vk::Format format, vk::ImageAspectFlags aspectFlags)
|
||||
fn createImageView(vk::Image image, vk::Format format, vk::ImageAspectFlags aspectFlags, u32 mipLevels)
|
||||
-> vk::UniqueImageView {
|
||||
vk::ImageViewCreateInfo viewInfo {
|
||||
.image = image, .viewType = vk::ImageViewType::e2D, .format = format, .subresourceRange = {
|
||||
.aspectMask = aspectFlags,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.levelCount = mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
}
|
||||
|
@ -804,6 +904,7 @@ class VulkanApp {
|
|||
fn createImage(
|
||||
u32 width,
|
||||
u32 height,
|
||||
u32 mipLevels,
|
||||
vk::Format format,
|
||||
vk::ImageTiling tiling,
|
||||
vk::ImageUsageFlags usage,
|
||||
|
@ -815,7 +916,7 @@ class VulkanApp {
|
|||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = { .width = width, .height = height, .depth = 1 },
|
||||
.mipLevels = 1,
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = tiling,
|
||||
|
@ -840,9 +941,9 @@ class VulkanApp {
|
|||
|
||||
fn transitionImageLayout(
|
||||
vk::Image image,
|
||||
vk::Format format,
|
||||
vk::ImageLayout oldLayout,
|
||||
vk::ImageLayout newLayout
|
||||
vk::ImageLayout newLayout,
|
||||
u32 mipLevels
|
||||
) -> void {
|
||||
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
|
@ -855,7 +956,7 @@ class VulkanApp {
|
|||
// clang-format off
|
||||
.subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.levelCount = mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1 }
|
||||
// clang-format on
|
||||
|
|
Loading…
Reference in a new issue