修改一些

This commit is contained in:
2026-08-18 10:50:14 +08:00
parent 4581b3fc05
commit 182fa2232a
26 changed files with 695 additions and 126 deletions
@@ -0,0 +1,39 @@
#pragma once
#include "renderive/renderable/base/Renderive_Owner.hpp"
#include <memory>
#include <string>
#include <utility>
#include <vector>
class Renderable_Base;
namespace renderive {
struct Renderable_Build_Relationship {
std::weak_ptr<Renderable_Base> child;
std::weak_ptr<Renderable_Base> parent;
};
struct Renderable_Build_Topology {
std::vector<Renderable_Build_Relationship> dependency;
std::vector<Renderable_Build_Relationship> display;
};
namespace detail {
class Renderable_Build_Access {
public:
static void set_object_name(Renderable_Base& renderable, std::string name);
static void set_topology(Renderable_Base& renderable,
Renderable_Build_Topology topology);
[[nodiscard]] static const Renderable_Build_Topology& topology(
const Renderable_Base& renderable) noexcept;
static void complete(Renderable_Base& renderable) noexcept;
};
template <class Child, class Parent>
[[nodiscard]] Renderable_Build_Relationship build_relationship(
const renderive_Owner<Child>& child,
const renderive_Owner<Parent>& parent) {
return {child.share(), parent.share()};
}
} // namespace detail
} // namespace renderive
@@ -1,5 +1,6 @@
#include <renderive/error/Error_Policy.hpp>
#include "Renderable_Base_p.hpp"
#include "renderive/renderable/Renderable_Build.hpp"
#include <algorithm>
#include <limits>
#include <stdexcept>
@@ -223,15 +224,33 @@ bool Renderable_Base::is_visible() const noexcept {
return d_func().visible.load(std::memory_order_acquire);
}
std::string Renderable_Base::object_name() const {
const auto& implementation = d_func();
std::lock_guard lock(implementation.metadata_mutex);
return implementation.object_name;
return d_func().object_name;
}
void Renderable_Base::set_object_name(std::string name) {
auto& implementation = d_func();
std::lock_guard lock(implementation.metadata_mutex);
void renderive::detail::Renderable_Build_Access::set_object_name(
Renderable_Base& renderable, std::string name) {
auto& implementation = renderable.d_func();
if (implementation.real_time_data_state->scene_lifetime)
::renderive::error::unexpected<std::logic_error>(
"object_name is immutable after scene construction");
implementation.object_name = std::move(name);
}
void renderive::detail::Renderable_Build_Access::set_topology(
Renderable_Base& renderable, renderive::Renderable_Build_Topology topology) {
auto& implementation = renderable.d_func();
if (implementation.real_time_data_state->scene_lifetime)
::renderive::error::unexpected<std::logic_error>(
"renderable build topology is immutable after scene construction");
implementation.build_topology = std::move(topology);
}
const renderive::Renderable_Build_Topology&
renderive::detail::Renderable_Build_Access::topology(
const Renderable_Base& renderable) noexcept {
return renderable.d_func().build_topology;
}
void renderive::detail::Renderable_Build_Access::complete(
Renderable_Base& renderable) noexcept {
renderable.d_func().build_topology = {};
}
void Renderable_Base::set_visible(bool visible) {
d_func().set_visible(visible);
}
@@ -14,13 +14,15 @@ class Scene_2D_Base;
namespace renderive::inheritance {
struct Observation_Source;
}
namespace renderive::detail {
class Renderable_Build_Access;
}
class Renderable_Base {
public:
virtual ~Renderable_Base();
[[nodiscard]] Renderable_Id renderable_id() const noexcept;
[[nodiscard]] bool is_visible() const noexcept;
[[nodiscard]] std::string object_name() const;
void set_object_name(std::string name);
void set_visible(bool visible);
void discard_stale_frame_on_latest_data_update(bool enabled) noexcept;
protected:
@@ -53,5 +55,6 @@ private:
friend class Real_Time_Data_Binding;
friend class Scene_Base;
friend class Scene_2D_Base;
friend class renderive::detail::Renderable_Build_Access;
std::unique_ptr<Impl> d_ptr;
};
@@ -1,5 +1,6 @@
#pragma once
#include "Renderable_Base.hpp"
#include "renderive/renderable/Renderable_Build.hpp"
#include "renderive/inheritance/Inheritance.hpp"
#include "renderive/inheritance/Observation.hpp"
#include <atomic>
@@ -76,8 +77,8 @@ public:
const Render_Node_Id composite_node_id;
std::atomic<Renderable_Configuration> configuration;
std::atomic<bool> visible{true};
mutable std::mutex metadata_mutex;
std::string object_name;
renderive::Renderable_Build_Topology build_topology;
std::mutex render_graph_mutex;
std::shared_ptr<const Renderable_Graph> render_graph;
std::unordered_map<std::string, Render_Node_Id> node_identities;
@@ -0,0 +1,13 @@
#pragma once
#include <cstdint>
enum class Scene_Build_Result : std::uint8_t {
null_renderable,
foreign_renderable,
dependency_endpoint_missing,
dependency_self_reference,
dependency_cycle,
display_endpoint_missing,
display_self_reference,
display_cycle
};
+123 -12
View File
@@ -1,52 +1,163 @@
#pragma once
#include "renderive/base/adapter/Expected.hpp"
#include "renderive/base/property/Concepts.hpp"
#include "renderive/base/property/Validators.hpp"
#include "renderive/error/Error_Policy.hpp"
#include "renderive/renderable/base/Renderable_Base.hpp"
#include "renderive/renderable/base/Renderive_Owner.hpp"
#include "renderive/scene/Inheritance.hpp"
#include "renderive/scene/Scene_Build_Result.hpp"
#include "renderive/scene/base/Scene_Base.hpp"
#include <concepts>
#include <functional>
#include <memory>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
namespace renderive::scene::detail {
struct Scene_Build_Access {
[[nodiscard]] static auto build_initial_topology(
Scene_Base& scene,
const std::vector<Scene_Base::Renderable>& renderables)
-> Expected<void, Scene_Build_Result> {
return scene.build_initial_topology(renderables);
}
};
} // namespace renderive::scene::detail
namespace renderive::scene {
template <Property_Product Product_Type, Property_Set Properties_Type, Property_Validator<Properties_Type> Validator_Type = No_Property_Validator<Properties_Type>>
template <Property_Product Product_Type, Property_Set Properties_Type,
Property_Validator<Properties_Type> Validator_Type =
No_Property_Validator<Properties_Type>>
struct Scene_Builder {
using Product = Product_Type;
using Properties = Properties_Type;
using Validator = Validator_Type;
using Self = Scene_Builder;
Scene_Builder() requires std::default_initializable<Validator> : constructor_(make_constructor()) {}
template <class... Args> requires (sizeof...(Args) > 0) && std::default_initializable<Validator>
explicit Scene_Builder(Args&&... args) : constructor_(make_constructor(std::forward<Args>(args)...)) {}
template <auto Member, Property_Member_Assignable<Properties, Member> Value>
using Renderable = Scene_Base::Renderable;
Scene_Builder() requires std::default_initializable<Validator>
: constructor_(make_constructor()) {}
template <class... Args>
requires (sizeof...(Args) > 0) && std::default_initializable<Validator>
explicit Scene_Builder(Args&&... args) {
(collect_constructor_renderable(args), ...);
constructor_ = make_constructor(std::forward<Args>(args)...);
}
template <auto Member,
Property_Member_Assignable<Properties, Member> Value>
Self& set(Value&& value) {
properties_.*Member = std::forward<Value>(value);
return *this;
}
template <Property_Configurator<Properties> Configure>
Self& configure(Configure&& configure) {
std::invoke(std::forward<Configure>(configure), properties_);
return *this;
}
[[nodiscard]] std::unique_ptr<Product> build() {
Self& add_renderable(Renderable renderable) {
renderables_.push_back(std::move(renderable));
return *this;
}
template <class Renderable_Type>
requires std::derived_from<Renderable_Type, Renderable_Base>
Self& add_renderable(const renderive_Owner<Renderable_Type>& renderable) {
renderables_.emplace_back(renderable);
return *this;
}
template <class Renderable_Type>
requires std::derived_from<Renderable_Type, Renderable_Base>
Self& add_renderable(const std::shared_ptr<Renderable_Type>& renderable) {
renderables_.emplace_back(
std::static_pointer_cast<Renderable_Base>(renderable));
return *this;
}
Self& add_renderables(std::vector<Renderable> renderables) {
for (auto& renderable : renderables)
renderables_.push_back(std::move(renderable));
return *this;
}
[[nodiscard]] const Properties& properties_value() const noexcept {
return properties_;
}
[[nodiscard]] auto build()
-> Expected<std::unique_ptr<Product>, Scene_Build_Result> {
static_assert(std::derived_from<Product, Scene_Base>);
validator_(properties_);
auto construct = std::exchange(constructor_, {});
return construct(properties_);
if (!construct)
::renderive::error::unexpected<std::logic_error>(
"scene builder can only build once");
auto result = construct(properties_);
if (!result)
::renderive::error::unexpected<std::logic_error>(
"scene constructor returned null");
auto topology = detail::Scene_Build_Access::build_initial_topology(
*result, renderables_);
if (!topology) return unexpected(topology.error());
return std::move(result);
}
protected:
[[nodiscard]] const std::vector<Renderable>& renderables() const noexcept {
return renderables_;
}
private:
using Constructor = std::function<std::unique_ptr<Product>(const Properties&)>;
using Constructor =
std::function<std::unique_ptr<Product>(const Properties&)>;
template <class... Args>
static Constructor make_constructor(Args&&... args) {
auto stored = std::make_shared<std::tuple<std::decay_t<Args>...>>(std::forward<Args>(args)...);
return [stored = std::move(stored)](const Properties& properties) mutable {
auto stored =
std::make_shared<std::tuple<std::decay_t<Args>...>>(
std::forward<Args>(args)...);
return [stored = std::move(stored)](
const Properties& properties) mutable {
return std::apply(
[&](auto&... values) {
return scene_inheritance::Builder_Access::make<Product>(properties, std::move(values)...);
return scene_inheritance::Builder_Access::make<Product>(
properties, std::move(values)...);
},
*stored);
};
}
template <class Renderable_Type>
requires std::derived_from<Renderable_Type, Renderable_Base>
void collect_constructor_renderable(
const renderive_Owner<Renderable_Type>& renderable) {
add_renderable(renderable);
}
template <class Renderable_Type>
requires std::derived_from<Renderable_Type, Renderable_Base>
void collect_constructor_renderable(
const std::shared_ptr<Renderable_Type>& renderable) {
add_renderable(renderable);
}
template <class Value>
void collect_constructor_renderable(const Value&) {}
Properties properties_{};
[[no_unique_address]] Validator validator_{};
Constructor constructor_;
std::vector<Renderable> renderables_;
};
}
} // namespace renderive::scene
@@ -20,6 +20,7 @@
#include <vector>
#include <oneapi/tbb/concurrent_queue.h>
#include <oneapi/tbb/flow_graph.h>
#include "renderive/renderable/Renderable_Build.hpp"
#include "renderive/renderable/Render_Frame_Completion.hpp"
#include "renderive/renderable/Renderive_Id_Allocator.hpp"
#include "renderive/renderable/base/Renderable_Base_p.hpp"
@@ -354,6 +355,111 @@ Scene_Base::Scene_Base(std::pmr::memory_resource& upstream_memory_resource,
Scene_Base::~Scene_Base() {
d_func().shutdown();
}
auto Scene_Base::build_initial_topology(
const std::vector<Renderable>& renderables)
-> renderive::Expected<void, Scene_Build_Result> {
std::unordered_set<const Renderable_Base*> build_renderables;
build_renderables.reserve(renderables.size());
for (const auto& renderable : renderables) {
if (!renderable)
return renderive::unexpected(Scene_Build_Result::null_renderable);
build_renderables.insert(renderable.get());
}
auto& implementation = d_func();
{
std::lock_guard<std::recursive_mutex> lock(implementation.task_mutex_);
if (implementation.runtime_started_)
::renderive::error::unexpected<std::logic_error>(
"initial scene topology must be built before runtime starts");
}
const Scene_Edit_Error edit_error = implementation.execute_renderable_edit(
[&]() -> Scene_Edit_Error {
Renderable_Editor editor(*this);
for (const auto& renderable : renderables) {
if (const auto error = editor.attach(renderable);
error != Scene_Edit_Error::none)
return error;
}
for (const auto& renderable : renderables) {
const auto& topology =
renderive::detail::Renderable_Build_Access::topology(
*renderable);
for (const auto& relationship : topology.dependency) {
auto child = relationship.child.lock();
auto parent = relationship.parent.lock();
if (!child || !parent ||
!build_renderables.contains(child.get()) ||
!build_renderables.contains(parent.get()))
return Scene_Edit_Error::dangling_dependency;
const auto error = editor.add_dependency_parent(
Renderable(std::move(child)),
Renderable(std::move(parent)));
if (error != Scene_Edit_Error::none) return error;
}
}
for (const auto& renderable : renderables) {
const auto& topology =
renderive::detail::Renderable_Build_Access::topology(
*renderable);
for (const auto& relationship : topology.display) {
auto child = relationship.child.lock();
auto parent = relationship.parent.lock();
if (!child || !parent ||
!build_renderables.contains(child.get()) ||
!build_renderables.contains(parent.get()))
return Scene_Edit_Error::dangling_display;
auto* composition = implementation.composition();
if (!composition) return Scene_Edit_Error::dangling_display;
const auto error = composition->add_parent(
child->renderable_id(), parent->renderable_id());
if (error != Scene_Edit_Error::none) return error;
}
}
return Scene_Edit_Error::none;
});
if (edit_error == Scene_Edit_Error::none) {
for (const auto& renderable : renderables)
renderive::detail::Renderable_Build_Access::complete(*renderable);
return {};
}
switch (edit_error) {
case Scene_Edit_Error::null_renderable:
return renderive::unexpected(Scene_Build_Result::null_renderable);
case Scene_Edit_Error::foreign_renderable:
return renderive::unexpected(Scene_Build_Result::foreign_renderable);
case Scene_Edit_Error::dependency_self_reference:
return renderive::unexpected(
Scene_Build_Result::dependency_self_reference);
case Scene_Edit_Error::dependency_cycle:
return renderive::unexpected(Scene_Build_Result::dependency_cycle);
case Scene_Edit_Error::display_self_reference:
return renderive::unexpected(
Scene_Build_Result::display_self_reference);
case Scene_Edit_Error::display_cycle:
return renderive::unexpected(Scene_Build_Result::display_cycle);
case Scene_Edit_Error::dangling_dependency:
return renderive::unexpected(
Scene_Build_Result::dependency_endpoint_missing);
case Scene_Edit_Error::dangling_display:
return renderive::unexpected(
Scene_Build_Result::display_endpoint_missing);
case Scene_Edit_Error::none:
break;
case Scene_Edit_Error::empty_edit:
case Scene_Edit_Error::renderable_not_attached:
case Scene_Edit_Error::shutting_down:
::renderive::error::unexpected<std::logic_error>(
"unexpected result while building initial scene topology");
}
::renderive::error::unexpected<std::logic_error>(
"unhandled initial scene topology result");
}
Scene_Base::Attach_Builder::Attach_Builder(Scene_Base& scene) : scene_(scene), task_lock_(scene.d_func().task_mutex_) {
if (scene.d_func().runtime_started_) ::renderive::error::unexpected<std::logic_error>("scene attach builder is only available before runtime starts");
}
@@ -1222,6 +1328,12 @@ std::shared_ptr<const Frame_Control_Strategy_Base> Scene_Base::frame_control_str
void Scene_2D_Base::Impl::attach(Renderable_Id id) {
if (!display_resolver_.contains(id)) display_resolver_.attach(id);
}
Scene_Edit_Error Scene_2D_Base::Impl::add_parent(
Renderable_Id child, Renderable_Id parent) {
const auto result = display_resolver_.add_parent(child, parent);
if (!result) return relationship_error(result.error, true);
return Scene_Edit_Error::none;
}
bool Scene_2D_Base::Impl::cleanup() {
for (const Renderable_Id id : display_resolver_.ids()) {
if (renderables_.contains(id)) continue;
@@ -16,6 +16,7 @@
#include <utility>
#include <variant>
#include <vector>
#include "renderive/base/adapter/Expected.hpp"
#include "renderive/base/memory/Memory_Resource.hpp"
#include "renderive/capture/Capture.hpp"
#include "renderive/frame_control/base/Frame_Control_Strategy_Base.hpp"
@@ -25,6 +26,7 @@
#include "renderive/render_graph/External_Operation.hpp"
#include "renderive/render_graph/Render_Plan.hpp"
#include "renderive/scene/Inheritance.hpp"
#include "renderive/scene/Scene_Build_Result.hpp"
#include "renderive/scene/dependency/Dependency_Resolver.hpp"
#include "Abstract_Frame.hpp"
#include "Frame_Render_Snapshot.hpp"
@@ -35,6 +37,9 @@
namespace renderive::inheritance {
struct Observation_Source;
}
namespace renderive::scene::detail {
struct Scene_Build_Access;
}
class Color_Cache;
enum class Scene_Render_Result : std::uint8_t {
none,
@@ -218,6 +223,10 @@ protected:
return static_cast<const Implementation&>(*impl_);
}
private:
[[nodiscard]] auto build_initial_topology(
const std::vector<Renderable>& renderables)
-> renderive::Expected<void, Scene_Build_Result>;
friend struct renderive::scene::detail::Scene_Build_Access;
friend class Renderable_Base;
friend class Scene_2D_Base;
std::unique_ptr<Impl> impl_;
@@ -25,6 +25,8 @@ public:
struct Composition_Relationships {
virtual ~Composition_Relationships() = default;
virtual void attach(Renderable_Id id) = 0;
[[nodiscard]] virtual Scene_Edit_Error add_parent(
Renderable_Id child, Renderable_Id parent) = 0;
[[nodiscard]] virtual bool cleanup() = 0;
[[nodiscard]] virtual bool valid() const = 0;
virtual renderive::scene::dependency::Resolution<Renderable_Id> resolve() const = 0;
@@ -175,6 +177,8 @@ struct Scene_2D_Base::Impl
[[nodiscard]] Scene_Edit_Error clear_display_parent_locked(
const Renderable& child);
void attach(Renderable_Id id) override;
[[nodiscard]] Scene_Edit_Error add_parent(
Renderable_Id child, Renderable_Id parent) override;
[[nodiscard]] bool cleanup() override;
[[nodiscard]] bool valid() const override;
[[nodiscard]] renderive::scene::dependency::Resolution<Renderable_Id> resolve() const override;