Added LoDs
This commit is contained in:
parent
2fbc0e8f22
commit
ddb6f97646
211
src/main.cpp
211
src/main.cpp
@ -11,6 +11,7 @@
|
||||
#include <ios>
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <fstream> // to load shaders
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <utility>
|
||||
@ -183,6 +184,8 @@ class HelloTriangleApplication {
|
||||
vk::raii::Image depthImage = nullptr;
|
||||
vk::raii::DeviceMemory depthImageMemory = nullptr;
|
||||
vk::raii::ImageView depthImageView = nullptr;
|
||||
// Minmaps
|
||||
uint32_t mipLevels;
|
||||
// Indexes
|
||||
uint32_t queueIndex = ~0;
|
||||
uint32_t frameIndex = 0;
|
||||
@ -490,7 +493,8 @@ class HelloTriangleApplication {
|
||||
swapChainImageViews.emplace_back(createImageView(
|
||||
swapChainImages[i],
|
||||
swapChainImageFormat,
|
||||
vk::ImageAspectFlagBits::eColor
|
||||
vk::ImageAspectFlagBits::eColor,
|
||||
1
|
||||
));
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
@ -684,6 +688,7 @@ class HelloTriangleApplication {
|
||||
createImage(
|
||||
swapChainExtent.width,
|
||||
swapChainExtent.height,
|
||||
1,
|
||||
depthFormat,
|
||||
vk::ImageTiling::eOptimal,
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||
@ -694,7 +699,8 @@ class HelloTriangleApplication {
|
||||
depthImageView = createImageView(
|
||||
depthImage,
|
||||
depthFormat,
|
||||
vk::ImageAspectFlagBits::eDepth
|
||||
vk::ImageAspectFlagBits::eDepth,
|
||||
1
|
||||
);
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Depth ressouce created !\n";
|
||||
@ -709,6 +715,8 @@ class HelloTriangleApplication {
|
||||
stbi_uc* pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
vk::DeviceSize imageSize = texWidth * texHeight * 4;
|
||||
|
||||
mipLevels = static_cast<uint32_t> (std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
|
||||
|
||||
if (!pixels) {
|
||||
throw std::runtime_error("Failed to load texture image!\nAborting...");
|
||||
}
|
||||
@ -731,17 +739,41 @@ class HelloTriangleApplication {
|
||||
createImage(
|
||||
texWidth,
|
||||
texHeight,
|
||||
mipLevels,
|
||||
vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageTiling::eOptimal,
|
||||
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
|
||||
vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
textureImage,
|
||||
textureImageMemory
|
||||
);
|
||||
|
||||
transitionImageLayout(textureImage, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
|
||||
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
|
||||
transitionImageLayout(textureImage, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
transitionImageLayout(
|
||||
textureImage,
|
||||
vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eTransferDstOptimal,
|
||||
mipLevels
|
||||
);
|
||||
copyBufferToImage(
|
||||
stagingBuffer,
|
||||
textureImage,
|
||||
static_cast<uint32_t>(texWidth),
|
||||
static_cast<uint32_t>(texHeight)
|
||||
);
|
||||
transitionImageLayout(
|
||||
textureImage,
|
||||
vk::ImageLayout::eTransferDstOptimal,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
mipLevels
|
||||
);
|
||||
|
||||
generateMipmaps(
|
||||
textureImage,
|
||||
vk::Format::eR8G8B8A8Srgb,
|
||||
texWidth,
|
||||
texHeight,
|
||||
mipLevels
|
||||
);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Texture image created !\n";
|
||||
@ -755,7 +787,8 @@ class HelloTriangleApplication {
|
||||
textureImageView = createImageView(
|
||||
textureImage,
|
||||
vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageAspectFlagBits::eColor
|
||||
vk::ImageAspectFlagBits::eColor,
|
||||
mipLevels
|
||||
);
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Texture Image created !\n";
|
||||
@ -765,6 +798,7 @@ class HelloTriangleApplication {
|
||||
void createImage(
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t mipLevels,
|
||||
vk::Format format,
|
||||
vk::ImageTiling tiling,
|
||||
vk::ImageUsageFlags usage,
|
||||
@ -779,7 +813,7 @@ class HelloTriangleApplication {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = { width, height, 1 },
|
||||
.mipLevels = 1,
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = tiling,
|
||||
@ -820,7 +854,7 @@ class HelloTriangleApplication {
|
||||
.compareEnable = vk::True,
|
||||
.compareOp = vk::CompareOp::eAlways,
|
||||
.minLod = 0.0f,
|
||||
.maxLod = 0.0f,
|
||||
.maxLod = vk::LodClampNone,
|
||||
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
||||
.unnormalizedCoordinates = vk::False
|
||||
};
|
||||
@ -1222,7 +1256,8 @@ class HelloTriangleApplication {
|
||||
void transitionImageLayout(
|
||||
const vk::raii::Image& image,
|
||||
vk::ImageLayout oldLayout,
|
||||
vk::ImageLayout newLayout
|
||||
vk::ImageLayout newLayout,
|
||||
uint32_t mipLevels
|
||||
) {
|
||||
auto commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
@ -1236,7 +1271,7 @@ class HelloTriangleApplication {
|
||||
.subresourceRange = {
|
||||
vk::ImageAspectFlagBits::eColor,
|
||||
0,
|
||||
1,
|
||||
mipLevels,
|
||||
0,
|
||||
1
|
||||
}
|
||||
@ -1444,21 +1479,28 @@ class HelloTriangleApplication {
|
||||
const vk::DebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
||||
void *
|
||||
){
|
||||
if (severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eError || severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning) {
|
||||
if (severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eError || severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning){
|
||||
#ifndef NDEBUG
|
||||
std::cerr << "Validation layer: type " << to_string(type) << " msg: " << pCallbackData->pMessage << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return vk::False;
|
||||
}
|
||||
};
|
||||
|
||||
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
|
||||
static void framebufferResizeCallback(
|
||||
GLFWwindow* window,
|
||||
int width,
|
||||
int height
|
||||
){
|
||||
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
|
||||
app->framebufferResized = true;
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties) {
|
||||
uint32_t findMemoryType(
|
||||
uint32_t typeFilter,
|
||||
vk::MemoryPropertyFlags properties
|
||||
){
|
||||
vk::PhysicalDeviceMemoryProperties memProperties = physicalDevice.getMemoryProperties();
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
@ -1593,11 +1635,12 @@ class HelloTriangleApplication {
|
||||
queue.waitIdle();
|
||||
}
|
||||
|
||||
vk::raii::ImageView createImageView(
|
||||
vk::Image image,
|
||||
[[nodiscard]] vk::raii::ImageView createImageView(
|
||||
const vk::Image& image,
|
||||
vk::Format format,
|
||||
vk::ImageAspectFlags aspectFlags
|
||||
) {
|
||||
vk::ImageAspectFlags aspectFlags,
|
||||
uint32_t mipLevels
|
||||
) const {
|
||||
vk::ImageViewCreateInfo viewInfo{
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
@ -1605,7 +1648,7 @@ class HelloTriangleApplication {
|
||||
.subresourceRange = {
|
||||
aspectFlags,
|
||||
0,
|
||||
1,
|
||||
mipLevels,
|
||||
0,
|
||||
1
|
||||
}
|
||||
@ -1649,6 +1692,132 @@ class HelloTriangleApplication {
|
||||
return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint;
|
||||
}
|
||||
|
||||
void generateMipmaps(
|
||||
vk::raii::Image& image,
|
||||
vk::Format imageFormat,
|
||||
int32_t texWidth,
|
||||
int32_t texHeight,
|
||||
uint32_t mipLevels
|
||||
){
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Generating mipmaps...\n";
|
||||
#endif
|
||||
vk::FormatProperties formatProperties = physicalDevice . getFormatProperties(imageFormat);
|
||||
if (!(formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear)) {
|
||||
throw std::runtime_error("Texture image format does not support linear blitting !\nAborting...");
|
||||
}
|
||||
vk::raii::CommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
vk::ImageMemoryBarrier barrier{};
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
barrier.srcQueueFamilyIndex = vk::QueueFamilyIgnored;
|
||||
barrier.dstQueueFamilyIndex = vk::QueueFamilyIgnored;
|
||||
barrier.image = image;
|
||||
|
||||
barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
|
||||
int32_t mipWidth = texWidth;
|
||||
int32_t mipHeight = texHeight;
|
||||
|
||||
for (uint32_t 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,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
barrier
|
||||
);
|
||||
|
||||
std::array<vk::Offset3D, 2> srcOffsets = {
|
||||
vk::Offset3D{0, 0, 0},
|
||||
vk::Offset3D{mipWidth, mipHeight, 1}
|
||||
};
|
||||
std::array<vk::Offset3D, 2> dstOffsets = {
|
||||
vk::Offset3D{0, 0, 0},
|
||||
vk::Offset3D{mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1}
|
||||
};
|
||||
|
||||
vk::ImageBlit blit = {
|
||||
.srcSubresource = {},
|
||||
.srcOffsets = srcOffsets,
|
||||
.dstSubresource = {},
|
||||
.dstOffsets = dstOffsets,
|
||||
};
|
||||
|
||||
blit.srcSubresource = vk::ImageSubresourceLayers(
|
||||
vk::ImageAspectFlagBits::eColor,
|
||||
i - 1,
|
||||
0,
|
||||
1
|
||||
);
|
||||
blit.dstSubresource = vk::ImageSubresourceLayers(
|
||||
vk::ImageAspectFlagBits::eColor,
|
||||
i,
|
||||
0,
|
||||
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,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
barrier
|
||||
);
|
||||
|
||||
if (mipWidth > 1) mipWidth /= 2;
|
||||
if (mipHeight > 1) mipHeight /= 2;
|
||||
}
|
||||
|
||||
barrier.subresourceRange.baseMipLevel = mipLevels - 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,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
barrier
|
||||
);
|
||||
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Mipmaps generated !\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user