Added LoDs
This commit is contained in:
parent
2fbc0e8f22
commit
ddb6f97646
209
src/main.cpp
209
src/main.cpp
@ -11,6 +11,7 @@
|
|||||||
#include <ios>
|
#include <ios>
|
||||||
#include <limits> // std::numeric_limits
|
#include <limits> // std::numeric_limits
|
||||||
#include <fstream> // to load shaders
|
#include <fstream> // to load shaders
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -183,6 +184,8 @@ class HelloTriangleApplication {
|
|||||||
vk::raii::Image depthImage = nullptr;
|
vk::raii::Image depthImage = nullptr;
|
||||||
vk::raii::DeviceMemory depthImageMemory = nullptr;
|
vk::raii::DeviceMemory depthImageMemory = nullptr;
|
||||||
vk::raii::ImageView depthImageView = nullptr;
|
vk::raii::ImageView depthImageView = nullptr;
|
||||||
|
// Minmaps
|
||||||
|
uint32_t mipLevels;
|
||||||
// Indexes
|
// Indexes
|
||||||
uint32_t queueIndex = ~0;
|
uint32_t queueIndex = ~0;
|
||||||
uint32_t frameIndex = 0;
|
uint32_t frameIndex = 0;
|
||||||
@ -490,7 +493,8 @@ class HelloTriangleApplication {
|
|||||||
swapChainImageViews.emplace_back(createImageView(
|
swapChainImageViews.emplace_back(createImageView(
|
||||||
swapChainImages[i],
|
swapChainImages[i],
|
||||||
swapChainImageFormat,
|
swapChainImageFormat,
|
||||||
vk::ImageAspectFlagBits::eColor
|
vk::ImageAspectFlagBits::eColor,
|
||||||
|
1
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@ -684,6 +688,7 @@ class HelloTriangleApplication {
|
|||||||
createImage(
|
createImage(
|
||||||
swapChainExtent.width,
|
swapChainExtent.width,
|
||||||
swapChainExtent.height,
|
swapChainExtent.height,
|
||||||
|
1,
|
||||||
depthFormat,
|
depthFormat,
|
||||||
vk::ImageTiling::eOptimal,
|
vk::ImageTiling::eOptimal,
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||||
@ -694,7 +699,8 @@ class HelloTriangleApplication {
|
|||||||
depthImageView = createImageView(
|
depthImageView = createImageView(
|
||||||
depthImage,
|
depthImage,
|
||||||
depthFormat,
|
depthFormat,
|
||||||
vk::ImageAspectFlagBits::eDepth
|
vk::ImageAspectFlagBits::eDepth,
|
||||||
|
1
|
||||||
);
|
);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "Depth ressouce created !\n";
|
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);
|
stbi_uc* pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
vk::DeviceSize imageSize = texWidth * texHeight * 4;
|
vk::DeviceSize imageSize = texWidth * texHeight * 4;
|
||||||
|
|
||||||
|
mipLevels = static_cast<uint32_t> (std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
|
||||||
|
|
||||||
if (!pixels) {
|
if (!pixels) {
|
||||||
throw std::runtime_error("Failed to load texture image!\nAborting...");
|
throw std::runtime_error("Failed to load texture image!\nAborting...");
|
||||||
}
|
}
|
||||||
@ -731,17 +739,41 @@ class HelloTriangleApplication {
|
|||||||
createImage(
|
createImage(
|
||||||
texWidth,
|
texWidth,
|
||||||
texHeight,
|
texHeight,
|
||||||
|
mipLevels,
|
||||||
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,
|
||||||
textureImage,
|
textureImage,
|
||||||
textureImageMemory
|
textureImageMemory
|
||||||
);
|
);
|
||||||
|
|
||||||
transitionImageLayout(textureImage, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
|
transitionImageLayout(
|
||||||
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
|
textureImage,
|
||||||
transitionImageLayout(textureImage, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
|
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
|
#ifndef NDEBUG
|
||||||
std::cout << "Texture image created !\n";
|
std::cout << "Texture image created !\n";
|
||||||
@ -755,7 +787,8 @@ class HelloTriangleApplication {
|
|||||||
textureImageView = createImageView(
|
textureImageView = createImageView(
|
||||||
textureImage,
|
textureImage,
|
||||||
vk::Format::eR8G8B8A8Srgb,
|
vk::Format::eR8G8B8A8Srgb,
|
||||||
vk::ImageAspectFlagBits::eColor
|
vk::ImageAspectFlagBits::eColor,
|
||||||
|
mipLevels
|
||||||
);
|
);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "Texture Image created !\n";
|
std::cout << "Texture Image created !\n";
|
||||||
@ -765,6 +798,7 @@ class HelloTriangleApplication {
|
|||||||
void createImage(
|
void createImage(
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height,
|
uint32_t height,
|
||||||
|
uint32_t mipLevels,
|
||||||
vk::Format format,
|
vk::Format format,
|
||||||
vk::ImageTiling tiling,
|
vk::ImageTiling tiling,
|
||||||
vk::ImageUsageFlags usage,
|
vk::ImageUsageFlags usage,
|
||||||
@ -779,7 +813,7 @@ class HelloTriangleApplication {
|
|||||||
.imageType = vk::ImageType::e2D,
|
.imageType = vk::ImageType::e2D,
|
||||||
.format = format,
|
.format = format,
|
||||||
.extent = { width, height, 1 },
|
.extent = { width, height, 1 },
|
||||||
.mipLevels = 1,
|
.mipLevels = mipLevels,
|
||||||
.arrayLayers = 1,
|
.arrayLayers = 1,
|
||||||
.samples = vk::SampleCountFlagBits::e1,
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
.tiling = tiling,
|
.tiling = tiling,
|
||||||
@ -820,7 +854,7 @@ class HelloTriangleApplication {
|
|||||||
.compareEnable = vk::True,
|
.compareEnable = vk::True,
|
||||||
.compareOp = vk::CompareOp::eAlways,
|
.compareOp = vk::CompareOp::eAlways,
|
||||||
.minLod = 0.0f,
|
.minLod = 0.0f,
|
||||||
.maxLod = 0.0f,
|
.maxLod = vk::LodClampNone,
|
||||||
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
||||||
.unnormalizedCoordinates = vk::False
|
.unnormalizedCoordinates = vk::False
|
||||||
};
|
};
|
||||||
@ -1222,7 +1256,8 @@ class HelloTriangleApplication {
|
|||||||
void transitionImageLayout(
|
void transitionImageLayout(
|
||||||
const vk::raii::Image& image,
|
const vk::raii::Image& image,
|
||||||
vk::ImageLayout oldLayout,
|
vk::ImageLayout oldLayout,
|
||||||
vk::ImageLayout newLayout
|
vk::ImageLayout newLayout,
|
||||||
|
uint32_t mipLevels
|
||||||
) {
|
) {
|
||||||
auto commandBuffer = beginSingleTimeCommands();
|
auto commandBuffer = beginSingleTimeCommands();
|
||||||
|
|
||||||
@ -1236,7 +1271,7 @@ class HelloTriangleApplication {
|
|||||||
.subresourceRange = {
|
.subresourceRange = {
|
||||||
vk::ImageAspectFlagBits::eColor,
|
vk::ImageAspectFlagBits::eColor,
|
||||||
0,
|
0,
|
||||||
1,
|
mipLevels,
|
||||||
0,
|
0,
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@ -1451,14 +1486,21 @@ class HelloTriangleApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return vk::False;
|
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));
|
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
|
||||||
app->framebufferResized = true;
|
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();
|
vk::PhysicalDeviceMemoryProperties memProperties = physicalDevice.getMemoryProperties();
|
||||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||||
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||||
@ -1593,11 +1635,12 @@ class HelloTriangleApplication {
|
|||||||
queue.waitIdle();
|
queue.waitIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::raii::ImageView createImageView(
|
[[nodiscard]] vk::raii::ImageView createImageView(
|
||||||
vk::Image image,
|
const vk::Image& image,
|
||||||
vk::Format format,
|
vk::Format format,
|
||||||
vk::ImageAspectFlags aspectFlags
|
vk::ImageAspectFlags aspectFlags,
|
||||||
) {
|
uint32_t mipLevels
|
||||||
|
) const {
|
||||||
vk::ImageViewCreateInfo viewInfo{
|
vk::ImageViewCreateInfo viewInfo{
|
||||||
.image = image,
|
.image = image,
|
||||||
.viewType = vk::ImageViewType::e2D,
|
.viewType = vk::ImageViewType::e2D,
|
||||||
@ -1605,7 +1648,7 @@ class HelloTriangleApplication {
|
|||||||
.subresourceRange = {
|
.subresourceRange = {
|
||||||
aspectFlags,
|
aspectFlags,
|
||||||
0,
|
0,
|
||||||
1,
|
mipLevels,
|
||||||
0,
|
0,
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@ -1649,6 +1692,132 @@ class HelloTriangleApplication {
|
|||||||
return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint;
|
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() {
|
int main() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user