#include #include #include #include #include #include #include "renderive/base/property/Property.hpp" #include "renderive/real_time_data/Real_Time_Data.hpp" #include "renderive/renderable/Renderable.hpp" #include "renderive/scene/Scene.hpp" class Scene_Memory_Resource_Test_Resource : public std::pmr::memory_resource { public: std::size_t allocation_count() const noexcept { return allocation_count_.load(std::memory_order_acquire); } std::size_t deallocation_count() const noexcept { return deallocation_count_.load(std::memory_order_acquire); } private: void* do_allocate(std::size_t bytes, std::size_t alignment) override { allocation_count_.fetch_add(1, std::memory_order_release); return std::pmr::new_delete_resource()->allocate(bytes, alignment); } void do_deallocate(void* pointer, std::size_t bytes, std::size_t alignment) override { deallocation_count_.fetch_add(1, std::memory_order_release); std::pmr::new_delete_resource()->deallocate(pointer, bytes, alignment); } bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; } std::atomic allocation_count_{}; std::atomic deallocation_count_{}; }; struct Scene_Memory_Resource_Test_Renderable : Renderable_Base { explicit Scene_Memory_Resource_Test_Renderable(Scene_Base& scene) : Renderable_Base(scene, {.cache_enabled = false}) {} void build_task_graph(Renderable_Task_Graph& graph) override { auto first = graph.emplace([](const Scene_Render_Context&) {}, "prepare_memory_resource_test"); auto second = graph.emplace([](const Scene_Render_Context&) {}, "render_memory_resource_test"); graph.precede(first, second); } }; struct Scene_Memory_Resource_Test_Product { explicit Scene_Memory_Resource_Test_Product(int value) : value(value) {} int value; }; struct Scene_Memory_Resource_Test_Properties { int value{}; }; struct Scene_Memory_Resource_Test_Property_Product { Scene_Memory_Resource_Test_Property_Product(const Scene_Memory_Resource_Test_Properties& properties, int offset) : value(properties.value + offset) {} int value; }; TEST(scene_memory_resource_test, propagates_thread_safe_scene_memory_domain) { Scene_Memory_Resource_Test_Resource upstream; Scene2D_Context<> scene(upstream); EXPECT_EQ(&scene.upstream_memory_resource(), &upstream); EXPECT_NE(&scene.memory_resource(), &upstream); auto factory_renderable = scene.make_renderable(); auto independent_renderable = std::make_shared(scene); EXPECT_EQ(&factory_renderable->memory_resource(), &scene.memory_resource()); EXPECT_EQ(&independent_renderable->memory_resource(), &scene.memory_resource()); scene.attach_renderable(factory_renderable); scene.attach_renderable(independent_renderable); scene.render(); scene.wait_for_render(); EXPECT_GT(upstream.allocation_count(), 0); } TEST(scene_memory_resource_test, keeps_factory_memory_domain_alive_until_renderable_release) { Scene_Memory_Resource_Test_Resource upstream; std::shared_ptr renderable; { Scene2D_Context<> scene(upstream); renderable = scene.make_renderable(); renderable->task_graph(); } renderable.reset(); EXPECT_GT(upstream.deallocation_count(), 0); } TEST(scene_memory_resource_test, supports_independent_resource_aware_components) { Scene_Memory_Resource_Test_Resource memory_resource; Flow_Refresh_Strategy flow(memory_resource); { auto painter = flow.acquire_painter(); EXPECT_TRUE(painter); } auto renderer = flow.acquire_renderer(); EXPECT_TRUE(renderer); History_Real_Time_Data> history(memory_resource); history.update(1); history.update(2); EXPECT_EQ(history.size(), 2); Property_Builder builder({3}); auto product = builder.build_with_resource(memory_resource, 4); auto unique_product = builder.build_unique_with_resource(memory_resource, 5); EXPECT_EQ(product->value, 7); EXPECT_EQ(unique_product->value, 8); EXPECT_GT(memory_resource.allocation_count(), 0); } TEST(scene_memory_resource_test, keeps_independent_renderable_memory_domain_alive_until_renderable_release) { Scene_Memory_Resource_Test_Resource upstream; std::shared_ptr renderable; { Scene2D_Context<> scene(upstream); renderable = std::make_shared(scene); renderable->task_graph(); } auto& memory_resource = renderable->memory_resource(); void* storage = memory_resource.allocate(32, alignof(std::max_align_t)); memory_resource.deallocate(storage, 32, alignof(std::max_align_t)); renderable.reset(); EXPECT_GT(upstream.deallocation_count(), 0); }