编译过
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
#include "render.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
namespace {
|
||||
struct Direct_State_Tag {};
|
||||
struct Graph_State_Tag {};
|
||||
struct Direct_Renderable : double_buffer::Impl<Direct_Renderable, aethera::Renderable, double_buffer::State_Type<Direct_State_Tag>> {
|
||||
struct Prop : Prev_Prop {};
|
||||
struct State : Prev_State<Direct_State_Tag> {
|
||||
bool operator==(const State&) const = default;
|
||||
};
|
||||
struct Private : Prev_Private {
|
||||
int prepare_calls{};
|
||||
int paint_calls{};
|
||||
void prepare_data(double_buffer::Attached auto*) {
|
||||
++prepare_calls;
|
||||
}
|
||||
void paint(double_buffer::Attached auto*) {
|
||||
++paint_calls;
|
||||
}
|
||||
};
|
||||
};
|
||||
struct Graph_Renderable : double_buffer::Impl<Graph_Renderable, aethera::Renderable, double_buffer::State_Type<Graph_State_Tag>> {
|
||||
struct Prop : Prev_Prop {};
|
||||
struct State : Prev_State<Graph_State_Tag> {
|
||||
bool operator==(const State&) const = default;
|
||||
};
|
||||
struct Private : Prev_Private {
|
||||
int prepare_calls{};
|
||||
int paint_calls{};
|
||||
int prepare_builds{};
|
||||
bool rebuild_prepare{};
|
||||
tf::Taskflow build_prepare_graph(double_buffer::Attached auto*, const State&) {
|
||||
++prepare_builds;
|
||||
tf::Taskflow graph;
|
||||
graph.emplace([this] { ++prepare_calls; }).name("test.prepare.graph.task");
|
||||
return graph;
|
||||
}
|
||||
bool should_rebuild_prepare_graph(double_buffer::Attached auto*, const State&) {
|
||||
return std::exchange(rebuild_prepare, false);
|
||||
}
|
||||
void paint(double_buffer::Attached auto*) {
|
||||
++paint_calls;
|
||||
}
|
||||
};
|
||||
};
|
||||
using Direct = double_buffer::Attach_Object<Direct_Renderable>;
|
||||
using Graph = double_buffer::Attach_Object<Graph_Renderable>;
|
||||
using Scene = double_buffer::Attach_Object<aethera::Scene>;
|
||||
struct Dependency_State_Tag {};
|
||||
struct Dependency_Renderable : double_buffer::Impl<Dependency_Renderable, aethera::Renderable, double_buffer::State_Type<Dependency_State_Tag>> {
|
||||
struct Prop : Prev_Prop {};
|
||||
struct State : Prev_State<Dependency_State_Tag> {
|
||||
int revision{};
|
||||
bool operator==(const State&) const = default;
|
||||
};
|
||||
struct Private : Prev_Private {
|
||||
int prepare_calls{};
|
||||
int paint_calls{};
|
||||
bool publish_revision{};
|
||||
void prepare_data(double_buffer::Attached auto* object) {
|
||||
++prepare_calls;
|
||||
if (std::exchange(publish_revision, false)) object->template update_state<&State::revision>(object->d.state.pending->revision + 1);
|
||||
}
|
||||
void paint(double_buffer::Attached auto*) {
|
||||
++paint_calls;
|
||||
}
|
||||
};
|
||||
};
|
||||
using Dependency = double_buffer::Attach_Object<Dependency_Renderable>;
|
||||
template <typename Renderable>
|
||||
void add_renderable(Scene& scene, Renderable* renderable) {
|
||||
ASSERT_TRUE((scene.edit_rely<aethera::Prepare_Data_Tag, aethera::Paint_Tag>(
|
||||
[&](auto& prepare, auto& paint) {
|
||||
prepare.add(renderable);
|
||||
paint.add(renderable);
|
||||
}
|
||||
).has_value()));
|
||||
}
|
||||
}
|
||||
TEST(renderable_capability, direct_stages_do_not_allocate_subgraphs) {
|
||||
aethera::initialize_runtime(2);
|
||||
Direct renderable;
|
||||
Scene scene;
|
||||
add_renderable(scene, &renderable);
|
||||
scene.process([](const auto&) {});
|
||||
auto& data = static_cast<Direct_Renderable::Private&>(renderable.d);
|
||||
auto& base = static_cast<aethera::Renderable::Private&>(renderable.d);
|
||||
EXPECT_EQ(data.prepare_calls, 1);
|
||||
EXPECT_EQ(data.paint_calls, 1);
|
||||
EXPECT_EQ(base.prepare_graph, nullptr);
|
||||
EXPECT_EQ(base.paint_graph, nullptr);
|
||||
scene.process([](const auto&) {});
|
||||
EXPECT_EQ(data.prepare_calls, 1);
|
||||
EXPECT_EQ(data.paint_calls, 1);
|
||||
}
|
||||
TEST(renderable_capability, graph_stage_builds_lazily_and_rebuilds_inside_condition) {
|
||||
aethera::initialize_runtime(2);
|
||||
Graph renderable;
|
||||
Scene scene;
|
||||
add_renderable(scene, &renderable);
|
||||
auto& data = static_cast<Graph_Renderable::Private&>(renderable.d);
|
||||
auto& base = static_cast<aethera::Renderable::Private&>(renderable.d);
|
||||
EXPECT_EQ(base.prepare_graph, nullptr);
|
||||
scene.process([](const auto&) {});
|
||||
ASSERT_NE(base.prepare_graph, nullptr);
|
||||
EXPECT_EQ(data.prepare_builds, 1);
|
||||
EXPECT_EQ(data.prepare_calls, 1);
|
||||
scene.process([](const auto&) {});
|
||||
EXPECT_EQ(data.prepare_builds, 1);
|
||||
EXPECT_EQ(data.prepare_calls, 1);
|
||||
data.rebuild_prepare = true;
|
||||
renderable.mark_dirty<aethera::Prepare_Data_Tag>();
|
||||
scene.process([](const auto&) {});
|
||||
EXPECT_EQ(data.prepare_builds, 2);
|
||||
EXPECT_EQ(data.prepare_calls, 2);
|
||||
}
|
||||
TEST(renderable_state, scene_and_renderable_callbacks_publish_at_stage_boundaries) {
|
||||
aethera::initialize_runtime(2);
|
||||
Direct renderable;
|
||||
Scene scene;
|
||||
add_renderable(scene, &renderable);
|
||||
int renderable_updates = 0;
|
||||
int scene_updates = 0;
|
||||
int runtime_updates = 0;
|
||||
renderable.set_state_callback<aethera::Renderable_State_Tag>([&](const auto& state) {
|
||||
++renderable_updates;
|
||||
EXPECT_TRUE(state.prepare_executed);
|
||||
EXPECT_TRUE(state.paint_executed);
|
||||
});
|
||||
scene.set_state_callback<aethera::Scene_State_Tag>([&](const auto& state) {
|
||||
++scene_updates;
|
||||
EXPECT_GT(state.taskflow_task_count, 0u);
|
||||
});
|
||||
aethera::set_runtime_state_callback<aethera::Task_Runtime_State_Tag>([&](const auto& state) {
|
||||
++runtime_updates;
|
||||
EXPECT_GE(state.completed_taskflow_count, 1u);
|
||||
EXPECT_GT(state.observed_task_count, 0u);
|
||||
});
|
||||
scene.process([](const auto&) {});
|
||||
EXPECT_EQ(renderable_updates, 1);
|
||||
EXPECT_EQ(scene_updates, 1);
|
||||
EXPECT_EQ(runtime_updates, 1);
|
||||
aethera::clear_runtime_state_callback<aethera::Task_Runtime_State_Tag>();
|
||||
}
|
||||
TEST(scene_condition, upstream_change_makes_downstream_run_in_same_taskflow) {
|
||||
aethera::initialize_runtime(2);
|
||||
Dependency source;
|
||||
Dependency target;
|
||||
Scene scene;
|
||||
ASSERT_TRUE((scene.edit_rely<aethera::Prepare_Data_Tag, aethera::Paint_Tag>(
|
||||
[&](auto& prepare, auto& paint) {
|
||||
prepare.add(&source);
|
||||
prepare.add(&target);
|
||||
prepare.template add_dependency<&Dependency_Renderable::State::revision>(&target, &source);
|
||||
paint.add(&source);
|
||||
paint.add(&target);
|
||||
}
|
||||
).has_value()));
|
||||
scene.process([](const auto&) {});
|
||||
auto& source_data = static_cast<Dependency_Renderable::Private&>(source.d);
|
||||
auto& target_data = static_cast<Dependency_Renderable::Private&>(target.d);
|
||||
EXPECT_EQ(source_data.prepare_calls, 1);
|
||||
EXPECT_EQ(target_data.prepare_calls, 1);
|
||||
scene.process([](const auto&) {});
|
||||
EXPECT_EQ(source_data.prepare_calls, 1);
|
||||
EXPECT_EQ(target_data.prepare_calls, 1);
|
||||
source_data.publish_revision = true;
|
||||
source.mark_dirty<aethera::Prepare_Data_Tag>();
|
||||
scene.process([](const auto&) {});
|
||||
EXPECT_EQ(source_data.prepare_calls, 2);
|
||||
EXPECT_EQ(target_data.prepare_calls, 2);
|
||||
}
|
||||
Reference in New Issue
Block a user