添加外部内存数据源

This commit is contained in:
2026-08-04 18:14:38 +08:00
parent f1b9cadd47
commit 44aa60f816
23 changed files with 500 additions and 105 deletions
+75
View File
@@ -0,0 +1,75 @@
#include <atomic>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#ifdef RENDERIVE_WITH_GTEST
#include <gtest/gtest.h>
#endif
#include "../src/renderive/base/property/Property.hpp"
#include "../src/renderive/renderable/Renderable.hpp"
#include "../src/renderive/scene/Scene.hpp"
#include "../src/renderive/state/State_Strategy.hpp"
struct Radio_State {
struct Even_Validator {
void operator()(const int& value) const {
if (value % 2 != 0) {
throw std::invalid_argument("buffer_count must be even");
}
}
};
Range_Value<int, 1, 65535> port{8080};
Validated_Value<int, Even_Validator> buffer_count{2};
int low_watermark{};
int high_watermark{};
};
struct Radio_Base {
Radio_Base(int id, std::string name) : id(id), name(std::move(name)) {}
static void validate_state(const Radio_State& state) {
if (state.low_watermark > state.high_watermark) {
throw std::invalid_argument("low_watermark must not exceed high_watermark");
}
}
int id;
std::string name;
};
struct Demo_Renderable : Renderable_Base {
explicit Demo_Renderable(Scene_Base& scene) : Renderable_Base(scene, {.cache_enabled = true}) {}
void render(const Scene_Render_Context&) override {
++render_count;
}
std::atomic<int> render_count{};
};
using Radio_Strategy = Double_State_Strategy<Radio_Base, Radio_State>;
using Radio = Attach_State_Builder<Radio_Strategy, Radio_State>;
int run_main_flow() {
auto radio = Radio::Builder{}
.set < &Radio_State::port > (9000)
.set<&Radio_State::buffer_count>(8)
.configure([](Radio_State& state) {
state.low_watermark = 16;
state.high_watermark = 64;
})
.build(1, "primary");
radio->set < &Radio_State::port > (9100);
radio->publish();
Scene2D_Context<> scene;
auto renderable = std::make_shared<Demo_Renderable>(scene);
scene.attach_renderable(renderable);
scene.render();
scene.wait_for_render();
const auto& state = radio->render_use_state();
std::cout << radio->id << ' ' << radio->name << ' ' << state.port.get() << ' ' << state.buffer_count.get() << ' ' << renderable->render_count.load() << ' ' << scene.frame_control.frequency_hz() << '\n';
return 0;
}
int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
#ifdef RENDERIVE_WITH_GTEST
if (argc > 1 && std::string(argv[1]) == "--gtest") {
--argc;
++argv;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#endif
return run_main_flow();
}
@@ -9,5 +9,7 @@ TEST(color_cache_test, composites_source_values_in_order) {
second.append(2);
result.composite(first);
result.composite(second);
EXPECT_EQ(result.values, (std::vector<std::uint64_t>{1, 2}));
EXPECT_EQ(result.values.size(), 2);
EXPECT_EQ(result.values.at(0), 1);
EXPECT_EQ(result.values.at(1), 2);
}
@@ -29,5 +29,7 @@ TEST(scene2d_render_order_test, separates_dependency_order_from_display_order) {
scene.render();
scene.wait_for_render();
EXPECT_EQ(state.render_order, (std::vector<std::uint64_t>{1, 2}));
EXPECT_EQ(scene.final_color_cache.values, (std::vector<std::uint64_t>{2, 1}));
EXPECT_EQ(scene.final_color_cache.values.size(), 2);
EXPECT_EQ(scene.final_color_cache.values.at(0), 2);
EXPECT_EQ(scene.final_color_cache.values.at(1), 1);
}
@@ -0,0 +1,98 @@
#include <gtest/gtest.h>
#include <atomic>
#include <cstddef>
#include <memory>
#include <memory_resource>
#include <vector>
#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<std::size_t> allocation_count_{};
std::atomic<std::size_t> 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<Scene_Memory_Resource_Test_Renderable>();
auto independent_renderable = std::make_shared<Scene_Memory_Resource_Test_Renderable>(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<Scene_Memory_Resource_Test_Renderable> renderable;
{
Scene2D_Context<> scene(upstream);
renderable = scene.make_renderable<Scene_Memory_Resource_Test_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<Scene2D_Frame_Data> flow(memory_resource);
{
auto painter = flow.acquire_painter();
EXPECT_TRUE(painter);
}
auto renderer = flow.acquire_renderer();
EXPECT_TRUE(renderer);
History_Real_Time_Data<int, std::pmr::vector<int>> history(memory_resource);
history.update(1);
history.update(2);
EXPECT_EQ(history.size(), 2);
Property_Builder<Scene_Memory_Resource_Test_Property_Product, Scene_Memory_Resource_Test_Properties> 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);
}