diff --git a/shaders/gradient_fullscreen.frag b/shaders/gradient_fullscreen.frag new file mode 100644 index 0000000..f2e3a82 --- /dev/null +++ b/shaders/gradient_fullscreen.frag @@ -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); +} + diff --git a/shaders/gradient_fullscreen.vert b/shaders/gradient_fullscreen.vert new file mode 100644 index 0000000..b828af0 --- /dev/null +++ b/shaders/gradient_fullscreen.vert @@ -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); +} + diff --git a/shaders/meson.build b/shaders/meson.build index 232fd5e..2f3c641 100644 --- a/shaders/meson.build +++ b/shaders/meson.build @@ -14,7 +14,6 @@ else endif shader_sources = files( - 'gradient.comp', 'triangle.frag', 'triangle.vert', 'triangle_mesh.frag', diff --git a/src/Application.cpp b/src/Application.cpp index 4e199de..87c7999 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -310,6 +310,8 @@ auto Application::run() -> void ImGui::Render(); + m_renderer->set_antialiasing(VulkanRenderer::AntiAliasingKind::MSAA_8X); + m_renderer->render([&](VulkanRenderer::GL &gl) { auto view { smath::matrix_look_at(smath::Vec3 { 0.0f, 0.0f, 3.0f }, smath::Vec3 { 0.0f, 0.0f, 0.0f }, diff --git a/src/GraphicsPipelineBuilder.cpp b/src/GraphicsPipelineBuilder.cpp index bc1b0c1..8adccff 100644 --- a/src/GraphicsPipelineBuilder.cpp +++ b/src/GraphicsPipelineBuilder.cpp @@ -79,9 +79,15 @@ auto GraphicsPipelineBuilder::set_cull_mode(VkCullModeFlags cull_mode, auto GraphicsPipelineBuilder::set_multisampling_none() -> GraphicsPipelineBuilder & +{ + return set_multisampling(VK_SAMPLE_COUNT_1_BIT); +} + +auto GraphicsPipelineBuilder::set_multisampling(VkSampleCountFlagBits samples) + -> GraphicsPipelineBuilder & { m_multisampling.sampleShadingEnable = VK_FALSE; - m_multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + m_multisampling.rasterizationSamples = samples; m_multisampling.minSampleShading = 1.0f; m_multisampling.pSampleMask = nullptr; m_multisampling.alphaToCoverageEnable = VK_FALSE; diff --git a/src/GraphicsPipelineBuilder.h b/src/GraphicsPipelineBuilder.h index 77ca58a..d788856 100644 --- a/src/GraphicsPipelineBuilder.h +++ b/src/GraphicsPipelineBuilder.h @@ -25,6 +25,8 @@ struct GraphicsPipelineBuilder { auto set_cull_mode(VkCullModeFlags cull_mode, VkFrontFace front_face) -> GraphicsPipelineBuilder &; auto set_multisampling_none() -> GraphicsPipelineBuilder &; + auto set_multisampling(VkSampleCountFlagBits samples) + -> GraphicsPipelineBuilder &; auto disable_blending() -> GraphicsPipelineBuilder &; auto enable_blending_additive() -> GraphicsPipelineBuilder &; auto enable_blending_alpha_blend() -> GraphicsPipelineBuilder &; diff --git a/src/Util.cpp b/src/Util.cpp index 7ba7350..eadc872 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -89,7 +89,7 @@ auto load_shader_module(std::span spirv_data, vk::Device device) namespace vkinit { 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 {}; info.imageType = vk::ImageType::e2D; @@ -97,7 +97,7 @@ auto image_create_info(vk::Format format, vk::ImageUsageFlags usage_flags, info.extent = extent; info.mipLevels = 1; info.arrayLayers = 1; - info.samples = vk::SampleCountFlagBits::e1; + info.samples = samples; info.tiling = vk::ImageTiling::eOptimal; info.usage = usage_flags; return info; diff --git a/src/Util.h b/src/Util.h index 5671cd4..0a66496 100644 --- a/src/Util.h +++ b/src/Util.h @@ -52,7 +52,9 @@ auto load_shader_module(std::span spirv_data, vk::Device device) namespace vkinit { 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, vk::ImageAspectFlags aspect_flags) -> vk::ImageViewCreateInfo; auto command_buffer_submit_info(vk::CommandBuffer cmd) diff --git a/src/VulkanRenderer.cpp b/src/VulkanRenderer.cpp index d43b395..087f338 100644 --- a/src/VulkanRenderer.cpp +++ b/src/VulkanRenderer.cpp @@ -56,8 +56,25 @@ auto VulkanRenderer::GL::begin_drawing(vk::CommandBuffer cmd, m_color_target->extent.height, }; - auto color_att { vkinit::attachment_info(m_color_target->image_view, - nullptr, vk::ImageLayout::eColorAttachmentOptimal) }; + vk::RenderingAttachmentInfo color_att {}; + 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 depth_att; if (m_depth_target) { depth_att = vkinit::depth_attachment_info(m_depth_target->image_view, @@ -192,21 +209,21 @@ auto VulkanRenderer::GL::flush() -> void | vk::BufferUsageFlagBits::eTransferDst, VMA_MEMORY_USAGE_GPU_ONLY) }; - m_renderer.immediate_submit([&](vk::CommandBuffer cmd) { - vk::BufferCopy vertex_copy {}; - vertex_copy.srcOffset = 0; - vertex_copy.dstOffset = 0; - vertex_copy.size = vertex_data_size; - cmd.copyBuffer( - staging.buffer, vertex_buffer.buffer, 1, &vertex_copy); + m_renderer.immediate_submit( + [&](vk::CommandBuffer cmd) { + vk::BufferCopy vertex_copy {}; + vertex_copy.srcOffset = 0; + vertex_copy.dstOffset = 0; + vertex_copy.size = vertex_data_size; + cmd.copyBuffer( + staging.buffer, vertex_buffer.buffer, 1, &vertex_copy); - vk::BufferCopy index_copy {}; - index_copy.srcOffset = vertex_data_size; - index_copy.dstOffset = 0; - index_copy.size = index_data_size; - cmd.copyBuffer( - staging.buffer, index_buffer.buffer, 1, &index_copy); - }, + vk::BufferCopy index_copy {}; + index_copy.srcOffset = vertex_data_size; + index_copy.dstOffset = 0; + index_copy.size = index_data_size; + cmd.copyBuffer(staging.buffer, index_buffer.buffer, 1, &index_copy); + }, /*flush_frame_deletion_queue=*/false, /*clear_frame_descriptors=*/false); @@ -280,9 +297,8 @@ auto VulkanRenderer::GL::set_transform(smath::Mat4 const &transform) -> void m_transform = transform; } -auto VulkanRenderer::GL::draw_rectangle( - smath::Vec2 pos, smath::Vec2 size, smath::Vec4 rect_color, float rotation) - -> void +auto VulkanRenderer::GL::draw_rectangle(smath::Vec2 pos, smath::Vec2 size, + smath::Vec4 rect_color, float rotation) -> void { auto const half_size = size * 0.5f; 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() }; }; - auto const br = center + rotate(smath::Vec2 { half_size.x(), -half_size.y() }); - auto const tr = 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() }); + auto const br + = center + rotate(smath::Vec2 { half_size.x(), -half_size.y() }); + auto const tr + = 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); @@ -473,7 +493,6 @@ VulkanRenderer::~VulkanRenderer() m_vk.imm_command_buffer.reset(); m_vk.imm_command_pool.reset(); m_vk.imm_fence.reset(); - m_vk.gradient_pipeline.reset(); m_vk.triangle_pipeline.reset(); m_vk.mesh_pipeline.reset(); m_vk.default_sampler_linear.reset(); @@ -481,6 +500,7 @@ VulkanRenderer::~VulkanRenderer() destroy_swapchain(); destroy_draw_image(); + destroy_msaa_color_image(); destroy_depth_image(); m_vk.deletion_queue.flush(); @@ -505,6 +525,97 @@ auto VulkanRenderer::resize(uint32_t width, uint32_t height) -> void 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(kind), static_cast(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( std::function &&function, 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_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 }; auto dev_ret { device_builder.build() }; if (!dev_ret) { @@ -672,6 +790,7 @@ auto VulkanRenderer::swapchain_init() -> void SDL_GetWindowSize(m_window, &w, &h); create_swapchain(static_cast(w), static_cast(h)); create_draw_image(static_cast(w), static_cast(h)); + create_msaa_color_image(static_cast(w), static_cast(h)); create_depth_image(static_cast(w), static_cast(h)); } @@ -719,26 +838,7 @@ auto VulkanRenderer::sync_init() -> void auto VulkanRenderer::descriptors_init() -> void { - std::vector 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.descriptor_allocator.destroy_pool(m_vkb.dev.device); - m_device.destroyDescriptorSetLayout(m_vk.draw_image_descriptor_layout); m_device.destroyDescriptorSetLayout( m_vk.gpu_scene_data_descriptor_layout); m_device.destroyDescriptorSetLayout( @@ -780,34 +880,10 @@ auto VulkanRenderer::descriptors_init() -> void auto VulkanRenderer::pipelines_init() -> void { - background_pipelines_init(); triangle_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( - 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 { 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()) .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) .set_polygon_mode(VK_POLYGON_MODE_FILL) - .set_multisampling_none() + .set_multisampling( + static_cast(m_vk.msaa_samples)) .enable_blending_additive() .disable_depth_testing() .set_color_attachment_format( @@ -897,7 +974,8 @@ auto VulkanRenderer::mesh_pipeline_init() -> void .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) .set_polygon_mode(VK_POLYGON_MODE_FILL) .set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE) - .set_multisampling_none() + .set_multisampling( + static_cast(m_vk.msaa_samples)) .disable_blending() .enable_depth_testing() .set_color_attachment_format( @@ -1109,15 +1187,22 @@ auto VulkanRenderer::render(std::function const &record) -> void vkBeginCommandBuffer(static_cast(cmd), reinterpret_cast(&cmd_begin_info))); - vkutil::transition_image(cmd, m_vk.draw_image.image, - vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral); + bool const msaa_enabled = m_vk.msaa_samples != vk::SampleCountFlagBits::e1; - 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, - 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); if (record) { @@ -1125,9 +1210,9 @@ auto VulkanRenderer::render(std::function const &record) -> void } gl.end_drawing(); - vkutil::transition_image(cmd, m_vk.draw_image.image, - vk::ImageLayout::eColorAttachmentOptimal, + vkutil::transition_image(cmd, m_vk.draw_image.image, m_vk.draw_image_layout, vk::ImageLayout::eTransferSrcOptimal); + m_vk.draw_image_layout = vk::ImageLayout::eTransferSrcOptimal; vkutil::transition_image(cmd, m_vk.swapchain_images.at(swapchain_image_idx), vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); @@ -1180,18 +1265,6 @@ auto VulkanRenderer::render(std::function const &record) -> void 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(std::ceil(m_vk.draw_extent.width / 16.0)), - static_cast(std::ceil(m_vk.draw_extent.height / 16.0)), 1); -} - auto VulkanRenderer::draw_imgui( vk::CommandBuffer cmd, vk::ImageView target_image_view) -> void { @@ -1260,10 +1333,26 @@ auto VulkanRenderer::create_draw_image(uint32_t width, uint32_t height) -> void auto const flags { vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst - | vk::ImageUsageFlagBits::eStorage + | vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eColorAttachment }; m_vk.draw_image = create_image( { 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 @@ -1273,8 +1362,9 @@ auto VulkanRenderer::create_depth_image(uint32_t width, uint32_t height) -> void auto const flags { vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eDepthStencilAttachment }; - m_vk.depth_image - = create_image({ width, height, 1 }, vk::Format::eD32Sfloat, flags); + m_vk.depth_image = create_image( + { 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 @@ -1288,17 +1378,10 @@ auto VulkanRenderer::destroy_depth_image() -> void m_vk.depth_image.image = vk::Image {}; m_vk.depth_image.allocation = nullptr; 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 { if (m_vk.draw_image.image) { @@ -1310,6 +1393,22 @@ auto VulkanRenderer::destroy_draw_image() -> void m_vk.draw_image.image = vk::Image {}; m_vk.draw_image.allocation = nullptr; 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(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 +1419,7 @@ auto VulkanRenderer::recreate_swapchain(uint32_t width, uint32_t height) -> void if (width == 0 || height == 0) { destroy_swapchain(); destroy_draw_image(); + destroy_msaa_color_image(); destroy_depth_image(); m_vk.swapchain_extent = vk::Extent2D { 0, 0 }; return; @@ -1327,12 +1427,13 @@ auto VulkanRenderer::recreate_swapchain(uint32_t width, uint32_t height) -> void destroy_swapchain(); destroy_draw_image(); + destroy_msaa_color_image(); destroy_depth_image(); create_swapchain(width, height); create_draw_image(width, height); + create_msaa_color_image(width, height); create_depth_image(width, height); - update_draw_image_descriptor(); } auto VulkanRenderer::destroy_swapchain() -> void @@ -1351,13 +1452,14 @@ auto VulkanRenderer::destroy_swapchain() -> void } 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; new_image.format = format; 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) { img_ci.mipLevels = static_cast(std::floor( std::log2(std::max(size.width, size.height)))) @@ -1418,7 +1520,7 @@ auto VulkanRenderer::create_image(void const *data, vk::Extent3D size, create_image(size, format, flags | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc, - mipmapped), + vk::SampleCountFlagBits::e1, mipmapped), }; immediate_submit([&](vk::CommandBuffer cmd) { diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index 58c0a9b..9e31cba 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -13,7 +13,6 @@ #include "Colors.h" #include "DeletionQueue.h" -#include "DescriptorAllocator.h" #include "Loader.h" #include "Logger.h" #include "Pipeline.h" @@ -29,6 +28,13 @@ struct GPUDrawPushConstants { constexpr unsigned FRAME_OVERLAP = 2; struct VulkanRenderer { + enum class AntiAliasingKind { + NONE, + MSAA_2X, + MSAA_4X, + MSAA_8X, + }; + struct GL { enum class GeometryKind { Triangles, @@ -105,6 +111,11 @@ struct VulkanRenderer { auto render(std::function const &record = {}) -> 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 &&function, bool flush_frame_deletion_queue = true, @@ -151,26 +162,27 @@ private: auto sync_init() -> void; auto descriptors_init() -> void; auto pipelines_init() -> void; - auto background_pipelines_init() -> void; auto triangle_pipeline_init() -> void; auto mesh_pipeline_init() -> void; auto imgui_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) -> void; auto create_swapchain(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 create_depth_image(uint32_t width, uint32_t height) -> void; auto destroy_depth_image() -> void; + auto destroy_msaa_color_image() -> void; auto recreate_swapchain(uint32_t width, uint32_t height) -> void; auto destroy_swapchain() -> void; 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, vk::ImageUsageFlags flags, bool mipmapped = false) -> AllocatedImage; auto destroy_image(AllocatedImage const &img) -> void; @@ -210,21 +222,23 @@ private: std::array frames; 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 {}; + vk::ImageLayout depth_image_layout { vk::ImageLayout::eUndefined }; vk::Extent2D draw_extent {}; + AntiAliasingKind antialiasing_kind { AntiAliasingKind::NONE }; + vk::SampleCountFlagBits msaa_samples { vk::SampleCountFlagBits::e1 }; + vk::SampleCountFlags supported_framebuffer_samples {}; VmaAllocator allocator; - DescriptorAllocator descriptor_allocator; - - VkDescriptorSet draw_image_descriptors {}; - vk::DescriptorSetLayout draw_image_descriptor_layout {}; GPUSceneData scene_data {}; vk::DescriptorSetLayout gpu_scene_data_descriptor_layout {}; vk::DescriptorSetLayout single_image_descriptor_layout {}; - Pipeline gradient_pipeline; Pipeline triangle_pipeline; Pipeline mesh_pipeline;