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::UniqueDeviceMemory mDepthImageMemory;
|
||||||
vk::UniqueImageView mDepthImageView;
|
vk::UniqueImageView mDepthImageView;
|
||||||
|
|
||||||
|
u32 mMipLevels;
|
||||||
vk::UniqueImage mTextureImage;
|
vk::UniqueImage mTextureImage;
|
||||||
vk::UniqueDeviceMemory mTextureImageMemory;
|
vk::UniqueDeviceMemory mTextureImageMemory;
|
||||||
vk::UniqueImageView mTextureImageView;
|
vk::UniqueImageView mTextureImageView;
|
||||||
|
@ -439,7 +440,7 @@ class VulkanApp {
|
||||||
|
|
||||||
for (u32 i = 0; i < mSwapChainImages.size(); i++)
|
for (u32 i = 0; i < mSwapChainImages.size(); i++)
|
||||||
mSwapChainImageViews[i] =
|
mSwapChainImageViews[i] =
|
||||||
createImageView(mSwapChainImages[i], mSwapChainImageFormat, vk::ImageAspectFlagBits::eColor);
|
createImageView(mSwapChainImages[i], mSwapChainImageFormat, vk::ImageAspectFlagBits::eColor, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createRenderPass() -> void {
|
fn createRenderPass() -> void {
|
||||||
|
@ -663,6 +664,7 @@ class VulkanApp {
|
||||||
createImage(
|
createImage(
|
||||||
mSwapChainExtent.width,
|
mSwapChainExtent.width,
|
||||||
mSwapChainExtent.height,
|
mSwapChainExtent.height,
|
||||||
|
1,
|
||||||
depthFormat,
|
depthFormat,
|
||||||
vk::ImageTiling::eOptimal,
|
vk::ImageTiling::eOptimal,
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||||
|
@ -671,7 +673,7 @@ class VulkanApp {
|
||||||
mDepthImageMemory
|
mDepthImageMemory
|
||||||
);
|
);
|
||||||
|
|
||||||
mDepthImageView = createImageView(mDepthImage.get(), depthFormat, vk::ImageAspectFlagBits::eDepth);
|
mDepthImageView = createImageView(mDepthImage.get(), depthFormat, vk::ImageAspectFlagBits::eDepth, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn findSupportedFormat(
|
fn findSupportedFormat(
|
||||||
|
@ -704,11 +706,14 @@ class VulkanApp {
|
||||||
|
|
||||||
fn createTextureImage() -> void {
|
fn createTextureImage() -> void {
|
||||||
i32 texWidth = 0, texHeight = 0, texChannels = 0;
|
i32 texWidth = 0, texHeight = 0, texChannels = 0;
|
||||||
|
|
||||||
u8* pixels = stbi_load(TEXTURE_PATH, &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
u8* pixels = stbi_load(TEXTURE_PATH, &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
|
|
||||||
vk::DeviceSize imageSize =
|
vk::DeviceSize imageSize =
|
||||||
static_cast<vk::DeviceSize>(texWidth) * static_cast<vk::DeviceSize>(texHeight) * 4;
|
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)
|
if (!pixels)
|
||||||
throw std::runtime_error("Failed to load texture image!");
|
throw std::runtime_error("Failed to load texture image!");
|
||||||
|
|
||||||
|
@ -730,36 +735,131 @@ class VulkanApp {
|
||||||
createImage(
|
createImage(
|
||||||
static_cast<u32>(texWidth),
|
static_cast<u32>(texWidth),
|
||||||
static_cast<u32>(texHeight),
|
static_cast<u32>(texHeight),
|
||||||
|
mMipLevels,
|
||||||
vk::Format::eR8G8B8A8Srgb,
|
vk::Format::eR8G8B8A8Srgb,
|
||||||
vk::ImageTiling::eOptimal,
|
vk::ImageTiling::eOptimal,
|
||||||
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
|
vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst |
|
||||||
|
vk::ImageUsageFlagBits::eSampled,
|
||||||
vk::MemoryPropertyFlagBits::eDeviceLocal,
|
vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||||
mTextureImage,
|
mTextureImage,
|
||||||
mTextureImageMemory
|
mTextureImageMemory
|
||||||
);
|
);
|
||||||
|
|
||||||
transitionImageLayout(
|
transitionImageLayout(
|
||||||
mTextureImage.get(),
|
mTextureImage.get(), vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, mMipLevels
|
||||||
vk::Format::eR8G8B8A8Srgb,
|
|
||||||
vk::ImageLayout::eUndefined,
|
|
||||||
vk::ImageLayout::eTransferDstOptimal
|
|
||||||
);
|
);
|
||||||
|
|
||||||
copyBufferToImage(
|
copyBufferToImage(
|
||||||
stagingBuffer.get(), mTextureImage.get(), static_cast<u32>(texWidth), static_cast<u32>(texHeight)
|
stagingBuffer.get(), mTextureImage.get(), static_cast<u32>(texWidth), static_cast<u32>(texHeight)
|
||||||
);
|
);
|
||||||
|
|
||||||
transitionImageLayout(
|
generateMipmaps(mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, texWidth, texHeight, mMipLevels);
|
||||||
mTextureImage.get(),
|
}
|
||||||
vk::Format::eR8G8B8A8Srgb,
|
|
||||||
vk::ImageLayout::eTransferDstOptimal,
|
fn generateMipmaps(vk::Image image, vk::Format imageFormat, i32 texWidth, i32 texHeight, u32 mipLevels)
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal
|
-> 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 {
|
fn createTextureImageView() -> void {
|
||||||
mTextureImageView =
|
mTextureImageView = createImageView(
|
||||||
createImageView(mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor);
|
mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor, mMipLevels
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createTextureSampler() -> void {
|
fn createTextureSampler() -> void {
|
||||||
|
@ -778,7 +878,7 @@ class VulkanApp {
|
||||||
.compareEnable = vk::False,
|
.compareEnable = vk::False,
|
||||||
.compareOp = vk::CompareOp::eAlways,
|
.compareOp = vk::CompareOp::eAlways,
|
||||||
.minLod = 0.0F,
|
.minLod = 0.0F,
|
||||||
.maxLod = 0.0F,
|
.maxLod = static_cast<f32>(mMipLevels),
|
||||||
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
||||||
.unnormalizedCoordinates = vk::False,
|
.unnormalizedCoordinates = vk::False,
|
||||||
};
|
};
|
||||||
|
@ -786,13 +886,13 @@ class VulkanApp {
|
||||||
mTextureSampler = mDevice->createSamplerUnique(samplerInfo);
|
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::UniqueImageView {
|
||||||
vk::ImageViewCreateInfo viewInfo {
|
vk::ImageViewCreateInfo viewInfo {
|
||||||
.image = image, .viewType = vk::ImageViewType::e2D, .format = format, .subresourceRange = {
|
.image = image, .viewType = vk::ImageViewType::e2D, .format = format, .subresourceRange = {
|
||||||
.aspectMask = aspectFlags,
|
.aspectMask = aspectFlags,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = 1,
|
.levelCount = mipLevels,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
}
|
}
|
||||||
|
@ -804,6 +904,7 @@ class VulkanApp {
|
||||||
fn createImage(
|
fn createImage(
|
||||||
u32 width,
|
u32 width,
|
||||||
u32 height,
|
u32 height,
|
||||||
|
u32 mipLevels,
|
||||||
vk::Format format,
|
vk::Format format,
|
||||||
vk::ImageTiling tiling,
|
vk::ImageTiling tiling,
|
||||||
vk::ImageUsageFlags usage,
|
vk::ImageUsageFlags usage,
|
||||||
|
@ -815,7 +916,7 @@ class VulkanApp {
|
||||||
.imageType = vk::ImageType::e2D,
|
.imageType = vk::ImageType::e2D,
|
||||||
.format = format,
|
.format = format,
|
||||||
.extent = { .width = width, .height = height, .depth = 1 },
|
.extent = { .width = width, .height = height, .depth = 1 },
|
||||||
.mipLevels = 1,
|
.mipLevels = mipLevels,
|
||||||
.arrayLayers = 1,
|
.arrayLayers = 1,
|
||||||
.samples = vk::SampleCountFlagBits::e1,
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
.tiling = tiling,
|
.tiling = tiling,
|
||||||
|
@ -840,9 +941,9 @@ class VulkanApp {
|
||||||
|
|
||||||
fn transitionImageLayout(
|
fn transitionImageLayout(
|
||||||
vk::Image image,
|
vk::Image image,
|
||||||
vk::Format format,
|
|
||||||
vk::ImageLayout oldLayout,
|
vk::ImageLayout oldLayout,
|
||||||
vk::ImageLayout newLayout
|
vk::ImageLayout newLayout,
|
||||||
|
u32 mipLevels
|
||||||
) -> void {
|
) -> void {
|
||||||
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||||
|
|
||||||
|
@ -855,7 +956,7 @@ class VulkanApp {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
.subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
.subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = 1,
|
.levelCount = mipLevels,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1 }
|
.layerCount = 1 }
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
Loading…
Reference in a new issue