From 736c37d2f1d7eb471052c2e5a6a386c1f8586c49 Mon Sep 17 00:00:00 2001 From: light7734 Date: Sun, 26 Oct 2025 16:43:56 +0330 Subject: [PATCH] feat(renderer/vk): dynamic rendering --- .../private/backend/vk/context/device.cpp | 7 + .../private/backend/vk/context/instance.cpp | 7 + .../private/backend/vk/context/swapchain.hpp | 11 ++ .../private/backend/vk/renderer/pass.cpp | 48 +++---- .../private/backend/vk/renderer/pass.hpp | 7 - .../private/backend/vk/renderer/renderer.cpp | 134 +++++++++++++----- .../private/backend/vk/renderer/renderer.hpp | 9 ++ .../renderer/private/backend/vk/vulkan.hpp | 3 + .../private/frontend/renderer/renderer.hpp | 7 + modules/renderer/private/system.cpp | 9 ++ modules/renderer/public/components/sprite.hpp | 77 ++++++++++ 11 files changed, 251 insertions(+), 68 deletions(-) create mode 100644 modules/renderer/public/components/sprite.hpp diff --git a/modules/renderer/private/backend/vk/context/device.cpp b/modules/renderer/private/backend/vk/context/device.cpp index c7ecaae..30d8849 100644 --- a/modules/renderer/private/backend/vk/context/device.cpp +++ b/modules/renderer/private/backend/vk/context/device.cpp @@ -75,10 +75,17 @@ void Device::initialize_logical_device() auto extensions = std::vector { VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, + }; + + const auto dynamic_rendering_features = VkPhysicalDeviceDynamicRenderingFeatures { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + .dynamicRendering = true, }; auto device_info = VkDeviceCreateInfo { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = &dynamic_rendering_features, .queueCreateInfoCount = static_cast(queue_infos.size()), .pQueueCreateInfos = queue_infos.data(), .enabledExtensionCount = static_cast(extensions.size()), diff --git a/modules/renderer/private/backend/vk/context/instance.cpp b/modules/renderer/private/backend/vk/context/instance.cpp index 909550b..29b138a 100644 --- a/modules/renderer/private/backend/vk/context/instance.cpp +++ b/modules/renderer/private/backend/vk/context/instance.cpp @@ -100,12 +100,16 @@ PFN_vkFreeMemory vk_free_memory {}; PFN_vkResetCommandBuffer vk_reset_command_buffer {}; +PFN_vkCmdBeginRendering vk_cmd_begin_rendering {}; +PFN_vkCmdEndRendering vk_cmd_end_rendering {}; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {}; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {}; PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {}; auto vk_create_xlib_surface_khr = PFN_vkCreateXlibSurfaceKHR {}; auto vk_destroy_surface_khr = PFN_vkDestroySurfaceKHR {}; + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) Instance::Instance() @@ -392,6 +396,9 @@ void Instance::load_device_functions_impl(VkDevice device) load_fn(vk_free_memory, "vkFreeMemory"); load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements"); load_fn(vk_reset_command_buffer, "vkResetCommandBuffer"); + + load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering"); + load_fn(vk_cmd_end_rendering, "vkCmdEndRendering"); } auto Instance::enumerate_gpus() const -> std::vector diff --git a/modules/renderer/private/backend/vk/context/swapchain.hpp b/modules/renderer/private/backend/vk/context/swapchain.hpp index 6a0bcd4..ade3cdb 100644 --- a/modules/renderer/private/backend/vk/context/swapchain.hpp +++ b/modules/renderer/private/backend/vk/context/swapchain.hpp @@ -49,6 +49,17 @@ public: return m_images.size(); } + [[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView + { + return m_image_views[idx]; + } + + [[nodiscard]] auto get_image(uint32_t idx) -> VkImage + { + return m_images[idx]; + } + + [[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const -> std::vector; diff --git a/modules/renderer/private/backend/vk/renderer/pass.cpp b/modules/renderer/private/backend/vk/renderer/pass.cpp index 2fa23d1..a994ad5 100644 --- a/modules/renderer/private/backend/vk/renderer/pass.cpp +++ b/modules/renderer/private/backend/vk/renderer/pass.cpp @@ -113,16 +113,16 @@ Pass::Pass( .blendConstants = { 0.0f, 0.0, 0.0, 0.0 }, }; - auto attachment_description = VkAttachmentDescription { - .format = static_cast(swapchain)->get_format(), - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - }; + // auto attachment_description = VkAttachmentDescription { + // .format =, + // .samples = VK_SAMPLE_COUNT_1_BIT, + // .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + // .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + // .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + // .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + // .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + // .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + // }; auto color_attachment_ref = VkAttachmentReference { .attachment = 0, @@ -144,21 +144,18 @@ Pass::Pass( .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, }; - m_pass = m_device->create_pass( - VkRenderPassCreateInfo { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 1u, - .pAttachments = &attachment_description, - .subpassCount = 1u, - .pSubpasses = &subpass_description, - .dependencyCount = 1u, - .pDependencies = &pass_dependency, - } - ); + auto color_format = static_cast(swapchain)->get_format(); + auto rendering_info = VkPipelineRenderingCreateInfoKHR { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .colorAttachmentCount = 1u, + .pColorAttachmentFormats = &color_format, + + }; m_pipeline = m_device->create_graphics_pipeline( VkGraphicsPipelineCreateInfo { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &rendering_info, .stageCount = static_cast(shader_stages.size()), .pStages = shader_stages.data(), .pVertexInputState = &vertex_input, @@ -170,14 +167,14 @@ Pass::Pass( .pColorBlendState = &color_blend, .pDynamicState = &dynamic_state, .layout = m_layout, - .renderPass = m_pass, + .renderPass = VK_NULL_HANDLE, .subpass = 0u, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = -1, } ); - m_framebuffers = static_cast(swapchain)->create_framebuffers_for_pass(m_pass); + // m_framebuffers = static_cast(swapchain)->create_framebuffers_for_pass(m_pass); m_device->destroy_shader_module(vertex_module); m_device->destroy_shader_module(fragment_module); @@ -193,7 +190,7 @@ Pass::~Pass() m_device->wait_idle(); m_device->destroy_framebuffers(m_framebuffers); m_device->destroy_pipeline(m_pipeline); - m_device->destroy_pass(m_pass); + // m_device->destroy_pass(m_pass); m_device->destroy_pipeline_layout(m_layout); } @@ -206,7 +203,8 @@ void Pass::replace_swapchain(const ISwapchain &swapchain) m_device->wait_idle(); m_device->destroy_framebuffers(m_framebuffers); - m_framebuffers = static_cast(swapchain).create_framebuffers_for_pass(m_pass); + // m_framebuffers = static_cast(swapchain).create_framebuffers_for_pass(m_pass); } auto Pass::create_module(lt::assets::Blob blob) -> VkShaderModule diff --git a/modules/renderer/private/backend/vk/renderer/pass.hpp b/modules/renderer/private/backend/vk/renderer/pass.hpp index 7d1d017..e41a665 100644 --- a/modules/renderer/private/backend/vk/renderer/pass.hpp +++ b/modules/renderer/private/backend/vk/renderer/pass.hpp @@ -29,11 +29,6 @@ public: void replace_swapchain(const ISwapchain &swapchain); - [[nodiscard]] auto get_pass() -> VkRenderPass - { - return m_pass; - } - [[nodiscard]] auto get_pipeline() -> VkPipeline { return m_pipeline; @@ -54,8 +49,6 @@ private: memory::NullOnMove m_device {}; - VkRenderPass m_pass = VK_NULL_HANDLE; - VkPipeline m_pipeline = VK_NULL_HANDLE; VkPipelineLayout m_layout = VK_NULL_HANDLE; diff --git a/modules/renderer/private/backend/vk/renderer/renderer.cpp b/modules/renderer/private/backend/vk/renderer/renderer.cpp index b86691d..3684bbb 100644 --- a/modules/renderer/private/backend/vk/renderer/renderer.cpp +++ b/modules/renderer/private/backend/vk/renderer/renderer.cpp @@ -143,12 +143,79 @@ void Renderer::replace_swapchain(ISwapchain *swapchain) void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx) { - auto cmd_begin_info = VkCommandBufferBeginInfo { + const auto cmd_begin_info = VkCommandBufferBeginInfo { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = {}, .pInheritanceInfo = nullptr, }; + const auto begin_frame_barrier = VkImageMemoryBarrier { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = {}, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .image = m_swapchain->get_image(image_idx), + .subresourceRange = VkImageSubresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0u, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0u, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + + }; + + const auto end_frame_barrier = VkImageMemoryBarrier { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = {}, + .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .image = m_swapchain->get_image(image_idx), + + .subresourceRange = VkImageSubresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0u, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0u, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + + const auto scissor = VkRect2D { + .offset = { .x = 0u, .y = 0u }, + .extent = m_resolution, + }; + + const auto viewport = VkViewport { + .x = 0.0f, + .y = 0.0f, + .width = static_cast(m_resolution.width), + .height = static_cast(m_resolution.height), + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + + const auto color_attachment_info = VkRenderingAttachmentInfoKHR { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = m_swapchain->get_image_view(image_idx), + .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .resolveMode = VK_RESOLVE_MODE_NONE, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .clearValue = VkClearValue { .color = { 0.93, 0.93, 0.93, 1.0 } }, + }; + + const auto rendering_info = VkRenderingInfoKHR { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR, + .renderArea = scissor, + .layerCount = 1, + .colorAttachmentCount = 1, + .pColorAttachments = &color_attachment_info, + + }; + vkc(vk_begin_command_buffer(cmd, &cmd_begin_info)); vk_cmd_push_constants( cmd, @@ -158,46 +225,41 @@ void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx) sizeof(FrameConstants), &m_frame_constants ); - - auto clear_value = VkClearValue { - .color = { - 0.93, - 0.93, - 0.93, - 1.0, - }, - }; - - auto pass_begin_info = VkRenderPassBeginInfo { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = m_pass->get_pass(), - .framebuffer = m_pass->get_framebuffers()[image_idx], - .renderArea = { .offset = {}, .extent = m_resolution }, - .clearValueCount = 1u, - .pClearValues = &clear_value - }; - vk_cmd_begin_render_pass(cmd, &pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); + vk_cmd_pipeline_barrier( + cmd, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + 0, + 0, + nullptr, + 0, + nullptr, + 1, + &begin_frame_barrier + ); + vk_cmd_begin_rendering(cmd, &rendering_info); vk_cmd_bind_pipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pass->get_pipeline()); - - auto viewport = VkViewport { - .x = 0.0f, - .y = 0.0f, - .width = static_cast(m_resolution.width), - .height = static_cast(m_resolution.height), - .minDepth = 0.0f, - .maxDepth = 1.0f, - }; vk_cmd_set_viewport(cmd, 0, 1, &viewport); - - auto scissor = VkRect2D { - .offset = { .x = 0u, .y = 0u }, - .extent = m_resolution, - }; vk_cmd_set_scissors(cmd, 0, 1, &scissor); - vk_cmd_draw(cmd, 3, 1, 0, 0); - vk_cmd_end_render_pass(cmd); + vk_cmd_end_rendering(cmd); + vk_cmd_pipeline_barrier( + cmd, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, + nullptr, + 0, + nullptr, + 1, + &end_frame_barrier + ); vkc(vk_end_command_buffer(cmd)); } +void submit_sprite(const components::Sprite &sprite, const math::components::Transform &transform) +{ +} + } // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/renderer/renderer.hpp b/modules/renderer/private/backend/vk/renderer/renderer.hpp index 6e0d692..f9e1850 100644 --- a/modules/renderer/private/backend/vk/renderer/renderer.hpp +++ b/modules/renderer/private/backend/vk/renderer/renderer.hpp @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -34,6 +36,13 @@ public: m_frame_constants = constants; } + void submit_sprite( + const components::Sprite &sprite, + const math::components::Transform &transform + ) override + { + } + private: void record_cmd(VkCommandBuffer cmd, uint32_t image_idx); diff --git a/modules/renderer/private/backend/vk/vulkan.hpp b/modules/renderer/private/backend/vk/vulkan.hpp index bf052a3..1636ce5 100644 --- a/modules/renderer/private/backend/vk/vulkan.hpp +++ b/modules/renderer/private/backend/vk/vulkan.hpp @@ -88,6 +88,9 @@ extern PFN_vkUnmapMemory vk_unmap_memory; extern PFN_vkFreeMemory vk_free_memory; extern PFN_vkResetCommandBuffer vk_reset_command_buffer; + +extern PFN_vkCmdBeginRendering vk_cmd_begin_rendering; +extern PFN_vkCmdEndRendering vk_cmd_end_rendering; // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) } // namespace lt::renderer::vk diff --git a/modules/renderer/private/frontend/renderer/renderer.hpp b/modules/renderer/private/frontend/renderer/renderer.hpp index aeaa6e6..24316c2 100644 --- a/modules/renderer/private/frontend/renderer/renderer.hpp +++ b/modules/renderer/private/frontend/renderer/renderer.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include namespace lt::renderer { @@ -44,6 +46,11 @@ public: virtual void replace_swapchain(class ISwapchain *swapchain) = 0; virtual void set_frame_constants(FrameConstants constants) = 0; + + virtual void submit_sprite( + const components::Sprite &sprite, + const math::components::Transform &transform + ) = 0; }; } // namespace lt::renderer diff --git a/modules/renderer/private/system.cpp b/modules/renderer/private/system.cpp index 1786396..99405f5 100644 --- a/modules/renderer/private/system.cpp +++ b/modules/renderer/private/system.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -88,6 +90,13 @@ void System::tick(app::TickInfo tick) } } + // for each sprite, submit a new "model matrix" + "color" to go into the scene's SSBO + for (auto &[id, sprite, transform] : + m_registry->view()) + { + m_renderer->submit_sprite(sprite, transform); + } + m_renderer->set_frame_constants({ .view_projection = perspective }); if (m_renderer->draw(m_frame_idx) != IRenderer::DrawResult::success) { diff --git a/modules/renderer/public/components/sprite.hpp b/modules/renderer/public/components/sprite.hpp new file mode 100644 index 0000000..142f407 --- /dev/null +++ b/modules/renderer/public/components/sprite.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include + +namespace lt::renderer::components { + +enum class VertexFormat : uint8_t +{ + r32_g32_b32_sfloat, + + r32_g32_sfloat, +}; + +enum class VertexInputRate : uint8_t +{ + per_vertex, + + per_instance, +}; + +struct VertexInputAttributeDescriptipn +{ + uint32_t location; + + uint32_t binding; + + uint32_t offset; + + VertexFormat format; +}; + +struct VertexInputBindingDescription +{ + uint32_t binding; + + uint32_t stride; +}; + +/** Requires a math::components::Transform component on the same entity to be functional. */ +struct Sprite +{ + struct Vertex + { + math::vec3 position; + + math::vec3 color; + + [[nodiscard]] constexpr static auto get_attributes() + -> std::array + { + return { + VertexInputAttributeDescriptipn { + .location = 0u, + .binding = 0u, + .offset = offsetof(Sprite::Vertex, position), + .format = VertexFormat::r32_g32_b32_sfloat, + + }, + + VertexInputAttributeDescriptipn { + .location = 1u, + .binding = 0u, + .offset = offsetof(Sprite::Vertex, color), + .format = VertexFormat::r32_g32_b32_sfloat, + }, + }; + } + }; + + memory::Ref vertex_shader; + + memory::Ref fragment_shader; +}; + +} // namespace lt::renderer::components