non-working example of how i want descriptor sets to be layed out.
All checks were successful
ci/woodpecker/push/woodpecker.json Pipeline was successful

This commit is contained in:
Rebekah 2024-08-01 08:19:24 -04:00
parent 61738cd4b3
commit 7d694ca7a2
Signed by: oneechanhax
GPG Key ID: 0074BF373B812798

View File

@ -132,10 +132,12 @@ private:
return { .codeSize = embeded_shader_frag_glsl_spv.size, .pCode = reinterpret_cast<const std::uint32_t*>(embeded_shader_frag_glsl_spv.begin) };
}
using Color = glm::vec4;
using TextureCoordinates = glm::vec2;
struct Vertex2 {
glm::vec2 pos;
glm::vec4 color;
glm::vec2 texture_coordinates;
Color color;
TextureCoordinates texture_coordinates;
DrawMode draw_mode;
static constexpr vk::ShaderModuleCreateInfo GetShaderInfoFragment() {
@ -185,8 +187,8 @@ private:
struct Vertex3 {
glm::vec3 pos;
glm::vec4 color;
glm::vec2 texture_coordinates;
Color color;
TextureCoordinates texture_coordinates;
DrawMode draw_mode;
static constexpr vk::ShaderModuleCreateInfo GetShaderInfoFragment() {
@ -237,6 +239,157 @@ private:
};
};
class Texture {
private:
const VulkanExampleApplication* parent;
private:
std::uint32_t vk_texture_mip_levels;
VulkanImage vk_texture_image;
public:
std::optional<vk::raii::ImageView> vk_texture_view;
std::optional<vk::raii::Sampler> vk_texture_sampler;
public:
std::optional<vk::raii::DescriptorSet> vk_descriptor_sets_second;
std::optional<vk::raii::DescriptorSet> vk_descriptor_sets_third;
public:
template <class DataT>
constexpr Texture(const VulkanExampleApplication* _parent, const DataT texture_buffer_data, const std::size_t texture_buffer_size, const vk::Extent2D texture_buffer_extent)
: parent(_parent) {
assert(parent != nullptr);
{ // Texture
const auto texture_format = vk::Format::eR8G8B8A8Srgb;
const auto texture_buffer_staging = this->parent->CreateBuffer(texture_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
this->vk_texture_mip_levels = static_cast<std::uint32_t>(std::floor(std::log2(std::max(texture_buffer_extent.width, texture_buffer_extent.height)))) + 1;
this->parent->vk_allocator->copyMemoryToAllocation(embeded_debug_north_png_rgba.data.begin, *texture_buffer_staging->second, 0, texture_buffer_size);
this->vk_texture_image = this->parent->CreateImage(texture_buffer_extent, texture_format, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, vk::MemoryPropertyFlagBits::eDeviceLocal, this->vk_texture_mip_levels, vk::SampleCountFlagBits::e1);
this->parent->SingleTimeSubmitCommand([&](const auto& command_buffer) {
this->parent->TransitionImageLayout(command_buffer, *this->vk_texture_image->first, texture_format, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, this->vk_texture_mip_levels);
this->parent->CopyBuffer(command_buffer, *texture_buffer_staging->first, *this->vk_texture_image->first, texture_buffer_extent);
const auto GenerateMipmaps = [this](const vk::CommandBuffer& command_buffer, const vk::Image& src_image, vk::Format src_format, vk::Extent2D texture_size, std::uint32_t mip_levels) {
assert(mip_levels);
if (!(this->parent->vk_gfx_card->getFormatProperties(src_format).optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear))
throw std::runtime_error("texture image format does not support linear blitting!");
vk::ImageMemoryBarrier image_memory_barrier {
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = src_image,
.subresourceRange {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
for (std::uint32_t i = 1; i < mip_levels; i++) {
image_memory_barrier.subresourceRange.baseMipLevel = i - 1;
image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead,
image_memory_barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
image_memory_barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal,
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, image_memory_barrier);
const std::array<vk::Offset3D, 2> image_offsets_src {
vk::Offset3D { 0, 0, 0 },
vk::Offset3D { static_cast<int32_t>(texture_size.width), static_cast<int32_t>(texture_size.height), 1 }
};
const vk::ImageSubresourceLayers image_subresource_layers_src {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = i - 1,
.baseArrayLayer = 0,
.layerCount = 1
};
const std::array<vk::Offset3D, 2> image_offsets_dest {
vk::Offset3D { 0, 0, 0 },
vk::Offset3D { static_cast<int32_t>(texture_size.width) > 1 ? static_cast<int32_t>(texture_size.width) / 2 : 1, static_cast<int32_t>(texture_size.height) > 1 ? static_cast<int32_t>(texture_size.height) / 2 : 1, 1 }
};
const vk::ImageSubresourceLayers image_subresource_layers_dest {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = i,
.baseArrayLayer = 0,
.layerCount = 1
};
const vk::ImageBlit image_blit {
.srcSubresource = image_subresource_layers_src,
.srcOffsets = image_offsets_src,
.dstSubresource = image_subresource_layers_dest,
.dstOffsets = image_offsets_dest
};
command_buffer.blitImage(src_image, vk::ImageLayout::eTransferSrcOptimal, src_image, vk::ImageLayout::eTransferDstOptimal, image_blit, vk::Filter::eLinear);
if (texture_size.width > 1)
texture_size.width /= 2;
if (texture_size.height > 1)
texture_size.height /= 2;
image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
image_memory_barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, image_memory_barrier);
}
image_memory_barrier.subresourceRange.baseMipLevel = mip_levels - 1;
image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
image_memory_barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, image_memory_barrier);
};
GenerateMipmaps(command_buffer, *this->vk_texture_image->first, texture_format, texture_buffer_extent, this->vk_texture_mip_levels);
});
this->vk_texture_view = this->parent->CreateImageView(*this->vk_texture_image->first, texture_format, vk::ImageAspectFlagBits::eColor, this->vk_texture_mip_levels);
}
{ // Sampler
const vk::SamplerCreateInfo sampler_create_info {
.magFilter = vk::Filter::eNearest,
.minFilter = vk::Filter::eLinear,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.addressModeU = vk::SamplerAddressMode::eRepeat, // https://docs.vulkan.org/tutorial/latest/06_Texture_mapping/01_Image_view_and_sampler.html#_samplers
.addressModeV = vk::SamplerAddressMode::eRepeat,
.addressModeW = vk::SamplerAddressMode::eRepeat,
.mipLodBias = 0.0f,
.anisotropyEnable = vk::True,
.maxAnisotropy = std::max<float>(4.0f, this->parent->vk_gfx_card->getProperties().limits.maxSamplerAnisotropy),
.compareEnable = vk::False,
.compareOp = vk::CompareOp::eAlways,
.minLod = 0.0f,
.maxLod = vk::LodClampNone,
.borderColor = vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = vk::False,
};
this->vk_texture_sampler.emplace(*this->parent->vk_gpu, sampler_create_info);
}
{
this->vk_descriptor_sets_second = this->parent->vk_pipeline_second.CreateImageDescriptorSet(*this->vk_texture_view, *this->vk_texture_sampler);
this->vk_descriptor_sets_third = this->parent->vk_pipeline_third.CreateImageDescriptorSet(*this->vk_texture_view, *this->vk_texture_sampler);
}
}
template <typename VertexT>
const vk::DescriptorSet& GetDescriptorSet() const {
if constexpr (typeid(VertexT) == typeid(Vertex2))
return **this->vk_descriptor_sets_second;
if constexpr (typeid(VertexT) == typeid(Vertex3))
return **this->vk_descriptor_sets_third;
else
assert(false && "Texture: No descriptor set availiable for this type of vertex.");
}
};
template <typename VertexT>
class VulkanRenderPipeline {
private:
@ -252,9 +405,11 @@ private:
: parent(_parent) { assert(_parent != nullptr); }
public:
std::optional<vk::raii::DescriptorSetLayout> vk_descriptor_set_layout;
std::optional<vk::raii::DescriptorPool> vk_descriptor_pool;
std::vector<vk::raii::DescriptorSet> vk_descriptor_sets;
std::optional<vk::raii::DescriptorSetLayout> vk_descriptor_set_layouts;
const Texture* current_texture = nullptr;
VulkanBuffer vk_buffer_vertex; // in order to get a clean destruction sequence, instantiate the DeviceMemory for the vertex buffer first // https://github.com/KhronosGroup/Vulkan-Hpp/blob/6f72ceca515d59f40d64b64cf2734f6261e1f9f2/RAII_Samples/13_InitVertexBuffer/13_InitVertexBuffer.cpp
VulkanBuffer vk_buffer_index; // used to make rendering models more efficent by sharing values
@ -281,8 +436,9 @@ private:
this->vk_shader_vertex.emplace(gpu, VertexT::GetShaderInfoVertex());
this->vk_shader_frag.emplace(gpu, VertexT::GetShaderInfoFragment());
}
{
constexpr auto descriptor_set_layout_bindings = [&]() {
{ // descriptor set layouts
const auto descriptor_set_layout_bindings = []() -> std::vector<vk::DescriptorSetLayoutBinding> {
constexpr vk::DescriptorSetLayoutBinding descriptor_set_layout_binding_sampler {
.binding = 0,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
@ -290,6 +446,7 @@ private:
.stageFlags = vk::ShaderStageFlagBits::eFragment,
.pImmutableSamplers = nullptr // Optional
};
if constexpr (UsesProjection()) {
constexpr vk::DescriptorSetLayoutBinding descriptor_set_layout_binding_ubo {
.binding = 1,
@ -298,16 +455,15 @@ private:
.stageFlags = vk::ShaderStageFlagBits::eVertex,
.pImmutableSamplers = nullptr // Optional
};
return std::array<vk::DescriptorSetLayoutBinding, 2> { descriptor_set_layout_binding_sampler, descriptor_set_layout_binding_ubo };
} else
return std::array<vk::DescriptorSetLayoutBinding, 1> { descriptor_set_layout_binding_sampler };
return { descriptor_set_layout_binding_sampler, descriptor_set_layout_binding_ubo };
}
return { descriptor_set_layout_binding_sampler };
}();
const vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info {
.bindingCount = static_cast<std::uint32_t>(descriptor_set_layout_bindings.size()),
.pBindings = descriptor_set_layout_bindings.data()
};
this->vk_descriptor_set_layout.emplace(gpu, descriptor_set_layout_create_info);
this->vk_descriptor_set_layouts.emplace(gpu, descriptor_set_layout_create_info);
}
{ // Init graphics pipeline/renderpass
const vk::PipelineShaderStageCreateInfo shader_stage_create_info_vertex {
@ -406,7 +562,7 @@ private:
const vk::PipelineLayoutCreateInfo pipeline_layout_create_info {
.setLayoutCount = 1, // Optional
.pSetLayouts = &**this->vk_descriptor_set_layout, // Optional
.pSetLayouts = &**this->vk_descriptor_set_layouts, // Optional
//.pushConstantRangeCount = 0, // Optional
//.pPushConstantRanges = nullptr // Optional
};
@ -431,7 +587,7 @@ private:
};
this->vk_pipeline.emplace(gpu, nullptr, pipeline_create_info);
}
if constexpr (UsesProjection()) { // uniform buffer object
if constexpr (UsesProjection()) { // create and map uniform buffer object
assert(this->vk_buffers_uniform.empty());
assert(this->vk_buffers_uniform_mapped.empty());
this->vk_buffers_uniform.reserve(this->parent->vk_max_frames_in_flight);
@ -444,16 +600,16 @@ private:
this->vk_buffers_uniform.emplace_back(std::move(uniform_buffer));
}
}
}
void UpdateDescriptors(const vk::ImageView& texture_view) {
{ // update descriptors
{ // create descriptor pool
const std::size_t ubo_count = 256;
const vk::DescriptorPoolSize descriptor_pool_size_ubo {
.type = vk::DescriptorType::eUniformBuffer,
.descriptorCount = static_cast<std::uint32_t>(this->parent->vk_max_frames_in_flight)
.descriptorCount = static_cast<std::uint32_t>(this->parent->vk_max_frames_in_flight) * 2
};
const std::size_t maximum_texture_count = 256;
const vk::DescriptorPoolSize descriptor_pool_size_sampler {
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = static_cast<std::uint32_t>(this->parent->vk_max_frames_in_flight)
.descriptorCount = maximum_texture_count
};
const auto descriptor_pool_sizes = [&]() {
if constexpr (UsesProjection())
@ -463,73 +619,85 @@ private:
}();
const vk::DescriptorPoolCreateInfo descriptor_pool_create_info {
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
.maxSets = static_cast<std::uint32_t>(this->parent->vk_max_frames_in_flight),
.maxSets = maximum_texture_count + (!UsesProjection() ? 0 : ubo_count),
.poolSizeCount = static_cast<std::uint32_t>(descriptor_pool_sizes.size()),
.pPoolSizes = descriptor_pool_sizes.data(),
};
assert(descriptor_pool_create_info.flags & vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet); // requirement, to soothe validation layer complaints
this->vk_descriptor_pool.emplace(*this->parent->vk_gpu, descriptor_pool_create_info);
const std::vector<vk::DescriptorSetLayout> descriptor_set_layouts = std::vector<vk::DescriptorSetLayout>(this->parent->vk_max_frames_in_flight, *this->vk_descriptor_set_layout);
}
{ // update descriptor sets
std::vector<vk::DescriptorSetLayout> descriptor_set_layouts;
descriptor_set_layouts.reserve(this->parent->vk_max_frames_in_flight + 1);
descriptor_set_layouts.emplace_back(*this->vk_descriptor_set_layouts);
if constexpr (UsesProjection()) {
const auto addition_layouts = std::vector<vk::DescriptorSetLayout>(this->parent->vk_max_frames_in_flight, *this->vk_descriptor_set_layouts);
descriptor_set_layouts.insert(descriptor_set_layouts.end(), addition_layouts.begin(), addition_layouts.end());
}
const vk::DescriptorSetAllocateInfo descriptor_set_allocate_info {
.descriptorPool = **this->vk_descriptor_pool,
.descriptorSetCount = static_cast<std::uint32_t>(descriptor_set_layouts.size()),
.pSetLayouts = descriptor_set_layouts.data()
};
this->vk_descriptor_sets = vk::raii::DescriptorSets(*this->parent->vk_gpu, descriptor_set_allocate_info);
}
if constexpr (UsesProjection()) { // update ubo descripor sets
std::vector<vk::WriteDescriptorSet> write_descriptor_sets;
write_descriptor_sets.reserve(this->parent->vk_max_frames_in_flight);
std::vector<vk::DescriptorImageInfo> image_infos;
image_infos.reserve(this->parent->vk_max_frames_in_flight);
std::vector<vk::DescriptorBufferInfo> buffer_infos;
buffer_infos.reserve(this->parent->vk_max_frames_in_flight);
for (std::size_t i = 0; i < this->parent->vk_max_frames_in_flight; i++) {
const vk::DescriptorImageInfo descriptor_image_info_texture {
.sampler = **this->parent->vk_texture_sampler,
.imageView = texture_view,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
const vk::DescriptorBufferInfo descriptor_buffer_info_ubo {
.buffer = *this->vk_buffers_uniform.at(i)->first,
.offset = 0,
.range = sizeof(UniformBufferObject_Projection),
};
const vk::DescriptorImageInfo& descriptor_image_info_handle = image_infos.emplace_back(descriptor_image_info_texture);
const vk::WriteDescriptorSet descriptor_write_texture {
const vk::DescriptorBufferInfo& descriptor_buffer_info_handle = buffer_infos.emplace_back(descriptor_buffer_info_ubo);
const vk::WriteDescriptorSet descriptor_write_ubo {
.dstSet = *this->vk_descriptor_sets[i],
.dstBinding = 0,
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = &descriptor_image_info_handle // Optional
.descriptorType = vk::DescriptorType::eUniformBuffer,
.pImageInfo = nullptr, // Optional
.pBufferInfo = &descriptor_buffer_info_handle,
.pTexelBufferView = nullptr, // Optional
};
write_descriptor_sets.emplace_back(descriptor_write_texture);
write_descriptor_sets.emplace_back(descriptor_write_ubo);
}
std::vector<vk::DescriptorBufferInfo> buffer_infos;
if constexpr (UsesProjection()) {
buffer_infos.reserve(this->parent->vk_max_frames_in_flight);
for (std::size_t i = 0; i < this->parent->vk_max_frames_in_flight; i++) {
const vk::DescriptorBufferInfo descriptor_buffer_info_ubo {
.buffer = *this->vk_buffers_uniform.at(i)->first,
.offset = 0,
.range = sizeof(UniformBufferObject_Projection),
};
const vk::DescriptorBufferInfo& descriptor_buffer_info_handle = buffer_infos.emplace_back(descriptor_buffer_info_ubo);
const vk::WriteDescriptorSet descriptor_write_ubo {
.dstSet = *this->vk_descriptor_sets[i],
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eUniformBuffer,
.pImageInfo = nullptr, // Optional
.pBufferInfo = &descriptor_buffer_info_handle,
.pTexelBufferView = nullptr, // Optional
};
write_descriptor_sets.emplace_back(descriptor_write_ubo);
}
}
std::cout << "UBO DESCRIPTORS" << std::endl;
this->parent->vk_gpu->updateDescriptorSets(write_descriptor_sets, nullptr);
}
}
vk::raii::DescriptorSet CreateImageDescriptorSet(const vk::raii::ImageView& texture_view, const vk::raii::Sampler& texture_sampler) const {
const vk::DescriptorSetAllocateInfo descriptor_set_allocate_info {
.descriptorPool = **this->vk_descriptor_pool,
.descriptorSetCount = 1,
.pSetLayouts = &**this->vk_descriptor_set_layouts
};
vk::raii::DescriptorSet descriptor_set = std::move(vk::raii::DescriptorSets(*this->parent->vk_gpu, descriptor_set_allocate_info).front());
const vk::DescriptorImageInfo descriptor_image_info_texture {
.sampler = texture_sampler,
.imageView = texture_view,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
const vk::WriteDescriptorSet descriptor_write_texture {
.dstSet = *descriptor_set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = &descriptor_image_info_texture
};
std::cout << "SAMPLER_TEXTURES DESCRIPTORS" << std::endl;
this->parent->vk_gpu->updateDescriptorSets({ descriptor_write_texture }, nullptr);
return descriptor_set;
}
void ReplaceModelInfo(const std::vector<VertexT>& vertices, const std::vector<IndexT>& indexes) {
const auto vertex_buffer_size = sizeof(VertexT) * vertices.size();
const auto vertex_buffer_staging = this->parent->CreateBuffer(vertex_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
@ -566,11 +734,19 @@ private:
ubo.proj[1][1] *= -1; // "GLM was originally designed for OpenGL, where the Y coordinate of the clip coordinates is inverted." - so it will flip the image to correct.
}
memcpy(this->vk_buffers_uniform_mapped[current_image], &ubo, sizeof(ubo));
} else {
static_assert(false && "Uniform Buffer Object only available using 3d");
}
}
void BindTexture(const Texture& t) {
this->current_texture = &t;
}
void Bind(const vk::raii::CommandBuffer& command_buffer, const std::size_t frame_index) const {
assert(this->current_texture != nullptr);
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, **this->vk_pipeline);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *this->vk_pipeline_layout, 0, *this->vk_descriptor_sets[frame_index], nullptr);
const auto descriptor_sets = std::array<vk::DescriptorSet, 2> { *this->vk_descriptor_sets[frame_index], this->current_texture->GetDescriptorSet<VertexT>() };
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *this->vk_pipeline_layout, 0, descriptor_sets, nullptr);
command_buffer.bindVertexBuffers(0, { *this->vk_buffer_vertex->first }, { 0 });
command_buffer.bindIndexBuffer(*this->vk_buffer_index->first, 0, vk::IndexType::eUint16);
}
@ -613,10 +789,7 @@ private:
std::optional<vk::raii::ImageView> vk_depth_view;
private:
std::uint32_t vk_texture_mip_levels;
VulkanImage vk_texture_image;
std::optional<vk::raii::ImageView> vk_texture_view;
std::optional<vk::raii::Sampler> vk_texture_sampler;
std::optional<Texture> vk_texture;
public:
VulkanExampleApplication()
@ -1057,122 +1230,11 @@ public:
}
{ // texture
const auto texture_format = vk::Format::eR8G8B8A8Srgb;
const auto texture_buffer_size = embeded_debug_north_png_rgba.data.size;
const vk::Extent2D texture_buffer_extent = { .width = static_cast<std::uint32_t>(embeded_debug_north_png_rgba.width), .height = static_cast<std::uint32_t>(embeded_debug_north_png_rgba.height) };
const auto texture_buffer_staging = this->CreateBuffer(texture_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
this->vk_texture_mip_levels = static_cast<std::uint32_t>(std::floor(std::log2(std::max(texture_buffer_extent.width, texture_buffer_extent.height)))) + 1;
this->vk_allocator->copyMemoryToAllocation(embeded_debug_north_png_rgba.data.begin, *texture_buffer_staging->second, 0, texture_buffer_size);
this->vk_texture_image = CreateImage(texture_buffer_extent, texture_format, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, vk::MemoryPropertyFlagBits::eDeviceLocal, this->vk_texture_mip_levels, vk::SampleCountFlagBits::e1);
this->SingleTimeSubmitCommand([&](const auto& command_buffer) {
this->TransitionImageLayout(command_buffer, *this->vk_texture_image->first, texture_format, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, this->vk_texture_mip_levels);
this->CopyBuffer(command_buffer, *texture_buffer_staging->first, *this->vk_texture_image->first, texture_buffer_extent);
const auto GenerateMipmaps = [this](const vk::CommandBuffer& command_buffer, const vk::Image& src_image, vk::Format src_format, vk::Extent2D texture_size, std::uint32_t mip_levels) {
assert(mip_levels);
if (!(this->vk_gfx_card->getFormatProperties(src_format).optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear))
throw std::runtime_error("texture image format does not support linear blitting!");
vk::ImageMemoryBarrier image_memory_barrier {
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = src_image,
.subresourceRange {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
for (std::uint32_t i = 1; i < mip_levels; i++) {
image_memory_barrier.subresourceRange.baseMipLevel = i - 1;
image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead,
image_memory_barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
image_memory_barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal,
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, image_memory_barrier);
const std::array<vk::Offset3D, 2> image_offsets_src {
vk::Offset3D { 0, 0, 0 },
vk::Offset3D { static_cast<int32_t>(texture_size.width), static_cast<int32_t>(texture_size.height), 1 }
};
const vk::ImageSubresourceLayers image_subresource_layers_src {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = i - 1,
.baseArrayLayer = 0,
.layerCount = 1
};
const std::array<vk::Offset3D, 2> image_offsets_dest {
vk::Offset3D { 0, 0, 0 },
vk::Offset3D { static_cast<int32_t>(texture_size.width) > 1 ? static_cast<int32_t>(texture_size.width) / 2 : 1, static_cast<int32_t>(texture_size.height) > 1 ? static_cast<int32_t>(texture_size.height) / 2 : 1, 1 }
};
const vk::ImageSubresourceLayers image_subresource_layers_dest {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = i,
.baseArrayLayer = 0,
.layerCount = 1
};
const vk::ImageBlit image_blit {
.srcSubresource = image_subresource_layers_src,
.srcOffsets = image_offsets_src,
.dstSubresource = image_subresource_layers_dest,
.dstOffsets = image_offsets_dest
};
command_buffer.blitImage(src_image, vk::ImageLayout::eTransferSrcOptimal, src_image, vk::ImageLayout::eTransferDstOptimal, image_blit, vk::Filter::eLinear);
if (texture_size.width > 1)
texture_size.width /= 2;
if (texture_size.height > 1)
texture_size.height /= 2;
image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
image_memory_barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, image_memory_barrier);
}
image_memory_barrier.subresourceRange.baseMipLevel = mip_levels - 1;
image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
image_memory_barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, image_memory_barrier);
};
GenerateMipmaps(command_buffer, *this->vk_texture_image->first, texture_format, texture_buffer_extent, this->vk_texture_mip_levels);
});
this->vk_texture_view = this->CreateImageView(*this->vk_texture_image->first, texture_format, vk::ImageAspectFlagBits::eColor, this->vk_texture_mip_levels);
}
{ // Sampler
const vk::SamplerCreateInfo sampler_create_info {
.magFilter = vk::Filter::eNearest,
.minFilter = vk::Filter::eLinear,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.addressModeU = vk::SamplerAddressMode::eRepeat, // https://docs.vulkan.org/tutorial/latest/06_Texture_mapping/01_Image_view_and_sampler.html#_samplers
.addressModeV = vk::SamplerAddressMode::eRepeat,
.addressModeW = vk::SamplerAddressMode::eRepeat,
.mipLodBias = 0.0f,
.anisotropyEnable = vk::True,
.maxAnisotropy = std::max<float>(4.0f, this->vk_gfx_card->getProperties().limits.maxSamplerAnisotropy),
.compareEnable = vk::False,
.compareOp = vk::CompareOp::eAlways,
.minLod = 0.0f,
.maxLod = vk::LodClampNone,
.borderColor = vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = vk::False,
};
this->vk_texture_sampler.emplace(*this->vk_gpu, sampler_create_info);
}
{
this->vk_pipeline_second.UpdateDescriptors(*this->vk_texture_view);
this->vk_pipeline_third.UpdateDescriptors(*this->vk_texture_view);
this->vk_texture.emplace(this, embeded_debug_north_png_rgba.data.begin, embeded_debug_north_png_rgba.data.size, vk::Extent2D { .width = static_cast<std::uint32_t>(embeded_debug_north_png_rgba.width), .height = static_cast<std::uint32_t>(embeded_debug_north_png_rgba.height) });
this->vk_pipeline_second.BindTexture(*this->vk_texture);
this->vk_pipeline_third.BindTexture(*this->vk_texture);
}
} catch (const vk::SystemError& error) {
std::cout << "Received Vulkan-Specific Error during process init: " << error.what() << std::endl
<< "Going to rethrow!" << std::endl;
@ -1740,8 +1802,10 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanExampleApplication_VulkanDebugCallba
if (message_severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
if constexpr (fatal_errors) {
const std::string_view msg = callback_data->pMessage;
if (!msg.starts_with("loader_scanned_icd_add: Could not get 'vkCreateInstance' via 'vk_icdGetInstanceProcAddr'"))
if (!msg.starts_with("loader_scanned_icd_add: Could not get 'vkCreateInstance' via 'vk_icdGetInstanceProcAddr'")) {
*reinterpret_cast<std::uint8_t*>(5) = 5;
throw std::logic_error(std::string("Received Vulkan-ValidationLayer Error: ") + callback_data->pMessage);
}
}
}
return vk::False;