This commit is contained in:
Mars 2024-10-11 20:50:23 -04:00
parent 8285b60211
commit 8bb2fafe01
Signed by: pupbrained
GPG key ID: 874E22DF2F9DFCB5

View file

@ -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