This commit is contained in:
2026-08-20 12:46:32 +08:00
parent 4d49dd3c18
commit f379907f1b
8 changed files with 141 additions and 67 deletions
View File
-2
View File
@@ -1,2 +0,0 @@
#pragma once
#include "base/object.hpp"
+1 -1
View File
@@ -18,7 +18,7 @@
#include <unordered_set>
#include <utility>
#include <vector>
namespace aethera {
namespace double_buffer {
template <typename T>
concept Lockable = requires(T& lock) {
{ lock.lock() } -> std::same_as<void>;
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "rely_storage.hpp"
namespace aethera {
namespace double_buffer {
template <typename T>
concept Object = requires {
requires Object_Root<T>;
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "core.hpp"
namespace aethera {
namespace double_buffer {
struct Rely {
using Error = Rely_Error;
struct Node {
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "rely.hpp"
namespace aethera {
namespace double_buffer {
namespace detail {
template <typename Callback, typename Tuple, typename... Tags>
concept Rely_Edit_Callback_For = Rely_List<Tuple> && std::invocable<
+10 -10
View File
@@ -2,13 +2,13 @@
#include <chrono>
#include <limits>
#include <taskflow/observer/interface.hpp>
namespace aethera::render {
namespace aethera {
namespace {
class Stage_Registry : Pinned {
class Stage_Registry : ::double_buffer::Pinned {
private:
struct Binding {
const tf::Taskflow* owner;
Root* object;
::double_buffer::Root* object;
Renderable::Private* data;
detail::Renderable_Stage stage;
detail::Stage_Observer_Point point;
@@ -16,7 +16,7 @@ private:
std::unordered_map<std::size_t, Binding> bindings;
std::mutex mutex;
public:
void bind(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) {
void bind(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) {
std::lock_guard guard(mutex);
bindings.insert_or_assign(task_hash, Binding{owner, object, data, stage, point});
}
@@ -246,7 +246,7 @@ public:
state.longest_task_type = longest_task_type;
}
};
class Task_Resource : Pinned {
class Task_Resource : ::double_buffer::Pinned {
private:
std::unique_ptr<tf::Executor> executor;
std::shared_ptr<Task_Observer> observer;
@@ -257,7 +257,7 @@ private:
std::atomic_size_t completed_taskflows{};
std::atomic_size_t failed_taskflows{};
Task_Runtime_State state;
::aethera::detail::State_Callback_Storage<Task_Runtime_State> state_callbacks;
::double_buffer::detail::State_Callback_Storage<Task_Runtime_State> state_callbacks;
std::recursive_mutex state_mutex;
void create_executor(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface) {
executor = std::make_unique<tf::Executor>(workers, std::move(worker_interface));
@@ -285,7 +285,7 @@ public:
static Task_Resource value;
return value;
}
void initialize(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, Pmr pmr) {
void initialize(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, ::double_buffer::Pmr pmr) {
std::lock_guard guard(state_mutex);
memory = pmr.resource();
create_executor(workers, std::move(worker_interface));
@@ -315,7 +315,7 @@ public:
publish_state();
return elapsed;
}
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) {
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) {
stage_registry.bind(owner, task_hash, object, data, stage, point);
}
void clear_stage_observers(const tf::Taskflow* owner) {
@@ -334,7 +334,7 @@ public:
}
};
}
void initialize_runtime(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, Pmr pmr) {
void initialize_runtime(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, ::double_buffer::Pmr pmr) {
Task_Resource::instance().initialize(workers, std::move(worker_interface), pmr);
}
namespace detail {
@@ -347,7 +347,7 @@ void clear_runtime_state_callback() {
std::uint64_t run_taskflow(tf::Taskflow& taskflow) {
return Task_Resource::instance().run(taskflow);
}
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point) {
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point) {
Task_Resource::instance().bind_stage_observer(owner, task_hash, object, data, stage, point);
}
void clear_stage_observers(const tf::Taskflow* owner) {
+127 -51
View File
@@ -1,5 +1,5 @@
#pragma once
#include "base.hpp"
#include "base/object.hpp"
#include <array>
#include <string>
#include <taskflow/taskflow.hpp>
@@ -30,7 +30,7 @@ struct Task_Worker_State {
double utilization{};
bool operator==(const Task_Worker_State&) const = default;
};
struct Task_Runtime_State : State_Type<Task_Runtime_State_Tag> {
struct Task_Runtime_State : ::double_buffer::State_Type<Task_Runtime_State_Tag> {
std::size_t worker_count{};
std::size_t active_topology_count{};
std::size_t active_taskflow_count{};
@@ -63,7 +63,7 @@ struct Task_Runtime_State : State_Type<Task_Runtime_State_Tag> {
};
void initialize_runtime(std::size_t workers = std::thread::hardware_concurrency(),
std::shared_ptr<tf::WorkerInterface> worker_interface = nullptr,
Pmr pmr = {});
::double_buffer::Pmr pmr = {});
namespace detail {
void set_runtime_state_callback(std::function<void(const Task_Runtime_State&)> callback);
void clear_runtime_state_callback();
@@ -80,30 +80,72 @@ void clear_runtime_state_callback() {
detail::clear_runtime_state_callback();
}
struct Renderable;
/*
* Prepare
* Private
* void prepare_data(T* object);
* build_prepare_graph(...)
* prepare_data(...) build_prepare_graph(...) Prepare
* prepare_data(...)
*/
template <typename T>
concept Prepare_Data_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object) {
concept Prepare_Data_Renderable = ::double_buffer::Attached<T> && requires(typename T::Private& private_data, T* object) {
{ private_data.prepare_data(object) } -> std::same_as<void>;
};
/*
* Prepare
* Private
* tf::Taskflow build_prepare_graph(T* object, const T::State& state);
* Prepare
* should_rebuild_prepare_graph(...) true
* PMR 使 detail::task_memory_resource()
* std::pmr::memory_resource Renderable
* Taskflow
*/
template <typename T>
concept Prepare_Graph_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::State& state, std::pmr::memory_resource* resource) {
{ private_data.build_prepare_graph(object, state, resource) } -> std::same_as<tf::Taskflow>;
concept Prepare_Graph_Renderable = ::double_buffer::Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::State& state) {
{ private_data.build_prepare_graph(object, state) } -> std::same_as<tf::Taskflow>;
};
/*
* Paint
* Private
* void paint(T* object);
* build_paint_graph(...)
* paint(...) build_paint_graph(...) Paint
* paint(...)
*/
template <typename T>
concept Paint_Data_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object) {
concept Paint_Data_Renderable = ::double_buffer::Attached<T> && requires(typename T::Private& private_data, T* object) {
{ private_data.paint(object) } -> std::same_as<void>;
};
/*
* Paint
* Private
* tf::Taskflow build_paint_graph(T* object, const T::State& state);
* Paint
* should_rebuild_paint_graph(...) true
* PMR 使 detail::task_memory_resource()
* std::pmr::memory_resource Renderable
* Taskflow
*/
template <typename T>
concept Paint_Graph_Renderable = Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::State& state, std::pmr::memory_resource* resource) {
{ private_data.build_paint_graph(object, state, resource) } -> std::same_as<tf::Taskflow>;
concept Paint_Graph_Renderable = ::double_buffer::Attached<T> && requires(typename T::Private& private_data, T* object, const typename T::State& state) {
{ private_data.build_paint_graph(object, state) } -> std::same_as<tf::Taskflow>;
};
/*
* Renderable
* Prepare Paint
* should_prepare(...)should_paint(...)should_rebuild_prepare_graph(...)
* should_rebuild_paint_graph(...) Renderable::Private
*/
template <typename T>
concept Renderable_Object = Attached<T> && std::derived_from<T, Renderable> && requires(typename T::Private& private_data, T* object, const typename T::State& state, bool dirty) {
concept Renderable_Object = ::double_buffer::Attached<T> && std::derived_from<T, Renderable> && requires(typename T::Private& private_data, T* object, const typename T::State& state, bool dirty) {
{ private_data.should_prepare(object, state, dirty) } -> std::same_as<bool>;
{ private_data.should_paint(object, state, dirty) } -> std::same_as<bool>;
{ private_data.should_rebuild_prepare_graph(object, state) } -> std::same_as<bool>;
{ private_data.should_rebuild_paint_graph(object, state) } -> std::same_as<bool>;
} && (Prepare_Data_Renderable<T> || Prepare_Graph_Renderable<T>) && (Paint_Data_Renderable<T> || Paint_Graph_Renderable<T>);
struct Renderable : Impl<Renderable, Root, State_Type<Renderable_State_Tag>, Tagged_Buffer<Color_Cache>> {
struct Renderable : ::double_buffer::Impl<Renderable, ::double_buffer::Root, ::double_buffer::State_Type<Renderable_State_Tag>, ::double_buffer::Tagged_Buffer<Color_Cache>> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Renderable_State_Tag> {
bool prepare_dirty{};
@@ -130,12 +172,12 @@ protected:
}
public:
struct Private : Prev_Private {
using Run_Predicate = bool (*)(Root*, bool);
using Rebuild_Predicate = bool (*)(Root*);
using Stage_Run = void (*)(Root*);
using Graph_Builder = tf::Taskflow (*)(Root*, std::pmr::memory_resource*);
using State_Access = State* (*)(Root*);
using State_Notify = void (*)(Root*);
using Run_Predicate = bool (*)(::double_buffer::Root*, bool);
using Rebuild_Predicate = bool (*)(::double_buffer::Root*);
using Stage_Run = void (*)(::double_buffer::Root*);
using Graph_Builder = tf::Taskflow (*)(::double_buffer::Root*);
using State_Access = State* (*)(::double_buffer::Root*);
using State_Notify = void (*)(::double_buffer::Root*);
struct Stage_Dispatch {
Run_Predicate predicate;
Rebuild_Predicate rebuild_predicate;
@@ -156,40 +198,74 @@ public:
std::unique_ptr<tf::Taskflow> paint_graph;
bool prepare_graph_built{};
bool paint_graph_built{};
bool should_rebuild_prepare_graph(Attached auto*, const State&) {
/*
* Prepare
* Private
* bool should_rebuild_prepare_graph(T* object, const T::State& state);
* build_prepare_graph(...) 使
* false
*/
bool should_rebuild_prepare_graph(::double_buffer::Attached auto*, const State&) {
return false;
}
bool should_rebuild_paint_graph(Attached auto*, const State&) {
/*
* Paint
* Private
* bool should_rebuild_paint_graph(T* object, const T::State& state);
* build_paint_graph(...) 使
* false
*/
bool should_rebuild_paint_graph(::double_buffer::Attached auto*, const State&) {
return false;
}
bool should_prepare(Attached auto*, const State&, bool dirty) {
/*
* Prepare
* Private
* bool should_prepare(T* object, const T::State& state, bool dirty);
* dirty Prepare
* true Prepare false dirty true
*/
bool should_prepare(::double_buffer::Attached auto*, const State&, bool dirty) {
return dirty;
}
bool should_paint(Attached auto*, const State&, bool dirty) {
/*
* Paint
* Private
* bool should_paint(T* object, const T::State& state, bool dirty);
* dirty Paint
* true Paint false dirty true
*/
bool should_paint(::double_buffer::Attached auto*, const State&, bool dirty) {
return dirty;
}
void after_prepare_data(Attached auto*) {}
/*
* Prepare
* Private
* void after_prepare_data(T* object);
* prepare_data(...) Prepare
*/
void after_prepare_data(::double_buffer::Attached auto*) {}
};
private:
void bind_rely_object(Attached auto* object) {
void bind_rely_object(::double_buffer::Attached auto* object) {
using Object = std::remove_pointer_t<decltype(object)>;
static_assert(Renderable_Object<Object>);
auto& data = static_cast<Private&>(object->d);
static const Private::Dispatch dispatch{
{
[](Root* root, bool dirty) {
[](::double_buffer::Root* root, bool dirty) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
return private_data.should_prepare(value, *value->d.state.current, dirty);
},
[](Root* root) {
[](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
return private_data.should_rebuild_prepare_graph(value, *value->d.state.current);
},
[]() -> Private::Stage_Run {
if constexpr (Prepare_Data_Renderable<Object>) {
return [](Root* root) {
return [](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
run_prepare_data(value);
};
@@ -200,10 +276,10 @@ private:
}(),
[]() -> Private::Graph_Builder {
if constexpr (Prepare_Graph_Renderable<Object>) {
return [](Root* root, std::pmr::memory_resource* resource) {
return [](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
return private_data.build_prepare_graph(value, *value->d.state.current, resource);
return private_data.build_prepare_graph(value, *value->d.state.current);
};
}
else {
@@ -212,19 +288,19 @@ private:
}()
},
{
[](Root* root, bool dirty) {
[](::double_buffer::Root* root, bool dirty) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
return private_data.should_paint(value, *value->d.state.current, dirty);
},
[](Root* root) {
[](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
return private_data.should_rebuild_paint_graph(value, *value->d.state.current);
},
[]() -> Private::Stage_Run {
if constexpr (Paint_Data_Renderable<Object>) {
return [](Root* root) {
return [](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
private_data.paint(value);
@@ -236,10 +312,10 @@ private:
}(),
[]() -> Private::Graph_Builder {
if constexpr (Paint_Graph_Renderable<Object>) {
return [](Root* root, std::pmr::memory_resource* resource) {
return [](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(value->d);
return private_data.build_paint_graph(value, *value->d.state.current, resource);
return private_data.build_paint_graph(value, *value->d.state.current);
};
}
else {
@@ -248,11 +324,11 @@ private:
}()
},
{
[](Root* root) {
[](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
return static_cast<State*>(value->d.state.current);
},
[](Root* root) {
[](::double_buffer::Root* root) {
auto* value = static_cast<Object*>(root);
value->template notify_state<Renderable_State_Tag>();
}
@@ -261,7 +337,7 @@ private:
data.dispatch = &dispatch;
object->template mark_dirty<Prepare_Data_Tag>();
}
friend struct ::aethera::Rely;
friend struct ::double_buffer::Rely;
};
namespace detail {
enum class Renderable_Stage {
@@ -272,10 +348,10 @@ enum class Stage_Observer_Point {
Begin,
End
};
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point);
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point);
void clear_stage_observers(const tf::Taskflow* owner);
}
struct Scene : Impl<Scene, Root, State_Type<Scene_State_Tag>, Rely_Type<Prepare_Data_Tag, Renderable>, Rely_Type<Paint_Tag, Renderable>> {
struct Scene : ::double_buffer::Impl<Scene, ::double_buffer::Root, ::double_buffer::State_Type<Scene_State_Tag>, ::double_buffer::Rely_Type<Prepare_Data_Tag, Renderable>, ::double_buffer::Rely_Type<Paint_Tag, Renderable>> {
struct Prop : Prev_Prop {};
struct State : Prev_State<Scene_State_Tag> {
bool taskflow_rebuilt{};
@@ -301,9 +377,9 @@ struct Scene : Impl<Scene, Root, State_Type<Scene_State_Tag>, Rely_Type<Prepare_
~Private() {
detail::clear_stage_observers(&taskflow);
}
void after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*);
void after_exchange(::double_buffer::Attached auto* object, Prop*, State*, const Prop*, const State*);
template <std::invocable<const Result&> Callback>
void process(Attached auto* object, Callback&& callback) {
void process(::double_buffer::Attached auto* object, Callback&& callback) {
auto& state = static_cast<State&>(*object->d.state.current);
state.taskflow_rebuilt = taskflow_rebuilt;
state.renderable_count = renderable_count;
@@ -319,15 +395,15 @@ struct Scene : Impl<Scene, Root, State_Type<Scene_State_Tag>, Rely_Type<Prepare_
}
};
};
void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*) {
void Scene::Private::after_exchange(::double_buffer::Attached auto* object, Prop*, State*, const Prop*, const State*) {
auto* resource = detail::task_memory_resource();
taskflow_rebuilt = false;
std::pmr::unordered_set<Root*> exchanged_objects{resource};
std::pmr::unordered_set<::double_buffer::Root*> exchanged_objects{resource};
exchanged_objects.insert(object);
object->for_each_current_rely(
[&](const Rely& rely) {
[&](const ::double_buffer::Rely& rely) {
rely.for_each(
[&](const Rely::Node& node) {
[&](const ::double_buffer::Rely::Node& node) {
if (exchanged_objects.insert(node.object).second) node.object->exchange_object();
}
);
@@ -362,9 +438,9 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const
tf::Task paint_entry;
tf::Task paint_exit;
};
std::pmr::unordered_map<Root*, Stage_Tasks> stage_tasks{resource};
std::pmr::unordered_map<::double_buffer::Root*, Stage_Tasks> stage_tasks{resource};
for (auto* renderable : renderables) {
Root* root = renderable;
::double_buffer::Root* root = renderable;
auto* data = prepare_dependencies.private_data(root);
if (!data) data = paint_dependencies.private_data(root);
if (!data) continue;
@@ -376,7 +452,7 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const
if (dispatch->prepare.builder) {
bool rebuild = dispatch->prepare.rebuild_predicate(root);
if (!data->prepare_graph_built || rebuild) {
*data->prepare_graph = dispatch->prepare.builder(root, detail::task_memory_resource());
*data->prepare_graph = dispatch->prepare.builder(root);
data->prepare_graph_built = true;
state.prepare_graph_rebuilt = true;
root->template mark_dirty<Prepare_Data_Tag>();
@@ -416,7 +492,7 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const
if (dispatch->paint.builder) {
bool rebuild = dispatch->paint.rebuild_predicate(root);
if (!data->paint_graph_built || rebuild) {
*data->paint_graph = dispatch->paint.builder(root, detail::task_memory_resource());
*data->paint_graph = dispatch->paint.builder(root);
data->paint_graph_built = true;
state.paint_graph_rebuilt = true;
root->template mark_dirty<Paint_Tag>();
@@ -457,12 +533,12 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const
}
auto connect_dependencies = [&](const auto& rely, bool prepare) {
rely.for_each(
[&](const Rely::Node& rely_node) {
[&](const ::double_buffer::Rely::Node& rely_node) {
if (!rely.private_data(rely_node)) return;
auto target = stage_tasks.find(rely_node.object);
if (target == stage_tasks.end()) return;
std::pmr::unordered_set<Root*> visited{resource};
std::pmr::vector<const Rely::Node*> pending{resource};
std::pmr::unordered_set<::double_buffer::Root*> visited{resource};
std::pmr::vector<const ::double_buffer::Rely::Node*> pending{resource};
for (const auto* dependency : rely_node.dependencies) pending.push_back(dependency);
while (!pending.empty()) {
const auto* dependency = pending.back();