中间状态暂存
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user