删除realtime 的一个组件

This commit is contained in:
2026-08-14 12:27:12 +08:00
parent 38231dbc1c
commit dfb2de6bf7
24 changed files with 3972 additions and 421 deletions
@@ -3,6 +3,7 @@
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <mutex>
#include <optional>
#include <tuple>
@@ -11,7 +12,6 @@
#include "renderive/base/Atomic_Mutex.hpp"
#include "renderive/base/Concepts.hpp"
#include "renderive/base/observer/Observer.hpp"
#include "base/State_Strategy_Base.hpp"
template <class Tag_Type, class Data_Type>
struct Buffered_Data {
using Tag = Tag_Type;
@@ -56,71 +56,14 @@ struct Entry_Index {
};
template <class Tag, class... Entries>
using Entry_Of = std::tuple_element_t<Entry_Index<Tag, Entries...>::value, std::tuple<Entries...>>;
}
template <Derivable_Type That, class Data_Type, Mutex_Type Mutex = Atomic_Spin_Mutex, class Observer = Observer_State<>>
struct Double_Buffer_Strategy : That, State_Strategy_Base {
using Self = Double_Buffer_Strategy;
using Data = Data_Type;
enum class Observation_Event {
cache_updated,
published
};
struct Observation {
Observation_Event event{};
std::uint64_t time_ns{};
std::uint64_t cache_update_count{};
std::uint64_t publish_count{};
};
static_assert(Timed_Struct_Observer<Observer, Observation>);
Double_Buffer_Strategy() requires std::default_initializable<That> && std::default_initializable<Data> : That() {}
explicit Double_Buffer_Strategy(With_Observer<Observer> option) requires std::default_initializable<That> && std::default_initializable<Data> : That(), observer(std::move(option.observer)) {}
template <class... Args>
explicit Double_Buffer_Strategy(std::in_place_t, Args&&... args) requires std::default_initializable<Data> : That(std::forward<Args>(args)...) {}
template <class... Args>
Double_Buffer_Strategy(std::in_place_t, With_Observer<Observer> option, Args&&... args) requires std::default_initializable<Data> : That(std::forward<Args>(args)...), observer(std::move(option.observer)) {}
Self& write(Data value) {
std::optional<Observation> observation;
{
std::lock_guard lock(mtx);
slot.buffers[slot.cache_index] = std::move(value);
slot.dirty = true;
++slot.cache_update_count;
observation.emplace(Observation_Event::cache_updated, observer.now_ns(), slot.cache_update_count, slot.publish_count);
}
observer.observe(*observation);
return *this;
}
void publish() override {
std::optional<Observation> observation;
{
std::lock_guard lock(mtx);
if(!slot.dirty) {
return;
}
std::swap(slot.render_index, slot.cache_index);
slot.dirty = false;
++slot.publish_count;
observation.emplace(Observation_Event::published, observer.now_ns(), slot.cache_update_count, slot.publish_count);
}
observer.observe(*observation);
}
std::uint64_t state_revision() const override {
std::lock_guard lock(mtx);
return slot.publish_count;
}
protected:
const Data& render_buffer_value() const noexcept {
return slot.buffers[slot.render_index];
}
private:
Observer observer;
double_buffer_detail::Slot<Data> slot;
mutable Mutex mtx;
struct No_Publish_Effect {
void operator()() const noexcept {}
};
}
template <Derivable_Type That, class Layout, Mutex_Type Mutex = Atomic_Spin_Mutex, class Observer = Observer_State<>>
struct Multi_Double_Buffer_Strategy;
template <Derivable_Type That, Mutex_Type Mutex, class Observer, Buffered_Data_Entry... Entries>
struct Multi_Double_Buffer_Strategy<That, Double_Buffer_Layout<Entries...>, Mutex, Observer> : That, State_Strategy_Base {
struct Multi_Double_Buffer_Strategy<That, Double_Buffer_Layout<Entries...>, Mutex, Observer> : That {
using Self = Multi_Double_Buffer_Strategy;
enum class Observation_Event {
cache_updated,
@@ -163,24 +106,31 @@ struct Multi_Double_Buffer_Strategy<That, Double_Buffer_Layout<Entries...>, Mute
observer.observe(*observation);
return *this;
}
void publish() override {
template <class Side_Effect = double_buffer_detail::No_Publish_Effect>
requires std::invocable<Side_Effect>
bool publish(Side_Effect&& side_effect = {}) {
std::array<Observation, sizeof...(Entries)> observations{};
std::size_t observation_count{};
bool published{};
{
std::lock_guard lock(mtx);
bool published{};
(publish_entry<Entries>(observations, observation_count, published), ...);
if(published) {
++revision;
++publish_revision;
}
}
for(std::size_t i = 0; i < observation_count; ++i) {
observer.observe(observations[i]);
}
if(!published) {
return false;
}
std::invoke(std::forward<Side_Effect>(side_effect));
return true;
}
std::uint64_t state_revision() const override {
std::uint64_t revision() const {
std::lock_guard lock(mtx);
return revision;
return publish_revision;
}
template <class Tag>
std::uint64_t buffer_revision() const {
@@ -217,6 +167,6 @@ private:
}
Observer observer;
std::tuple<double_buffer_detail::Slot<typename Entries::Data>...> slots;
std::uint64_t revision{};
std::uint64_t publish_revision{};
mutable Mutex mtx;
};
@@ -6,11 +6,53 @@
#include <mutex>
#include <thread>
#include <vector>
#include "renderive/real_time_data/Double_Buffer_Strategy.hpp"
#include "renderive/real_time_data/Real_Time_Data.hpp"
#include "renderive/renderable/Renderable.hpp"
#include "renderive/renderable/Renderable_Test_Harness.hpp"
#include "renderive/scene/Scene.hpp"
#include "renderive/scene/Scene_Test_Helpers.hpp"
#include "renderive/state/base/State_Strategy_Base.hpp"
namespace {
struct Double_Buffer_Test_Base {};
struct Double_Buffer_Test_Tag {};
using Double_Buffer_Test_Layout =
Double_Buffer_Layout<Buffered_Data<Double_Buffer_Test_Tag,
std::vector<int>>>;
class Double_Buffer_Test_Strategy final
: public Multi_Double_Buffer_Strategy<Double_Buffer_Test_Base,
Double_Buffer_Test_Layout,
std::mutex> {
using Base = Multi_Double_Buffer_Strategy<Double_Buffer_Test_Base,
Double_Buffer_Test_Layout,
std::mutex>;
public:
using Base::buffer_revision;
using Base::publish;
using Base::revision;
using Base::write;
[[nodiscard]] const std::vector<int>& published() const noexcept {
return Base::render_buffer_value<Double_Buffer_Test_Tag>();
}
};
static_assert(!std::derived_from<Double_Buffer_Test_Strategy,
State_Strategy_Base>);
}
TEST(double_buffer_strategy_test,
single_entry_layout_publishes_with_external_side_effect) {
Double_Buffer_Test_Strategy strategy;
int side_effect_count{};
strategy.write<Double_Buffer_Test_Tag>({1, 2, 3});
EXPECT_TRUE(strategy.publish([&] { ++side_effect_count; }));
EXPECT_EQ(strategy.published(), (std::vector<int>{1, 2, 3}));
EXPECT_EQ(strategy.revision(), 1U);
EXPECT_EQ(strategy.buffer_revision<Double_Buffer_Test_Tag>(), 1U);
EXPECT_EQ(side_effect_count, 1);
EXPECT_FALSE(strategy.publish([&] { ++side_effect_count; }));
EXPECT_EQ(side_effect_count, 1);
}
struct Real_Time_Data_Test_Time_Source {
std::shared_ptr<std::atomic<std::uint64_t>> time_ns{std::make_shared<std::atomic<std::uint64_t>>()};
std::uint64_t now_ns() const noexcept {