添加外部内存数据源

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
+43 -42
View File
@@ -2,72 +2,73 @@ cmake_minimum_required(VERSION 3.20)
project(Renderive_Scene_Taskflow LANGUAGES CXX)
set(RENDERIVE_TASKFLOW_ROOT "" CACHE PATH "Taskflow 4.1.0 root")
find_path(RENDERIVE_TASKFLOW_INCLUDE_DIR
NAMES taskflow/taskflow.hpp
PATHS
NAMES taskflow/taskflow.hpp
PATHS
"${RENDERIVE_TASKFLOW_ROOT}"
"${RENDERIVE_TASKFLOW_ROOT}/include"
"${CMAKE_CURRENT_LIST_DIR}/third_party/taskflow"
"${CMAKE_CURRENT_LIST_DIR}/third_party/taskflow/include"
)
if(NOT RENDERIVE_TASKFLOW_INCLUDE_DIR)
if (NOT RENDERIVE_TASKFLOW_INCLUDE_DIR)
set(RENDERIVE_TASKFLOW_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/tests/compat")
message(STATUS "Taskflow 4.1.0 not found; using the private dependency-graph compatibility layer")
endif()
endif ()
add_library(renderive_scene STATIC
"${CMAKE_CURRENT_LIST_DIR}/src/renderive/renderable/Renderable_Task_Graph.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/renderive/renderable/base/Renderable_Base.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/renderive/scene/base/Scene_Base.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/renderive/renderable/Renderable_Task_Graph.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/renderive/renderable/base/Renderable_Base.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/renderive/scene/base/Scene_Base.cpp"
)
target_include_directories(renderive_scene
PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/src>"
PRIVATE "${RENDERIVE_TASKFLOW_INCLUDE_DIR}"
PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/src>"
PRIVATE "${RENDERIVE_TASKFLOW_INCLUDE_DIR}"
)
target_compile_features(renderive_scene PUBLIC cxx_std_20)
find_package(Threads REQUIRED)
target_link_libraries(renderive_scene PRIVATE Threads::Threads)
set(renderive_test_sources
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/node/Multiway_Node_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/observer/Observer_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/observer/time_source/Steady_Time_Source_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/property/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/property/Property_Builder_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/property/Validated_Value_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/base/Frame_Control_Strategy_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/concept/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/real_time_data/base/Real_Time_Data_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/real_time_data/Real_Time_Data_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/base/Renderable_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/color/Color_Cache_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/concept/Renderable_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/Renderable_Task_Graph_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/base/Scene_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/concept/Scene_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene2D_Context_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene2D_Render_Order_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene3D_Context_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene_State_Observer_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/base/State_Strategy_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/Double_State_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/Triple_State_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/node/Multiway_Node_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/observer/Observer_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/observer/time_source/Steady_Time_Source_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/property/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/property/Property_Builder_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/base/property/Validated_Value_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/base/Frame_Control_Strategy_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/concept/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/real_time_data/base/Real_Time_Data_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/real_time_data/Real_Time_Data_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/base/Renderable_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/color/Color_Cache_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/concept/Renderable_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/renderable/Renderable_Task_Graph_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/base/Scene_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene_Memory_Resource_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/concept/Scene_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene2D_Context_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene2D_Render_Order_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene3D_Context_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/scene/Scene_State_Observer_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/base/State_Strategy_Base_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/Concepts_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/Double_State_Strategy_Test.cpp"
"${CMAKE_CURRENT_LIST_DIR}/tests/renderive/state/Triple_State_Strategy_Test.cpp"
)
add_executable(renderive_scene_app "${CMAKE_CURRENT_LIST_DIR}/src/main.cpp")
add_executable(renderive_scene_app "tests/main.cpp")
target_link_libraries(renderive_scene_app PRIVATE renderive_scene)
include(CTest)
if(BUILD_TESTING)
if (BUILD_TESTING)
find_package(GTest CONFIG QUIET)
if(NOT GTest_FOUND)
if (NOT GTest_FOUND)
add_library(renderive_gtest_compat INTERFACE)
target_include_directories(renderive_gtest_compat INTERFACE "${CMAKE_CURRENT_LIST_DIR}/tests/compat")
add_library(GTest::gtest ALIAS renderive_gtest_compat)
message(STATUS "GTest not found; using the test-only compatibility runner")
endif()
endif ()
target_sources(renderive_scene_app PRIVATE ${renderive_test_sources})
target_compile_definitions(renderive_scene_app PRIVATE RENDERIVE_WITH_GTEST=1)
target_link_libraries(renderive_scene_app PRIVATE GTest::gtest)
add_test(NAME renderive_scene_tests COMMAND renderive_scene_app --gtest)
endif()
endif ()
+74
View File
@@ -98,3 +98,77 @@ renderive_scene_app --gtest
## Taskflow 查找
CMake 通过 `RENDERIVE_TASKFLOW_ROOT` 或系统 include 路径查找 `taskflow/taskflow.hpp`。Taskflow 不存在时,仅测试和沙盒构建使用 `tests/compat/taskflow/taskflow.hpp` 验证图生成与依赖语义;正式集成时把 `RENDERIVE_TASKFLOW_ROOT` 指向 Taskflow 4.1.0 根目录或 include 目录。
## Scene 内存域
`Scene_Base` 接受外部 `std::pmr::memory_resource` 作为上游资源。Scene 内部建立 `std::pmr::synchronized_pool_resource`,所有可能跨线程访问的持久容器都使用该线程安全内存域:
```cpp
std::pmr::unsynchronized_pool_resource application_resource;
Scene2D_Context<> scene(application_resource);
```
外部资源决定最终的上游分配机制。Scene 内部的同步池负责将来自调用线程、后台 Scene 线程和 Renderable 构图路径的分配串行化。外部资源必须比 Scene 以及由 Scene 工厂创建后仍存活的 Renderable 更长寿。
可通过以下接口访问两个层级:
```cpp
scene.upstream_memory_resource();
scene.memory_resource();
```
`upstream_memory_resource()` 返回构造时传入的资源;`memory_resource()` 返回 Scene 实际使用的线程安全同步池。
单次渲染构图不长期占用同步池。`Scene_Base::execute_taskflow()` 和 Scene2D 树顺序生成使用局部 `std::pmr::monotonic_buffer_resource`,返回后整体释放临时索引、标记和任务句柄容器。
## Renderable 两种构造模式
Scene 工厂模式同时控制 Renderable 对象、`shared_ptr` 控制块以及 Renderable 内部树和任务图分配:
```cpp
Scene2D_Context<> scene(memory_resource);
auto renderable = scene.make_renderable<Spectrum_Renderable>(configuration);
scene.attach_renderable(renderable);
```
工厂只构造对象,不自动挂载,`attach_renderable()` 的原有语义不变。工厂分配器持有 Scene 内存域的共享所有权,因此 Renderable 析构时内存域仍然有效。
独立构造模式继续保留:
```cpp
auto renderable = std::make_shared<Spectrum_Renderable>(scene, configuration);
Spectrum_Renderable stack_renderable(scene, configuration);
```
独立模式下,Renderable 对象本身和 `shared_ptr` 控制块由调用方选择的机制分配;`Multiway_Node``Renderable_Task_Graph`、任务名称和依赖边仍使用所属 Scene 的内存域。
## 独立 allocator-aware 组件
以下组件可脱离 Scene 独立注入资源:
- `Multiway_Node`
- `Renderable_Task_Graph`
- `Recording_Color_Cache`
- `Flow_Refresh_Strategy`
- `History_Real_Time_Data`
- `Property_Builder::build_with_resource()`
- `Property_Builder::build_unique_with_resource()`
`History_Real_Time_Data` 的时间戳容器始终使用传入资源。历史值容器只有在 `Container` 本身支持 PMR allocator 时才使用该资源:
```cpp
History_Real_Time_Data<int, std::pmr::vector<int>> history(memory_resource);
```
## 不受 Scene PMR 控制的分配
以下内存不属于 Renderive 自己的 allocator-aware 场景域:
- Taskflow 4.1.0 内部任务节点、执行队列和 executor 工作资源
- `std::function` 超出小对象优化后的内部存储
- `std::thread` 的系统线程对象和线程栈
- 异常运行时对象
- 用户自定义 State、Frame、Observer、Renderable 成员内部自行使用的非 PMR 容器
- 第三方渲染后端内部资源
Scene PMR 的语义是控制 Renderive 明确实现为 allocator-aware 的核心对象,不承诺接管第三方库和用户类型的全部动态分配。
@@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
#include <memory>
#include <memory_resource>
#include <utility>
class Scene_Memory_Domain {
public:
explicit Scene_Memory_Domain(std::pmr::memory_resource& upstream) : upstream_(&upstream), resource_(&upstream) {}
std::pmr::memory_resource& resource() noexcept {
return resource_;
}
std::pmr::memory_resource& upstream() noexcept {
return *upstream_;
}
private:
std::pmr::memory_resource* const upstream_;
std::pmr::synchronized_pool_resource resource_;
};
template <class Value>
class Scene_Memory_Allocator {
public:
using value_type = Value;
template <class Other>
struct rebind {
using other = Scene_Memory_Allocator<Other>;
};
Scene_Memory_Allocator() = delete;
explicit Scene_Memory_Allocator(std::shared_ptr<Scene_Memory_Domain> domain) noexcept : domain_(std::move(domain)) {}
template <class Other>
Scene_Memory_Allocator(const Scene_Memory_Allocator<Other>& other) noexcept : domain_(other.domain_) {}
Value* allocate(std::size_t count) {
return static_cast<Value*>(domain_->resource().allocate(count * sizeof(Value), alignof(Value)));
}
void deallocate(Value* pointer, std::size_t count) noexcept {
domain_->resource().deallocate(pointer, count * sizeof(Value), alignof(Value));
}
template <class Other>
bool operator==(const Scene_Memory_Allocator<Other>& other) const noexcept {
return domain_ == other.domain_;
}
private:
template <class>
friend class Scene_Memory_Allocator;
std::shared_ptr<Scene_Memory_Domain> domain_;
};
template <class Value>
struct Memory_Resource_Deleter {
std::pmr::memory_resource* resource{std::pmr::get_default_resource()};
void operator()(Value* value) const noexcept {
std::destroy_at(value);
resource->deallocate(value, sizeof(Value), alignof(Value));
}
};
template <class Value>
using Memory_Resource_Unique_Ptr = std::unique_ptr<Value, Memory_Resource_Deleter<Value>>;
template <class Value, class... Args>
Memory_Resource_Unique_Ptr<Value> make_memory_resource_unique(std::pmr::memory_resource& resource, Args&&... args) {
void* storage = resource.allocate(sizeof(Value), alignof(Value));
try {
Value* value = std::construct_at(static_cast<Value*>(storage), std::forward<Args>(args)...);
return Memory_Resource_Unique_Ptr<Value>(value, Memory_Resource_Deleter<Value>{&resource});
} catch (...) {
resource.deallocate(storage, sizeof(Value), alignof(Value));
throw;
}
}
@@ -1,12 +1,14 @@
#pragma once
#include <algorithm>
#include <cstddef>
#include <memory_resource>
#include <stdexcept>
#include <vector>
template <class Owner, class Tag = void>
class Multiway_Node {
public:
explicit Multiway_Node(Owner* owner = nullptr) noexcept : owner(owner) {}
explicit Multiway_Node(Owner* owner = nullptr, std::pmr::memory_resource& memory_resource = *std::pmr::get_default_resource()) noexcept
: owner(owner), children(&memory_resource) {}
Multiway_Node(const Multiway_Node&) = delete;
Multiway_Node& operator=(const Multiway_Node&) = delete;
Multiway_Node(Multiway_Node&&) = delete;
@@ -45,5 +47,5 @@ public:
}
Owner* owner{};
Multiway_Node* parent{};
std::vector<Multiway_Node*> children;
std::pmr::vector<Multiway_Node*> children;
};
@@ -1,6 +1,7 @@
#pragma once
#include "Concepts.hpp"
#include "Validators.hpp"
#include "renderive/base/memory/Memory_Resource.hpp"
#include <functional>
#include <memory>
#include <utility>
@@ -35,10 +36,22 @@ public:
}
template <class... Args>
requires Property_Constructible<Product, Properties, Args&&...>
std::shared_ptr<Product> build_with_resource(std::pmr::memory_resource& memory_resource, Args&&... args) const {
validator(properties);
return std::allocate_shared<Product>(std::pmr::polymorphic_allocator<Product>(&memory_resource), properties, std::forward<Args>(args)...);
}
template <class... Args>
requires Property_Constructible<Product, Properties, Args&&...>
std::unique_ptr<Product> build_unique(Args&&... args) const {
validator(properties);
return std::make_unique<Product>(properties, std::forward<Args>(args)...);
}
template <class... Args>
requires Property_Constructible<Product, Properties, Args&&...>
Memory_Resource_Unique_Ptr<Product> build_unique_with_resource(std::pmr::memory_resource& memory_resource, Args&&... args) const {
validator(properties);
return make_memory_resource_unique<Product>(memory_resource, properties, std::forward<Args>(args)...);
}
private:
Properties properties;
[[no_unique_address]] Validator validator;
@@ -3,9 +3,12 @@
#include <cstdint>
#include <deque>
#include <memory>
#include <memory_resource>
#include <mutex>
#include <utility>
#include <deque>
#include "renderive/base/Concepts.hpp"
#include "renderive/base/memory/Memory_Resource.hpp"
#include "renderive/base/observer/Observer.hpp"
#include "renderive/frame_control/base/Frame_Control_Strategy_Base.hpp"
#include "renderive/real_time_data/Observation.hpp"
@@ -67,7 +70,7 @@ public:
const Frame* get() const;
private:
Flow_Refresh_Strategy* strategy_{};
std::unique_ptr<Frame> frame_;
Memory_Resource_Unique_Ptr<Frame> frame_;
};
class Render_Lease {
public:
@@ -86,10 +89,11 @@ public:
const Frame* get() const;
private:
Flow_Refresh_Strategy* strategy_{};
std::unique_ptr<Frame> frame_;
Memory_Resource_Unique_Ptr<Frame> frame_;
std::unique_lock<Mutex> lease_lock_;
};
explicit Flow_Refresh_Strategy(Observer observer = {});
Flow_Refresh_Strategy(std::pmr::memory_resource& memory_resource, Observer observer = {});
Painter_Lease acquire_painter();
Render_Lease acquire_renderer();
void swap() override;
@@ -102,8 +106,9 @@ public:
private:
std::uint64_t now_ns() const noexcept;
void observe(const Observation& observation) noexcept;
std::pmr::memory_resource* const memory_resource_;
Observer observer_;
std::deque<std::unique_ptr<Frame>> frames_;
std::pmr::deque<Memory_Resource_Unique_Ptr<Frame>> frames_;
std::uint64_t next_sequence_{};
std::uint64_t real_time_data_update_sequence_{};
Real_Time_Data_Update_State last_real_time_data_update_;
@@ -1,7 +1,7 @@
#pragma once
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>::Painter_Lease::Painter_Lease(Flow_Refresh_Strategy& strategy)
: strategy_(&strategy), frame_(std::make_unique<Frame>()) {
: strategy_(&strategy), frame_(make_memory_resource_unique<Frame>(*strategy.memory_resource_)) {
std::lock_guard<Mutex> lock(strategy.state_mutex_);
frame_->statistics.sequence = ++strategy.next_sequence_;
frame_->statistics.real_time_data_update_sequence = strategy.real_time_data_update_sequence_;
@@ -136,7 +136,11 @@ auto Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>::Render_Lease::get() co
return frame_.get();
}
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>::Flow_Refresh_Strategy(Observer observer) : Frame_Control_Strategy_Base(), observer_(std::move(observer)) {}
Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>::Flow_Refresh_Strategy(Observer observer)
: Flow_Refresh_Strategy(*std::pmr::get_default_resource(), std::move(observer)) {}
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>::Flow_Refresh_Strategy(std::pmr::memory_resource& memory_resource, Observer observer)
: Frame_Control_Strategy_Base(), memory_resource_(&memory_resource), observer_(std::move(observer)), frames_(&memory_resource) {}
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
auto Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>::acquire_painter() -> Painter_Lease {
return Painter_Lease(*this);
@@ -2,6 +2,7 @@
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <memory_resource>
#include <mutex>
#include <utility>
#include <vector>
@@ -19,6 +20,7 @@ public:
static_assert(Real_Time_Data_History_Container<Container, Value>);
static_assert(Timed_Struct_Observer<Observer, Real_Time_Data_Observation>);
explicit History_Real_Time_Data(Observer observer = {});
History_Real_Time_Data(std::pmr::memory_resource& memory_resource, Observer observer = {});
History_Real_Time_Data(const History_Real_Time_Data&) = delete;
History_Real_Time_Data& operator=(const History_Real_Time_Data&) = delete;
void update(Value value);
@@ -37,10 +39,11 @@ public:
observer_.bind(target);
}
private:
static Container make_container(std::pmr::memory_resource& memory_resource);
mutable Mutex mutex_;
Observer observer_;
Container values_;
std::vector<std::uint64_t> update_times_;
std::pmr::vector<std::uint64_t> update_times_;
std::uint64_t revision_{};
std::uint64_t total_update_count_{};
std::uint64_t last_update_time_ns_{};
@@ -1,6 +1,23 @@
#pragma once
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::History_Real_Time_Data(Observer observer) : observer_(std::move(observer)) {}
History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::History_Real_Time_Data(Observer observer)
: History_Real_Time_Data(*std::pmr::get_default_resource(), std::move(observer)) {}
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::History_Real_Time_Data(std::pmr::memory_resource& memory_resource, Observer observer)
: observer_(std::move(observer)), values_(make_container(memory_resource)), update_times_(&memory_resource) {}
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
auto History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::make_container(std::pmr::memory_resource& memory_resource) -> Container {
if constexpr (requires { typename Container::allocator_type; }) {
using Allocator = typename Container::allocator_type;
if constexpr (std::constructible_from<Allocator, std::pmr::memory_resource*> && std::constructible_from<Container, Allocator>) {
return Container(Allocator(&memory_resource));
} else {
return Container();
}
} else {
return Container();
}
}
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
void History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::update(Value value) {
Real_Time_Data_Observation observation;
@@ -1,8 +1,10 @@
#include "Renderable_Task_Graph.hpp"
#include <stdexcept>
#include <utility>
Renderable_Task_Graph::Renderable_Task_Graph(std::pmr::memory_resource& memory_resource) noexcept
: memory_resource_(&memory_resource), nodes_(&memory_resource) {}
Renderable_Task_Graph::Task Renderable_Task_Graph::emplace(Task_Function function, std::string name) {
nodes_.push_back({std::move(function), std::move(name), {}});
nodes_.emplace_back(std::move(function), std::move(name), *memory_resource_);
return {nodes_.size() - 1};
}
void Renderable_Task_Graph::precede(Task from, Task to) {
@@ -17,6 +19,6 @@ void Renderable_Task_Graph::clear() {
bool Renderable_Task_Graph::empty() const noexcept {
return nodes_.empty();
}
const std::vector<Renderable_Task_Graph::Node>& Renderable_Task_Graph::nodes() const noexcept {
const std::pmr::vector<Renderable_Task_Graph::Node>& Renderable_Task_Graph::nodes() const noexcept {
return nodes_;
}
@@ -1,6 +1,7 @@
#pragma once
#include <cstddef>
#include <functional>
#include <memory_resource>
#include <string>
#include <vector>
#include "renderive/scene/base/Scene_Render_Context.hpp"
@@ -12,15 +13,19 @@ public:
friend bool operator==(Task, Task) = default;
};
struct Node {
Node(Task_Function function, std::string name, std::pmr::memory_resource& memory_resource)
: function(std::move(function)), name(name.data(), name.size(), &memory_resource), successors(&memory_resource) {}
Task_Function function;
std::string name;
std::vector<std::size_t> successors;
std::pmr::string name;
std::pmr::vector<std::size_t> successors;
};
explicit Renderable_Task_Graph(std::pmr::memory_resource& memory_resource = *std::pmr::get_default_resource()) noexcept;
Task emplace(Task_Function function, std::string name = {});
void precede(Task from, Task to);
void clear();
bool empty() const noexcept;
const std::vector<Node>& nodes() const noexcept;
const std::pmr::vector<Node>& nodes() const noexcept;
private:
std::vector<Node> nodes_;
std::pmr::memory_resource* const memory_resource_;
std::pmr::vector<Node> nodes_;
};
@@ -1,7 +1,7 @@
#include "Renderable_Base.hpp"
#include "renderive/scene/base/Scene_Base.hpp"
Renderable_Base::Renderable_Base(Scene_Base& scene, Renderable_Configuration configuration) noexcept
: scene(&scene), layer_node(this), dependency_node(this), configuration(configuration) {}
: scene(&scene), layer_node(this, scene.memory_resource()), dependency_node(this, scene.memory_resource()), configuration(configuration), memory_resource_(&scene.memory_resource()), task_graph_(*memory_resource_) {}
Renderable_Base::~Renderable_Base() = default;
void Renderable_Base::render(const Scene_Render_Context&) {}
void Renderable_Base::invalidate_cache() noexcept {
@@ -28,6 +28,9 @@ const Renderable_Task_Graph& Renderable_Base::task_graph() {
}
return task_graph_;
}
std::pmr::memory_resource& Renderable_Base::memory_resource() const noexcept {
return *memory_resource_;
}
void Renderable_Base::build_task_graph(Renderable_Task_Graph& graph) {
graph.emplace([this](const Scene_Render_Context& context) {
render(context);
@@ -1,6 +1,7 @@
#pragma once
#include <atomic>
#include <cstdint>
#include <memory_resource>
#include "renderive/base/node/Multiway_Node.hpp"
#include "renderive/renderable/Renderable_Task_Graph.hpp"
class Scene_Base;
@@ -22,6 +23,7 @@ public:
bool cache_valid() const noexcept;
void rebuild_task_graph() noexcept;
const Renderable_Task_Graph& task_graph();
std::pmr::memory_resource& memory_resource() const noexcept;
Scene_Base* scene;
Layer_Node layer_node;
Dependency_Node dependency_node;
@@ -33,6 +35,7 @@ private:
friend class Scene_Base;
bool requires_render() const noexcept;
void mark_rendered() noexcept;
std::pmr::memory_resource* const memory_resource_;
Renderable_Task_Graph task_graph_;
std::atomic<std::uint64_t> cache_revision_{1};
std::atomic<std::uint64_t> rendered_cache_revision_{};
@@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <memory_resource>
#include <vector>
class Color_Cache {
public:
@@ -9,6 +10,7 @@ public:
};
class Recording_Color_Cache : public Color_Cache {
public:
explicit Recording_Color_Cache(std::pmr::memory_resource& memory_resource = *std::pmr::get_default_resource()) : values(&memory_resource) {}
void clear() override {
values.clear();
++revision;
@@ -22,6 +24,6 @@ public:
values.push_back(value);
++revision;
}
std::vector<std::uint64_t> values;
std::pmr::vector<std::uint64_t> values;
std::uint64_t revision{};
};
+52 -15
View File
@@ -1,10 +1,13 @@
#pragma once
#include <algorithm>
#include <concepts>
#include <cstddef>
#include <memory>
#include <memory_resource>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "renderive/base/memory/Memory_Resource.hpp"
#include "renderive/base/observer/Observer.hpp"
#include "renderive/frame_control/Frame_Control.hpp"
#include "renderive/renderable/color/Concepts.hpp"
@@ -14,6 +17,8 @@ struct Scene2D_Frame_Data {};
struct Scene2D_State {
std::uint64_t revision{};
};
template <class Frame_Control, class... Args>
concept Scene2D_Frame_Control_Constructible = std::constructible_from<Frame_Control, Args...> || std::constructible_from<Frame_Control, std::pmr::memory_resource&, Args...>;
template <class Strategy = Low_Latency_Strategy<Scene2D_Frame_Data>, Color_Cache_Type Cache = Recording_Color_Cache, class State = Scene2D_State, class State_Observer = Observer_State<>, class Scene_Observer = Observer_State<>>
requires Frame_Control_Strategy_For<Strategy, Scene2D_Frame_Data> && State_Value<State>
class Scene2D_Context : public Triple_State_Strategy<Scene_2D_Base, State, Atomic_Spin_Mutex, State_Observer> {
@@ -27,14 +32,22 @@ public:
using Painter_Lease = typename Frame_Control::Painter_Lease;
using Render_Lease = typename Frame_Control::Render_Lease;
template <class... Args>
requires std::constructible_from<Frame_Control, Args&&...>
explicit Scene2D_Context(Args&&... args) : Scene_State_Strategy(), frame_control(std::forward<Args>(args)...), display_root(nullptr), dependency_root(nullptr) {
requires Scene2D_Frame_Control_Constructible<Frame_Control, Args&&...>
explicit Scene2D_Context(Args&&... args) : Scene2D_Context(*std::pmr::get_default_resource(), std::forward<Args>(args)...) {}
template <class... Args>
requires Scene2D_Frame_Control_Constructible<Frame_Control, Args&&...>
explicit Scene2D_Context(std::pmr::memory_resource& memory_resource, Args&&... args)
: Scene_State_Strategy(State{}, memory_resource), frame_control(make_frame_control(this->memory_resource(), std::forward<Args>(args)...)), display_root(nullptr, this->memory_resource()), dependency_root(nullptr, this->memory_resource()), final_color_cache(make_cache(this->memory_resource())), color_caches_(&this->memory_resource()) {
this->frame_control_strategy = &frame_control;
}
template <class... Args>
requires std::constructible_from<Frame_Control, Args&&...>
requires Scene2D_Frame_Control_Constructible<Frame_Control, Args&&...>
Scene2D_Context(With_Observer<State_Observer> state_observer, With_Observer<Scene_Observer> scene_observer, Args&&... args)
: Scene_State_Strategy(std::move(state_observer)), frame_control(std::forward<Args>(args)...), display_root(nullptr), dependency_root(nullptr), scene_observer_(std::move(scene_observer.observer)) {
: Scene2D_Context(*std::pmr::get_default_resource(), std::move(state_observer), std::move(scene_observer), std::forward<Args>(args)...) {}
template <class... Args>
requires Scene2D_Frame_Control_Constructible<Frame_Control, Args&&...>
Scene2D_Context(std::pmr::memory_resource& memory_resource, With_Observer<State_Observer> state_observer, With_Observer<Scene_Observer> scene_observer, Args&&... args)
: Scene_State_Strategy(State{}, std::move(state_observer), memory_resource), frame_control(make_frame_control(this->memory_resource(), std::forward<Args>(args)...)), display_root(nullptr, this->memory_resource()), dependency_root(nullptr, this->memory_resource()), final_color_cache(make_cache(this->memory_resource())), scene_observer_(std::move(scene_observer.observer)), color_caches_(&this->memory_resource()) {
this->frame_control_strategy = &frame_control;
}
~Scene2D_Context() override {
@@ -53,7 +66,7 @@ protected:
if (!renderable.dependency_node.parent) {
dependency_root.append_child(renderable.dependency_node);
}
color_caches_.try_emplace(&renderable, std::make_unique<Cache>());
color_caches_.try_emplace(&renderable, make_cache_pointer(this->memory_resource()));
}
void on_renderable_detached(Renderable_Base& renderable) override {
promote_children(renderable.layer_node);
@@ -87,22 +100,45 @@ protected:
return scene_observer_.now_ns();
}
private:
using Cache_Pointer = Memory_Resource_Unique_Ptr<Cache>;
template <class... Args>
static Frame_Control make_frame_control(std::pmr::memory_resource& memory_resource, Args&&... args) {
if constexpr (std::constructible_from<Frame_Control, std::pmr::memory_resource&, Args&&...>) {
return Frame_Control(memory_resource, std::forward<Args>(args)...);
} else {
return Frame_Control(std::forward<Args>(args)...);
}
}
static Cache make_cache(std::pmr::memory_resource& memory_resource) {
if constexpr (std::constructible_from<Cache, std::pmr::memory_resource&>) {
return Cache(memory_resource);
} else {
return Cache();
}
}
static Cache_Pointer make_cache_pointer(std::pmr::memory_resource& memory_resource) {
if constexpr (std::constructible_from<Cache, std::pmr::memory_resource&>) {
return make_memory_resource_unique<Cache>(memory_resource, memory_resource);
} else {
return make_memory_resource_unique<Cache>(memory_resource);
}
}
template <class Node>
static void promote_children(Node& node) {
void promote_children(Node& node) {
if (!node.parent) {
return;
}
Node* parent = node.parent;
const auto iterator = std::find(parent->children.begin(), parent->children.end(), &node);
std::size_t index = static_cast<std::size_t>(iterator - parent->children.begin());
const auto children = node.children;
std::pmr::vector<Node*> children(node.children.begin(), node.children.end(), &this->memory_resource());
node.detach();
for (Node* child : children) {
parent->insert_child(index++, *child);
}
}
template <class Node>
static void append_tree_order(Node& node, const std::unordered_map<Renderable_Base*, Renderable>& attached, std::unordered_set<Renderable_Base*>& visited, Renderable_List& order) {
template <class Node, class Attached, class Visited>
static void append_tree_order(Node& node, const Attached& attached, Visited& visited, Renderable_List& order) {
if (node.owner) {
auto iterator = attached.find(node.owner);
if (iterator != attached.end() && visited.insert(node.owner).second) {
@@ -114,14 +150,15 @@ private:
}
}
template <class Node>
static Renderable_List tree_order(Node& root, const Renderable_List& renderables) {
std::unordered_map<Renderable_Base*, Renderable> attached;
Renderable_List tree_order(Node& root, const Renderable_List& renderables) {
std::pmr::monotonic_buffer_resource scratch_resource(&this->memory_resource());
std::pmr::unordered_map<Renderable_Base*, Renderable> attached(&scratch_resource);
attached.reserve(renderables.size());
for (const Renderable& renderable : renderables) {
attached.emplace(renderable.get(), renderable);
}
std::unordered_set<Renderable_Base*> visited;
Renderable_List order;
std::pmr::unordered_set<Renderable_Base*> visited(&scratch_resource);
Renderable_List order(&this->memory_resource());
order.reserve(renderables.size());
append_tree_order(root, attached, visited, order);
for (const Renderable& renderable : renderables) {
@@ -132,5 +169,5 @@ private:
return order;
}
Scene_Observer scene_observer_;
std::unordered_map<Renderable_Base*, std::unique_ptr<Cache>> color_caches_;
std::pmr::unordered_map<Renderable_Base*, Cache_Pointer> color_caches_;
};
+24 -4
View File
@@ -1,4 +1,6 @@
#pragma once
#include <concepts>
#include <memory_resource>
#include <utility>
#include "renderive/base/observer/Observer.hpp"
#include "renderive/frame_control/Frame_Control.hpp"
@@ -8,6 +10,8 @@ struct Scene3D_Frame_Data {};
struct Scene3D_State {
std::uint64_t revision{};
};
template <class Frame_Control, class... Args>
concept Scene3D_Frame_Control_Constructible = std::constructible_from<Frame_Control, Args...> || std::constructible_from<Frame_Control, std::pmr::memory_resource&, Args...>;
template <class Strategy = Low_Latency_Strategy<Scene3D_Frame_Data>, class State = Scene3D_State, class State_Observer = Observer_State<>, class Scene_Observer = Observer_State<>>
requires Frame_Control_Strategy_For<Strategy, Scene3D_Frame_Data> && State_Value<State>
class Scene3D_Context : public Triple_State_Strategy<Scene_3D_Base, State, Atomic_Spin_Mutex, State_Observer> {
@@ -18,14 +22,22 @@ public:
using Painter_Lease = typename Frame_Control::Painter_Lease;
using Render_Lease = typename Frame_Control::Render_Lease;
template <class... Args>
requires std::constructible_from<Frame_Control, Args&&...>
explicit Scene3D_Context(Args&&... args) : Scene_State_Strategy(), frame_control(std::forward<Args>(args)...) {
requires Scene3D_Frame_Control_Constructible<Frame_Control, Args&&...>
explicit Scene3D_Context(Args&&... args) : Scene3D_Context(*std::pmr::get_default_resource(), std::forward<Args>(args)...) {}
template <class... Args>
requires Scene3D_Frame_Control_Constructible<Frame_Control, Args&&...>
explicit Scene3D_Context(std::pmr::memory_resource& memory_resource, Args&&... args)
: Scene_State_Strategy(State{}, memory_resource), frame_control(make_frame_control(this->memory_resource(), std::forward<Args>(args)...)) {
this->frame_control_strategy = &frame_control;
}
template <class... Args>
requires std::constructible_from<Frame_Control, Args&&...>
requires Scene3D_Frame_Control_Constructible<Frame_Control, Args&&...>
Scene3D_Context(With_Observer<State_Observer> state_observer, With_Observer<Scene_Observer> scene_observer, Args&&... args)
: Scene_State_Strategy(std::move(state_observer)), frame_control(std::forward<Args>(args)...), scene_observer_(std::move(scene_observer.observer)) {
: Scene3D_Context(*std::pmr::get_default_resource(), std::move(state_observer), std::move(scene_observer), std::forward<Args>(args)...) {}
template <class... Args>
requires Scene3D_Frame_Control_Constructible<Frame_Control, Args&&...>
Scene3D_Context(std::pmr::memory_resource& memory_resource, With_Observer<State_Observer> state_observer, With_Observer<Scene_Observer> scene_observer, Args&&... args)
: Scene_State_Strategy(State{}, std::move(state_observer), memory_resource), frame_control(make_frame_control(this->memory_resource(), std::forward<Args>(args)...)), scene_observer_(std::move(scene_observer.observer)) {
this->frame_control_strategy = &frame_control;
}
~Scene3D_Context() override {
@@ -44,5 +56,13 @@ protected:
return scene_observer_.now_ns();
}
private:
template <class... Args>
static Frame_Control make_frame_control(std::pmr::memory_resource& memory_resource, Args&&... args) {
if constexpr (std::constructible_from<Frame_Control, std::pmr::memory_resource&, Args&&...>) {
return Frame_Control(memory_resource, std::forward<Args>(args)...);
} else {
return Frame_Control(std::forward<Args>(args)...);
}
}
Scene_Observer scene_observer_;
};
+21 -9
View File
@@ -1,12 +1,16 @@
#include "Scene_Base.hpp"
#include <algorithm>
#include <memory_resource>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <taskflow/taskflow.hpp>
#include "renderive/renderable/color/Color_Cache.hpp"
static_assert(TF_VERSION == 400100, "Renderive requires Taskflow 4.1.0");
Scene_Base::Scene_Base() : render_renderables_(&renderable_states_[0]), cache_renderables_(&renderable_states_[1]) {
Scene_Base::Scene_Base() : Scene_Base(*std::pmr::get_default_resource()) {}
Scene_Base::Scene_Base(std::pmr::memory_resource& upstream_memory_resource)
: memory_domain_(std::allocate_shared<Scene_Memory_Domain>(std::pmr::polymorphic_allocator<Scene_Memory_Domain>(&upstream_memory_resource), upstream_memory_resource)), renderable_states_{Renderable_List(&memory_domain_->resource()), Renderable_List(&memory_domain_->resource())}, render_renderables_(&renderable_states_[0]), cache_renderables_(&renderable_states_[1]), task_(memory_domain_->resource()) {
worker_ = std::thread([this] {
render_loop();
});
@@ -37,7 +41,7 @@ void Scene_Base::render() {
if (!frame_control_strategy) {
throw std::logic_error("frame control strategy is not bound");
}
Render_Task task;
Render_Task task(memory_resource());
{
std::lock_guard<std::mutex> renderable_lock(renderable_mutex_);
std::swap(render_renderables_, cache_renderables_);
@@ -89,6 +93,12 @@ std::size_t Scene_Base::renderable_count() const {
std::lock_guard<std::mutex> lock(renderable_mutex_);
return cache_renderables_->size();
}
std::pmr::memory_resource& Scene_Base::memory_resource() const noexcept {
return memory_domain_->resource();
}
std::pmr::memory_resource& Scene_Base::upstream_memory_resource() const noexcept {
return memory_domain_->upstream();
}
void Scene_Base::on_renderable_attached(Renderable_Base&) {}
void Scene_Base::on_renderable_detached(Renderable_Base&) {}
void Scene_Base::prepare_render_task(Render_Task& task, const Renderable_List& renderables) {
@@ -108,7 +118,7 @@ std::uint64_t Scene_Base::observer_now_ns() const noexcept {
}
void Scene_Base::render_loop() {
for (;;) {
Render_Task task;
Render_Task task(memory_resource());
{
std::unique_lock<std::mutex> lock(task_mutex_);
task_ready_.wait(lock, [this] {
@@ -145,11 +155,12 @@ void Scene_Base::execute_taskflow(Render_Task& task) {
tf::Task module_task;
bool render{};
};
std::pmr::monotonic_buffer_resource scratch_resource(&memory_resource());
tf::Executor executor;
tf::Taskflow scene_graph;
std::unordered_map<Renderable_Base*, std::size_t> indices;
std::pmr::unordered_map<Renderable_Base*, std::size_t> indices(&scratch_resource);
indices.reserve(task.render_order.size());
std::vector<bool> render_flags(task.render_order.size());
std::pmr::vector<bool> render_flags(task.render_order.size(), false, &scratch_resource);
for (std::size_t index = 0; index < task.render_order.size(); ++index) {
indices.emplace(task.render_order[index].get(), index);
render_flags[index] = task.render_order[index]->requires_render();
@@ -161,7 +172,8 @@ void Scene_Base::execute_taskflow(Render_Task& task) {
render_flags[index] = true;
}
}
std::vector<Module> modules(task.render_order.size());
std::pmr::vector<Module> modules(&scratch_resource);
modules.resize(task.render_order.size());
for (std::size_t index = 0; index < task.render_order.size(); ++index) {
Renderable_Base& renderable = *task.render_order[index];
Module& module = modules[index];
@@ -170,12 +182,12 @@ void Scene_Base::execute_taskflow(Render_Task& task) {
Color_Cache* color_cache = prepare_renderable_cache(renderable, true);
const Scene_Render_Context context{this, task.frame_control_state, task.scene_state_revision, task.render_sequence, &renderable, color_cache};
const auto& nodes = renderable.task_graph().nodes();
std::vector<tf::Task> internal_tasks;
std::pmr::vector<tf::Task> internal_tasks(&scratch_resource);
internal_tasks.reserve(nodes.size());
for (const auto& node : nodes) {
internal_tasks.push_back(module.graph.emplace([function = node.function, context] {
function(context);
}).name(node.name));
}).name(std::string(node.name)));
}
for (std::size_t node_index = 0; node_index < nodes.size(); ++node_index) {
for (std::size_t successor : nodes[node_index].successors) {
@@ -188,7 +200,7 @@ void Scene_Base::execute_taskflow(Render_Task& task) {
if (internal_tasks.empty()) {
module.graph.emplace([] {}).precede(mark_rendered);
} else {
std::vector<bool> has_successor(nodes.size());
std::pmr::vector<bool> has_successor(nodes.size(), false, &scratch_resource);
for (std::size_t node_index = 0; node_index < nodes.size(); ++node_index) {
has_successor[node_index] = !nodes[node_index].successors.empty();
if (!has_successor[node_index]) {
+27 -4
View File
@@ -1,11 +1,16 @@
#pragma once
#include <array>
#include <condition_variable>
#include <concepts>
#include <cstdint>
#include <exception>
#include <memory>
#include <memory_resource>
#include <mutex>
#include <thread>
#include <vector>
#include <utility>
#include "renderive/base/memory/Memory_Resource.hpp"
#include "renderive/frame_control/base/Frame_Control_Strategy_Base.hpp"
#include "renderive/renderable/base/Renderable_Base.hpp"
#include "Scene_Render_Context.hpp"
@@ -13,7 +18,7 @@ class Color_Cache;
class Scene_Base {
public:
using Renderable = std::shared_ptr<Renderable_Base>;
using Renderable_List = std::vector<Renderable>;
using Renderable_List = std::pmr::vector<Renderable>;
enum class Observation_Event {
render_submitted,
render_started,
@@ -28,6 +33,7 @@ public:
std::size_t renderable_count{};
};
Scene_Base();
explicit Scene_Base(std::pmr::memory_resource& upstream_memory_resource);
Scene_Base(const Scene_Base&) = delete;
Scene_Base& operator=(const Scene_Base&) = delete;
Scene_Base(Scene_Base&&) = delete;
@@ -38,9 +44,17 @@ public:
void attach_renderable(Renderable renderable);
void detach_renderable(const Renderable_Base& renderable);
std::size_t renderable_count() const;
std::pmr::memory_resource& memory_resource() const noexcept;
std::pmr::memory_resource& upstream_memory_resource() const noexcept;
template <class Renderable_Type, class... Args>
requires std::derived_from<Renderable_Type, Renderable_Base> && std::constructible_from<Renderable_Type, Scene_Base&, Args&&...>
std::shared_ptr<Renderable_Type> make_renderable(Args&&... args) {
return std::allocate_shared<Renderable_Type>(Scene_Memory_Allocator<Renderable_Type>{memory_domain_}, *this, std::forward<Args>(args)...);
}
Frame_Control_Strategy_Base* frame_control_strategy{};
protected:
struct Render_Task {
explicit Render_Task(std::pmr::memory_resource& memory_resource) : render_order(&memory_resource), display_order(&memory_resource) {}
Frame_Control_Strategy_Base::State frame_control_state;
std::uint64_t scene_state_revision{};
std::uint64_t render_sequence{};
@@ -58,7 +72,8 @@ protected:
private:
void render_loop();
void execute_taskflow(Render_Task& task);
Renderable_List renderable_states_[2];
std::shared_ptr<Scene_Memory_Domain> memory_domain_;
std::array<Renderable_List, 2> renderable_states_;
Renderable_List* render_renderables_;
Renderable_List* cache_renderables_;
mutable std::mutex renderable_mutex_;
@@ -73,5 +88,13 @@ private:
bool rendering_{};
bool stop_{};
};
class Scene_2D_Base : public Scene_Base {};
class Scene_3D_Base : public Scene_Base {};
class Scene_2D_Base : public Scene_Base {
public:
Scene_2D_Base() = default;
explicit Scene_2D_Base(std::pmr::memory_resource& memory_resource) : Scene_Base(memory_resource) {}
};
class Scene_3D_Base : public Scene_Base {
public:
Scene_3D_Base() = default;
explicit Scene_3D_Base(std::pmr::memory_resource& memory_resource) : Scene_Base(memory_resource) {}
};
+12 -12
View File
@@ -6,10 +6,10 @@
#ifdef RENDERIVE_WITH_GTEST
#include <gtest/gtest.h>
#endif
#include "renderive/base/property/Property.hpp"
#include "renderive/renderable/Renderable.hpp"
#include "renderive/scene/Scene.hpp"
#include "renderive/state/State_Strategy.hpp"
#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 {
@@ -44,14 +44,14 @@ 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);
.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);
@@ -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);
}
+1
View File
@@ -42,6 +42,7 @@ add_executable(Renderive_Kernel
target_include_directories(Renderive_Kernel PUBLIC
${root_dir}/Kernel/src
)
target_compile_definitions(Renderive_Kernel PUBLIC RENDERIVE_WITH_GTEST)
target_link_libraries(Renderive_Kernel PUBLIC ${renderive_private_libraries})
append_glob_source(srcs ${root_dir}/Core)
add_library(Renderive_Core STATIC ${srcs})