diff --git a/include/inexor/vulkan-renderer/renderers/imgui.hpp b/include/inexor/vulkan-renderer/renderers/imgui.hpp index c5b15869e..98ca13648 100644 --- a/include/inexor/vulkan-renderer/renderers/imgui.hpp +++ b/include/inexor/vulkan-renderer/renderers/imgui.hpp @@ -45,7 +45,7 @@ class ImGuiRenderer { std::weak_ptr m_index_buffer; std::weak_ptr m_vertex_buffer; std::weak_ptr m_imgui_texture; - std::shared_ptr m_imgui_pipeline; + std::shared_ptr m_imgui_pipeline; // This is the color attachment we will write to std::weak_ptr m_swapchain; @@ -87,16 +87,15 @@ class ImGuiRenderer { public: /// Default constructor /// @param device The device wrapper - /// @param swapchain The swapchain to render to /// @param render_graph The rendergraph /// @param previous_pass The previous pass /// @param color_attachment The color attachment + /// @param swapchain The swapchain to render to /// @param on_update_user_data The user-specified ImGui update function ImGuiRenderer(const Device &device, - std::weak_ptr swapchain, std::weak_ptr render_graph, std::weak_ptr previous_pass, - //std::weak_ptr color_attachment, + std::weak_ptr swapchain, std::function on_update_user_data); ImGuiRenderer(const ImGuiRenderer &) = delete; diff --git a/include/inexor/vulkan-renderer/wrapper/commands/command_pool.hpp b/include/inexor/vulkan-renderer/wrapper/commands/command_pool.hpp index 98014a8cc..769365f91 100644 --- a/include/inexor/vulkan-renderer/wrapper/commands/command_pool.hpp +++ b/include/inexor/vulkan-renderer/wrapper/commands/command_pool.hpp @@ -5,8 +5,6 @@ #include "inexor/vulkan-renderer/wrapper/commands/command_buffer.hpp" -#include - namespace inexor::vulkan_renderer::wrapper { // Forward declaration class Device; @@ -22,6 +20,7 @@ class CommandPool { std::string m_name; const Device &m_device; VkCommandPool m_cmd_pool{VK_NULL_HANDLE}; + VkQueueFlagBits m_queue_type; /// The command buffers which can be requested by the current thread mutable std::vector> m_cmd_bufs; @@ -29,9 +28,9 @@ class CommandPool { public: /// Default constructor /// @param device The device wrapper instance - /// @param queue_family_index The queue family index of the commands pool + /// @param queue_type The queue type /// @param name The internal debug marker name which will be assigned to this command pool - CommandPool(const Device &device, std::uint32_t queue_family_index, std::string name); + CommandPool(const Device &device, VkQueueFlagBits queue_type, std::string name); CommandPool(const CommandPool &) = delete; CommandPool(CommandPool &&) noexcept; @@ -43,7 +42,7 @@ class CommandPool { /// Request a command buffer /// @param name The internal debug name which will be assigned to this command buffer (must not be empty) /// @return A command buffer handle instance which allows access to the requested command buffer - [[nodiscard]] const CommandBuffer &request_command_buffer(const std::string &name) const; + [[nodiscard]] CommandBuffer &request_command_buffer(const std::string &name) const; }; } // namespace inexor::vulkan_renderer::wrapper::commands diff --git a/include/inexor/vulkan-renderer/wrapper/device.hpp b/include/inexor/vulkan-renderer/wrapper/device.hpp index 7aa5c2310..514c38a1e 100644 --- a/include/inexor/vulkan-renderer/wrapper/device.hpp +++ b/include/inexor/vulkan-renderer/wrapper/device.hpp @@ -98,6 +98,8 @@ class Device { /// @param name the internal debug name of the Vulkan object void set_debug_utils_object_name(VkObjectType obj_type, std::uint64_t obj_handle, const std::string &name) const; + // TODO: Maybe we can merge those three functions into one? Use a thread_local std::array? + /// Get the thread_local compute pool for transfer commands /// @note This method will create a command pool for the thread if it doesn't already exist const CommandPool &thread_local_compute_command_pool() const; @@ -245,6 +247,10 @@ class Device { return m_transfer_queue; } + [[nodiscard]] std::uint32_t compute_queue_family_index() const { + return m_compute_queue_family_index; + } + [[nodiscard]] std::uint32_t graphics_queue_family_index() const { return m_graphics_queue_family_index; } @@ -253,14 +259,14 @@ class Device { return m_present_queue_family_index; } - [[nodiscard]] VkPhysicalDeviceProperties physical_device_properties() const noexcept { - return m_properties; - } - [[nodiscard]] std::uint32_t transfer_queue_family_index() const { return m_transfer_queue_family_index; } + [[nodiscard]] VkPhysicalDeviceProperties physical_device_properties() const noexcept { + return m_properties; + } + /// Set the internal debug name of a Vulkan object /// @tparam VulkanObjectType /// @param vk_object diff --git a/src/vulkan-renderer/application.cpp b/src/vulkan-renderer/application.cpp index 14c747b7d..61cdfa3b3 100644 --- a/src/vulkan-renderer/application.cpp +++ b/src/vulkan-renderer/application.cpp @@ -553,9 +553,8 @@ void Application::setup_render_graph() { // TODO: We don't need to recreate the imgui overlay when swapchain is recreated, use a .recreate() method instead? // TODO: Decouple ImGuiRenderer form ImGuiLoader - // m_imgui_overlay = std::make_unique(*m_device, m_swapchain, m_render_graph, - // m_octree_pass, - // [&]() { update_imgui_overlay(); }); + m_imgui_overlay = std::make_unique(*m_device, m_render_graph, m_octree_pass, m_swapchain, + [&]() { update_imgui_overlay(); }); m_render_graph->compile(); } diff --git a/src/vulkan-renderer/render-graph/render_graph.cpp b/src/vulkan-renderer/render-graph/render_graph.cpp index 15bf8069d..17afea2aa 100644 --- a/src/vulkan-renderer/render-graph/render_graph.cpp +++ b/src/vulkan-renderer/render-graph/render_graph.cpp @@ -283,16 +283,17 @@ void RenderGraph::record_command_buffer_for_pass(const CommandBuffer &cmd_buf, G // NOTE: Pipeline barriers must not be placed inside of dynamic rendering instances, which means we must change the // image layout of all swapchains we write to before we call begin_rendering and then again after we call // end_rendering. - // ---------------------------------------------------------------------------------------------------------------- + // Start dynamic rendering with the compiled rendering info cmd_buf.begin_rendering(pass.m_rendering_info); + // Call the command buffer recording function of this graphics pass. In this function, the actual rendering takes // place: the programmer binds pipelines, descriptor sets, buffers, and calls Vulkan commands. Note that rendergraph // does not bind any pipelines, descriptor sets, or buffers automatically! std::invoke(pass.m_on_record_cmd_buffer, cmd_buf); + // End dynamic rendering cmd_buf.end_rendering(); - // ---------------------------------------------------------------------------------------------------------------- // TODO: Only change image layout of swapchain if previous pass did not already do this! diff --git a/src/vulkan-renderer/renderers/imgui.cpp b/src/vulkan-renderer/renderers/imgui.cpp index ccf01a8ba..642fb1c4c 100644 --- a/src/vulkan-renderer/renderers/imgui.cpp +++ b/src/vulkan-renderer/renderers/imgui.cpp @@ -13,10 +13,9 @@ namespace inexor::vulkan_renderer::renderers { ImGuiRenderer::ImGuiRenderer(const Device &device, - std::weak_ptr swapchain, std::weak_ptr render_graph, std::weak_ptr previous_pass, - // std::weak_ptr color_attachment, + std::weak_ptr swapchain, std::function on_update_user_data) : m_on_update_user_data(std::move(on_update_user_data)), m_previous_pass(std::move(previous_pass)), m_swapchain(std::move(swapchain)) /*, m_color_attachment(std::move(color_attachment))*/ { @@ -139,9 +138,8 @@ ImGuiRenderer::ImGuiRenderer(const Device &device, // NOTE: ImGui does not write to depth buffer and it reads from octree pass (previous pass) // NOTE: We directly return the ImGui graphics pass and do not store it in here because it's the last pass (for // now) and there is no reads_from function which would need it. - return builder - .writes_to(m_swapchain) - //.conditionally_reads_from(m_previous_pass, !m_previous_pass.expired()) + return builder.writes_to(m_swapchain) + .conditionally_reads_from(m_previous_pass, !m_previous_pass.expired()) .set_on_record([&](const wrapper::commands::CommandBuffer &cmd_buf) { ImDrawData *draw_data = ImGui::GetDrawData(); if (draw_data == nullptr || draw_data->TotalIdxCount == 0 || draw_data->TotalVtxCount == 0) { diff --git a/src/vulkan-renderer/wrapper/commands/command_pool.cpp b/src/vulkan-renderer/wrapper/commands/command_pool.cpp index f3484f5e8..3d9acf395 100644 --- a/src/vulkan-renderer/wrapper/commands/command_pool.cpp +++ b/src/vulkan-renderer/wrapper/commands/command_pool.cpp @@ -10,16 +10,33 @@ namespace inexor::vulkan_renderer::wrapper::commands { -CommandPool::CommandPool(const Device &device, std::uint32_t queue_family_index, std::string name) - : m_device(device), m_name(std::move(name)) { +CommandPool::CommandPool(const Device &device, const VkQueueFlagBits queue_type, std::string name) + : m_device(device), m_queue_type(queue_type), m_name(std::move(name)) { + + auto get_queue_family_index = [&]() { + switch (queue_type) { + case VK_QUEUE_TRANSFER_BIT: { + return m_device.transfer_queue_family_index(); + } + case VK_QUEUE_COMPUTE_BIT: { + return m_device.compute_queue_family_index(); + } + default: { + // VK_QUEUE_GRAPHICS_BIT and rest + return m_device.graphics_queue_family_index(); + } + } + }; + const auto cmd_pool_ci = make_info({ .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, - .queueFamilyIndex = queue_family_index, + .queueFamilyIndex = get_queue_family_index(), }); // Get the thread id as string for naming the command pool and the command buffers - const std::size_t thread_id = std::hash{}(std::this_thread::get_id()); - spdlog::trace("Creating command pool for thread {}", thread_id); + std::ostringstream thread_id; + thread_id << std::this_thread::get_id(); + spdlog::trace("Creating {} command pool for thread ID {}", vk_tools::as_string(queue_type), thread_id.str()); if (const auto result = vkCreateCommandPool(m_device.device(), &cmd_pool_ci, nullptr, &m_cmd_pool); result != VK_SUCCESS) { @@ -32,13 +49,14 @@ CommandPool::CommandPool(CommandPool &&other) noexcept : m_device(other.m_device m_cmd_pool = std::exchange(other.m_cmd_pool, nullptr); m_name = std::move(other.m_name); m_cmd_bufs = std::move(other.m_cmd_bufs); + m_queue_type = other.m_queue_type; } CommandPool::~CommandPool() { vkDestroyCommandPool(m_device.device(), m_cmd_pool, nullptr); } -const commands::CommandBuffer &CommandPool::request_command_buffer(const std::string &name) const { +CommandBuffer &CommandPool::request_command_buffer(const std::string &name) const { // Try to find a command buffer which is currently not used for (const auto &cmd_buf : m_cmd_bufs) { if (cmd_buf->m_cmd_buf_execution_completed->status() == VK_SUCCESS) { @@ -50,11 +68,11 @@ const commands::CommandBuffer &CommandPool::request_command_buffer(const std::st } } - spdlog::trace("Creating new command buffer #{}", 1 + m_cmd_bufs.size()); + spdlog::trace("Creating {} new command buffer #{}", vk_tools::as_string(m_queue_type), 1 + m_cmd_bufs.size()); // No free command buffer was found so we need to create a new one // Note that there is currently no method for shrinking m_cmd_bufs, but this should not be a problem - m_cmd_bufs.emplace_back(std::make_unique(m_device, m_cmd_pool, name)); + m_cmd_bufs.emplace_back(std::make_unique(m_device, m_cmd_pool, name)); auto &new_cmd_buf = *m_cmd_bufs.back(); new_cmd_buf.begin_command_buffer(); diff --git a/src/vulkan-renderer/wrapper/device.cpp b/src/vulkan-renderer/wrapper/device.cpp index b0c6ca2ef..b29118b8a 100644 --- a/src/vulkan-renderer/wrapper/device.cpp +++ b/src/vulkan-renderer/wrapper/device.cpp @@ -557,7 +557,7 @@ const CommandPool &Device::thread_local_compute_command_pool() const { // NOTE: thread_graphics_pool is implicitly static! thread_local CommandPool *compute_pool = nullptr; // NOLINT if (compute_pool == nullptr) { - auto cmd_pool = std::make_unique(*this, m_compute_queue_family_index, "Compute Command Pool"); + auto cmd_pool = std::make_unique(*this, VK_QUEUE_COMPUTE_BIT, "Compute Command Pool"); std::scoped_lock locker(m_mutex); compute_pool = m_cmd_pools.emplace_back(std::move(cmd_pool)).get(); } @@ -568,7 +568,7 @@ const CommandPool &Device::thread_local_graphics_command_pool() const { // NOTE: thread_graphics_pool is implicitly static! thread_local CommandPool *graphics_pool = nullptr; // NOLINT if (graphics_pool == nullptr) { - auto cmd_pool = std::make_unique(*this, m_graphics_queue_family_index, "Graphics Command Pool"); + auto cmd_pool = std::make_unique(*this, VK_QUEUE_GRAPHICS_BIT, "Graphics Command Pool"); std::scoped_lock locker(m_mutex); graphics_pool = m_cmd_pools.emplace_back(std::move(cmd_pool)).get(); } @@ -579,7 +579,7 @@ const CommandPool &Device::thread_local_transfer_command_pool() const { // NOTE: thread_graphics_pool is implicitly static! thread_local CommandPool *graphics_pool = nullptr; // NOLINT if (graphics_pool == nullptr) { - auto cmd_pool = std::make_unique(*this, m_transfer_queue_family_index, "Transfer Command Pool"); + auto cmd_pool = std::make_unique(*this, VK_QUEUE_TRANSFER_BIT, "Transfer Command Pool"); std::scoped_lock locker(m_mutex); graphics_pool = m_cmd_pools.emplace_back(std::move(cmd_pool)).get(); }