From b8ca9757ded70160f0e22ed6de4e4e951e4b7911 Mon Sep 17 00:00:00 2001 From: Egor Orachev Date: Sun, 29 Oct 2023 14:58:30 +0300 Subject: [PATCH] gh-54: cache gfx framebuffers & cache allocated desc sets for speed --- engine/gfx/gfx_ctx.hpp | 22 ++++++ engine/gfx/threaded/gfx_ctx_wrapper.cpp | 75 +++--------------- engine/gfx/threaded/gfx_ctx_wrapper.hpp | 5 ++ engine/gfx/threaded/gfx_driver_wrapper.cpp | 2 - engine/gfx/vulkan/vk_ctx.cpp | 28 ++++++- engine/gfx/vulkan/vk_ctx.hpp | 5 ++ engine/gfx/vulkan/vk_defs.hpp | 1 + engine/gfx/vulkan/vk_desc_manager.cpp | 37 ++++++--- engine/gfx/vulkan/vk_desc_manager.hpp | 6 +- engine/gfx/vulkan/vk_desc_set.cpp | 5 +- engine/gfx/vulkan/vk_desc_set.hpp | 1 + engine/gfx/vulkan/vk_driver.cpp | 18 ++++- engine/gfx/vulkan/vk_driver.hpp | 8 +- engine/gfx/vulkan/vk_render_pass.cpp | 89 +++++++++++++--------- engine/gfx/vulkan/vk_render_pass.hpp | 45 +++++++++-- engine/render/post_process/pass_bloom.cpp | 86 ++++++++++++--------- engine/render/post_process/pass_bloom.hpp | 2 + engine/scene/scene.cpp | 8 ++ engine/scene/scene.hpp | 1 + engine/scene/scene_manager.cpp | 2 +- template/config/engine.cfg | 2 +- 21 files changed, 279 insertions(+), 169 deletions(-) diff --git a/engine/gfx/gfx_ctx.hpp b/engine/gfx/gfx_ctx.hpp index 68927453d..f3b0c359b 100644 --- a/engine/gfx/gfx_ctx.hpp +++ b/engine/gfx/gfx_ctx.hpp @@ -62,6 +62,8 @@ namespace wmoge { public: virtual ~GfxCtx() = default; + virtual void update_desc_set(const Ref& set, const GfxDescSetResources& resources) = 0; + virtual void update_vert_buffer(const Ref& buffer, int offset, int range, const Ref& data) = 0; virtual void update_index_buffer(const Ref& buffer, int offset, int range, const Ref& data) = 0; virtual void update_uniform_buffer(const Ref& buffer, int offset, int range, const Ref& data) = 0; @@ -101,10 +103,30 @@ namespace wmoge { virtual void begin_frame() = 0; virtual void end_frame() = 0; + virtual void begin_label(const StringId& label) = 0; + virtual void end_label() = 0; + [[nodiscard]] virtual const Mat4x4f& clip_matrix() const = 0; [[nodiscard]] virtual GfxCtxType ctx_type() const = 0; }; + /** + * @class GfxDebugLabel + * @brief Scope for debug laber + */ + struct GfxDebugLabel { + GfxDebugLabel(GfxCtx* ctx, const StringId& label) : ctx(ctx) { ctx->begin_label(label); } + ~GfxDebugLabel() { ctx->end_label(); } + GfxCtx* ctx; + }; + +#ifndef WMOGE_RELEASE + #define WG_GFX_LABEL(ctx, label) \ + GfxDebugLabel __label_guard(ctx, label); +#else + #define WG_GFX_LABEL(ctx, label) +#endif + }// namespace wmoge #endif//WMOGE_GFX_CTX_H diff --git a/engine/gfx/threaded/gfx_ctx_wrapper.cpp b/engine/gfx/threaded/gfx_ctx_wrapper.cpp index 6cb30164a..838ed326c 100644 --- a/engine/gfx/threaded/gfx_ctx_wrapper.cpp +++ b/engine/gfx/threaded/gfx_ctx_wrapper.cpp @@ -44,166 +44,110 @@ namespace wmoge { m_ctx_type = ctx->ctx_type(); } - void GfxCtxWrapper::update_vert_buffer(const Ref& buffer, int offset, int range, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_vert_buffer"); + void GfxCtxWrapper::update_desc_set(const Ref& set, const GfxDescSetResources& resources) { + m_stream->push([=]() { m_ctx->update_desc_set(set, resources); }); + } + void GfxCtxWrapper::update_vert_buffer(const Ref& buffer, int offset, int range, const Ref& data) { m_stream->push([=]() { m_ctx->update_vert_buffer(buffer, offset, range, data); }); } void GfxCtxWrapper::update_index_buffer(const Ref& buffer, int offset, int range, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_index_buffer"); - m_stream->push([=]() { m_ctx->update_index_buffer(buffer, offset, range, data); }); } void GfxCtxWrapper::update_uniform_buffer(const Ref& buffer, int offset, int range, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_uniform_buffer"); - m_stream->push([=]() { m_ctx->update_uniform_buffer(buffer, offset, range, data); }); } void GfxCtxWrapper::update_storage_buffer(const Ref& buffer, int offset, int range, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_storage_buffer"); - m_stream->push([=]() { m_ctx->update_storage_buffer(buffer, offset, range, data); }); } void GfxCtxWrapper::update_texture_2d(const Ref& texture, int mip, Rect2i region, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_texture_2d"); - m_stream->push([=]() { m_ctx->update_texture_2d(texture, mip, region, data); }); } void GfxCtxWrapper::update_texture_2d_array(const Ref& texture, int mip, int slice, Rect2i region, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_texture_2d_array"); - m_stream->push([=]() { m_ctx->update_texture_2d_array(texture, mip, slice, region, data); }); } void GfxCtxWrapper::update_texture_cube(const Ref& texture, int mip, int face, Rect2i region, const Ref& data) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::update_texture_cube"); - m_stream->push([=]() { m_ctx->update_texture_cube(texture, mip, face, region, data); }); } void* GfxCtxWrapper::map_vert_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::map_vert_buffer"); - void* mapped_ptr = nullptr; m_stream->push_and_wait([&]() { mapped_ptr = m_ctx->map_vert_buffer(buffer); }); return mapped_ptr; } void* GfxCtxWrapper::map_index_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::map_index_buffer"); - void* mapped_ptr = nullptr; m_stream->push_and_wait([&]() { mapped_ptr = m_ctx->map_index_buffer(buffer); }); return mapped_ptr; } void* GfxCtxWrapper::map_uniform_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::map_uniform_buffer"); - void* mapped_ptr = nullptr; m_stream->push_and_wait([&]() { mapped_ptr = m_ctx->map_uniform_buffer(buffer); }); return mapped_ptr; } void* GfxCtxWrapper::map_storage_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::map_storage_buffer"); - void* mapped_ptr = nullptr; m_stream->push_and_wait([&]() { mapped_ptr = m_ctx->map_storage_buffer(buffer); }); return mapped_ptr; } void GfxCtxWrapper::unmap_vert_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::unmap_vert_buffer"); - m_stream->push([=]() { m_ctx->unmap_vert_buffer(buffer); }); } void GfxCtxWrapper::unmap_index_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::unmap_index_buffer"); - m_stream->push([=]() { m_ctx->unmap_index_buffer(buffer); }); } void GfxCtxWrapper::unmap_uniform_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::unmap_uniform_buffer"); - m_stream->push([=]() { m_ctx->unmap_uniform_buffer(buffer); }); } void GfxCtxWrapper::unmap_storage_buffer(const Ref& buffer) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::unmap_storage_buffer"); - m_stream->push([=]() { m_ctx->unmap_storage_buffer(buffer); }); } void GfxCtxWrapper::begin_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::begin_render_pass"); - m_stream->push([=]() { m_ctx->begin_render_pass(pass_desc, name); }); } void GfxCtxWrapper::bind_target(const Ref& window) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_target"); - m_stream->push([=]() { m_ctx->bind_target(window); }); } void GfxCtxWrapper::bind_color_target(const Ref& texture, int target, int mip, int slice) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_color_target"); - m_stream->push([=]() { m_ctx->bind_color_target(texture, target, mip, slice); }); } void GfxCtxWrapper::bind_depth_target(const Ref& texture, int mip, int slice) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_depth_target"); - m_stream->push([=]() { m_ctx->bind_depth_target(texture, mip, slice); }); } void GfxCtxWrapper::viewport(const Rect2i& viewport) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::viewport"); - m_stream->push([=]() { m_ctx->viewport(viewport); }); } void GfxCtxWrapper::clear(int target, const Vec4f& color) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::clear"); - m_stream->push([=]() { m_ctx->clear(target, color); }); } void GfxCtxWrapper::clear(float depth, int stencil) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::clear"); - m_stream->push([=]() { m_ctx->clear(depth, stencil); }); } bool GfxCtxWrapper::bind_pipeline(const Ref& pipeline) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_pipeline"); - bool is_bound = false; m_stream->push_and_wait([&]() { is_bound = m_ctx->bind_pipeline(pipeline); }); return is_bound; } void GfxCtxWrapper::bind_vert_buffer(const Ref& buffer, int index, int offset) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_vert_buffer"); - m_stream->push([=]() { m_ctx->bind_vert_buffer(buffer, index, offset); }); } void GfxCtxWrapper::bind_index_buffer(const Ref& buffer, GfxIndexType index_type, int offset) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_index_buffer"); - m_stream->push([=]() { m_ctx->bind_index_buffer(buffer, index_type, offset); }); } void GfxCtxWrapper::bind_desc_set(const Ref& set, int index) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_desc_set"); - m_stream->push([=]() { m_ctx->bind_desc_set(set, index); }); } void GfxCtxWrapper::bind_desc_sets(const ArrayView& sets, int offset) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::bind_desc_sets"); - m_stream->push([=]() { m_ctx->bind_desc_sets(sets, offset); }); } void GfxCtxWrapper::draw(int vertex_count, int base_vertex, int instance_count) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::draw"); - m_stream->push([=]() { m_ctx->draw(vertex_count, base_vertex, instance_count); }); } void GfxCtxWrapper::draw_indexed(int index_count, int base_vertex, int instance_count) { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::draw_indexed"); - m_stream->push([=]() { m_ctx->draw_indexed(index_count, base_vertex, instance_count); }); } void GfxCtxWrapper::end_render_pass() { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::end_render_pass"); - m_stream->push([=]() { m_ctx->end_render_pass(); }); } @@ -219,16 +163,19 @@ namespace wmoge { } void GfxCtxWrapper::begin_frame() { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::begin_frame"); - m_stream->push([=]() { m_ctx->begin_frame(); }); } void GfxCtxWrapper::end_frame() { - WG_AUTO_PROFILE_GFX("GfxCtxWrapper::end_frame"); - m_stream->push([=]() { m_ctx->end_frame(); }); } + void GfxCtxWrapper::begin_label(const StringId& label) { + m_stream->push([=]() { m_ctx->begin_label(label); }); + } + void GfxCtxWrapper::end_label() { + m_stream->push([=]() { m_ctx->end_label(); }); + } + const Mat4x4f& GfxCtxWrapper::clip_matrix() const { return m_clip_matrix; } diff --git a/engine/gfx/threaded/gfx_ctx_wrapper.hpp b/engine/gfx/threaded/gfx_ctx_wrapper.hpp index 19b4b7bb4..40ed061b7 100644 --- a/engine/gfx/threaded/gfx_ctx_wrapper.hpp +++ b/engine/gfx/threaded/gfx_ctx_wrapper.hpp @@ -52,6 +52,8 @@ namespace wmoge { ~GfxCtxWrapper() override = default; + void update_desc_set(const Ref& set, const GfxDescSetResources& resources) override; + void update_vert_buffer(const Ref& buffer, int offset, int range, const Ref& data) override; void update_index_buffer(const Ref& buffer, int offset, int range, const Ref& data) override; void update_uniform_buffer(const Ref& buffer, int offset, int range, const Ref& data) override; @@ -92,6 +94,9 @@ namespace wmoge { void begin_frame() override; void end_frame() override; + void begin_label(const StringId& label) override; + void end_label() override; + [[nodiscard]] const Mat4x4f& clip_matrix() const override; [[nodiscard]] GfxCtxType ctx_type() const override; diff --git a/engine/gfx/threaded/gfx_driver_wrapper.cpp b/engine/gfx/threaded/gfx_driver_wrapper.cpp index bed9e7f88..2091dc91d 100644 --- a/engine/gfx/threaded/gfx_driver_wrapper.cpp +++ b/engine/gfx/threaded/gfx_driver_wrapper.cpp @@ -59,8 +59,6 @@ namespace wmoge { } Ref GfxDriverWrapper::make_vert_format(const GfxVertElements& elements, const StringId& name) { - WG_AUTO_PROFILE_GFX("GfxDriverWrapper::make_vert_format"); - auto cached = m_vert_fmt_cache->get(elements); if (cached.has_value()) { return cached.value(); diff --git a/engine/gfx/vulkan/vk_ctx.cpp b/engine/gfx/vulkan/vk_ctx.cpp index 0c299c058..c605d6fdb 100644 --- a/engine/gfx/vulkan/vk_ctx.cpp +++ b/engine/gfx/vulkan/vk_ctx.cpp @@ -52,6 +52,19 @@ namespace wmoge { WG_LOG_INFO("shutdown vulkan gfx context"); } + void VKCtx::update_desc_set(const Ref& set, const GfxDescSetResources& resources) { + WG_AUTO_PROFILE_VULKAN("VKCtx::update_desc_set"); + + assert(check_thread_valid()); + assert(set); + assert(!m_in_render_pass); + + auto vk_desc_set = dynamic_cast(set.get()); + + vk_desc_set->update(resources); + vk_desc_set->merge(resources); + } + void VKCtx::update_vert_buffer(const Ref& buffer, int offset, int range, const Ref& data) { WG_AUTO_PROFILE_VULKAN("VKCtx::update_vert_buffer"); @@ -372,8 +385,8 @@ namespace wmoge { assert(m_render_pass_started); - WG_VK_END_LABEL(cmd_current()); vkCmdEndRenderPass(cmd_current()); + WG_VK_END_LABEL(cmd_current()); m_render_pass_binder->finish(cmd_current()); m_current_pass.reset(); @@ -414,6 +427,17 @@ namespace wmoge { m_cmd_manager->update(); } + void VKCtx::begin_label(const StringId& label) { + assert(!m_in_render_pass); + + WG_VK_BEGIN_LABEL(cmd_current(), label); + } + void VKCtx::end_label() { + assert(!m_in_render_pass); + + WG_VK_END_LABEL(cmd_current()); + } + const Mat4x4f& VKCtx::clip_matrix() const { return m_clip_matrix; } @@ -467,8 +491,8 @@ namespace wmoge { render_pass_info.clearValueCount = clear_value_count; render_pass_info.pClearValues = clear_values.data(); - vkCmdBeginRenderPass(cmd_current(), &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); WG_VK_BEGIN_LABEL(cmd_current(), m_render_pass_name); + vkCmdBeginRenderPass(cmd_current(), &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport; viewport.x = static_cast(m_viewport.x()); diff --git a/engine/gfx/vulkan/vk_ctx.hpp b/engine/gfx/vulkan/vk_ctx.hpp index 82cf58bab..6cb049553 100644 --- a/engine/gfx/vulkan/vk_ctx.hpp +++ b/engine/gfx/vulkan/vk_ctx.hpp @@ -61,6 +61,8 @@ namespace wmoge { explicit VKCtx(class VKDriver& driver); ~VKCtx() override; + void update_desc_set(const Ref& set, const GfxDescSetResources& resources) override; + void update_vert_buffer(const Ref& buffer, int offset, int range, const Ref& data) override; void update_index_buffer(const Ref& buffer, int offset, int range, const Ref& data) override; void update_uniform_buffer(const Ref& buffer, int offset, int range, const Ref& data) override; @@ -100,6 +102,9 @@ namespace wmoge { void begin_frame() override; void end_frame() override; + void begin_label(const StringId& label) override; + void end_label() override; + [[nodiscard]] const Mat4x4f& clip_matrix() const override; [[nodiscard]] GfxCtxType ctx_type() const override; [[nodiscard]] CallbackStream* cmd_stream() override; diff --git a/engine/gfx/vulkan/vk_defs.hpp b/engine/gfx/vulkan/vk_defs.hpp index 418ef324b..12ad86581 100644 --- a/engine/gfx/vulkan/vk_defs.hpp +++ b/engine/gfx/vulkan/vk_defs.hpp @@ -36,6 +36,7 @@ #endif #endif +#include #include #include #include diff --git a/engine/gfx/vulkan/vk_desc_manager.cpp b/engine/gfx/vulkan/vk_desc_manager.cpp index cd79b37eb..08e8d473c 100644 --- a/engine/gfx/vulkan/vk_desc_manager.cpp +++ b/engine/gfx/vulkan/vk_desc_manager.cpp @@ -59,25 +59,40 @@ namespace wmoge { WG_VK_NAME(m_driver.device(), m_pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL, pool_name.str()); } VKDescManager::~VKDescManager() { + for (auto& bucket : m_buckets) { + vkFreeDescriptorSets(m_driver.device(), m_pool, std::uint32_t(bucket.second.size()), bucket.second.data()); + } + vkDestroyDescriptorPool(m_driver.device(), m_pool, nullptr); } VkDescriptorSet VKDescManager::allocate(const Ref& layout) { - VkDescriptorSetLayout layouts[1] = {layout->layout()}; - VkDescriptorSet sets[1] = {VK_NULL_HANDLE}; + auto& bucket = m_buckets[layout]; + + if (bucket.empty()) { + VkDescriptorSetLayout layouts[1] = {layout->layout()}; + VkDescriptorSet sets[1] = {VK_NULL_HANDLE}; + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = m_pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = layouts; + WG_VK_CHECK(vkAllocateDescriptorSets(m_driver.device(), &alloc_info, sets)); + + bucket.push_back(sets[0]); + } + + assert(!bucket.empty()); - VkDescriptorSetAllocateInfo alloc_info{}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = m_pool; - alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = layouts; - WG_VK_CHECK(vkAllocateDescriptorSets(m_driver.device(), &alloc_info, sets)); + VkDescriptorSet set = bucket.back(); + bucket.pop_back(); - return sets[0]; + return set; } - void VKDescManager::free(VkDescriptorSet set) { - vkFreeDescriptorSets(m_driver.device(), m_pool, 1, &set); + void VKDescManager::free(const Ref& layout, VkDescriptorSet set) { + m_buckets[layout].push_back(set); } }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/vulkan/vk_desc_manager.hpp b/engine/gfx/vulkan/vk_desc_manager.hpp index 4dba6dda3..165871dcb 100644 --- a/engine/gfx/vulkan/vk_desc_manager.hpp +++ b/engine/gfx/vulkan/vk_desc_manager.hpp @@ -29,7 +29,6 @@ #define WMOGE_VK_DESC_MANAGER_HPP #include "core/fast_map.hpp" - #include "gfx/gfx_desc_set.hpp" #include "gfx/vulkan/vk_buffers.hpp" #include "gfx/vulkan/vk_defs.hpp" @@ -64,10 +63,11 @@ namespace wmoge { ~VKDescManager(); VkDescriptorSet allocate(const Ref& layout); - void free(VkDescriptorSet set); + void free(const Ref& layout, VkDescriptorSet set); private: - VkDescriptorPool m_pool = VK_NULL_HANDLE; + fast_map, std::vector> m_buckets; + VkDescriptorPool m_pool = VK_NULL_HANDLE; class VKDriver& m_driver; }; diff --git a/engine/gfx/vulkan/vk_desc_set.cpp b/engine/gfx/vulkan/vk_desc_set.cpp index e97934fac..d92480478 100644 --- a/engine/gfx/vulkan/vk_desc_set.cpp +++ b/engine/gfx/vulkan/vk_desc_set.cpp @@ -75,10 +75,13 @@ namespace wmoge { } VKDescSet::~VKDescSet() { if (m_set) { - m_driver.desc_manager()->free(m_set); + m_driver.desc_manager()->free(m_layout, m_set); m_set = VK_NULL_HANDLE; } } + void VKDescSet::copy(const GfxDescSetResources& resources) { + m_resources = resources; + } void VKDescSet::merge(const GfxDescSetResources& resources) { for (const auto& resource : resources) { auto& point = resource.first; diff --git a/engine/gfx/vulkan/vk_desc_set.hpp b/engine/gfx/vulkan/vk_desc_set.hpp index 89f9d604f..f266ccb64 100644 --- a/engine/gfx/vulkan/vk_desc_set.hpp +++ b/engine/gfx/vulkan/vk_desc_set.hpp @@ -60,6 +60,7 @@ namespace wmoge { VKDescSet(const GfxDescSetResources& resources, const Ref& layout, const StringId& name, class VKDriver& driver); ~VKDescSet() override; + void copy(const GfxDescSetResources& resources); void merge(const GfxDescSetResources& resources); void update(const GfxDescSetResources& resources); diff --git a/engine/gfx/vulkan/vk_driver.cpp b/engine/gfx/vulkan/vk_driver.cpp index 9d400cbb2..a735ebde1 100644 --- a/engine/gfx/vulkan/vk_driver.cpp +++ b/engine/gfx/vulkan/vk_driver.cpp @@ -299,6 +299,17 @@ namespace wmoge { return render_pass; } + Ref VKDriver::make_frame_buffer(const VKFrameBufferDesc& desc, const StringId& name) { + WG_AUTO_PROFILE_VULKAN("VKDriver::make_frame_buffer"); + + auto& frame_buffer = m_frame_buffers[desc]; + if (!frame_buffer) { + frame_buffer = make_ref(desc, name, *this); + WG_LOG_INFO("cache new frame buffer " << name); + } + + return frame_buffer; + } Ref VKDriver::make_dyn_vert_buffer(int chunk_size, const StringId& name) { WG_AUTO_PROFILE_VULKAN("VKDriver::make_dyn_vert_buffer"); @@ -366,9 +377,15 @@ namespace wmoge { m_ctx_async.reset(); flush_release(); + m_frame_buffers.clear(); + flush_release(); + m_render_passes.clear(); flush_release(); + m_desc_manager.reset(); + flush_release(); + m_layouts.clear(); flush_release(); @@ -384,7 +401,6 @@ namespace wmoge { glslang::FinalizeProcess(); - m_desc_manager.reset(); m_mem_manager.reset(); m_queues.reset(); m_driver_worker.reset(); diff --git a/engine/gfx/vulkan/vk_driver.hpp b/engine/gfx/vulkan/vk_driver.hpp index 24a8a971f..2f4436a0f 100644 --- a/engine/gfx/vulkan/vk_driver.hpp +++ b/engine/gfx/vulkan/vk_driver.hpp @@ -77,6 +77,7 @@ namespace wmoge { Ref make_sampler(const GfxSamplerDesc& desc, const StringId& name) override; Ref make_pipeline(const GfxPipelineState& state, const StringId& name) override; Ref make_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) override; + Ref make_frame_buffer(const VKFrameBufferDesc& desc, const StringId& name); Ref make_dyn_vert_buffer(int chunk_size, const StringId& name) override; Ref make_dyn_index_buffer(int chunk_size, const StringId& name) override; Ref make_dyn_uniform_buffer(int chunk_size, const StringId& name) override; @@ -163,9 +164,10 @@ namespace wmoge { Ref m_dyn_index_buffer; Ref m_dyn_uniform_buffer; - fast_map> m_samplers; - fast_map> m_render_passes; - fast_map> m_layouts; + fast_map> m_samplers; + fast_map> m_render_passes; + fast_map> m_frame_buffers; + fast_map> m_layouts; GfxDeviceCaps m_device_caps; StringId m_driver_name = SID("unknown"); diff --git a/engine/gfx/vulkan/vk_render_pass.cpp b/engine/gfx/vulkan/vk_render_pass.cpp index bee8d9af0..97c8149f7 100644 --- a/engine/gfx/vulkan/vk_render_pass.cpp +++ b/engine/gfx/vulkan/vk_render_pass.cpp @@ -26,9 +26,10 @@ /**********************************************************************************/ #include "vk_render_pass.hpp" -#include "vk_driver.hpp" +#include "core/crc32.hpp" #include "debug/profiler.hpp" +#include "gfx/vulkan/vk_driver.hpp" namespace wmoge { @@ -113,9 +114,50 @@ namespace wmoge { } } - VKFramebufferObject::VKFramebufferObject(VkFramebuffer framebuffer, class VKDriver& driver) - : VKResource(driver), - m_framebuffer(framebuffer) { + bool VKFrameBufferDesc::operator==(const VKFrameBufferDesc& other) const { + return std::memcmp(this, &other, sizeof(VKFrameBufferDesc)) == 0; + } + std::size_t VKFrameBufferDesc::hash() const { + return static_cast(Crc32::hash(this, sizeof(VKFrameBufferDesc))); + } + + VKFramebufferObject::VKFramebufferObject(const VKFrameBufferDesc& desc, const StringId& name, class VKDriver& driver) + : VKResource(driver) { + m_desc = desc; + m_name = name; + + VkFramebufferCreateInfo create_info{}; + create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + create_info.renderPass = desc.render_pass->render_pass(); + + std::array views; + int views_count = 0; + + for (int i = 0; i < GfxLimits::MAX_COLOR_TARGETS; i++) { + if (!desc.color_targets[i].texture) { + break; + } + + auto& texture = desc.color_targets[i].texture; + views[views_count++] = texture->has_rt_views() ? texture->rt_view(desc.color_targets[i].slice, desc.color_targets[i].mip) : texture->view(); + } + if (desc.depth_stencil_target.texture) { + auto& texture = desc.depth_stencil_target.texture; + views[views_count++] = texture->rt_view(desc.depth_stencil_target.slice, desc.depth_stencil_target.mip); + } + + Ref ref = desc.depth_stencil_target.texture ? desc.depth_stencil_target.texture : desc.color_targets[0].texture; + m_size[0] = ref->width(); + m_size[1] = ref->height(); + + create_info.attachmentCount = views_count; + create_info.pAttachments = views.data(); + create_info.width = ref->width(); + create_info.height = ref->height(); + create_info.layers = 1; + + WG_VK_CHECK(vkCreateFramebuffer(m_driver.device(), &create_info, nullptr, &m_framebuffer)); + WG_VK_NAME(m_driver.device(), m_framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER, "frame_buff " + m_name.str()); } VKFramebufferObject::~VKFramebufferObject() { WG_AUTO_PROFILE_VULKAN("VKFramebufferObject::~VKFramebufferObject"); @@ -211,41 +253,12 @@ namespace wmoge { void VKRenderPassBinder::prepare_framebuffer() { WG_AUTO_PROFILE_VULKAN("VKRenderPassBinder::prepare_framebuffer"); - VkFramebufferCreateInfo create_info{}; - create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - create_info.renderPass = m_current_render_pass->render_pass(); - - std::array views; - int views_count = 0; - - for (int i = 0; i < GfxLimits::MAX_COLOR_TARGETS; i++) { - if (!m_color_targets[i].texture) { - break; - } - - auto& texture = m_color_targets[i].texture; - views[views_count++] = texture->has_rt_views() ? texture->rt_view(m_color_targets[i].slice, m_color_targets[i].mip) : texture->view(); - } - if (m_depth_stencil_target.texture) { - auto& texture = m_depth_stencil_target.texture; - views[views_count++] = texture->rt_view(m_depth_stencil_target.slice, m_depth_stencil_target.mip); - } - - Ref ref = m_depth_stencil_target.texture ? m_depth_stencil_target.texture : m_color_targets[0].texture; - m_current_size[0] = ref->width(); - m_current_size[1] = ref->height(); - - create_info.attachmentCount = views_count; - create_info.pAttachments = views.data(); - create_info.width = ref->width(); - create_info.height = ref->height(); - create_info.layers = 1; - - VkFramebuffer framebuffer; + m_current_fb_desc.color_targets = m_color_targets; + m_current_fb_desc.depth_stencil_target = m_depth_stencil_target; + m_current_fb_desc.render_pass = m_current_render_pass; - WG_VK_CHECK(vkCreateFramebuffer(m_driver.device(), &create_info, nullptr, &framebuffer)); - WG_VK_NAME(m_driver.device(), framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER, "frame_buff " + m_current_name.str()); - m_current_framebuffer = make_ref(framebuffer, m_driver); + m_current_framebuffer = m_driver.make_frame_buffer(m_current_fb_desc, m_current_name); + m_current_size = m_current_framebuffer->size(); } }// namespace wmoge diff --git a/engine/gfx/vulkan/vk_render_pass.hpp b/engine/gfx/vulkan/vk_render_pass.hpp index b4c114aa1..b32d81038 100644 --- a/engine/gfx/vulkan/vk_render_pass.hpp +++ b/engine/gfx/vulkan/vk_render_pass.hpp @@ -43,17 +43,19 @@ namespace wmoge { /** * @class VKTargetInfo * @brief Info to bind texture as a render target - */ + */ struct VKTargetInfo { Ref texture; int slice = -1; int mip = -1; }; + static_assert(sizeof(VKTargetInfo) == 16, "VKTargetInfo must fit 16 exactly"); + /** * @class VKRenderPass * @brief Vulkan single render pass implementation required for PSO and drawing - */ + */ class VKRenderPass : public VKResource { public: VKRenderPass(const GfxRenderPassDesc& pass_desc, const StringId& name, class VKDriver& driver); @@ -71,25 +73,44 @@ namespace wmoge { int m_color_targets_count = 0; }; + /** + * @class VKFrameBufferDesc + * @brief Frame buffer desc for creation and caching + */ + struct VKFrameBufferDesc { + VKFrameBufferDesc() = default; + bool operator==(const VKFrameBufferDesc& other) const; + std::size_t hash() const; + + std::array color_targets{}; + VKTargetInfo depth_stencil_target{}; + Ref render_pass; + }; + + static_assert(sizeof(VKFrameBufferDesc) == (sizeof(VKTargetInfo) * 9 + sizeof(void*)), "VKFrameBufferDesc must fit exactly"); + /** * @class VKFramebufferObject * @brief Raii wrapper for VkFramebuffer object - */ + */ class VKFramebufferObject : public VKResource { public: - VKFramebufferObject(VkFramebuffer framebuffer, class VKDriver& driver); + VKFramebufferObject(const VKFrameBufferDesc& desc, const StringId& name, class VKDriver& driver); ~VKFramebufferObject() override; + Size2i size() const { return m_size; } VkFramebuffer framebuffer() const { return m_framebuffer; } private: - VkFramebuffer m_framebuffer = VK_NULL_HANDLE; + Size2i m_size; + VKFrameBufferDesc m_desc; + VkFramebuffer m_framebuffer = VK_NULL_HANDLE; }; /** * @class VKRenderPassBinder * @brief Binds color targets to prepare render pass and frame buffer - */ + */ class VKRenderPassBinder { public: explicit VKRenderPassBinder(class VKDriver& driver); @@ -121,6 +142,7 @@ namespace wmoge { Ref m_window; GfxRenderPassDesc m_current_pass_desc{}; + VKFrameBufferDesc m_current_fb_desc{}; Ref m_current_render_pass{}; Ref m_current_framebuffer{}; Size2i m_current_size{}; @@ -131,4 +153,15 @@ namespace wmoge { }// namespace wmoge +namespace std { + + template<> + struct hash { + std::size_t operator()(const wmoge::VKFrameBufferDesc& desc) const { + return desc.hash(); + } + }; + +}// namespace std + #endif//WMOGE_VK_RENDER_PASS_HPP diff --git a/engine/render/post_process/pass_bloom.cpp b/engine/render/post_process/pass_bloom.cpp index 3c700f930..2a12058d8 100644 --- a/engine/render/post_process/pass_bloom.cpp +++ b/engine/render/post_process/pass_bloom.cpp @@ -104,49 +104,28 @@ namespace wmoge { value.sampler = m_sampler; } - // Downsample prefilter pass - { - auto desc_set = get_gfx_driver()->make_desc_set(resources, SID("bloom_downsample_prefilter")); - - get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("PassBloom::execute (downsample + prefilter)")); - { - const int w = textures.bloom_downsample[0]->width(); - const int h = textures.bloom_downsample[0]->height(); - - thread_ctx->bind_color_target(textures.bloom_downsample[0], 0, 0, 0); - thread_ctx->viewport(Rect2i(0, 0, w, h)); - - if (thread_ctx->bind_pipeline(m_pipeline_downsample_prefilter)) { - thread_ctx->bind_desc_set(desc_set, 0); - thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); - thread_ctx->draw(3, 0, 1); - } - } - thread_ctx->end_render_pass(); - }); - } + WG_GFX_LABEL(get_gfx_ctx(), SID("PassBloom::execute")); - // Downsample pass + // Downsample { - for (int i = 1; i < num_bloom_mips; i++) { - { - auto& [bind, value] = resources[ShaderBloom::SOURCE_SLOT]; - value.resource = textures.bloom_downsample[i - 1]; - } + WG_GFX_LABEL(get_gfx_ctx(), SID("downsample")); + + // Downsample prefilter pass + { + WG_AUTO_PROFILE_RENDER("downsample + prefilter"); - auto desc_set = get_gfx_driver()->make_desc_set(resources, SID("bloom_downsample")); + auto desc_set = get_gfx_driver()->make_desc_set(resources); get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("PassBloom::execute (downsample mip=" + StringUtils::from_int(i) + ")")); + thread_ctx->begin_render_pass({}, SID("downsample + prefilter")); { - const int w = textures.bloom_downsample[i]->width(); - const int h = textures.bloom_downsample[i]->height(); + const int w = textures.bloom_downsample[0]->width(); + const int h = textures.bloom_downsample[0]->height(); - thread_ctx->bind_color_target(textures.bloom_downsample[i], 0, 0, 0); + thread_ctx->bind_color_target(textures.bloom_downsample[0], 0, 0, 0); thread_ctx->viewport(Rect2i(0, 0, w, h)); - if (thread_ctx->bind_pipeline(m_pipeline_downsample)) { + if (thread_ctx->bind_pipeline(m_pipeline_downsample_prefilter)) { thread_ctx->bind_desc_set(desc_set, 0); thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); thread_ctx->draw(3, 0, 1); @@ -155,10 +134,45 @@ namespace wmoge { thread_ctx->end_render_pass(); }); } + + // Downsample pass + { + WG_AUTO_PROFILE_RENDER("downsample"); + + for (int i = 1; i < num_bloom_mips; i++) { + { + auto& [bind, value] = resources[ShaderBloom::SOURCE_SLOT]; + value.resource = textures.bloom_downsample[i - 1]; + } + + auto desc_set = get_gfx_driver()->make_desc_set(resources); + + get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { + thread_ctx->begin_render_pass({}, SID("downsample mip=" + StringUtils::from_int(i))); + { + const int w = textures.bloom_downsample[i]->width(); + const int h = textures.bloom_downsample[i]->height(); + + thread_ctx->bind_color_target(textures.bloom_downsample[i], 0, 0, 0); + thread_ctx->viewport(Rect2i(0, 0, w, h)); + + if (thread_ctx->bind_pipeline(m_pipeline_downsample)) { + thread_ctx->bind_desc_set(desc_set, 0); + thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); + thread_ctx->draw(3, 0, 1); + } + } + thread_ctx->end_render_pass(); + }); + } + } } // Upsample pass { + WG_GFX_LABEL(get_gfx_ctx(), SID("upsample")); + WG_AUTO_PROFILE_RENDER("upsample"); + Ref source_prev = textures.bloom_downsample.back(); for (int i = num_bloom_mips - 2; i >= 0; i--) { @@ -171,10 +185,10 @@ namespace wmoge { value.resource = source_prev; } - auto desc_set = get_gfx_driver()->make_desc_set(resources, SID("bloom_upsample")); + auto desc_set = get_gfx_driver()->make_desc_set(resources); get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("PassBloom::execute (upsample mip=" + StringUtils::from_int(i) + ")")); + thread_ctx->begin_render_pass({}, SID("upsample mip=" + StringUtils::from_int(i))); { const int w = textures.bloom_upsample[i]->width(); const int h = textures.bloom_upsample[i]->height(); diff --git a/engine/render/post_process/pass_bloom.hpp b/engine/render/post_process/pass_bloom.hpp index 6ef8b54a8..1e693f11d 100644 --- a/engine/render/post_process/pass_bloom.hpp +++ b/engine/render/post_process/pass_bloom.hpp @@ -35,6 +35,8 @@ #include "render/graphics_pipeline.hpp" #include "render/render_engine.hpp" +#include + namespace wmoge { /** diff --git a/engine/scene/scene.cpp b/engine/scene/scene.cpp index 58794528a..23f9f9e62 100644 --- a/engine/scene/scene.cpp +++ b/engine/scene/scene.cpp @@ -136,6 +136,14 @@ namespace wmoge { void Scene::set_state(SceneState state) { m_state = state; } + void Scene::finalize() { + m_ecs_world.reset(); + m_transforms.reset(); + m_cameras.reset(); + m_visibility_system.reset(); + m_render_scene.reset(); + m_graphics_pipeline.reset(); + } const StringId& Scene::get_name() { return m_name; } diff --git a/engine/scene/scene.hpp b/engine/scene/scene.hpp index ff0009381..8f94cfd7e 100644 --- a/engine/scene/scene.hpp +++ b/engine/scene/scene.hpp @@ -176,6 +176,7 @@ namespace wmoge { void advance(float delta_time); void clear(); void set_state(SceneState state); + void finalize(); [[nodiscard]] const StringId& get_name(); [[nodiscard]] EcsWorld* get_ecs_world(); diff --git a/engine/scene/scene_manager.cpp b/engine/scene/scene_manager.cpp index d2fcf1d2b..2d8628c4e 100644 --- a/engine/scene/scene_manager.cpp +++ b/engine/scene/scene_manager.cpp @@ -64,7 +64,7 @@ namespace wmoge { void SceneManager::clear() { for (auto& scene : m_scenes) { - scene->clear(); + scene->finalize(); } m_scenes.clear(); diff --git a/template/config/engine.cfg b/template/config/engine.cfg index bd0dd270a..37addc9e6 100644 --- a/template/config/engine.cfg +++ b/template/config/engine.cfg @@ -49,7 +49,7 @@ chunk_size = 16 expand_size = 2 [debug] -profiler = false +profiler = true [debug.console] font = "res://fonts/anonymous_pro"