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

View file

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