secene 接入 多继承链

This commit is contained in:
2026-08-15 00:23:52 +08:00
parent 12e46b4c21
commit 2c7c8abd4f
15 changed files with 1011 additions and 355 deletions
@@ -0,0 +1,62 @@
#include <gtest/gtest.h>
#include <memory_resource>
#include <stdexcept>
#include "renderive/scene/dependency/Dependency_Resolver.hpp"
namespace {
enum class Preparation {
acquire_source,
transform_vertices,
upload_visual
};
using Resolver =
renderive::scene::dependency::Dependency_Resolver<Preparation>;
TEST(dependency_resolver_test,
resolves_declared_dependencies_in_deterministic_order) {
std::pmr::unsynchronized_pool_resource memory;
Resolver resolver(memory);
resolver.attach(Preparation::upload_visual);
resolver.attach(Preparation::acquire_source);
resolver.attach(Preparation::transform_vertices);
resolver.add_parent(Preparation::transform_vertices,
Preparation::acquire_source);
resolver.add_parent(Preparation::upload_visual,
Preparation::transform_vertices);
const auto resolution = resolver.resolve();
EXPECT_EQ(resolution.order,
(std::vector{Preparation::acquire_source,
Preparation::transform_vertices,
Preparation::upload_visual}));
}
TEST(dependency_resolver_test,
rejected_cycle_preserves_the_previous_authoritative_relationships) {
std::pmr::unsynchronized_pool_resource memory;
Resolver resolver(memory);
resolver.attach(Preparation::acquire_source);
resolver.attach(Preparation::transform_vertices);
resolver.attach(Preparation::upload_visual);
resolver.add_parent(Preparation::transform_vertices,
Preparation::acquire_source);
resolver.add_parent(Preparation::upload_visual,
Preparation::transform_vertices);
EXPECT_THROW(
resolver.add_parent(Preparation::acquire_source,
Preparation::upload_visual),
std::logic_error);
EXPECT_TRUE(resolver.parents(Preparation::acquire_source).empty());
EXPECT_EQ(resolver.resolve().order,
(std::vector{Preparation::acquire_source,
Preparation::transform_vertices,
Preparation::upload_visual}));
}
} // namespace
@@ -155,8 +155,6 @@ TEST(scene3d_context_test, runtime_edit_explicitly_reparents_children_before_det
attach.attach(grandparent);
attach.attach(parent);
attach.attach(child);
attach.set_display_parent(parent, grandparent);
attach.set_display_parent(child, parent);
attach.set_dependency_parent(parent, grandparent);
attach.set_dependency_parent(child, parent);
});
@@ -164,28 +162,19 @@ TEST(scene3d_context_test, runtime_edit_explicitly_reparents_children_before_det
scene.wait_for_render();
EXPECT_EQ(child->render_count, 1);
wait_renderable_edit(scene, [grandparent, parent, child](auto& editor) {
editor.set_display_parent(child, grandparent);
editor.set_dependency_parent(child, grandparent);
editor.clear_display_parent(parent);
editor.clear_dependency_parent(parent);
editor.detach(parent);
});
const auto topology = scene.topology_snapshot();
bool display_checked{};
bool dependency_checked{};
for (const auto& relation : topology.display) {
if (relation.child.get() == child.get()) {
EXPECT_EQ(relation.parent.get(), grandparent.get());
display_checked = true;
}
}
for (const auto& relation : topology.dependency) {
if (relation.child.get() == child.get()) {
EXPECT_EQ(relation.parent.get(), grandparent.get());
dependency_checked = true;
}
}
EXPECT_TRUE(display_checked);
EXPECT_TRUE(topology.display.empty());
EXPECT_TRUE(dependency_checked);
scene.render();
scene.wait_for_render();
@@ -0,0 +1,128 @@
#include <gtest/gtest.h>
#include <string>
#include <type_traits>
#include <vector>
#include "renderive/inheritance/Registry.hpp"
#include "renderive/scene/Inheritance.hpp"
namespace {
struct Lifecycle_Event {
std::vector<std::string>& handled_by;
};
struct Scene_Impl
: renderive::scene_inheritance::Impl_Root<Scene_Impl,
Lifecycle_Event> {
struct Observer :
renderive::scene_inheritance::Observer_Root<Scene_Impl> {
static void handle(Scene_Impl&, const Lifecycle_Event& event) {
event.handled_by.emplace_back("scene");
}
};
};
struct Scene2D_Impl
: renderive::scene_inheritance::Impl_Node<Scene2D_Impl, Scene_Impl> {
struct Observer
: renderive::scene_inheritance::Observer_Node<
Scene2D_Impl, Scene_Impl::Observer> {
static void handle(Scene2D_Impl&, const Lifecycle_Event& event) {
event.handled_by.emplace_back("scene_2d");
}
};
};
struct Plot_Scene_Impl
: renderive::scene_inheritance::Impl_Node<Plot_Scene_Impl,
Scene2D_Impl> {
struct Observer
: renderive::scene_inheritance::Observer_Node<
Plot_Scene_Impl, Scene2D_Impl::Observer> {
static void handle(Plot_Scene_Impl&, const Lifecycle_Event& event) {
event.handled_by.emplace_back("plot_scene");
}
};
};
struct Scene_Editor
: renderive::scene_inheritance::Editor_Root<Scene_Editor> {};
struct Scene2D_Editor
: renderive::scene_inheritance::Editor_Node<Scene2D_Editor,
Scene_Editor> {};
struct Plot_Scene_Editor
: renderive::scene_inheritance::Editor_Node<Plot_Scene_Editor,
Scene2D_Editor> {};
struct Scene_Builder
: renderive::scene_inheritance::Builder_Root<Scene_Builder> {};
struct Scene2D_Builder
: renderive::scene_inheritance::Builder_Node<Scene2D_Builder,
Scene_Builder> {};
struct Plot_Scene_Builder
: renderive::scene_inheritance::Builder_Node<Plot_Scene_Builder,
Scene2D_Builder> {};
struct Scene_State
: renderive::scene_inheritance::State_Root<Scene_State> {};
struct Scene2D_State
: renderive::scene_inheritance::State_Node<Scene2D_State,
Scene_State> {};
struct Plot_Scene_State
: renderive::scene_inheritance::State_Node<Plot_Scene_State,
Scene2D_State> {};
TEST(scene_inheritance_test,
observer_dispatch_follows_the_scene_chain_parent_before_child) {
Plot_Scene_Impl impl;
std::vector<std::string> handled_by;
impl.dispatch({handled_by});
EXPECT_EQ(handled_by,
(std::vector<std::string>{"scene", "scene_2d", "plot_scene"}));
}
TEST(scene_inheritance_test,
editor_chain_registers_each_semantic_layer_at_its_own_position) {
using Registry = Plot_Scene_Editor::Inheritance_Registry;
using Chain = renderive::scene_inheritance::Editor_Chain;
static_assert(renderive::inheritance::Chain_Registration_Count_V<
Registry, Chain> == 3);
static_assert(std::same_as<
renderive::inheritance::Type_At_Position_T<Registry, Chain,
0>,
Scene_Editor>);
static_assert(std::same_as<
renderive::inheritance::Type_At_Position_T<Registry, Chain,
2>,
Plot_Scene_Editor>);
SUCCEED();
}
TEST(scene_inheritance_test,
builder_and_state_chains_extend_without_sharing_registrations) {
using Builder_Registry = Plot_Scene_Builder::Inheritance_Registry;
using State_Registry = Plot_Scene_State::Inheritance_Registry;
using Builder_Chain = renderive::scene_inheritance::Builder_Chain;
using State_Chain = renderive::scene_inheritance::State_Chain;
static_assert(renderive::inheritance::Chain_Registration_Count_V<
Builder_Registry, Builder_Chain> == 3);
static_assert(renderive::inheritance::Chain_Registration_Count_V<
Builder_Registry, State_Chain> == 0);
static_assert(renderive::inheritance::Chain_Registration_Count_V<
State_Registry, State_Chain> == 3);
static_assert(renderive::inheritance::Chain_Registration_Count_V<
State_Registry, Builder_Chain> == 0);
static_assert(std::same_as<
renderive::inheritance::Type_At_Position_T<
Builder_Registry, Builder_Chain, 2>,
Plot_Scene_Builder>);
static_assert(std::same_as<
renderive::inheritance::Type_At_Position_T<
State_Registry, State_Chain, 2>,
Plot_Scene_State>);
SUCCEED();
}
} // namespace
@@ -16,12 +16,17 @@ struct Scene_State_Observer_Test_Time_Source {
};
struct Scene_State_Observer_Test_Data {
std::vector<Scene_Base::Observation_Event> events;
std::atomic<int> complete_snapshot_count{};
};
struct Scene_State_Observer_Test_Recorder {
static constexpr bool enabled = true;
std::shared_ptr<Scene_State_Observer_Test_Data> data{std::make_shared<Scene_State_Observer_Test_Data>()};
void observe(const Scene_Base::Observation& observation) noexcept {
data->events.push_back(observation.event);
if (observation.topology && observation.frame_snapshot &&
observation.render_plan)
data->complete_snapshot_count.fetch_add(1,
std::memory_order_relaxed);
}
};
using Scene_State_Observer_Test_Scene_Observer = Observer_State<Scene_State_Observer_Test_Recorder, Scene_State_Observer_Test_Time_Source>;
@@ -37,6 +42,7 @@ TEST(scene_state_observer_test, scene_uses_double_state_and_observes_lifecycle)
scene.wait_for_render();
EXPECT_EQ(render.read(static_cast<const Scene::Scene_State_Strategy&>(scene)).value, 9);
EXPECT_EQ(recorder.data->events, (std::vector<Scene_Base::Observation_Event>{Scene_Base::Observation_Event::render_submitted, Scene_Base::Observation_Event::render_started, Scene_Base::Observation_Event::render_completed}));
EXPECT_EQ(recorder.data->complete_snapshot_count.load(), 3);
}
struct Scene_Reentrant_Observer_Data {
std::function<void(Scene_Base::Observation_Event)> callback;
@@ -2,21 +2,21 @@
#include <future>
#include <utility>
#include "renderive/scene/base/Scene_Base.hpp"
template <class... Owners>
void attach_initial(Scene_Base& scene, const Owners&... owners) {
template <class Scene, class... Owners>
void attach_initial(Scene& scene, const Owners&... owners) {
auto builder = scene.attach_builder();
(builder.attach(owners), ...);
}
template <class Edit>
void with_attach_builder(Scene_Base& scene, Edit&& edit) {
template <class Scene, class Edit>
void with_attach_builder(Scene& scene, Edit&& edit) {
auto builder = scene.attach_builder();
edit(builder);
}
template <class Edit>
void wait_renderable_edit(Scene_Base& scene, Edit&& edit) {
template <class Scene, class Edit>
void wait_renderable_edit(Scene& scene, Edit&& edit) {
std::promise<void> completed;
auto future = completed.get_future();
scene.edit_renderables([edit = std::forward<Edit>(edit), &completed](Scene_Base::Renderable_Editor& editor) mutable {
scene.edit_renderables([edit = std::forward<Edit>(edit), &completed](auto& editor) mutable {
edit(editor);
completed.set_value();
});
@@ -473,7 +473,7 @@ TEST(scene_base_test, detached_topology_reference_fails_fast_after_callback) {
});
scene.render();
},
"dependency topology still references detached renderable");
"dependency graph still references detached renderable");
}
TEST(scene_base_test, wait_for_render_propagates_background_render_failure) {
Scene2D_Context<> scene;