删除realtime 的一个组件
This commit is contained in:
+18
-68
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user