Compare commits

..

2 Commits

Author SHA1 Message Date
ffe4712663 fix stuff
Signed-off-by: Slendi <slendi@socopon.com>
2025-12-17 18:02:21 +02:00
a99233fcbe hiu
Signed-off-by: Slendi <slendi@socopon.com>
2025-12-17 15:51:38 +02:00
14 changed files with 346 additions and 142 deletions

View File

@@ -45,6 +45,7 @@
with pkgs; with pkgs;
[ [
llvmPackages_21.clang-tools llvmPackages_21.clang-tools
llvmPackages_21.bintools
lldb lldb
codespell codespell
doxygen doxygen

View File

@@ -82,6 +82,8 @@ add_project_arguments(
'-Wno-macro-redefined', '-Wno-macro-redefined',
'-DVULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE', '-DVULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE',
'-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1', '-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1',
# Thanks forityf source
'-Wno-#warnings'
], ],
language : 'cpp' language : 'cpp'
) )

View File

@@ -0,0 +1,21 @@
#version 450
layout(location = 0) out vec4 out_color;
layout(push_constant) uniform PushConstants {
vec2 resolution;
} pc;
void main()
{
vec2 uv = (gl_FragCoord.xy + vec2(0.5)) / pc.resolution;
float v = sin(uv.x * 10.0) + cos(uv.y * 10.0);
float r = 0.5 + 0.5 * cos(6.2831 * (uv.x + v));
float g = 0.5 + 0.5 * cos(6.2831 * (uv.y + v + 0.33));
float b = 0.5 + 0.5 * cos(6.2831 * (uv.x - uv.y + 0.66));
out_color = vec4(r, g, b, 1.0);
}

View File

@@ -0,0 +1,13 @@
#version 450
void main()
{
vec2 positions[3] = vec2[](
vec2(-1.0, -1.0),
vec2( 3.0, -1.0),
vec2(-1.0, 3.0)
);
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
}

View File

@@ -14,7 +14,6 @@ else
endif endif
shader_sources = files( shader_sources = files(
'gradient.comp',
'triangle.frag', 'triangle.frag',
'triangle.vert', 'triangle.vert',
'triangle_mesh.frag', 'triangle_mesh.frag',

View File

@@ -310,6 +310,8 @@ auto Application::run() -> void
ImGui::Render(); ImGui::Render();
m_renderer->set_antialiasing(VulkanRenderer::AntiAliasingKind::MSAA_8X);
m_renderer->render([&](VulkanRenderer::GL &gl) { m_renderer->render([&](VulkanRenderer::GL &gl) {
auto view { smath::matrix_look_at(smath::Vec3 { 0.0f, 0.0f, 3.0f }, auto view { smath::matrix_look_at(smath::Vec3 { 0.0f, 0.0f, 3.0f },
smath::Vec3 { 0.0f, 0.0f, 0.0f }, smath::Vec3 { 0.0f, 0.0f, 0.0f },

View File

@@ -1,5 +1,7 @@
#include "DescriptorAllocatorGrowable.h" #include "DescriptorAllocatorGrowable.h"
#include <algorithm>
#include "Logger.h" #include "Logger.h"
#include "Util.h" #include "Util.h"
@@ -9,6 +11,10 @@ auto DescriptorAllocatorGrowable::init(VkDevice dev, uint32_t max_sets,
std::span<PoolSizeRatio> pool_ratios) -> void std::span<PoolSizeRatio> pool_ratios) -> void
{ {
m_ratios.clear(); m_ratios.clear();
m_current_pool = VK_NULL_HANDLE;
m_full_pools.clear();
m_used_pools.clear();
m_ready_pools.clear();
m_ratios.insert(m_ratios.begin(), pool_ratios.begin(), pool_ratios.end()); m_ratios.insert(m_ratios.begin(), pool_ratios.begin(), pool_ratios.end());
@@ -23,25 +29,50 @@ auto DescriptorAllocatorGrowable::init(VkDevice dev, uint32_t max_sets,
auto DescriptorAllocatorGrowable::clear_pools(VkDevice dev) -> void auto DescriptorAllocatorGrowable::clear_pools(VkDevice dev) -> void
{ {
for (auto const p : m_ready_pools) std::vector<VkDescriptorPool> all_pools;
all_pools.reserve(
m_ready_pools.size() + m_used_pools.size() + m_full_pools.size());
all_pools.insert(
all_pools.end(), m_ready_pools.begin(), m_ready_pools.end());
all_pools.insert(all_pools.end(), m_used_pools.begin(), m_used_pools.end());
all_pools.insert(all_pools.end(), m_full_pools.begin(), m_full_pools.end());
std::sort(all_pools.begin(), all_pools.end());
all_pools.erase(
std::unique(all_pools.begin(), all_pools.end()), all_pools.end());
for (auto const p : all_pools) {
vkResetDescriptorPool(dev, p, 0); vkResetDescriptorPool(dev, p, 0);
for (auto const p : m_full_pools) {
vkResetDescriptorPool(dev, p, 0);
m_ready_pools.emplace_back(p);
} }
m_ready_pools = std::move(all_pools);
m_used_pools.clear();
m_full_pools.clear(); m_full_pools.clear();
m_current_pool = VK_NULL_HANDLE;
} }
auto DescriptorAllocatorGrowable::destroy_pools(VkDevice dev) -> void auto DescriptorAllocatorGrowable::destroy_pools(VkDevice dev) -> void
{ {
for (auto const p : m_ready_pools) { std::vector<VkDescriptorPool> all_pools;
all_pools.reserve(
m_ready_pools.size() + m_used_pools.size() + m_full_pools.size());
all_pools.insert(
all_pools.end(), m_ready_pools.begin(), m_ready_pools.end());
all_pools.insert(all_pools.end(), m_used_pools.begin(), m_used_pools.end());
all_pools.insert(all_pools.end(), m_full_pools.begin(), m_full_pools.end());
std::sort(all_pools.begin(), all_pools.end());
all_pools.erase(
std::unique(all_pools.begin(), all_pools.end()), all_pools.end());
for (auto const p : all_pools) {
vkDestroyDescriptorPool(dev, p, nullptr); vkDestroyDescriptorPool(dev, p, nullptr);
} }
m_ready_pools.clear(); m_ready_pools.clear();
for (auto const p : m_full_pools) { m_used_pools.clear();
vkDestroyDescriptorPool(dev, p, nullptr);
}
m_full_pools.clear(); m_full_pools.clear();
m_current_pool = VK_NULL_HANDLE;
} }
auto DescriptorAllocatorGrowable::allocate(Logger &logger, VkDevice dev, auto DescriptorAllocatorGrowable::allocate(Logger &logger, VkDevice dev,
@@ -60,31 +91,36 @@ auto DescriptorAllocatorGrowable::allocate(Logger &logger, VkDevice dev,
auto const res = vkAllocateDescriptorSets(dev, &alloci, &ds); auto const res = vkAllocateDescriptorSets(dev, &alloci, &ds);
if (res == VK_ERROR_OUT_OF_POOL_MEMORY || res == VK_ERROR_FRAGMENTED_POOL) { if (res == VK_ERROR_OUT_OF_POOL_MEMORY || res == VK_ERROR_FRAGMENTED_POOL) {
m_full_pools.emplace_back(pool_to_use); m_full_pools.emplace_back(pool_to_use);
if (m_current_pool == pool_to_use) {
m_current_pool = VK_NULL_HANDLE;
}
pool_to_use = get_pool(dev); pool_to_use = get_pool(dev);
alloci.descriptorPool = pool_to_use; alloci.descriptorPool = pool_to_use;
VK_CHECK(logger, vkAllocateDescriptorSets(dev, &alloci, &ds)); VK_CHECK(logger, vkAllocateDescriptorSets(dev, &alloci, &ds));
} }
m_ready_pools.emplace_back(pool_to_use);
return ds; return ds;
} }
auto DescriptorAllocatorGrowable::get_pool(VkDevice dev) -> VkDescriptorPool auto DescriptorAllocatorGrowable::get_pool(VkDevice dev) -> VkDescriptorPool
{ {
VkDescriptorPool new_pool; if (m_current_pool != VK_NULL_HANDLE) {
return m_current_pool;
}
if (m_ready_pools.empty()) { if (!m_ready_pools.empty()) {
new_pool = create_pool(dev, m_sets_per_pool, m_ratios); m_current_pool = m_ready_pools.back();
m_ready_pools.pop_back();
} else {
m_current_pool = create_pool(dev, m_sets_per_pool, m_ratios);
m_sets_per_pool = static_cast<uint32_t>(m_sets_per_pool * 1.5); m_sets_per_pool = static_cast<uint32_t>(m_sets_per_pool * 1.5);
if (m_sets_per_pool > 4092) if (m_sets_per_pool > 4092)
m_sets_per_pool = 4092; m_sets_per_pool = 4092;
} else {
new_pool = m_ready_pools.back();
m_ready_pools.pop_back();
} }
return new_pool; m_used_pools.emplace_back(m_current_pool);
return m_current_pool;
} }
auto DescriptorAllocatorGrowable::create_pool(VkDevice dev, uint32_t set_count, auto DescriptorAllocatorGrowable::create_pool(VkDevice dev, uint32_t set_count,

View File

@@ -30,7 +30,9 @@ private:
std::span<PoolSizeRatio> pool_ratios) -> VkDescriptorPool; std::span<PoolSizeRatio> pool_ratios) -> VkDescriptorPool;
std::vector<PoolSizeRatio> m_ratios; std::vector<PoolSizeRatio> m_ratios;
VkDescriptorPool m_current_pool { VK_NULL_HANDLE };
std::vector<VkDescriptorPool> m_full_pools; std::vector<VkDescriptorPool> m_full_pools;
std::vector<VkDescriptorPool> m_used_pools;
std::vector<VkDescriptorPool> m_ready_pools; std::vector<VkDescriptorPool> m_ready_pools;
uint32_t m_sets_per_pool; uint32_t m_sets_per_pool;
}; };

View File

@@ -79,9 +79,15 @@ auto GraphicsPipelineBuilder::set_cull_mode(VkCullModeFlags cull_mode,
auto GraphicsPipelineBuilder::set_multisampling_none() auto GraphicsPipelineBuilder::set_multisampling_none()
-> GraphicsPipelineBuilder & -> GraphicsPipelineBuilder &
{
return set_multisampling(VK_SAMPLE_COUNT_1_BIT);
}
auto GraphicsPipelineBuilder::set_multisampling(VkSampleCountFlagBits samples)
-> GraphicsPipelineBuilder &
{ {
m_multisampling.sampleShadingEnable = VK_FALSE; m_multisampling.sampleShadingEnable = VK_FALSE;
m_multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; m_multisampling.rasterizationSamples = samples;
m_multisampling.minSampleShading = 1.0f; m_multisampling.minSampleShading = 1.0f;
m_multisampling.pSampleMask = nullptr; m_multisampling.pSampleMask = nullptr;
m_multisampling.alphaToCoverageEnable = VK_FALSE; m_multisampling.alphaToCoverageEnable = VK_FALSE;

View File

@@ -25,6 +25,8 @@ struct GraphicsPipelineBuilder {
auto set_cull_mode(VkCullModeFlags cull_mode, VkFrontFace front_face) auto set_cull_mode(VkCullModeFlags cull_mode, VkFrontFace front_face)
-> GraphicsPipelineBuilder &; -> GraphicsPipelineBuilder &;
auto set_multisampling_none() -> GraphicsPipelineBuilder &; auto set_multisampling_none() -> GraphicsPipelineBuilder &;
auto set_multisampling(VkSampleCountFlagBits samples)
-> GraphicsPipelineBuilder &;
auto disable_blending() -> GraphicsPipelineBuilder &; auto disable_blending() -> GraphicsPipelineBuilder &;
auto enable_blending_additive() -> GraphicsPipelineBuilder &; auto enable_blending_additive() -> GraphicsPipelineBuilder &;
auto enable_blending_alpha_blend() -> GraphicsPipelineBuilder &; auto enable_blending_alpha_blend() -> GraphicsPipelineBuilder &;

View File

@@ -89,7 +89,7 @@ auto load_shader_module(std::span<uint8_t> spirv_data, vk::Device device)
namespace vkinit { namespace vkinit {
auto image_create_info(vk::Format format, vk::ImageUsageFlags usage_flags, auto image_create_info(vk::Format format, vk::ImageUsageFlags usage_flags,
vk::Extent3D extent) -> vk::ImageCreateInfo vk::Extent3D extent, vk::SampleCountFlagBits samples) -> vk::ImageCreateInfo
{ {
vk::ImageCreateInfo info {}; vk::ImageCreateInfo info {};
info.imageType = vk::ImageType::e2D; info.imageType = vk::ImageType::e2D;
@@ -97,7 +97,7 @@ auto image_create_info(vk::Format format, vk::ImageUsageFlags usage_flags,
info.extent = extent; info.extent = extent;
info.mipLevels = 1; info.mipLevels = 1;
info.arrayLayers = 1; info.arrayLayers = 1;
info.samples = vk::SampleCountFlagBits::e1; info.samples = samples;
info.tiling = vk::ImageTiling::eOptimal; info.tiling = vk::ImageTiling::eOptimal;
info.usage = usage_flags; info.usage = usage_flags;
return info; return info;

View File

@@ -52,7 +52,9 @@ auto load_shader_module(std::span<uint8_t> spirv_data, vk::Device device)
namespace vkinit { namespace vkinit {
auto image_create_info(vk::Format format, vk::ImageUsageFlags usage_flags, auto image_create_info(vk::Format format, vk::ImageUsageFlags usage_flags,
vk::Extent3D extent) -> vk::ImageCreateInfo; vk::Extent3D extent,
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1)
-> vk::ImageCreateInfo;
auto imageview_create_info(vk::Format format, vk::Image image, auto imageview_create_info(vk::Format format, vk::Image image,
vk::ImageAspectFlags aspect_flags) -> vk::ImageViewCreateInfo; vk::ImageAspectFlags aspect_flags) -> vk::ImageViewCreateInfo;
auto command_buffer_submit_info(vk::CommandBuffer cmd) auto command_buffer_submit_info(vk::CommandBuffer cmd)

View File

@@ -56,8 +56,25 @@ auto VulkanRenderer::GL::begin_drawing(vk::CommandBuffer cmd,
m_color_target->extent.height, m_color_target->extent.height,
}; };
auto color_att { vkinit::attachment_info(m_color_target->image_view, vk::RenderingAttachmentInfo color_att {};
nullptr, vk::ImageLayout::eColorAttachmentOptimal) }; vk::ClearValue clear {};
clear.color = vk::ClearColorValue {
smath::Vec4 { Colors::DARK_SLATE_GRAY, 1.0f },
};
if (m_renderer.m_vk.msaa_samples != vk::SampleCountFlagBits::e1) {
assert(m_renderer.m_vk.msaa_color_image.image_view
&& "MSAA enabled but MSAA color image is missing");
color_att = vkinit::attachment_info(
m_renderer.m_vk.msaa_color_image.image_view, &clear,
vk::ImageLayout::eColorAttachmentOptimal);
color_att.resolveMode = vk::ResolveModeFlagBits::eAverage;
color_att.resolveImageView = m_color_target->image_view;
color_att.resolveImageLayout = vk::ImageLayout::eColorAttachmentOptimal;
color_att.storeOp = vk::AttachmentStoreOp::eDontCare;
} else {
color_att = vkinit::attachment_info(m_color_target->image_view, &clear,
vk::ImageLayout::eColorAttachmentOptimal);
}
std::optional<vk::RenderingAttachmentInfo> depth_att; std::optional<vk::RenderingAttachmentInfo> depth_att;
if (m_depth_target) { if (m_depth_target) {
depth_att = vkinit::depth_attachment_info(m_depth_target->image_view, depth_att = vkinit::depth_attachment_info(m_depth_target->image_view,
@@ -192,21 +209,21 @@ auto VulkanRenderer::GL::flush() -> void
| vk::BufferUsageFlagBits::eTransferDst, | vk::BufferUsageFlagBits::eTransferDst,
VMA_MEMORY_USAGE_GPU_ONLY) }; VMA_MEMORY_USAGE_GPU_ONLY) };
m_renderer.immediate_submit([&](vk::CommandBuffer cmd) { m_renderer.immediate_submit(
vk::BufferCopy vertex_copy {}; [&](vk::CommandBuffer cmd) {
vertex_copy.srcOffset = 0; vk::BufferCopy vertex_copy {};
vertex_copy.dstOffset = 0; vertex_copy.srcOffset = 0;
vertex_copy.size = vertex_data_size; vertex_copy.dstOffset = 0;
cmd.copyBuffer( vertex_copy.size = vertex_data_size;
staging.buffer, vertex_buffer.buffer, 1, &vertex_copy); cmd.copyBuffer(
staging.buffer, vertex_buffer.buffer, 1, &vertex_copy);
vk::BufferCopy index_copy {}; vk::BufferCopy index_copy {};
index_copy.srcOffset = vertex_data_size; index_copy.srcOffset = vertex_data_size;
index_copy.dstOffset = 0; index_copy.dstOffset = 0;
index_copy.size = index_data_size; index_copy.size = index_data_size;
cmd.copyBuffer( cmd.copyBuffer(staging.buffer, index_buffer.buffer, 1, &index_copy);
staging.buffer, index_buffer.buffer, 1, &index_copy); },
},
/*flush_frame_deletion_queue=*/false, /*flush_frame_deletion_queue=*/false,
/*clear_frame_descriptors=*/false); /*clear_frame_descriptors=*/false);
@@ -280,9 +297,8 @@ auto VulkanRenderer::GL::set_transform(smath::Mat4 const &transform) -> void
m_transform = transform; m_transform = transform;
} }
auto VulkanRenderer::GL::draw_rectangle( auto VulkanRenderer::GL::draw_rectangle(smath::Vec2 pos, smath::Vec2 size,
smath::Vec2 pos, smath::Vec2 size, smath::Vec4 rect_color, float rotation) smath::Vec4 rect_color, float rotation) -> void
-> void
{ {
auto const half_size = size * 0.5f; auto const half_size = size * 0.5f;
auto const center = pos + half_size; auto const center = pos + half_size;
@@ -293,10 +309,14 @@ auto VulkanRenderer::GL::draw_rectangle(
return smath::Vec2 { c * p.x() - s * p.y(), s * p.x() + c * p.y() }; return smath::Vec2 { c * p.x() - s * p.y(), s * p.x() + c * p.y() };
}; };
auto const br = center + rotate(smath::Vec2 { half_size.x(), -half_size.y() }); auto const br
auto const tr = center + rotate(smath::Vec2 { half_size.x(), half_size.y() }); = center + rotate(smath::Vec2 { half_size.x(), -half_size.y() });
auto const bl = center + rotate(smath::Vec2 { -half_size.x(), -half_size.y() }); auto const tr
auto const tl = center + rotate(smath::Vec2 { -half_size.x(), half_size.y() }); = center + rotate(smath::Vec2 { half_size.x(), half_size.y() });
auto const bl
= center + rotate(smath::Vec2 { -half_size.x(), -half_size.y() });
auto const tl
= center + rotate(smath::Vec2 { -half_size.x(), half_size.y() });
begin(GeometryKind::Quads); begin(GeometryKind::Quads);
@@ -473,7 +493,6 @@ VulkanRenderer::~VulkanRenderer()
m_vk.imm_command_buffer.reset(); m_vk.imm_command_buffer.reset();
m_vk.imm_command_pool.reset(); m_vk.imm_command_pool.reset();
m_vk.imm_fence.reset(); m_vk.imm_fence.reset();
m_vk.gradient_pipeline.reset();
m_vk.triangle_pipeline.reset(); m_vk.triangle_pipeline.reset();
m_vk.mesh_pipeline.reset(); m_vk.mesh_pipeline.reset();
m_vk.default_sampler_linear.reset(); m_vk.default_sampler_linear.reset();
@@ -481,6 +500,7 @@ VulkanRenderer::~VulkanRenderer()
destroy_swapchain(); destroy_swapchain();
destroy_draw_image(); destroy_draw_image();
destroy_msaa_color_image();
destroy_depth_image(); destroy_depth_image();
m_vk.deletion_queue.flush(); m_vk.deletion_queue.flush();
@@ -505,6 +525,97 @@ auto VulkanRenderer::resize(uint32_t width, uint32_t height) -> void
recreate_swapchain(width, height); recreate_swapchain(width, height);
} }
auto VulkanRenderer::set_antialiasing(AntiAliasingKind kind) -> void
{
auto requested_samples = [&](AntiAliasingKind aa) {
switch (aa) {
case AntiAliasingKind::NONE:
return vk::SampleCountFlagBits::e1;
case AntiAliasingKind::MSAA_2X:
return vk::SampleCountFlagBits::e2;
case AntiAliasingKind::MSAA_4X:
return vk::SampleCountFlagBits::e4;
case AntiAliasingKind::MSAA_8X:
return vk::SampleCountFlagBits::e8;
}
return vk::SampleCountFlagBits::e1;
}(kind);
auto best_supported = [&](vk::SampleCountFlagBits requested) {
auto const supported = m_vk.supported_framebuffer_samples;
auto pick_if_supported = [&](vk::SampleCountFlagBits candidate) {
return (supported & candidate) == candidate;
};
if (requested >= vk::SampleCountFlagBits::e64
&& pick_if_supported(vk::SampleCountFlagBits::e64)) {
return vk::SampleCountFlagBits::e64;
}
if (requested >= vk::SampleCountFlagBits::e32
&& pick_if_supported(vk::SampleCountFlagBits::e32)) {
return vk::SampleCountFlagBits::e32;
}
if (requested >= vk::SampleCountFlagBits::e16
&& pick_if_supported(vk::SampleCountFlagBits::e16)) {
return vk::SampleCountFlagBits::e16;
}
if (requested >= vk::SampleCountFlagBits::e8
&& pick_if_supported(vk::SampleCountFlagBits::e8)) {
return vk::SampleCountFlagBits::e8;
}
if (requested >= vk::SampleCountFlagBits::e4
&& pick_if_supported(vk::SampleCountFlagBits::e4)) {
return vk::SampleCountFlagBits::e4;
}
if (requested >= vk::SampleCountFlagBits::e2
&& pick_if_supported(vk::SampleCountFlagBits::e2)) {
return vk::SampleCountFlagBits::e2;
}
return vk::SampleCountFlagBits::e1;
}(requested_samples);
auto kind_for_samples = [](vk::SampleCountFlagBits samples) {
switch (samples) {
case vk::SampleCountFlagBits::e2:
return AntiAliasingKind::MSAA_2X;
case vk::SampleCountFlagBits::e4:
return AntiAliasingKind::MSAA_4X;
case vk::SampleCountFlagBits::e8:
return AntiAliasingKind::MSAA_8X;
default:
return AntiAliasingKind::NONE;
}
};
auto const effective_kind = kind_for_samples(best_supported);
if (m_vk.antialiasing_kind == effective_kind
&& m_vk.msaa_samples == best_supported) {
return;
}
if (best_supported != requested_samples) {
m_logger.warn("Requested antialiasing {} but using {}",
static_cast<int>(kind), static_cast<int>(effective_kind));
}
m_vk.antialiasing_kind = effective_kind;
m_vk.msaa_samples = best_supported;
if (!m_vk.swapchain || m_vk.swapchain_extent.width == 0
|| m_vk.swapchain_extent.height == 0) {
return;
}
m_device.waitIdle();
create_msaa_color_image(
m_vk.swapchain_extent.width, m_vk.swapchain_extent.height);
create_depth_image(
m_vk.swapchain_extent.width, m_vk.swapchain_extent.height);
pipelines_init();
}
auto VulkanRenderer::immediate_submit( auto VulkanRenderer::immediate_submit(
std::function<void(vk::CommandBuffer cmd)> &&function, std::function<void(vk::CommandBuffer cmd)> &&function,
bool flush_frame_deletion_queue, bool clear_frame_descriptors) -> void bool flush_frame_deletion_queue, bool clear_frame_descriptors) -> void
@@ -637,6 +748,13 @@ auto VulkanRenderer::vk_init() -> void
m_logger.info("Chosen Vulkan physical device: {}", m_logger.info("Chosen Vulkan physical device: {}",
m_vkb.phys_dev.properties.deviceName); m_vkb.phys_dev.properties.deviceName);
auto const props = m_physical_device.getProperties();
m_vk.supported_framebuffer_samples
= props.limits.framebufferColorSampleCounts
& props.limits.framebufferDepthSampleCounts;
m_vk.msaa_samples = vk::SampleCountFlagBits::e1;
m_vk.antialiasing_kind = AntiAliasingKind::NONE;
vkb::DeviceBuilder device_builder { m_vkb.phys_dev }; vkb::DeviceBuilder device_builder { m_vkb.phys_dev };
auto dev_ret { device_builder.build() }; auto dev_ret { device_builder.build() };
if (!dev_ret) { if (!dev_ret) {
@@ -672,6 +790,7 @@ auto VulkanRenderer::swapchain_init() -> void
SDL_GetWindowSize(m_window, &w, &h); SDL_GetWindowSize(m_window, &w, &h);
create_swapchain(static_cast<uint32_t>(w), static_cast<uint32_t>(h)); create_swapchain(static_cast<uint32_t>(w), static_cast<uint32_t>(h));
create_draw_image(static_cast<uint32_t>(w), static_cast<uint32_t>(h)); create_draw_image(static_cast<uint32_t>(w), static_cast<uint32_t>(h));
create_msaa_color_image(static_cast<uint32_t>(w), static_cast<uint32_t>(h));
create_depth_image(static_cast<uint32_t>(w), static_cast<uint32_t>(h)); create_depth_image(static_cast<uint32_t>(w), static_cast<uint32_t>(h));
} }
@@ -719,26 +838,7 @@ auto VulkanRenderer::sync_init() -> void
auto VulkanRenderer::descriptors_init() -> void auto VulkanRenderer::descriptors_init() -> void
{ {
std::vector<DescriptorAllocator::PoolSizeRatio> sizes {
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
};
m_vk.descriptor_allocator.init_pool(m_vkb.dev.device, 10, sizes);
auto draw_layout_raw
= DescriptorLayoutBuilder()
.add_binding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
.build(m_logger, m_vkb.dev.device, VK_SHADER_STAGE_COMPUTE_BIT);
m_vk.draw_image_descriptor_layout
= vk::DescriptorSetLayout { draw_layout_raw };
m_vk.draw_image_descriptors = m_vk.descriptor_allocator.allocate(
m_logger, m_vkb.dev.device, m_vk.draw_image_descriptor_layout);
update_draw_image_descriptor();
m_vk.deletion_queue.emplace([&]() { m_vk.deletion_queue.emplace([&]() {
m_vk.descriptor_allocator.destroy_pool(m_vkb.dev.device);
m_device.destroyDescriptorSetLayout(m_vk.draw_image_descriptor_layout);
m_device.destroyDescriptorSetLayout( m_device.destroyDescriptorSetLayout(
m_vk.gpu_scene_data_descriptor_layout); m_vk.gpu_scene_data_descriptor_layout);
m_device.destroyDescriptorSetLayout( m_device.destroyDescriptorSetLayout(
@@ -780,34 +880,10 @@ auto VulkanRenderer::descriptors_init() -> void
auto VulkanRenderer::pipelines_init() -> void auto VulkanRenderer::pipelines_init() -> void
{ {
background_pipelines_init();
triangle_pipeline_init(); triangle_pipeline_init();
mesh_pipeline_init(); mesh_pipeline_init();
} }
auto VulkanRenderer::background_pipelines_init() -> void
{
Pipeline::Builder builder { m_device, m_logger };
std::array layout_handles { m_vk.draw_image_descriptor_layout };
builder.set_descriptor_set_layouts(layout_handles);
uint8_t compute_draw_shader_data[] {
#embed "gradient_comp.spv"
};
auto compute_draw_shader { vkutil::load_shader_module(
std::span<uint8_t>(
compute_draw_shader_data, sizeof(compute_draw_shader_data)),
m_device) };
if (!compute_draw_shader) {
m_logger.err("Failed to load gradient compute shader");
}
auto stage_ci { vkinit::pipeline_shader_stage(
vk::ShaderStageFlagBits::eCompute, compute_draw_shader.get()) };
m_vk.gradient_pipeline = builder.build_compute(stage_ci);
}
auto VulkanRenderer::triangle_pipeline_init() -> void auto VulkanRenderer::triangle_pipeline_init() -> void
{ {
Pipeline::Builder builder { m_device, m_logger }; Pipeline::Builder builder { m_device, m_logger };
@@ -842,7 +918,8 @@ auto VulkanRenderer::triangle_pipeline_init() -> void
triangle_vert_shader.get(), triangle_frag_shader.get()) triangle_vert_shader.get(), triangle_frag_shader.get())
.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
.set_polygon_mode(VK_POLYGON_MODE_FILL) .set_polygon_mode(VK_POLYGON_MODE_FILL)
.set_multisampling_none() .set_multisampling(
static_cast<VkSampleCountFlagBits>(m_vk.msaa_samples))
.enable_blending_additive() .enable_blending_additive()
.disable_depth_testing() .disable_depth_testing()
.set_color_attachment_format( .set_color_attachment_format(
@@ -897,7 +974,8 @@ auto VulkanRenderer::mesh_pipeline_init() -> void
.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
.set_polygon_mode(VK_POLYGON_MODE_FILL) .set_polygon_mode(VK_POLYGON_MODE_FILL)
.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE) .set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE)
.set_multisampling_none() .set_multisampling(
static_cast<VkSampleCountFlagBits>(m_vk.msaa_samples))
.disable_blending() .disable_blending()
.enable_depth_testing() .enable_depth_testing()
.set_color_attachment_format( .set_color_attachment_format(
@@ -1077,15 +1155,17 @@ auto VulkanRenderer::render(std::function<void(GL &)> const &record) -> void
return; return;
} }
auto &frame = m_vk.get_current_frame();
VK_CHECK(m_logger, VK_CHECK(m_logger,
m_device.waitForFences( m_device.waitForFences(frame.render_fence.get(), true, 1'000'000'000));
m_vk.get_current_frame().render_fence.get(), true, 1'000'000'000)); frame.deletion_queue.flush();
auto raw_fence frame.frame_descriptors.clear_pools(m_vkb.dev.device);
= static_cast<VkFence>(m_vk.get_current_frame().render_fence.get());
auto raw_fence = static_cast<VkFence>(frame.render_fence.get());
VK_CHECK(m_logger, vkResetFences(m_vkb.dev.device, 1, &raw_fence)); VK_CHECK(m_logger, vkResetFences(m_vkb.dev.device, 1, &raw_fence));
auto const acquire_result = m_device.acquireNextImageKHR(m_vk.swapchain, auto const acquire_result = m_device.acquireNextImageKHR(
1'000'000'000, m_vk.get_current_frame().swapchain_semaphore.get(), {}); m_vk.swapchain, 1'000'000'000, frame.swapchain_semaphore.get(), {});
if (acquire_result.result == vk::Result::eErrorOutOfDateKHR if (acquire_result.result == vk::Result::eErrorOutOfDateKHR
|| acquire_result.result == vk::Result::eSuboptimalKHR) { || acquire_result.result == vk::Result::eSuboptimalKHR) {
int width {}, height {}; int width {}, height {};
@@ -1097,7 +1177,7 @@ auto VulkanRenderer::render(std::function<void(GL &)> const &record) -> void
VK_CHECK(m_logger, acquire_result.result); VK_CHECK(m_logger, acquire_result.result);
uint32_t const swapchain_image_idx { acquire_result.value }; uint32_t const swapchain_image_idx { acquire_result.value };
auto cmd { m_vk.get_current_frame().main_command_buffer.get() }; auto cmd { frame.main_command_buffer.get() };
cmd.reset(); cmd.reset();
m_vk.draw_extent.width = m_vk.draw_image.extent.width; m_vk.draw_extent.width = m_vk.draw_image.extent.width;
@@ -1109,15 +1189,22 @@ auto VulkanRenderer::render(std::function<void(GL &)> const &record) -> void
vkBeginCommandBuffer(static_cast<VkCommandBuffer>(cmd), vkBeginCommandBuffer(static_cast<VkCommandBuffer>(cmd),
reinterpret_cast<VkCommandBufferBeginInfo *>(&cmd_begin_info))); reinterpret_cast<VkCommandBufferBeginInfo *>(&cmd_begin_info)));
vkutil::transition_image(cmd, m_vk.draw_image.image, bool const msaa_enabled = m_vk.msaa_samples != vk::SampleCountFlagBits::e1;
vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral);
draw_background(cmd); vkutil::transition_image(cmd, m_vk.draw_image.image, m_vk.draw_image_layout,
vk::ImageLayout::eColorAttachmentOptimal);
m_vk.draw_image_layout = vk::ImageLayout::eColorAttachmentOptimal;
if (msaa_enabled) {
vkutil::transition_image(cmd, m_vk.msaa_color_image.image,
m_vk.msaa_color_image_layout,
vk::ImageLayout::eColorAttachmentOptimal);
m_vk.msaa_color_image_layout = vk::ImageLayout::eColorAttachmentOptimal;
}
vkutil::transition_image(cmd, m_vk.draw_image.image,
vk::ImageLayout::eGeneral, vk::ImageLayout::eColorAttachmentOptimal);
vkutil::transition_image(cmd, m_vk.depth_image.image, vkutil::transition_image(cmd, m_vk.depth_image.image,
vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthAttachmentOptimal); m_vk.depth_image_layout, vk::ImageLayout::eDepthAttachmentOptimal);
m_vk.depth_image_layout = vk::ImageLayout::eDepthAttachmentOptimal;
gl.begin_drawing(cmd, m_vk.draw_image, &m_vk.depth_image); gl.begin_drawing(cmd, m_vk.draw_image, &m_vk.depth_image);
if (record) { if (record) {
@@ -1125,9 +1212,9 @@ auto VulkanRenderer::render(std::function<void(GL &)> const &record) -> void
} }
gl.end_drawing(); gl.end_drawing();
vkutil::transition_image(cmd, m_vk.draw_image.image, vkutil::transition_image(cmd, m_vk.draw_image.image, m_vk.draw_image_layout,
vk::ImageLayout::eColorAttachmentOptimal,
vk::ImageLayout::eTransferSrcOptimal); vk::ImageLayout::eTransferSrcOptimal);
m_vk.draw_image_layout = vk::ImageLayout::eTransferSrcOptimal;
vkutil::transition_image(cmd, m_vk.swapchain_images.at(swapchain_image_idx), vkutil::transition_image(cmd, m_vk.swapchain_images.at(swapchain_image_idx),
vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
@@ -1180,18 +1267,6 @@ auto VulkanRenderer::render(std::function<void(GL &)> const &record) -> void
VK_CHECK(m_logger, present_result); VK_CHECK(m_logger, present_result);
} }
auto VulkanRenderer::draw_background(vk::CommandBuffer cmd) -> void
{
cmd.bindPipeline(
vk::PipelineBindPoint::eCompute, m_vk.gradient_pipeline.get());
auto compute_set = vk::DescriptorSet { m_vk.draw_image_descriptors };
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
m_vk.gradient_pipeline.get_layout(), 0, compute_set, {});
cmd.dispatch(
static_cast<uint32_t>(std::ceil(m_vk.draw_extent.width / 16.0)),
static_cast<uint32_t>(std::ceil(m_vk.draw_extent.height / 16.0)), 1);
}
auto VulkanRenderer::draw_imgui( auto VulkanRenderer::draw_imgui(
vk::CommandBuffer cmd, vk::ImageView target_image_view) -> void vk::CommandBuffer cmd, vk::ImageView target_image_view) -> void
{ {
@@ -1260,10 +1335,26 @@ auto VulkanRenderer::create_draw_image(uint32_t width, uint32_t height) -> void
auto const flags { vk::ImageUsageFlagBits::eTransferSrc auto const flags { vk::ImageUsageFlagBits::eTransferSrc
| vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferDst
| vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eColorAttachment }; | vk::ImageUsageFlagBits::eColorAttachment };
m_vk.draw_image = create_image( m_vk.draw_image = create_image(
{ width, height, 1 }, vk::Format::eR16G16B16A16Sfloat, flags); { width, height, 1 }, vk::Format::eR16G16B16A16Sfloat, flags);
m_vk.draw_image_layout = vk::ImageLayout::eUndefined;
}
auto VulkanRenderer::create_msaa_color_image(uint32_t width, uint32_t height)
-> void
{
destroy_msaa_color_image();
if (m_vk.msaa_samples == vk::SampleCountFlagBits::e1) {
return;
}
auto const flags { vk::ImageUsageFlagBits::eColorAttachment };
m_vk.msaa_color_image = create_image(
{ width, height, 1 }, m_vk.draw_image.format, flags, m_vk.msaa_samples);
m_vk.msaa_color_image_layout = vk::ImageLayout::eUndefined;
} }
auto VulkanRenderer::create_depth_image(uint32_t width, uint32_t height) -> void auto VulkanRenderer::create_depth_image(uint32_t width, uint32_t height) -> void
@@ -1273,8 +1364,9 @@ auto VulkanRenderer::create_depth_image(uint32_t width, uint32_t height) -> void
auto const flags { vk::ImageUsageFlagBits::eTransferSrc auto const flags { vk::ImageUsageFlagBits::eTransferSrc
| vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferDst
| vk::ImageUsageFlagBits::eDepthStencilAttachment }; | vk::ImageUsageFlagBits::eDepthStencilAttachment };
m_vk.depth_image m_vk.depth_image = create_image(
= create_image({ width, height, 1 }, vk::Format::eD32Sfloat, flags); { width, height, 1 }, vk::Format::eD32Sfloat, flags, m_vk.msaa_samples);
m_vk.depth_image_layout = vk::ImageLayout::eUndefined;
} }
auto VulkanRenderer::destroy_depth_image() -> void auto VulkanRenderer::destroy_depth_image() -> void
@@ -1288,17 +1380,10 @@ auto VulkanRenderer::destroy_depth_image() -> void
m_vk.depth_image.image = vk::Image {}; m_vk.depth_image.image = vk::Image {};
m_vk.depth_image.allocation = nullptr; m_vk.depth_image.allocation = nullptr;
m_vk.depth_image.extent = vk::Extent3D { 0, 0, 0 }; m_vk.depth_image.extent = vk::Extent3D { 0, 0, 0 };
m_vk.depth_image_layout = vk::ImageLayout::eUndefined;
} }
} }
auto VulkanRenderer::update_draw_image_descriptor() -> void
{
DescriptorWriter()
.write_image(0, m_vk.draw_image.image_view, VK_NULL_HANDLE,
VK_IMAGE_LAYOUT_GENERAL, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
.update_set(m_vkb.dev.device, m_vk.draw_image_descriptors);
}
auto VulkanRenderer::destroy_draw_image() -> void auto VulkanRenderer::destroy_draw_image() -> void
{ {
if (m_vk.draw_image.image) { if (m_vk.draw_image.image) {
@@ -1310,6 +1395,22 @@ auto VulkanRenderer::destroy_draw_image() -> void
m_vk.draw_image.image = vk::Image {}; m_vk.draw_image.image = vk::Image {};
m_vk.draw_image.allocation = nullptr; m_vk.draw_image.allocation = nullptr;
m_vk.draw_image.extent = vk::Extent3D { 0, 0, 0 }; m_vk.draw_image.extent = vk::Extent3D { 0, 0, 0 };
m_vk.draw_image_layout = vk::ImageLayout::eUndefined;
}
}
auto VulkanRenderer::destroy_msaa_color_image() -> void
{
if (m_vk.msaa_color_image.image) {
m_device.destroyImageView(m_vk.msaa_color_image.image_view);
m_vk.msaa_color_image.image_view = vk::ImageView {};
vmaDestroyImage(m_vk.allocator,
static_cast<VkImage>(m_vk.msaa_color_image.image),
m_vk.msaa_color_image.allocation);
m_vk.msaa_color_image.image = vk::Image {};
m_vk.msaa_color_image.allocation = nullptr;
m_vk.msaa_color_image.extent = vk::Extent3D { 0, 0, 0 };
m_vk.msaa_color_image_layout = vk::ImageLayout::eUndefined;
} }
} }
@@ -1320,6 +1421,7 @@ auto VulkanRenderer::recreate_swapchain(uint32_t width, uint32_t height) -> void
if (width == 0 || height == 0) { if (width == 0 || height == 0) {
destroy_swapchain(); destroy_swapchain();
destroy_draw_image(); destroy_draw_image();
destroy_msaa_color_image();
destroy_depth_image(); destroy_depth_image();
m_vk.swapchain_extent = vk::Extent2D { 0, 0 }; m_vk.swapchain_extent = vk::Extent2D { 0, 0 };
return; return;
@@ -1327,12 +1429,13 @@ auto VulkanRenderer::recreate_swapchain(uint32_t width, uint32_t height) -> void
destroy_swapchain(); destroy_swapchain();
destroy_draw_image(); destroy_draw_image();
destroy_msaa_color_image();
destroy_depth_image(); destroy_depth_image();
create_swapchain(width, height); create_swapchain(width, height);
create_draw_image(width, height); create_draw_image(width, height);
create_msaa_color_image(width, height);
create_depth_image(width, height); create_depth_image(width, height);
update_draw_image_descriptor();
} }
auto VulkanRenderer::destroy_swapchain() -> void auto VulkanRenderer::destroy_swapchain() -> void
@@ -1351,13 +1454,14 @@ auto VulkanRenderer::destroy_swapchain() -> void
} }
auto VulkanRenderer::create_image(vk::Extent3D size, vk::Format format, auto VulkanRenderer::create_image(vk::Extent3D size, vk::Format format,
vk::ImageUsageFlags flags, bool mipmapped) -> AllocatedImage vk::ImageUsageFlags flags, vk::SampleCountFlagBits samples, bool mipmapped)
-> AllocatedImage
{ {
AllocatedImage new_image; AllocatedImage new_image;
new_image.format = format; new_image.format = format;
new_image.extent = size; new_image.extent = size;
auto img_ci { vkinit::image_create_info(format, flags, size) }; auto img_ci { vkinit::image_create_info(format, flags, size, samples) };
if (mipmapped) { if (mipmapped) {
img_ci.mipLevels = static_cast<uint32_t>(std::floor( img_ci.mipLevels = static_cast<uint32_t>(std::floor(
std::log2(std::max(size.width, size.height)))) std::log2(std::max(size.width, size.height))))
@@ -1418,7 +1522,7 @@ auto VulkanRenderer::create_image(void const *data, vk::Extent3D size,
create_image(size, format, create_image(size, format,
flags | vk::ImageUsageFlagBits::eTransferDst flags | vk::ImageUsageFlagBits::eTransferDst
| vk::ImageUsageFlagBits::eTransferSrc, | vk::ImageUsageFlagBits::eTransferSrc,
mipmapped), vk::SampleCountFlagBits::e1, mipmapped),
}; };
immediate_submit([&](vk::CommandBuffer cmd) { immediate_submit([&](vk::CommandBuffer cmd) {

View File

@@ -13,7 +13,6 @@
#include "Colors.h" #include "Colors.h"
#include "DeletionQueue.h" #include "DeletionQueue.h"
#include "DescriptorAllocator.h"
#include "Loader.h" #include "Loader.h"
#include "Logger.h" #include "Logger.h"
#include "Pipeline.h" #include "Pipeline.h"
@@ -29,6 +28,13 @@ struct GPUDrawPushConstants {
constexpr unsigned FRAME_OVERLAP = 2; constexpr unsigned FRAME_OVERLAP = 2;
struct VulkanRenderer { struct VulkanRenderer {
enum class AntiAliasingKind {
NONE,
MSAA_2X,
MSAA_4X,
MSAA_8X,
};
struct GL { struct GL {
enum class GeometryKind { enum class GeometryKind {
Triangles, Triangles,
@@ -105,6 +111,11 @@ struct VulkanRenderer {
auto render(std::function<void(GL &)> const &record = {}) -> void; auto render(std::function<void(GL &)> const &record = {}) -> void;
auto resize(uint32_t width, uint32_t height) -> void; auto resize(uint32_t width, uint32_t height) -> void;
auto set_antialiasing(AntiAliasingKind kind) -> void;
auto antialiasing() const -> AntiAliasingKind
{
return m_vk.antialiasing_kind;
}
auto immediate_submit(std::function<void(vk::CommandBuffer cmd)> &&function, auto immediate_submit(std::function<void(vk::CommandBuffer cmd)> &&function,
bool flush_frame_deletion_queue = true, bool flush_frame_deletion_queue = true,
@@ -151,26 +162,27 @@ private:
auto sync_init() -> void; auto sync_init() -> void;
auto descriptors_init() -> void; auto descriptors_init() -> void;
auto pipelines_init() -> void; auto pipelines_init() -> void;
auto background_pipelines_init() -> void;
auto triangle_pipeline_init() -> void; auto triangle_pipeline_init() -> void;
auto mesh_pipeline_init() -> void; auto mesh_pipeline_init() -> void;
auto imgui_init() -> void; auto imgui_init() -> void;
auto default_data_init() -> void; auto default_data_init() -> void;
auto draw_background(vk::CommandBuffer cmd) -> void;
auto draw_imgui(vk::CommandBuffer cmd, vk::ImageView target_image_view) auto draw_imgui(vk::CommandBuffer cmd, vk::ImageView target_image_view)
-> void; -> void;
auto create_swapchain(uint32_t width, uint32_t height) -> void; auto create_swapchain(uint32_t width, uint32_t height) -> void;
auto create_draw_image(uint32_t width, uint32_t height) -> void; auto create_draw_image(uint32_t width, uint32_t height) -> void;
auto update_draw_image_descriptor() -> void; auto create_msaa_color_image(uint32_t width, uint32_t height) -> void;
auto destroy_draw_image() -> void; auto destroy_draw_image() -> void;
auto create_depth_image(uint32_t width, uint32_t height) -> void; auto create_depth_image(uint32_t width, uint32_t height) -> void;
auto destroy_depth_image() -> void; auto destroy_depth_image() -> void;
auto destroy_msaa_color_image() -> void;
auto recreate_swapchain(uint32_t width, uint32_t height) -> void; auto recreate_swapchain(uint32_t width, uint32_t height) -> void;
auto destroy_swapchain() -> void; auto destroy_swapchain() -> void;
auto create_image(vk::Extent3D size, vk::Format format, auto create_image(vk::Extent3D size, vk::Format format,
vk::ImageUsageFlags flags, bool mipmapped = false) -> AllocatedImage; vk::ImageUsageFlags flags,
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1,
bool mipmapped = false) -> AllocatedImage;
auto create_image(void const *data, vk::Extent3D size, vk::Format format, auto create_image(void const *data, vk::Extent3D size, vk::Format format,
vk::ImageUsageFlags flags, bool mipmapped = false) -> AllocatedImage; vk::ImageUsageFlags flags, bool mipmapped = false) -> AllocatedImage;
auto destroy_image(AllocatedImage const &img) -> void; auto destroy_image(AllocatedImage const &img) -> void;
@@ -210,21 +222,23 @@ private:
std::array<FrameData, FRAME_OVERLAP> frames; std::array<FrameData, FRAME_OVERLAP> frames;
AllocatedImage draw_image {}; AllocatedImage draw_image {};
vk::ImageLayout draw_image_layout { vk::ImageLayout::eUndefined };
AllocatedImage msaa_color_image {};
vk::ImageLayout msaa_color_image_layout { vk::ImageLayout::eUndefined };
AllocatedImage depth_image {}; AllocatedImage depth_image {};
vk::ImageLayout depth_image_layout { vk::ImageLayout::eUndefined };
vk::Extent2D draw_extent {}; vk::Extent2D draw_extent {};
AntiAliasingKind antialiasing_kind { AntiAliasingKind::NONE };
vk::SampleCountFlagBits msaa_samples { vk::SampleCountFlagBits::e1 };
vk::SampleCountFlags supported_framebuffer_samples {};
VmaAllocator allocator; VmaAllocator allocator;
DescriptorAllocator descriptor_allocator;
VkDescriptorSet draw_image_descriptors {};
vk::DescriptorSetLayout draw_image_descriptor_layout {};
GPUSceneData scene_data {}; GPUSceneData scene_data {};
vk::DescriptorSetLayout gpu_scene_data_descriptor_layout {}; vk::DescriptorSetLayout gpu_scene_data_descriptor_layout {};
vk::DescriptorSetLayout single_image_descriptor_layout {}; vk::DescriptorSetLayout single_image_descriptor_layout {};
Pipeline gradient_pipeline;
Pipeline triangle_pipeline; Pipeline triangle_pipeline;
Pipeline mesh_pipeline; Pipeline mesh_pipeline;