From aa96b41cdd96573c8b687b6fd3187bcda3c2b445 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Tue, 16 Jul 2024 04:47:54 +0200 Subject: [PATCH] [WIP] Work in progress --- .../render-graph/graphics_pass.hpp | 19 +++-- .../render-graph/graphics_pass_builder.hpp | 66 +++++------------ .../vulkan-renderer/render-graph/image.hpp | 4 +- .../render-graph/render_graph.hpp | 7 +- .../vulkan-renderer/render-graph/texture.hpp | 20 +++-- src/vulkan-renderer/application.cpp | 4 +- .../render-graph/graphics_pass_builder.cpp | 48 +++++++++++- src/vulkan-renderer/render-graph/image.cpp | 20 +++-- .../render-graph/render_graph.cpp | 17 ++--- src/vulkan-renderer/render-graph/texture.cpp | 73 ++++++++++++++++++- src/vulkan-renderer/renderers/imgui.cpp | 10 +-- 11 files changed, 191 insertions(+), 97 deletions(-) diff --git a/include/inexor/vulkan-renderer/render-graph/graphics_pass.hpp b/include/inexor/vulkan-renderer/render-graph/graphics_pass.hpp index 08552d4aa..c9e65ed00 100644 --- a/include/inexor/vulkan-renderer/render-graph/graphics_pass.hpp +++ b/include/inexor/vulkan-renderer/render-graph/graphics_pass.hpp @@ -24,7 +24,7 @@ class RenderGraph; // Using declaration using wrapper::descriptors::DescriptorSetLayout; -// This will make our life easier +/// An attachment is just a texture paired with an optional clear value using Attachment = std::pair, std::optional>; /// A wrapper for graphics passes inside of rendergraph @@ -40,8 +40,11 @@ class GraphicsPass { /// NOTE: We do not have members like m_has_depth_buffer or m_has_stencil_buffer because we can simply check if the /// std::weak_ptr of the Attachment is expire() instead! + /// The color attachments of the graphics pass std::vector m_color_attachments{}; + /// The depth attachment of the graphics pass Attachment m_depth_attachment{}; + /// The stencil attachment of the graphics pass Attachment m_stencil_attachment{}; /// The descriptor set layout of the pass (this will be created by rendergraph) @@ -58,21 +61,23 @@ class GraphicsPass { /// The color attachments inside of m_rendering_info std::vector m_color_attachment_infos{}; + /// The depth attachment inside of m_rendering_info VkRenderingAttachmentInfo m_depth_attachment_info{}; + /// The stencil attachment inside of m_rendering_info VkRenderingAttachmentInfo m_stencil_attachment_info{}; public: /// Default constructor /// @param name The name of the graphics pass /// @param on_record_cmd_buffer The command buffer recording function of the graphics pass - /// @param m_color_attachment - /// @param m_depth_attachment The depth attachment of the graphics pass - /// @param m_stencil_attachment + /// @param color_attachments The color attachments of the graphics pass + /// @param depth_attachment The depth attachment of the graphics pass + /// @param stencil_attachment The stencil attachment of the graphics pass GraphicsPass(std::string name, std::function on_record_cmd_buffer, - std::vector m_color_attachments, - Attachment m_depth_attachment, - Attachment m_stencil_attachment); + std::vector color_attachments, + Attachment depth_attachment, + Attachment stencil_attachment); GraphicsPass(const GraphicsPass &) = delete; GraphicsPass(GraphicsPass &&other) noexcept; diff --git a/include/inexor/vulkan-renderer/render-graph/graphics_pass_builder.hpp b/include/inexor/vulkan-renderer/render-graph/graphics_pass_builder.hpp index ffe86c18c..2d68475e3 100644 --- a/include/inexor/vulkan-renderer/render-graph/graphics_pass_builder.hpp +++ b/include/inexor/vulkan-renderer/render-graph/graphics_pass_builder.hpp @@ -24,13 +24,13 @@ using wrapper::commands::CommandBuffer; class GraphicsPassBuilder { private: /// Add members which describe data related to graphics passes here - std::function m_on_record_cmd_buffer; + std::function m_on_record_cmd_buffer{}; /// The color attachments of the graphics pass - std::vector m_color_attachments; + std::vector m_color_attachments{}; /// The depth attachment of the graphics pass - Attachment m_depth_attachment; + Attachment m_depth_attachment{}; /// The stencil attachment of the graphics pass - Attachment m_stencil_attachment; + Attachment m_stencil_attachment{}; /// Reset all data of the graphics pass builder void reset(); @@ -42,64 +42,38 @@ class GraphicsPassBuilder { ~GraphicsPassBuilder() = default; GraphicsPassBuilder &operator=(const GraphicsPassBuilder &) = delete; - GraphicsPassBuilder &operator=(GraphicsPassBuilder &&) noexcept; + GraphicsPassBuilder &operator=(GraphicsPassBuilder &&) = delete; /// Add a color attachment to the pass /// @param color_attachment The color attachment - /// @param clear_color The clear color for the color attachment (``std::nullopt`` by default) + /// @param clear_value The clear value for the color attachment (``std::nullopt`` by default) /// @return A const reference to the this pointer (allowing method calls to be chained) - [[nodiscard]] auto &add_color_attachment(std::weak_ptr color_attachment, - std::optional clear_color = std::nullopt) { - if (color_attachment.expired()) { - throw std::invalid_argument( - "[GraphicsPassBuilder::add_color_attachment] Error: 'color_attachment' is expired!"); - } - m_color_attachments.emplace_back(std::move(color_attachment), clear_color); - return *this; - } + [[nodiscard]] GraphicsPassBuilder &add_color_attachment(std::weak_ptr color_attachment, + std::optional clear_value = std::nullopt); + + /// Enable depth testing for the pass + /// @param depth_attachment The depth attachment + /// @param clear_value The clear value for the depth attachment (``std::nullopt`` by default) + /// @return A const reference to the this pointer (allowing method calls to be chained) + [[nodiscard]] GraphicsPassBuilder &add_depth_attachment(std::weak_ptr depth_attachment, + std::optional clear_value = std::nullopt); /// Add a stencil attachment to the pass /// @param stencil_attachment The stencil attachment - /// @param clear_color The clear color value for the stencil attachment (``std::nullopt`` by default) + /// @param clear_value The clear value for the stencil attachment (``std::nullopt`` by default) /// @return A const reference to the this pointer (allowing method calls to be chained) - [[nodiscard]] auto &add_stencil_attachment(std::weak_ptr stencil_attachment, - std::optional clear_color = std::nullopt) { - if (stencil_attachment.expired()) { - throw std::invalid_argument( - "[GraphicsPassBuilder::add_stencil_attachment] Error: 'stencil_attachment' is expired!"); - } - return *this; - } + [[nodiscard]] GraphicsPassBuilder &add_stencil_attachment(std::weak_ptr stencil_attachment, + std::optional clear_value = std::nullopt); /// Build the graphics pass /// @param name The name of the graphics pass /// @return The graphics pass that was just created - [[nodiscard]] auto build(std::string name) { - auto graphics_pass = - GraphicsPass(std::move(name), std::move(m_on_record_cmd_buffer), std::move(m_color_attachments), - std::move(m_depth_attachment), std::move(m_stencil_attachment)); - reset(); - return graphics_pass; - } - - /// Enable depth testing for the pass - /// @param depth_buffer - /// @return A const reference to the this pointer (allowing method calls to be chained) - [[nodiscard]] auto &enable_depth_test(std::weak_ptr depth_attachment) { - if (depth_attachment.expired()) { - throw std::invalid_argument("[GraphicsPassBuilder::enable_depth_test] Error: 'depth_buffer' is expired!"); - } - m_depth_attachment = Attachment(std::move(depth_attachment), std::nullopt); - return *this; - } + [[nodiscard]] GraphicsPass build(std::string name); /// Set the function which will be called when the command buffer for rendering of the pass is being recorded /// @param on_record_cmd_buffer The command buffer recording function /// @return A const reference to the this pointer (allowing method calls to be chained) - [[nodiscard]] auto &set_on_record(std::function on_record_cmd_buffer) { - on_record_cmd_buffer = std::move(on_record_cmd_buffer); - return *this; - } + [[nodiscard]] GraphicsPassBuilder &set_on_record(std::function on_record_cmd_buffer); }; } // namespace inexor::vulkan_renderer::render_graph diff --git a/include/inexor/vulkan-renderer/render-graph/image.hpp b/include/inexor/vulkan-renderer/render-graph/image.hpp index f70202490..0790e4a0a 100644 --- a/include/inexor/vulkan-renderer/render-graph/image.hpp +++ b/include/inexor/vulkan-renderer/render-graph/image.hpp @@ -44,8 +44,6 @@ class Image { VmaAllocation m_alloc{VK_NULL_HANDLE}; VmaAllocationInfo m_alloc_info{}; VmaAllocationCreateInfo m_alloc_ci{}; - VkImageCreateInfo m_img_ci{}; - VkImageViewCreateInfo m_img_view_ci{}; /// The combined image sampler for the texture /// This is only relevant if the texture is used as TextureUsage::NORMAL @@ -68,7 +66,7 @@ class Image { ~Image(); Image &operator=(const Image &other) = delete; - Image &operator=(Image &&other) noexcept; + Image &operator=(Image &&other) = delete; }; } // namespace inexor::vulkan_renderer::render_graph diff --git a/include/inexor/vulkan-renderer/render-graph/render_graph.hpp b/include/inexor/vulkan-renderer/render-graph/render_graph.hpp index be2c78076..944dc887f 100644 --- a/include/inexor/vulkan-renderer/render-graph/render_graph.hpp +++ b/include/inexor/vulkan-renderer/render-graph/render_graph.hpp @@ -181,6 +181,7 @@ class RenderGraph { DescriptorSetAllocator m_descriptor_set_allocator; /// The descriptor set update builder (a builder pattern for descriptor set updates) DescriptorSetUpdateBuilder m_descriptor_set_update_builder; + /// A user-defined function which creates the descriptor set layout using OnBuildDescriptorSetLayout = std::function; /// A user-defined function which allocates a descriptor set @@ -273,12 +274,6 @@ class RenderGraph { /// @note Move semantics is used to std::move on_pass_create void add_graphics_pass(OnCreateGraphicsPass on_pass_create); - // TODO: One thread_local GraphicsPipelineBuilder? Once graphics pipelines will be created in parallel! - - // TODO: The only reason we would need graphics pipelines create functions would be if during creation it would - // reference resources which would need to be set up by rendergraph before! DESCRIPTOR SET LAYOUT!!!!!! - // DESCRIPTOR SET LAYOUT!!!!!!!! - /// Add a new graphics pipeline to the rendergraph /// @param on_pipeline_create A function to create the graphics pipeline using GraphicsPipelineBuilder /// @note Move semantics is used to std::move on_pipeline_create diff --git a/include/inexor/vulkan-renderer/render-graph/texture.hpp b/include/inexor/vulkan-renderer/render-graph/texture.hpp index 2978008af..d21988d0d 100644 --- a/include/inexor/vulkan-renderer/render-graph/texture.hpp +++ b/include/inexor/vulkan-renderer/render-graph/texture.hpp @@ -49,11 +49,19 @@ class Texture { /// The name of the texture std::string m_name; /// The usage of this texture - TextureUsage m_texture_usage; + TextureUsage m_usage; /// The format of the texture VkFormat m_format{VK_FORMAT_UNDEFINED}; + /// The width of the texture + std::uint32_t m_width{0}; + /// The height of the texture + std::uint32_t m_height{0}; + /// The image of the texture std::unique_ptr m_img; + + /// The sample count of the MSAA image (if MSAA is enabled) + VkSampleCountFlagBits m_sample_count; /// This is only used internally inside of rendergraph in case this texture used as a back buffer, depth buffer, or /// stencil buffer and MSAA is enabled. std::unique_ptr m_msaa_img; @@ -76,10 +84,10 @@ class Texture { /// The descriptor image info required for descriptor updates VkDescriptorImageInfo m_descriptor_img_info{}; - /// + /// Create the texture (and the MSAA texture if specified) void create(); - /// + /// Destroy the texture (and the MSAA texture if specified) void destroy(); /// Upload the data into the texture @@ -92,12 +100,16 @@ class Texture { /// @param name The internal debug name of the texture /// @param usage The usage of the texture inside of rendergraph /// @param format The format of the texture + /// @param width The width of the texture + /// @param height The height of the texture /// @param on_init The initialization function of the texture /// @param on_update The update function of the texture Texture(const Device &device, std::string name, TextureUsage usage, VkFormat format, + std::uint32_t width, + std::uint32_t height, std::optional> on_init = std::nullopt, std::optional> on_update = std::nullopt); @@ -108,8 +120,6 @@ class Texture { Texture &operator=(const Texture &) = delete; Texture &operator=(Texture &&) noexcept; - // TODO: request_update with other width x height so the texture is recreated?? - /// Request rendergraph to update the texture /// @param src_texture_data A pointer to the source data /// @param src_texture_data_size The size of the source data diff --git a/src/vulkan-renderer/application.cpp b/src/vulkan-renderer/application.cpp index bf20455f1..1e1ed8a8b 100644 --- a/src/vulkan-renderer/application.cpp +++ b/src/vulkan-renderer/application.cpp @@ -536,8 +536,8 @@ void Application::setup_render_graph() { using render_graph::GraphicsPassBuilder; m_render_graph->add_graphics_pass([&](GraphicsPassBuilder &builder) { - return builder.add_color_attachment(m_back_buffer, VkClearColorValue{1.0f, 0.0f, 0.0f, 1.0f}) - .enable_depth_test(m_depth_buffer) + return builder.add_color_attachment(m_back_buffer, VkClearValue{1.0f, 0.0f, 0.0f, 1.0f}) + .add_depth_attachment(m_depth_buffer) .set_on_record(std::move(on_record_cmd_buffer)) .build("Octree"); }); diff --git a/src/vulkan-renderer/render-graph/graphics_pass_builder.cpp b/src/vulkan-renderer/render-graph/graphics_pass_builder.cpp index 35d4b7216..37146ef27 100644 --- a/src/vulkan-renderer/render-graph/graphics_pass_builder.cpp +++ b/src/vulkan-renderer/render-graph/graphics_pass_builder.cpp @@ -6,10 +6,54 @@ GraphicsPassBuilder::GraphicsPassBuilder() { reset(); } +GraphicsPassBuilder &GraphicsPassBuilder::add_color_attachment(std::weak_ptr color_attachment, + std::optional clear_value) { + if (color_attachment.expired()) { + throw std::invalid_argument( + "[GraphicsPassBuilder::add_color_attachment] Error: 'color_attachment' is expired!"); + } + m_color_attachments.emplace_back(std::move(color_attachment), std::move(clear_value)); + return *this; +} + +GraphicsPassBuilder &GraphicsPassBuilder::add_depth_attachment(std::weak_ptr depth_attachment, + std::optional clear_value) { + if (depth_attachment.expired()) { + throw std::invalid_argument("[GraphicsPassBuilder::enable_depth_test] Error: 'depth_buffer' is expired!"); + } + m_depth_attachment = Attachment(std::move(depth_attachment), std::move(clear_value)); + return *this; +} + +GraphicsPassBuilder &GraphicsPassBuilder::add_stencil_attachment(std::weak_ptr stencil_attachment, + std::optional clear_value) { + if (stencil_attachment.expired()) { + throw std::invalid_argument( + "[GraphicsPassBuilder::add_stencil_attachment] Error: 'stencil_attachment' is expired!"); + } + m_stencil_attachment = Attachment(std::move(stencil_attachment), std::move(clear_value)); + return *this; +} + +GraphicsPass GraphicsPassBuilder::build(std::string name) { + auto graphics_pass = + GraphicsPass(std::move(name), std::move(m_on_record_cmd_buffer), std::move(m_color_attachments), + std::move(m_depth_attachment), std::move(m_stencil_attachment)); + reset(); + return graphics_pass; +} + void GraphicsPassBuilder::reset() { - // TODO: Fix me! + m_on_record_cmd_buffer = {}; + m_color_attachments = {}; + m_depth_attachment = {}; + m_stencil_attachment = {}; } -// TODO: Move stuff to .cpp file again. Header files should contain declarations, cpp files should contain definitions! +GraphicsPassBuilder & +GraphicsPassBuilder::set_on_record(std::function on_record_cmd_buffer) { + on_record_cmd_buffer = std::move(on_record_cmd_buffer); + return *this; +} } // namespace inexor::vulkan_renderer::render_graph diff --git a/src/vulkan-renderer/render-graph/image.cpp b/src/vulkan-renderer/render-graph/image.cpp index e2b7f154f..e5e4fcb10 100644 --- a/src/vulkan-renderer/render-graph/image.cpp +++ b/src/vulkan-renderer/render-graph/image.cpp @@ -8,14 +8,15 @@ namespace inexor::vulkan_renderer::render_graph { Image::Image(const Device &device) : m_device(device) {} +Image::Image(Image &&other) noexcept : m_device(other.m_device) { + // TODO: Fix me! +} + Image::~Image() { destroy(); } -void Image::create(const VkImageCreateInfo img_ci, const VkImageViewCreateInfo img_view_ci) { - m_img_ci = img_ci; - m_img_view_ci = img_view_ci; - +void Image::create(const VkImageCreateInfo img_ci, VkImageViewCreateInfo img_view_ci) { // Create the image if (const auto result = vmaCreateImage(m_device.allocator(), &img_ci, &m_alloc_ci, &m_img, &m_alloc, &m_alloc_info); result != VK_SUCCESS) { @@ -25,25 +26,30 @@ void Image::create(const VkImageCreateInfo img_ci, const VkImageViewCreateInfo i m_device.set_debug_name(m_img, m_name); // Set the image in the VkImageViewCreateInfo - m_img_view_ci.image = m_img; + img_view_ci.image = m_img; // Create the image view - if (const auto result = vkCreateImageView(m_device.device(), &m_img_view_ci, nullptr, &m_img_view); + if (const auto result = vkCreateImageView(m_device.device(), &img_view_ci, nullptr, &m_img_view); result != VK_SUCCESS) { throw VulkanException("Error: vkCreateImageView failed for image view " + m_name + "!", result); } m_device.set_debug_name(m_img_view, m_name); - // TODO: Pass VkSamplerCreateInfo as parameter from Image wrapper to the Sampler wrapper // Create a default sampler m_sampler = std::make_unique(m_device, "Default"); } void Image::destroy() { + // Destroy the image view vkDestroyImageView(m_device.device(), m_img_view, nullptr); m_img_view = VK_NULL_HANDLE; + + // Destroy the image vmaDestroyImage(m_device.allocator(), m_img, m_alloc); m_img = VK_NULL_HANDLE; + m_alloc = VK_NULL_HANDLE; + + // Destroy the sampler m_sampler.reset(); m_sampler = nullptr; } diff --git a/src/vulkan-renderer/render-graph/render_graph.cpp b/src/vulkan-renderer/render-graph/render_graph.cpp index 822b0218b..b9e1f0c4a 100644 --- a/src/vulkan-renderer/render-graph/render_graph.cpp +++ b/src/vulkan-renderer/render-graph/render_graph.cpp @@ -30,7 +30,7 @@ RenderGraph::add_buffer(std::string buffer_name, const BufferType buffer_type, s void RenderGraph::allocate_descriptor_sets() { for (const auto &descriptor : m_resource_descriptors) { - // Call on_update_descriptor_set for each descriptor + // Call the on_update_descriptor_set function of each resource descriptor std::invoke(std::get<1>(descriptor), m_descriptor_set_allocator); } } @@ -39,9 +39,8 @@ void RenderGraph::add_resource_descriptor(OnBuildDescriptorSetLayout on_build_de OnAllocateDescriptorSet on_allocate_descriptor_set, OnUpdateDescriptorSet on_update_descriptor_set) { // NOTE: This only stores the functions and they will be called in the correct order during rendergraph compilation - m_resource_descriptors.emplace_back(std::move(on_build_descriptor_set_layout), // to build descriptor set layout - std::move(on_allocate_descriptor_set), // to allocate the descriptor set - std::move(on_update_descriptor_set)); // to update the descriptor set + m_resource_descriptors.emplace_back(std::move(on_build_descriptor_set_layout), + std::move(on_allocate_descriptor_set), std::move(on_update_descriptor_set)); } std::weak_ptr RenderGraph::add_texture(std::string texture_name, @@ -51,7 +50,7 @@ std::weak_ptr RenderGraph::add_texture(std::string texture_name, const std::uint32_t height, std::optional> on_init, std::optional> on_update) { - m_textures.emplace_back(std::make_shared(m_device, std::move(texture_name), usage, format, + m_textures.emplace_back(std::make_shared(m_device, std::move(texture_name), usage, format, width, height, std::move(on_init), std::move(on_update))); return m_textures.back(); } @@ -112,7 +111,7 @@ void RenderGraph::create_rendering_infos() { auto fill_rendering_info = [&](const Attachment &attachment) { const auto attach_ptr = attachment.first.lock(); const auto img_layout = [&]() -> VkImageLayout { - switch (attach_ptr->m_texture_usage) { + switch (attach_ptr->m_usage) { case TextureUsage::BACK_BUFFER: case TextureUsage::DEPTH_STENCIL_BUFFER: { return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -149,7 +148,6 @@ void RenderGraph::create_rendering_infos() { if (has_stencil_attachment) { pass.m_stencil_attachment_info = fill_rendering_info(pass.m_stencil_attachment); } - // We store all this data in the rendering info in the graphics pass itself // The advantage of this is that we don't have to fill this during the actual rendering pass.m_rendering_info = std::move(wrapper::make_info({ @@ -169,7 +167,7 @@ void RenderGraph::create_rendering_infos() { void RenderGraph::create_textures() { m_device.execute("[RenderGraph::create_textures]", [&](const CommandBuffer &cmd_buf) { for (const auto &texture : m_textures) { - switch (texture->m_texture_usage) { + switch (texture->m_usage) { case TextureUsage::NORMAL: { if (texture->m_on_init) { std::invoke(texture->m_on_init.value()); @@ -201,6 +199,7 @@ void RenderGraph::determine_pass_order() { } void RenderGraph::record_command_buffer_for_pass(const CommandBuffer &cmd_buf, const GraphicsPass &pass) { + // TODO: Define default color values for debug labels! // Start a new debug label for this graphics pass (visible in graphics debuggers like RenderDoc) cmd_buf.begin_debug_label_region(pass.m_name, {1.0f, 0.0f, 0.0f, 1.0f}); // Start dynamic rendering with the compiled rendering info @@ -228,6 +227,7 @@ void RenderGraph::record_command_buffers(const CommandBuffer &cmd_buf, const std void RenderGraph::render() { const auto &cmd_buf = m_device.request_command_buffer("[RenderGraph::render]"); + // TODO: Record command buffers for passes in parallel! record_command_buffers(cmd_buf, m_swapchain.acquire_next_image_index()); // TODO: Further abstract this away? @@ -239,7 +239,6 @@ void RenderGraph::render() { .commandBufferCount = 1, .pCommandBuffers = cmd_buf.ptr(), })); - m_swapchain.present(); } diff --git a/src/vulkan-renderer/render-graph/texture.cpp b/src/vulkan-renderer/render-graph/texture.cpp index 6f0eb48e4..18286ba1c 100644 --- a/src/vulkan-renderer/render-graph/texture.cpp +++ b/src/vulkan-renderer/render-graph/texture.cpp @@ -14,23 +14,90 @@ Texture::Texture(const Device &device, std::string name, const TextureUsage usage, const VkFormat format, + const std::uint32_t width, + const std::uint32_t height, std::optional> on_init, std::optional> on_update) - : m_device(device), m_name(std::move(name)), m_texture_usage(usage), m_format(format), + : m_device(device), m_name(std::move(name)), m_usage(usage), m_format(format), m_width(width), m_height(height), m_on_init(std::move(on_init)), m_on_update(std::move(on_update)) { if (m_name.empty()) { throw std::invalid_argument("[Texture::Texture] Error: Parameter 'name' is empty!"); } } +void Texture::create() { + auto img_ci = wrapper::make_info({ + .imageType = VK_IMAGE_TYPE_2D, + .format = m_format, + .extent = + { + .width = m_width, + .height = m_height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = [&]() -> VkImageUsageFlags { + switch (m_usage) { + case TextureUsage::NORMAL: { + return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + case TextureUsage::DEPTH_STENCIL_BUFFER: + case TextureUsage::BACK_BUFFER: { + return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + } + }(), + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }); + + const auto img_view_ci = wrapper::make_info({ + // NOTE: .image will be filled by the Texture wrapper + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = m_format, + .subresourceRange = + { + .aspectMask = [&]() -> VkImageAspectFlags { + switch (m_usage) { + case TextureUsage::NORMAL: { + return VK_IMAGE_ASPECT_COLOR_BIT; + } + case TextureUsage::DEPTH_STENCIL_BUFFER: + case TextureUsage::BACK_BUFFER: { + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + } + }(), + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }); + + // Create the texture + m_img->create(img_ci, img_view_ci); + + // If MSAA is enabled, create the MSAA texture as well + if (m_sample_count != VK_SAMPLE_COUNT_1_BIT) { + // Just overwrite the sample count and re-use the image create info + img_ci.samples = m_sample_count; + m_msaa_img->create(img_ci, img_view_ci); + } +} + void Texture::destroy() { - // TODO: Do we need this here? m_img->destroy(); + if (m_msaa_img) { + m_msaa_img->destroy(); + } } void Texture::update(const CommandBuffer &cmd_buf) { #if 0 - // TODO: Validate parameters again before update! if (m_staging_buffer != VK_NULL_HANDLE) { vmaDestroyBuffer(m_device.allocator(), m_staging_buffer, m_staging_buffer_alloc); m_staging_buffer = VK_NULL_HANDLE; diff --git a/src/vulkan-renderer/renderers/imgui.cpp b/src/vulkan-renderer/renderers/imgui.cpp index adad51b2b..6fd729736 100644 --- a/src/vulkan-renderer/renderers/imgui.cpp +++ b/src/vulkan-renderer/renderers/imgui.cpp @@ -29,10 +29,7 @@ ImGuiRenderer::ImGuiRenderer(const Device &device, spdlog::trace("Setting ImGui style"); set_imgui_style(); - // TODO: Do we need this here? using render_graph::BufferType; - - // TODO: Do we really need vert_input_attr_descs here? m_vertex_buffer = render_graph.add_buffer("ImGui", BufferType::VERTEX_BUFFER, [&]() { m_on_update_user_data(); const ImDrawData *draw_data = ImGui::GetDrawData(); @@ -52,16 +49,15 @@ ImGuiRenderer::ImGuiRenderer(const Device &device, m_vertex_data.push_back(cmd_list->VtxBuffer.Data[j]); // NOLINT } } - // NOTE: The index buffer does not have a separate update code because it is updated here with the vertices + // Request rendergraph to do an update of the vertex buffer m_vertex_buffer.lock()->request_update(m_vertex_data); - m_index_buffer.lock()->request_update(m_index_data); }); m_index_buffer = render_graph.add_buffer("ImGui", BufferType::INDEX_BUFFER, [&]() { - // Index buffer is already being updated in vertex buffer update lambda... + // Request rendergraph to do an update of the index buffer + m_index_buffer.lock()->request_update(m_index_data); }); - // TODO: Implement a ShaderManager (ShaderCache?) inside of Device wrapper? m_vertex_shader = std::make_shared(m_device, "ImGui", VK_SHADER_STAGE_VERTEX_BIT, "shaders/ui.vert.spv"); m_fragment_shader =