更换为 taskflow了
This commit is contained in:
+34
-26
@@ -1,34 +1,42 @@
|
||||
include_guard(GLOBAL)
|
||||
block()
|
||||
rcl_init(render_kernel)
|
||||
set(oneTBB_option ${base_options})
|
||||
list(APPEND oneTBB_option
|
||||
-DBUILD_SHARED_LIBS=ON
|
||||
-DTBB_BUILD=ON
|
||||
-DTBB_INSTALL=ON
|
||||
-DTBB_TEST=OFF
|
||||
-DTBB_EXAMPLES=OFF
|
||||
-DTBB_STRICT=OFF
|
||||
-DTBB4PY_BUILD=OFF
|
||||
-DTBBMALLOC_BUILD=OFF
|
||||
-DTBBMALLOC_PROXY_BUILD=OFF
|
||||
rcl_init(aethera_kernel)
|
||||
set(taskflow_option ${base_options})
|
||||
list(APPEND taskflow_option
|
||||
-DTF_BUILD_EXAMPLES=OFF
|
||||
-DTF_BUILD_TESTS=OFF
|
||||
-DTF_BUILD_BENCHMARKS=OFF
|
||||
-DTF_BUILD_PROFILER=OFF
|
||||
-DTF_BUILD_CUDA=OFF
|
||||
-DTF_BUILD_MODULES=OFF
|
||||
)
|
||||
_register_git_cmake_library(render_kernel::oneTBB
|
||||
"https://github.com/uxlfoundation/oneTBB.git"
|
||||
"v2023.1.0"
|
||||
_register_git_cmake_library(aethera_kernel::taskflow
|
||||
"https://github.com/taskflow/taskflow.git"
|
||||
"v4.1.0"
|
||||
)
|
||||
rcl_get_effective_install_dir(render_kernel::oneTBB ONETBB_ROOT)
|
||||
set(TBB_CONFIG_DIR "${ONETBB_ROOT}/lib/cmake/TBB")
|
||||
rcl_cmake_library_set_cmake_options(render_kernel::oneTBB ${oneTBB_option})
|
||||
rcl_cmake_library_set_other_use_opt(render_kernel::oneTBB
|
||||
"-DTBB_DIR=\"${TBB_CONFIG_DIR}\""
|
||||
rcl_get_effective_install_dir(
|
||||
aethera_kernel::taskflow
|
||||
TASKFLOW_ROOT
|
||||
)
|
||||
rcl_cmake_library_set_init_script(render_kernel::oneTBB
|
||||
"set(ONETBB_ROOT \"${ONETBB_ROOT}\")"
|
||||
"set(TBB_DIR \"${TBB_CONFIG_DIR}\")"
|
||||
set(Taskflow_DIR
|
||||
"${TASKFLOW_ROOT}/share/cmake/Taskflow"
|
||||
)
|
||||
rcl_cmake_library_set_clear_script(render_kernel::oneTBB
|
||||
"unset(ONETBB_ROOT)"
|
||||
"unset(TBB_DIR)"
|
||||
rcl_cmake_library_set_cmake_options(
|
||||
aethera_kernel::taskflow
|
||||
${taskflow_option}
|
||||
)
|
||||
rcl_cmake_library_set_other_use_opt(
|
||||
aethera_kernel::taskflow
|
||||
"-DTaskflow_DIR=\"${Taskflow_DIR}\""
|
||||
)
|
||||
rcl_cmake_library_set_init_script(
|
||||
aethera_kernel::taskflow
|
||||
"set(TASKFLOW_ROOT \"${TASKFLOW_ROOT}\")"
|
||||
"set(Taskflow_DIR \"${Taskflow_DIR}\")"
|
||||
)
|
||||
rcl_cmake_library_set_clear_script(
|
||||
aethera_kernel::taskflow
|
||||
"unset(TASKFLOW_ROOT)"
|
||||
"unset(Taskflow_DIR)"
|
||||
)
|
||||
endblock()
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/rely.cmake)
|
||||
set(Aethera_Kernel_dependencies render_kernel::oneTBB global::magic_enum global::expected)
|
||||
set(Aethera_Kernel_dependencies aethera_kernel::taskflow global::magic_enum global::expected)
|
||||
if (Aethera_BUILD_TESTS)
|
||||
set(Aethera_Kernel_test_targets)
|
||||
list(APPEND Aethera_Kernel_dependencies global::GTest)
|
||||
@@ -13,7 +13,7 @@ if (Aethera_Kernel_dependencies_installed)
|
||||
endif ()
|
||||
rcl_load_dependency_environment(${Aethera_Kernel_dependencies})
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(TBB CONFIG REQUIRED)
|
||||
find_package(Taskflow CONFIG REQUIRED)
|
||||
find_package(magic_enum CONFIG REQUIRED)
|
||||
find_package(tl-expected CONFIG REQUIRED)
|
||||
if (Aethera_BUILD_TESTS)
|
||||
@@ -30,9 +30,10 @@ target_include_directories(Aethera_Kernel PUBLIC
|
||||
)
|
||||
target_compile_features(Aethera_Kernel PUBLIC cxx_std_20)
|
||||
target_link_libraries(Aethera_Kernel PUBLIC
|
||||
TBB::tbb
|
||||
Taskflow::Taskflow
|
||||
magic_enum::magic_enum
|
||||
tl::expected)
|
||||
tl::expected
|
||||
)
|
||||
target_link_libraries(Aethera_Kernel PRIVATE Threads::Threads)
|
||||
function(Aethera_stage_kernel_runtime target)
|
||||
if (WIN32)
|
||||
|
||||
@@ -178,6 +178,11 @@ public:
|
||||
[[nodiscard]] const Rely& render_rely() const {
|
||||
return *d.rely_storage.template get<Tag>().render;
|
||||
}
|
||||
template <detail::Rely_Tag_In<Relies>... Tags, detail::Rely_Render_State_Callback_For<Tags...> Callback> requires
|
||||
detail::Unique_Types<Tags...>::value
|
||||
void render_rely(Callback&& callback) {
|
||||
d.rely_storage.template render<Tags...>(std::forward<Callback>(callback));
|
||||
}
|
||||
template <detail::Rely_Tag_In<Relies>... Tags, detail::Rely_Edit_Callback_For<Tags...> Callback> requires
|
||||
detail::Unique_Types<Tags...>::value
|
||||
std::expected<void, Rely_Error> edit_rely(Callback&& callback) {
|
||||
|
||||
@@ -241,9 +241,10 @@ private:
|
||||
}
|
||||
template <Root_Derived Object>
|
||||
static Node::Bind node_bind() {
|
||||
if constexpr (requires(Object* object, Node* node) { object->template bind_rely_node<Object>(node); }) {
|
||||
if constexpr (requires(Object* object, Node* node) { object->bind_rely_node(node, object); }) {
|
||||
return [](Node* node, Root* root) {
|
||||
static_cast<Object*>(root)->template bind_rely_node<Object>(node);
|
||||
auto* object = static_cast<Object*>(root);
|
||||
object->bind_rely_node(node, object);
|
||||
};
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -11,6 +11,8 @@ template <typename Callback>
|
||||
concept Rely_View_Node_Callback = std::invocable<Callback, const Rely::View&, const Rely::Node&>;
|
||||
template <typename Callback>
|
||||
concept Rely_Render_Callback = std::invocable<Callback, const Rely&>;
|
||||
template <typename Callback, typename... Tags>
|
||||
concept Rely_Render_State_Callback_For = std::invocable<Callback, Rely_Type<Tags>&...>;
|
||||
}
|
||||
inline bool Root::mark_dirty_id(const void* tag, const void* dirty_key) {
|
||||
if (std::find(dirty_tags.begin(), dirty_tags.end(), tag) != dirty_tags.end()) return false;
|
||||
@@ -73,6 +75,13 @@ public:
|
||||
const auto& get() const {
|
||||
return std::get<index<Tag>()>(relies);
|
||||
}
|
||||
template <Rely_Tag_In<std::tuple<Relies...>>... Tags, Rely_Render_State_Callback_For<Tags...> Callback> requires Unique_Types<Tags...>::value
|
||||
void render(Callback&& callback) {
|
||||
std::invoke(
|
||||
std::forward<Callback>(callback),
|
||||
static_cast<Rely_Type<Tags>&>(get<Tags>())...
|
||||
);
|
||||
}
|
||||
template <Rely_Tag_In<std::tuple<Relies...>>... Tags, Rely_Edit_Callback_For<Tags...> Callback> requires Unique_Types<Tags...>::value
|
||||
std::expected<void, Rely_Error> edit(Callback&& callback) {
|
||||
std::tuple<std::conditional_t<true, Rely, Tags>...> next(*get<Tags>().cache...);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "render_2D.hpp"
|
||||
namespace aethera::_2D {
|
||||
namespace {
|
||||
class Task_Resource : Pinned {
|
||||
private:
|
||||
std::unique_ptr<tf::Executor> executor_value;
|
||||
std::pmr::memory_resource* memory_value;
|
||||
public:
|
||||
Task_Resource() : memory_value(std::pmr::get_default_resource()) {}
|
||||
static Task_Resource& instance() {
|
||||
static Task_Resource value;
|
||||
return value;
|
||||
}
|
||||
void initialize(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, Pmr pmr) {
|
||||
executor_value = std::make_unique<tf::Executor>(workers, std::move(worker_interface));
|
||||
memory_value = pmr.resource();
|
||||
}
|
||||
tf::Executor& executor() {
|
||||
if (!executor_value) executor_value = std::make_unique<tf::Executor>();
|
||||
return *executor_value;
|
||||
}
|
||||
std::pmr::memory_resource* memory_resource() const noexcept {
|
||||
return memory_value;
|
||||
}
|
||||
};
|
||||
}
|
||||
void initialize(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, Pmr pmr) {
|
||||
Task_Resource::instance().initialize(workers, std::move(worker_interface), pmr);
|
||||
}
|
||||
namespace detail {
|
||||
tf::Executor& task_executor() {
|
||||
return Task_Resource::instance().executor();
|
||||
}
|
||||
std::pmr::memory_resource* task_memory_resource() noexcept {
|
||||
return Task_Resource::instance().memory_resource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+137
-265
@@ -1,10 +1,17 @@
|
||||
#pragma once
|
||||
#include "base.hpp"
|
||||
#include <oneapi/tbb/flow_graph.h>
|
||||
#include <taskflow/taskflow.hpp>
|
||||
namespace aethera::_2D {
|
||||
struct Prepare_Data_Tag {};
|
||||
struct Paint_Tag {};
|
||||
struct Color_Cache {};
|
||||
void initialize(std::size_t workers = std::thread::hardware_concurrency(),
|
||||
std::shared_ptr<tf::WorkerInterface> worker_interface = nullptr,
|
||||
Pmr pmr = {});
|
||||
namespace detail {
|
||||
tf::Executor& task_executor();
|
||||
std::pmr::memory_resource* task_memory_resource() noexcept;
|
||||
}
|
||||
struct Renderable;
|
||||
struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_Tag>> {
|
||||
struct Prop : Prev_Prop {};
|
||||
@@ -13,102 +20,14 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
|
||||
struct Result {};
|
||||
friend struct Renderable;
|
||||
private:
|
||||
using Message = oneapi::tbb::flow::continue_msg;
|
||||
struct Task : Pinned {
|
||||
using Gate = oneapi::tbb::flow::continue_node<Message>;
|
||||
using Execute = oneapi::tbb::flow::async_node<Message, Message>;
|
||||
using Gateway = typename Execute::gateway_type;
|
||||
struct Async_Tag {};
|
||||
struct Completion {
|
||||
Gateway* gateway;
|
||||
void operator()() const {
|
||||
(void)gateway->try_put(Message{});
|
||||
gateway->release_wait();
|
||||
}
|
||||
};
|
||||
Gate gate;
|
||||
Execute execute;
|
||||
template <std::invocable Callback>
|
||||
Task(oneapi::tbb::flow::graph& graph, bool* enabled, Callback&& callback) : gate(
|
||||
graph,
|
||||
[](const Message&) {
|
||||
return Message{};
|
||||
}
|
||||
),
|
||||
execute(
|
||||
graph,
|
||||
oneapi::tbb::flow::unlimited,
|
||||
[state = enabled, task = std::forward<Callback>(callback)](const Message&, Gateway& gateway) mutable {
|
||||
if (!state || *state) std::invoke(task);
|
||||
(void)gateway.try_put(Message{});
|
||||
}
|
||||
) {
|
||||
oneapi::tbb::flow::make_edge(gate, execute);
|
||||
}
|
||||
template <std::invocable<Completion> Callback>
|
||||
Task(
|
||||
oneapi::tbb::flow::graph& graph,
|
||||
bool* enabled,
|
||||
Async_Tag,
|
||||
Callback&& callback) : gate(
|
||||
graph,
|
||||
[](const Message&) {
|
||||
return Message{};
|
||||
}
|
||||
),
|
||||
execute(
|
||||
graph,
|
||||
oneapi::tbb::flow::unlimited,
|
||||
[state = enabled, task = std::forward<Callback>(callback)](const Message&, Gateway& gateway) mutable {
|
||||
if (state && !*state) {
|
||||
(void)gateway.try_put(Message{});
|
||||
return;
|
||||
}
|
||||
gateway.reserve_wait();
|
||||
try {
|
||||
std::invoke(task, Completion{&gateway});
|
||||
}
|
||||
catch (...) {
|
||||
gateway.release_wait();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
) {
|
||||
oneapi::tbb::flow::make_edge(gate, execute);
|
||||
}
|
||||
};
|
||||
std::unique_ptr<oneapi::tbb::flow::graph> graph;
|
||||
std::unique_ptr<oneapi::tbb::flow::broadcast_node<Message>> start;
|
||||
std::unique_ptr<std::pmr::list<Task>> tasks;
|
||||
bool* building_enabled{};
|
||||
tf::Taskflow graph;
|
||||
bool graph_ready{};
|
||||
public:
|
||||
template <std::invocable Callback>
|
||||
Task* add(Callback&& callback) {
|
||||
tasks->emplace_back(*graph, building_enabled, std::forward<Callback>(callback));
|
||||
return &tasks->back();
|
||||
}
|
||||
template <std::invocable<typename Task::Completion> Callback>
|
||||
Task* add_async(Callback&& callback) {
|
||||
tasks->emplace_back(
|
||||
*graph,
|
||||
building_enabled,
|
||||
typename Task::Async_Tag{},
|
||||
std::forward<Callback>(callback)
|
||||
);
|
||||
return &tasks->back();
|
||||
}
|
||||
void add_rely(Task* target, Task* source) {
|
||||
oneapi::tbb::flow::make_edge(source->execute, target->gate);
|
||||
}
|
||||
template <Attached Object>
|
||||
void after_exchange(Object* object, Prop*, State*, const Prop*, const State*);
|
||||
template <Attached Object, std::invocable<const Result&> Callback>
|
||||
void render_scene(Object*, Callback&& callback) {
|
||||
void after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*);
|
||||
template <std::invocable<const Result&> Callback>
|
||||
void render_scene(Root*, Callback&& callback) {
|
||||
Result result;
|
||||
if (graph && tasks && !tasks->empty()) {
|
||||
(void)start->try_put(Message{});
|
||||
graph->wait_for_all();
|
||||
}
|
||||
if (graph_ready && !graph.empty()) detail::task_executor().run(graph).get();
|
||||
std::invoke(std::forward<Callback>(callback), std::as_const(result));
|
||||
}
|
||||
};
|
||||
@@ -119,15 +38,15 @@ struct Renderable : Impl<Renderable, Root, Tagged_Buffer<Color_Cache>> {
|
||||
bool operator==(const State&) const = default;
|
||||
};
|
||||
protected:
|
||||
template <Attached Object>
|
||||
static void execute_prepare_data(Object* object) {
|
||||
static void execute_prepare_data(Attached auto* object) {
|
||||
using Object = std::remove_pointer_t<decltype(object)>;
|
||||
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
||||
if constexpr (requires { private_data.template prepare_data<Object>(object); }) {
|
||||
private_data.template prepare_data<Object>(object);
|
||||
if constexpr (requires { private_data.prepare_data(object); }) {
|
||||
private_data.prepare_data(object);
|
||||
}
|
||||
auto callback = [&](auto& value) {
|
||||
if constexpr (requires { value.template after_prepare_data<Object>(object); }) {
|
||||
value.template after_prepare_data<Object>(object);
|
||||
if constexpr (requires { value.after_prepare_data(object); }) {
|
||||
value.after_prepare_data(object);
|
||||
}
|
||||
};
|
||||
walk_private<true, typename Object::Attached_Object>(object, callback);
|
||||
@@ -135,103 +54,136 @@ protected:
|
||||
public:
|
||||
struct Private : Prev_Private {
|
||||
using Need_Call = bool (*)(Root*, bool);
|
||||
using Make_Call = void (*)(Root*, Secene::Private&);
|
||||
using Update_Call = bool (*)(Root*);
|
||||
using Make_Call = tf::Taskflow (*)(Root*, std::pmr::memory_resource*);
|
||||
Need_Call need_prepare_call{};
|
||||
Need_Call need_paint_call{};
|
||||
Update_Call update_prepare_call{};
|
||||
Update_Call update_paint_call{};
|
||||
Make_Call make_prepare_call{};
|
||||
Make_Call make_paint_call{};
|
||||
bool prepare_graph_dirty{true};
|
||||
bool paint_graph_dirty{true};
|
||||
bool prepare_enabled{};
|
||||
bool paint_enabled{};
|
||||
template <Attached Object>
|
||||
bool need_update_prepare_graph(Object*, const State&) {
|
||||
tf::Taskflow prepare_graph;
|
||||
tf::Taskflow paint_graph;
|
||||
tf::Taskflow prepare_flow;
|
||||
tf::Taskflow paint_flow;
|
||||
bool prepare_graph_ready{};
|
||||
bool paint_graph_ready{};
|
||||
bool flow_ready{};
|
||||
bool need_update_prepare_graph(Attached auto*, const State&) {
|
||||
return false;
|
||||
}
|
||||
template <Attached Object>
|
||||
bool need_update_paint_graph(Object*, const State&) {
|
||||
bool need_update_paint_graph(Attached auto*, const State&) {
|
||||
return false;
|
||||
}
|
||||
template <Attached Object>
|
||||
bool need_prepare(Object*, const State&, bool dirty) {
|
||||
bool need_prepare(Attached auto*, const State&, bool dirty) {
|
||||
return dirty;
|
||||
}
|
||||
template <Attached Object>
|
||||
bool need_paint(Object*, const State&, bool dirty) {
|
||||
bool need_paint(Attached auto*, const State&, bool dirty) {
|
||||
return dirty;
|
||||
}
|
||||
template <Attached Object>
|
||||
void make_prepare_graph(Object* object, const State&, auto& graph) {
|
||||
graph.add(
|
||||
[object] {
|
||||
execute_prepare_data(object);
|
||||
tf::Taskflow make_prepare_graph(Attached auto* object, const State&, std::pmr::memory_resource*) {
|
||||
tf::Taskflow graph;
|
||||
graph.emplace([object] {
|
||||
execute_prepare_data(object);
|
||||
});
|
||||
return graph;
|
||||
}
|
||||
tf::Taskflow make_paint_graph(Attached auto* object, const State&, std::pmr::memory_resource*) {
|
||||
using Object = std::remove_pointer_t<decltype(object)>;
|
||||
tf::Taskflow graph;
|
||||
graph.emplace([object] {
|
||||
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
||||
private_data.paint(object);
|
||||
});
|
||||
return graph;
|
||||
}
|
||||
void prepare_data(Attached auto*) {}
|
||||
void after_prepare_data(Attached auto*) {}
|
||||
void paint(Attached auto*) {}
|
||||
private:
|
||||
void make_flow(Root* root) {
|
||||
prepare_flow.clear();
|
||||
paint_flow.clear();
|
||||
auto prepare_if = prepare_flow.emplace([this, root] {
|
||||
bool update = update_prepare_call(root);
|
||||
if (!prepare_graph_ready || update) {
|
||||
prepare_graph = make_prepare_call(root, detail::task_memory_resource());
|
||||
prepare_graph_ready = true;
|
||||
root->template mark_dirty<Prepare_Data_Tag>();
|
||||
}
|
||||
);
|
||||
}
|
||||
template <Attached Object>
|
||||
void make_paint_graph(Object* object, const State&, auto& graph) {
|
||||
graph.add(
|
||||
[object] {
|
||||
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
||||
private_data.template paint<Object>(object);
|
||||
return need_prepare_call(root, root->template dirty<Prepare_Data_Tag>()) ? 0 : -1;
|
||||
});
|
||||
auto prepare_run = prepare_flow.composed_of(prepare_graph);
|
||||
auto prepare_done = prepare_flow.emplace([root] {
|
||||
root->template take_dirty<Prepare_Data_Tag>();
|
||||
root->template mark_dirty<Paint_Tag>();
|
||||
});
|
||||
prepare_if.precede(prepare_run);
|
||||
prepare_run.precede(prepare_done);
|
||||
auto paint_if = paint_flow.emplace([this, root] {
|
||||
bool update = update_paint_call(root);
|
||||
if (!paint_graph_ready || update) {
|
||||
paint_graph = make_paint_call(root, detail::task_memory_resource());
|
||||
paint_graph_ready = true;
|
||||
root->template mark_dirty<Paint_Tag>();
|
||||
}
|
||||
);
|
||||
return need_paint_call(root, root->template dirty<Paint_Tag>()) ? 0 : -1;
|
||||
});
|
||||
auto paint_run = paint_flow.composed_of(paint_graph);
|
||||
auto paint_done = paint_flow.emplace([root] {
|
||||
root->template take_dirty<Paint_Tag>();
|
||||
});
|
||||
paint_if.precede(paint_run);
|
||||
paint_run.precede(paint_done);
|
||||
flow_ready = true;
|
||||
}
|
||||
template <Attached Object>
|
||||
void prepare_data(Object*) {}
|
||||
template <Attached Object>
|
||||
void after_prepare_data(Object*) {}
|
||||
template <Attached Object>
|
||||
void after_exchange(Object* object, Prop*, State*, const Prop*, const State*) {
|
||||
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
||||
const auto& state = *object->d.state.render;
|
||||
if (private_data.template need_update_prepare_graph<Object>(object, state)) {
|
||||
prepare_graph_dirty = true;
|
||||
object->template mark_dirty<Prepare_Data_Tag>();
|
||||
}
|
||||
if (private_data.template need_update_paint_graph<Object>(object, state)) {
|
||||
paint_graph_dirty = true;
|
||||
object->template mark_dirty<Paint_Tag>();
|
||||
}
|
||||
}
|
||||
template <Attached Object>
|
||||
void paint(Object*) {}
|
||||
friend struct Renderable;
|
||||
};
|
||||
private:
|
||||
template <Attached Object>
|
||||
void bind_rely_node(Rely::Node* node) {
|
||||
auto* object = static_cast<Object*>(this);
|
||||
void bind_rely_node(Rely::Node* node, Attached auto* object) {
|
||||
using Object = std::remove_pointer_t<decltype(object)>;
|
||||
auto& data = static_cast<Private&>(object->d);
|
||||
data.need_prepare_call = [](Root* root, bool dirty) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
||||
return private_data.template need_prepare<Object>(value, *value->d.state.render, dirty);
|
||||
return private_data.need_prepare(value, *value->d.state.render, dirty);
|
||||
};
|
||||
data.need_paint_call = [](Root* root, bool dirty) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
||||
return private_data.template need_paint<Object>(value, *value->d.state.render, dirty);
|
||||
return private_data.need_paint(value, *value->d.state.render, dirty);
|
||||
};
|
||||
data.make_prepare_call = [](Root* root, Secene::Private& graph) {
|
||||
data.update_prepare_call = [](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
||||
private_data.template make_prepare_graph<Object>(value, *value->d.state.render, graph);
|
||||
return private_data.need_update_prepare_graph(value, *value->d.state.render);
|
||||
};
|
||||
data.make_paint_call = [](Root* root, Secene::Private& graph) {
|
||||
data.update_paint_call = [](Root* root) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
||||
private_data.template make_paint_graph<Object>(value, *value->d.state.render, graph);
|
||||
return private_data.need_update_paint_graph(value, *value->d.state.render);
|
||||
};
|
||||
data.make_prepare_call = [](Root* root, std::pmr::memory_resource* resource) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
||||
return private_data.make_prepare_graph(value, *value->d.state.render, resource);
|
||||
};
|
||||
data.make_paint_call = [](Root* root, std::pmr::memory_resource* resource) {
|
||||
auto* value = static_cast<Object*>(root);
|
||||
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
||||
return private_data.make_paint_graph(value, *value->d.state.render, resource);
|
||||
};
|
||||
if (!data.flow_ready) data.make_flow(object);
|
||||
object->template mark_dirty<Prepare_Data_Tag>();
|
||||
node->data = &data;
|
||||
}
|
||||
friend struct ::aethera::Rely;
|
||||
};
|
||||
template <Attached Object>
|
||||
void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*, const State*) {
|
||||
auto* resource = object->memory_resource();
|
||||
void Secene::Private::after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*) {
|
||||
auto* resource = detail::task_memory_resource();
|
||||
std::pmr::unordered_set<Root*> exchanged{resource};
|
||||
exchanged.insert(object);
|
||||
// 交换双缓冲
|
||||
object->for_each_render_rely(
|
||||
[&](const Rely& rely) {
|
||||
rely.for_each(
|
||||
@@ -241,44 +193,30 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*,
|
||||
);
|
||||
}
|
||||
);
|
||||
auto& prepare_state = object->d.rely_storage.template get<Prepare_Data_Tag>();
|
||||
auto& paint_state = object->d.rely_storage.template get<Paint_Tag>();
|
||||
bool prepare_graph_dirty = prepare_state.dirty();
|
||||
bool paint_graph_dirty = paint_state.dirty();
|
||||
bool scene_graph_dirty = !graph_ready;
|
||||
object->template render_rely<Prepare_Data_Tag, Paint_Tag>(
|
||||
[&](auto& prepare_state, auto& paint_state) {
|
||||
scene_graph_dirty = scene_graph_dirty || prepare_state.dirty() || paint_state.dirty();
|
||||
}
|
||||
);
|
||||
if (!scene_graph_dirty) return;
|
||||
const auto& prepare_rely = object->template render_rely<Prepare_Data_Tag>();
|
||||
const auto& paint_rely = object->template render_rely<Paint_Tag>();
|
||||
std::pmr::unordered_set<Root*> renderables{resource};
|
||||
prepare_rely.for_each(
|
||||
[&](const Rely::Node& node) {
|
||||
if (!node.data) return;
|
||||
renderables.insert(node.object);
|
||||
auto* data = static_cast<Renderable::Private*>(node.data);
|
||||
prepare_graph_dirty = prepare_graph_dirty || data->prepare_graph_dirty;
|
||||
paint_graph_dirty = paint_graph_dirty || data->paint_graph_dirty;
|
||||
if (node.data) renderables.insert(node.object);
|
||||
}
|
||||
);
|
||||
paint_rely.for_each(
|
||||
[&](const Rely::Node& node) {
|
||||
if (!node.data) return;
|
||||
renderables.insert(node.object);
|
||||
auto* data = static_cast<Renderable::Private*>(node.data);
|
||||
prepare_graph_dirty = prepare_graph_dirty || data->prepare_graph_dirty;
|
||||
paint_graph_dirty = paint_graph_dirty || data->paint_graph_dirty;
|
||||
if (node.data) renderables.insert(node.object);
|
||||
}
|
||||
);
|
||||
if (graph && !prepare_graph_dirty && !paint_graph_dirty) return;
|
||||
if (graph) graph->wait_for_all();
|
||||
tasks.reset();
|
||||
start.reset();
|
||||
graph.reset();
|
||||
graph = std::make_unique<oneapi::tbb::flow::graph>();
|
||||
start = std::make_unique<oneapi::tbb::flow::broadcast_node<Message>>(*graph);
|
||||
tasks = std::make_unique<std::pmr::list<Task>>(resource);
|
||||
graph.clear();
|
||||
struct Endpoints {
|
||||
Task* prepare_entry;
|
||||
Task* prepare_exit;
|
||||
Task* paint_entry;
|
||||
Task* paint_exit;
|
||||
tf::Task prepare;
|
||||
tf::Task paint;
|
||||
};
|
||||
std::pmr::unordered_map<Root*, Endpoints> endpoints{resource};
|
||||
for (auto* root : renderables) {
|
||||
@@ -286,74 +224,11 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*,
|
||||
if (!rely_node || !rely_node->data) rely_node = paint_rely.find(root);
|
||||
if (!rely_node || !rely_node->data) continue;
|
||||
auto* data = static_cast<Renderable::Private*>(rely_node->data);
|
||||
tasks->emplace_back(
|
||||
*graph,
|
||||
nullptr,
|
||||
[root, data] {
|
||||
data->prepare_enabled = data->need_prepare_call(root, root->template dirty<Prepare_Data_Tag>());
|
||||
}
|
||||
);
|
||||
auto* prepare_entry = &tasks->back();
|
||||
tasks->emplace_back(
|
||||
*graph,
|
||||
nullptr,
|
||||
[root, data] {
|
||||
if (!data->prepare_enabled) return;
|
||||
root->template take_dirty<Prepare_Data_Tag>();
|
||||
root->template mark_dirty<Paint_Tag>();
|
||||
}
|
||||
);
|
||||
auto* prepare_exit = &tasks->back();
|
||||
tasks->emplace_back(
|
||||
*graph,
|
||||
nullptr,
|
||||
[root, data] {
|
||||
data->paint_enabled = data->need_paint_call(root, root->template dirty<Paint_Tag>());
|
||||
}
|
||||
);
|
||||
auto* paint_entry = &tasks->back();
|
||||
tasks->emplace_back(
|
||||
*graph,
|
||||
nullptr,
|
||||
[root, data] {
|
||||
if (data->paint_enabled) root->template take_dirty<Paint_Tag>();
|
||||
}
|
||||
);
|
||||
auto* paint_exit = &tasks->back();
|
||||
oneapi::tbb::flow::make_edge(*start, prepare_entry->gate);
|
||||
oneapi::tbb::flow::make_edge(*start, paint_entry->gate);
|
||||
oneapi::tbb::flow::make_edge(prepare_exit->execute, paint_entry->gate);
|
||||
auto prepare_begin = tasks->size();
|
||||
building_enabled = &data->prepare_enabled;
|
||||
data->make_prepare_call(root, *this);
|
||||
if (tasks->size() == prepare_begin) {
|
||||
oneapi::tbb::flow::make_edge(prepare_entry->execute, prepare_exit->gate);
|
||||
}
|
||||
else {
|
||||
std::size_t index = 0;
|
||||
for (auto& task : *tasks) {
|
||||
if (index++ < prepare_begin) continue;
|
||||
oneapi::tbb::flow::make_edge(prepare_entry->execute, task.gate);
|
||||
oneapi::tbb::flow::make_edge(task.execute, prepare_exit->gate);
|
||||
}
|
||||
}
|
||||
auto paint_begin = tasks->size();
|
||||
building_enabled = &data->paint_enabled;
|
||||
data->make_paint_call(root, *this);
|
||||
if (tasks->size() == paint_begin) {
|
||||
oneapi::tbb::flow::make_edge(paint_entry->execute, paint_exit->gate);
|
||||
}
|
||||
else {
|
||||
std::size_t index = 0;
|
||||
for (auto& task : *tasks) {
|
||||
if (index++ < paint_begin) continue;
|
||||
oneapi::tbb::flow::make_edge(paint_entry->execute, task.gate);
|
||||
oneapi::tbb::flow::make_edge(task.execute, paint_exit->gate);
|
||||
}
|
||||
}
|
||||
endpoints.emplace(root, Endpoints{prepare_entry, prepare_exit, paint_entry, paint_exit});
|
||||
auto prepare = graph.composed_of(data->prepare_flow);
|
||||
auto paint = graph.composed_of(data->paint_flow);
|
||||
prepare.precede(paint);
|
||||
endpoints.emplace(root, Endpoints{prepare, paint});
|
||||
}
|
||||
building_enabled = nullptr;
|
||||
auto connect_rely = [&](const Rely& rely, bool prepare) {
|
||||
rely.for_each(
|
||||
[&](const Rely::Node& rely_node) {
|
||||
@@ -370,9 +245,9 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*,
|
||||
if (dependency->data) {
|
||||
auto source = endpoints.find(dependency->object);
|
||||
if (source != endpoints.end()) {
|
||||
auto* source_exit = prepare ? source->second.prepare_exit : source->second.paint_exit;
|
||||
auto* target_entry = prepare ? target->second.prepare_entry : target->second.paint_entry;
|
||||
oneapi::tbb::flow::make_edge(source_exit->execute, target_entry->gate);
|
||||
auto source_task = prepare ? source->second.prepare : source->second.paint;
|
||||
auto target_task = prepare ? target->second.prepare : target->second.paint;
|
||||
source_task.precede(target_task);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -383,15 +258,12 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*,
|
||||
};
|
||||
connect_rely(prepare_rely, true);
|
||||
connect_rely(paint_rely, false);
|
||||
if (prepare_state.dirty()) prepare_state.take_dirty();
|
||||
if (paint_state.dirty()) paint_state.take_dirty();
|
||||
for (auto* root : renderables) {
|
||||
const Rely::Node* rely_node = prepare_rely.find(root);
|
||||
if (!rely_node || !rely_node->data) rely_node = paint_rely.find(root);
|
||||
if (!rely_node || !rely_node->data) continue;
|
||||
auto* data = static_cast<Renderable::Private*>(rely_node->data);
|
||||
data->prepare_graph_dirty = false;
|
||||
data->paint_graph_dirty = false;
|
||||
}
|
||||
object->template render_rely<Prepare_Data_Tag, Paint_Tag>(
|
||||
[](auto& prepare_state, auto& paint_state) {
|
||||
if (prepare_state.dirty()) prepare_state.take_dirty();
|
||||
if (paint_state.dirty()) paint_state.take_dirty();
|
||||
}
|
||||
);
|
||||
graph_ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user