中间状态暂存

This commit is contained in:
2026-08-14 17:53:13 +08:00
parent 260f649b08
commit bb64801679
75 changed files with 2984 additions and 1823 deletions
+72 -48
View File
@@ -2,7 +2,11 @@
#include "detail/Point_Core.h"
#include <renderive/real_time_data/Double_Buffer_Strategy.hpp>
#include <renderive/state/Double_State_Storage.hpp>
#include <cmath>
#include <mutex>
#include <stdexcept>
#include <utility>
@@ -30,75 +34,95 @@ void validate(const std::vector<Point>& points) {
} // namespace
namespace detail {
struct Point_Payload_Tag {};
using Point_Payload = std::shared_ptr<const std::vector<Point>>;
using Point_Buffer_Layout = ::Double_Buffer_Layout<
::Buffered_Data<Point_Payload_Tag, Point_Payload>>;
using Point_Buffer_Strategy =
::Multi_Double_Buffer_Strategy<Point_Buffer_Layout, std::mutex>;
using Point_State_Strategy =
::Double_State_Storage<Point_State, std::mutex>;
} // namespace detail
struct Point_Visual::Impl final : detail::Point_Buffer_Strategy,
detail::Point_State_Strategy {
Impl(std::vector<Point> points, const Point_State& initial)
: detail::Point_State_Strategy(initial) {
validate(initial);
update_points(std::move(points));
}
void update_points(std::vector<Point> points) {
validate(points);
write<detail::Point_Payload_Tag>(
std::make_shared<const std::vector<Point>>(std::move(points)));
}
void edit_points(const std::function<void(std::vector<Point>&)>& edit) {
if (!edit)
throw std::invalid_argument("Point_Visual point edit is empty");
const auto& published = points();
auto next = published ? *published : std::vector<Point>{};
edit(next);
update_points(std::move(next));
}
[[nodiscard]] const detail::Point_Payload& points() const noexcept {
return render_buffer_value<detail::Point_Payload_Tag>();
}
[[nodiscard]] std::size_t point_count() const noexcept {
return points() ? points()->size() : 0U;
}
void configure(Point_State state) {
validate(state);
update([state = std::move(state)](Point_State& target) mutable {
target = std::move(state);
});
}
[[nodiscard]] detail::Published_Point publish_frame() {
detail::Point_State_Strategy::publish();
detail::Point_Buffer_Strategy::publish();
return {
detail::Point_State_Strategy::render_state_value(),
detail::Point_Buffer_Strategy::render_buffer_value<
detail::Point_Payload_Tag>(),
detail::Point_State_Strategy::state_revision(),
detail::Point_Buffer_Strategy::revision()};
}
};
Point_Visual::Point_Visual(std::vector<Point> points, Point_State initial)
: detail::Point_Visual_Strategy(std::in_place, initial) {
validate(initial);
validate(points);
detail::Point_Visual_Strategy::write<detail::Point_Payload_Tag>(
std::make_shared<const std::vector<Point>>(std::move(points)));
}
: impl_(std::make_unique<Impl>(std::move(points), initial)) {}
Point_Visual::~Point_Visual() = default;
void Point_Visual::update_points(std::vector<Point> points) {
validate(points);
detail::Point_Visual_Strategy::write<detail::Point_Payload_Tag>(
std::make_shared<const std::vector<Point>>(std::move(points)));
impl_->update_points(std::move(points));
}
void Point_Visual::edit_points(
const std::function<void(std::vector<Point>&)>& edit) {
if (!edit)
throw std::invalid_argument("Point_Visual point edit is empty");
const auto& published =
detail::Point_Visual_Strategy::render_buffer_value<
detail::Point_Payload_Tag>();
auto points = published ? *published : std::vector<Point>{};
edit(points);
update_points(std::move(points));
impl_->edit_points(edit);
}
std::size_t Point_Visual::point_count() const {
const auto& points =
detail::Point_Visual_Strategy::render_buffer_value<
detail::Point_Payload_Tag>();
return points ? points->size() : 0U;
return impl_->point_count();
}
std::uint64_t Point_Visual::data_revision() const {
return detail::Point_Visual_Strategy::revision();
return impl_->revision();
}
void Point_Visual::configure(Point_State state) {
validate(state);
detail::Point_State_Strategy::update(
[state = std::move(state)](Point_State& target) mutable {
target = std::move(state);
});
impl_->configure(std::move(state));
}
detail::Published_Point detail::Point_State_Access::publish(Point_Visual& visual) {
return visual.publish_frame();
}
detail::Published_Point Point_Visual::publish_frame() {
publish();
return {
detail::Point_State_Strategy::render_state_value(),
detail::Point_Visual_Strategy::render_buffer_value<
detail::Point_Payload_Tag>(),
detail::Point_State_Strategy::state_revision(),
detail::Point_Visual_Strategy::revision()};
}
void Point_Visual::publish() {
detail::Point_State_Strategy::publish();
detail::Point_Visual_Strategy::publish();
}
std::uint64_t Point_Visual::state_revision() const {
return detail::Point_State_Strategy::state_revision() +
detail::Point_Visual_Strategy::revision();
return visual.impl_->publish_frame();
}
} // namespace renderive::render_3d
+16 -39
View File
@@ -1,13 +1,11 @@
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <vector>
#include <renderive/base/Concepts.hpp>
#include <renderive/real_time_data/Double_Buffer_Strategy.hpp>
#include <renderive/state/Double_State_Strategy.hpp>
namespace renderive::render_3d {
struct Vec3 {
float x{};
@@ -48,53 +46,32 @@ struct Point_Style {
Point_Aspect aspect{Point_Aspect::Filled};
bool operator==(const Point_Style&) const = default;
};
struct Point_State {
Point_Style style;
Matrix4 transform;
bool visible{true};
bool depth_test{true};
bool operator==(const Point_State&) const = default;
};
namespace detail {
struct Point_State_Base {};
struct Point_Payload_Tag {};
using Point_Payload = std::shared_ptr<const std::vector<Point>>;
using Point_State_Strategy =
::Double_State_Strategy<Point_State_Base, Point_State, std::mutex>;
using Point_Buffer_Layout =
::Double_Buffer_Layout<
::Buffered_Data<Point_Payload_Tag, Point_Payload>>;
class Point_Visual_Strategy
: public ::Multi_Double_Buffer_Strategy<
Point_State_Strategy, Point_Buffer_Layout, std::mutex> {
using Base = ::Multi_Double_Buffer_Strategy<
Point_State_Strategy, Point_Buffer_Layout, std::mutex>;
protected:
using Base::Base;
using Base::publish;
using Base::render_buffer_value;
using Base::revision;
using Base::write;
};
struct Published_Point;
class Point_State_Access;
}
// Thread-safe logical point visual. Datoviz resources deliberately do not live here.
class Point_Visual final : private detail::Point_Visual_Strategy,
Non_Copyable {
public:
explicit Point_Visual(std::vector<Point> points = {}, Point_State initial = {});
~Point_Visual();
struct Point_Visual final : Non_Copyable {
struct State {
Point_Style style;
Matrix4 transform;
bool visible{true};
bool depth_test{true};
bool operator==(const State&) const = default;
};
explicit Point_Visual(std::vector<Point> points = {}, State initial = {});
~Point_Visual();
void update_points(std::vector<Point> points);
void edit_points(const std::function<void(std::vector<Point>&)>& edit);
[[nodiscard]] std::size_t point_count() const;
[[nodiscard]] std::uint64_t data_revision() const;
void configure(Point_State state);
void configure(State state);
private:
struct Impl;
std::unique_ptr<Impl> impl_;
friend class detail::Point_State_Access;
[[nodiscard]] detail::Published_Point publish_frame();
void publish() override;
[[nodiscard]] std::uint64_t state_revision() const override;
};
using Point_State = Point_Visual::State;
} // namespace renderive::render_3d
+3 -5
View File
@@ -3,7 +3,7 @@
#include "render_3D/Point_Scene.h"
#include <renderive/frame_control/concept/Frame_Control_Strategy.hpp>
#include <renderive/state/Double_State_Strategy.hpp>
#include <renderive/state/Double_State_Storage.hpp>
#include <cstdint>
#include <concepts>
@@ -35,11 +35,9 @@ struct Scene_State {
bool operator==(const Scene_State&) const = default;
};
struct Scene_State_Base {};
class Scene_State_Buffer final
: public ::Double_State_Strategy<Scene_State_Base, Scene_State, std::mutex> {
using Base = ::Double_State_Strategy<Scene_State_Base, Scene_State, std::mutex>;
: public ::Double_State_Storage<Scene_State, std::mutex> {
using Base = ::Double_State_Storage<Scene_State, std::mutex>;
public:
struct Published {
+3 -1
View File
@@ -31,6 +31,7 @@ TEST(PointState, UsesKernelDoubleStateAtFrameBoundary) {
TEST(PointState, PublishesImmutableBulkPayloadsThroughDoubleBuffer) {
Point_Visual visual;
constexpr int update_count = 500;
constexpr std::uint64_t initial_data_revision = 1;
std::atomic<bool> done{};
std::thread writer([&] {
@@ -57,7 +58,8 @@ TEST(PointState, PublishesImmutableBulkPayloadsThroughDoubleBuffer) {
const auto published = detail::Point_State_Access::publish(visual);
EXPECT_GT(published.data_revision, 0U);
EXPECT_LE(published.data_revision, update_count);
EXPECT_LE(published.data_revision,
initial_data_revision + update_count);
ASSERT_FALSE(published.data->empty());
EXPECT_EQ(published.data->front().position.x, static_cast<float>(update_count));
}