优化
This commit is contained in:
@@ -2172,58 +2172,62 @@ void Datoviz_Visual_Backend::destroy() {
|
||||
queue_lock = std::unique_lock(context->queue_mutex(), std::defer_lock);
|
||||
std::lock(api_lock, queue_lock);
|
||||
}
|
||||
std::lock_guard target_lock(target_mutex_);
|
||||
for (auto& slot : runtime_slots_) {
|
||||
if (slot.runtime != nullptr) {
|
||||
dvz_drp2_runtime_destroy(slot.runtime);
|
||||
slot.runtime = nullptr;
|
||||
{
|
||||
std::lock_guard target_lock(target_mutex_);
|
||||
for (auto& slot : runtime_slots_) {
|
||||
if (slot.runtime != nullptr) {
|
||||
dvz_drp2_runtime_destroy(slot.runtime);
|
||||
slot.runtime = nullptr;
|
||||
}
|
||||
if (slot.emitter != nullptr) {
|
||||
dvz_frame_plan_emitter_destroy(slot.emitter);
|
||||
slot.emitter = nullptr;
|
||||
}
|
||||
}
|
||||
if (slot.emitter != nullptr) {
|
||||
dvz_frame_plan_emitter_destroy(slot.emitter);
|
||||
slot.emitter = nullptr;
|
||||
for (auto& target : targets_->values) target.reset();
|
||||
for (auto* buffer : external_buffers_) {
|
||||
if (buffer == nullptr) continue;
|
||||
dvz_buffer_destroy(buffer);
|
||||
dvz_buffer_free(buffer);
|
||||
}
|
||||
external_buffers_.clear();
|
||||
if (camera_controller_ != nullptr) {
|
||||
dvz_controller_destroy(camera_controller_);
|
||||
camera_controller_ = nullptr;
|
||||
}
|
||||
if (item_interaction_ != nullptr) {
|
||||
dvz_item_interaction_destroy(item_interaction_);
|
||||
item_interaction_ = nullptr;
|
||||
}
|
||||
if (hover_readout_ != nullptr) {
|
||||
dvz_pinned_readout_destroy(hover_readout_);
|
||||
hover_readout_ = nullptr;
|
||||
}
|
||||
if (panel_ != nullptr && input_router_ != nullptr)
|
||||
(void)dvz_panel_connect_input(panel_, nullptr);
|
||||
if (gesture_handler_ != nullptr) {
|
||||
dvz_pointer_gesture_handler_destroy(gesture_handler_);
|
||||
gesture_handler_ = nullptr;
|
||||
}
|
||||
if (input_router_ != nullptr) {
|
||||
dvz_input_router_destroy(input_router_);
|
||||
input_router_ = nullptr;
|
||||
}
|
||||
visuals_.clear();
|
||||
axes_visual_ = nullptr;
|
||||
axes_text_ = nullptr;
|
||||
applied_camera_.reset();
|
||||
applied_axes_.reset();
|
||||
panel_ = nullptr;
|
||||
figure_ = nullptr;
|
||||
if (scene_ != nullptr) {
|
||||
dvz_scene_destroy(scene_);
|
||||
scene_ = nullptr;
|
||||
}
|
||||
}
|
||||
for (auto& target : targets_->values) target.reset();
|
||||
for (auto* buffer : external_buffers_) {
|
||||
if (buffer == nullptr) continue;
|
||||
dvz_buffer_destroy(buffer);
|
||||
dvz_buffer_free(buffer);
|
||||
}
|
||||
external_buffers_.clear();
|
||||
if (camera_controller_ != nullptr) {
|
||||
dvz_controller_destroy(camera_controller_);
|
||||
camera_controller_ = nullptr;
|
||||
}
|
||||
if (item_interaction_ != nullptr) {
|
||||
dvz_item_interaction_destroy(item_interaction_);
|
||||
item_interaction_ = nullptr;
|
||||
}
|
||||
if (hover_readout_ != nullptr) {
|
||||
dvz_pinned_readout_destroy(hover_readout_);
|
||||
hover_readout_ = nullptr;
|
||||
}
|
||||
if (panel_ != nullptr && input_router_ != nullptr) (void)dvz_panel_connect_input(panel_, nullptr);
|
||||
if (gesture_handler_ != nullptr) {
|
||||
dvz_pointer_gesture_handler_destroy(gesture_handler_);
|
||||
gesture_handler_ = nullptr;
|
||||
}
|
||||
if (input_router_ != nullptr) {
|
||||
dvz_input_router_destroy(input_router_);
|
||||
input_router_ = nullptr;
|
||||
}
|
||||
visuals_.clear();
|
||||
axes_visual_ = nullptr;
|
||||
axes_text_ = nullptr;
|
||||
applied_camera_.reset();
|
||||
applied_axes_.reset();
|
||||
panel_ = nullptr;
|
||||
figure_ = nullptr;
|
||||
if (scene_ != nullptr) {
|
||||
dvz_scene_destroy(scene_);
|
||||
scene_ = nullptr;
|
||||
}
|
||||
render_context_.reset();
|
||||
if (api_lock.owns_lock()) api_lock.unlock();
|
||||
if (queue_lock.owns_lock()) queue_lock.unlock();
|
||||
context.reset();
|
||||
}
|
||||
} // namespace aethera::render_3d::detail
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
#include <vector>
|
||||
namespace aethera::render_3d {
|
||||
template <typename Spec>
|
||||
struct Basic_Visual : Def<Basic_Visual<Spec>, Renderable,
|
||||
Tagged_Buffer<detail::Prepared_Visual_Tag,
|
||||
detail::Prepared_Visual_For<typename Spec::Prepared_Data>>> {
|
||||
struct Basic_Visual : Def<Basic_Visual<Spec>, Renderable> {
|
||||
using Specification = Spec;
|
||||
using Item = typename Spec::Item;
|
||||
using Prepared_Data = typename Spec::Prepared_Data;
|
||||
|
||||
@@ -10,13 +10,14 @@ struct Basic_Visual<Spec>::Private : Basic_Visual::Prev_Private {
|
||||
Enqueue_Paint enqueue{}; /* 只入队不等待 GPU 完成的 Paint 入口。 */
|
||||
};
|
||||
Paint_Target paint_target{}; /* Builder 绑定的所属 Scene 异步 Paint 目标。 */
|
||||
Prepared_Visual prepared{}; /* 最近一次 Prepare 生成的唯一提交产物。 */
|
||||
std::uint64_t next_revision{1}; /* 下一份 Prepared_Visual 的单调版本。 */
|
||||
/* Scene Builder 调用:绑定只入队的异步 Paint 目标,目标生命周期必须覆盖 Visual。 */
|
||||
void bind_paint_target(std::shared_ptr<void> context, Enqueue_Paint enqueue);
|
||||
/* CRTP 数据能力:从当前 Prop 构建后端字段,不访问其他缓冲角色。 */
|
||||
template <Attached Object>
|
||||
void prepare_data(Object* object);
|
||||
/* CRTP 子图能力:每帧提交一次后端渲染;比较双槽 revision 后直接使用最新 Prepared 数据。 */
|
||||
/* CRTP 子图能力:提交本 Visual 最近一次 Prepare 生成的唯一产物。 */
|
||||
template <Attached Object>
|
||||
[[nodiscard]] tf::Taskflow build_paint_graph(Object* object, const Prop& prop);
|
||||
/* CRTP 覆盖:绑定 Scene 后每帧执行 Paint;dirty 只表示 Prepared 数据是否更新,不控制帧生成。 */
|
||||
@@ -25,9 +26,6 @@ struct Basic_Visual<Spec>::Private : Basic_Visual::Prev_Private {
|
||||
/* CRTP Prop hook:本层字段改变时标记 Prepare。 */
|
||||
template <typename Object, typename Owner, typename Member, typename Prop_Type>
|
||||
void after_prop_set(Object* object, Member Owner::* member, Prop_Access<Prop_Type> props);
|
||||
/* CRTP 推进 hook:从 Prop 计算公开计数,不复制图元集合。 */
|
||||
template <typename Object, typename Prop_Type, typename State_Type>
|
||||
void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
[[nodiscard]] static bool valid_items(const std::vector<Item>& items);
|
||||
};
|
||||
template <typename Spec>
|
||||
@@ -53,15 +51,16 @@ void Basic_Visual<Spec>::Private::prepare_data(Object* object) {
|
||||
auto data = std::make_shared<Prepared_Data>();
|
||||
Spec::prepare(prop.items, *data);
|
||||
if constexpr (requires { data->style = prop.style; }) data->style = prop.style;
|
||||
auto& output = object->template pending_buffer<detail::Prepared_Visual_Tag>();
|
||||
auto& output = prepared;
|
||||
output = {};
|
||||
output.transform = prop.transform;
|
||||
output.visible = prop.visible;
|
||||
output.depth_test = prop.depth_test;
|
||||
output.revision = next_revision++;
|
||||
output.data = std::move(data);
|
||||
object->template update_state<&State::prepared_item_count, &State::prepared_revision>([&](State_Access<typename Object::State> states) {
|
||||
object->template update_state<&State::item_count, &State::prepared_item_count, &State::prepared_revision>([&](State_Access<typename Object::State> states) {
|
||||
auto& state = states.template get<Visual_Tag>();
|
||||
state.item_count = prop.items.size();
|
||||
state.prepared_item_count = prop.items.size();
|
||||
state.prepared_revision = output.revision;
|
||||
});
|
||||
@@ -72,9 +71,7 @@ tf::Taskflow Basic_Visual<Spec>::Private::build_paint_graph(Object* object, cons
|
||||
tf::Taskflow graph;
|
||||
graph.emplace([this, object] {
|
||||
if (auto context = paint_target.context.lock(); context && paint_target.enqueue) {
|
||||
const auto& pending = object->template pending_buffer<detail::Prepared_Visual_Tag>();
|
||||
const auto& current = object->template current_buffer<detail::Prepared_Visual_Tag>();
|
||||
paint_target.enqueue(context.get(), object, pending.revision >= current.revision ? pending : current);
|
||||
paint_target.enqueue(context.get(), object, prepared);
|
||||
}
|
||||
}).name("render_3d.paint.publish");
|
||||
return graph;
|
||||
@@ -89,10 +86,4 @@ template <typename Object, typename Owner, typename Member, typename Prop_Type>
|
||||
void Basic_Visual<Spec>::Private::after_prop_set(Object* object, Member Owner::*, Prop_Access<Prop_Type>) {
|
||||
if constexpr (std::same_as<Owner, Prop>) object->template mark_dirty<Prepare_Data_Tag>();
|
||||
}
|
||||
template <typename Spec>
|
||||
template <typename Object, typename Prop_Type, typename State_Type>
|
||||
void Basic_Visual<Spec>::Private::before_advance(Object*, Prop_Type*, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type>) {
|
||||
using Visual_Tag = typename Basic_Visual::Base_Tag;
|
||||
pending_states.template get<Visual_Tag>().item_count = static_cast<const Prop&>(*current_prop).items.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
#include "../base/Types.hpp"
|
||||
#include <memory>
|
||||
namespace aethera::render_3d::detail {
|
||||
struct Prepared_Visual_Tag {};
|
||||
using Prepared_Position = std::array<float, 3>;
|
||||
using Prepared_Color = std::array<std::uint8_t, 4>;
|
||||
|
||||
/* 每个 Visual 的双缓冲只保存自己 Spec::Prepared_Data 的强类型结果。 */
|
||||
/* 每个 Visual 的 Private 只保存自己 Spec::Prepared_Data 的强类型结果。 */
|
||||
template <typename Data>
|
||||
struct Prepared_Visual_For {
|
||||
Matrix4 transform{};
|
||||
|
||||
@@ -15,7 +15,6 @@ void verify_visual(Item valid, Item) {
|
||||
object->template set<&Visual::Prop::items>(std::vector<Item>{valid});
|
||||
object->advance();
|
||||
EXPECT_EQ(object->template read_prop<typename Visual::Base_Tag>().items.size(), 1U);
|
||||
EXPECT_EQ(object->template read_state<typename Visual::Base_Tag>().item_count, 1U);
|
||||
}
|
||||
}
|
||||
TEST(Render_3D_Visual, Migrated_Families_Build_And_Validate) {
|
||||
@@ -41,7 +40,10 @@ TEST(Render_3D_Scene, Builder_Instantiates_Async_Paint_Contract) {
|
||||
auto visual_result = typename Visual_Object::Builder{}.build();
|
||||
ASSERT_TRUE(visual_result.has_value());
|
||||
auto visual = std::move(visual_result).value();
|
||||
typename Scene_Object::Builder scene_builder(visual.get());
|
||||
auto camera = *Impl<Camera_3D>::Builder{}.build();
|
||||
auto axes = *Impl<Axes_3D>::Builder{}.build();
|
||||
typename Scene_Object::Builder scene_builder;
|
||||
scene_builder.add_renderable(visual.get()).add_camera(camera.get()).add_axes(axes.get());
|
||||
static_assert(std::same_as<decltype(scene_builder.build()), std::expected<std::unique_ptr<Scene_Object>, Dependency_Graph_Error>>);
|
||||
}
|
||||
TEST(Render_3D_Scene, Paint_Submits_Without_Waiting_For_Gpu) {
|
||||
@@ -50,10 +52,14 @@ TEST(Render_3D_Scene, Paint_Submits_Without_Waiting_For_Gpu) {
|
||||
auto visual_result = typename Visual_Object::Builder{}.build();
|
||||
ASSERT_TRUE(visual_result.has_value());
|
||||
auto visual = std::move(visual_result).value();
|
||||
auto camera = *Impl<Camera_3D>::Builder{}.build();
|
||||
auto axes = *Impl<Axes_3D>::Builder{}.build();
|
||||
visual->set<&Point_Visual::Prop::items>(std::vector<Point>{Point{.position = {0.0F, 0.0F, 0.0F}, .color = Color::red_color(), .diameter_px = 8.0F}});
|
||||
visual->advance();
|
||||
try {
|
||||
auto scene_result = typename Scene_Object::Builder(visual.get()).build();
|
||||
typename Scene_Object::Builder scene_builder;
|
||||
scene_builder.add_renderable(visual.get()).add_camera(camera.get()).add_axes(axes.get());
|
||||
auto scene_result = scene_builder.build();
|
||||
ASSERT_TRUE(scene_result.has_value());
|
||||
auto scene = std::move(scene_result).value();
|
||||
std::atomic_bool frame_ready{};
|
||||
|
||||
Reference in New Issue
Block a user