Files
Aethera/render_3D/render_3D/detail/Datoviz_Visual_Backend.ipp
T
2026-08-28 12:14:15 +08:00

166 lines
9.4 KiB
C++

#pragma once
#include <datoviz/drp2/runtime.h>
#include <datoviz/input/router.h>
#include <datoviz/scene.h>
#include <datoviz/stream/frame_stream.h>
#include <datoviz/vk/gpu_ctx.h>
#include <datoviz/vklite.h>
#include <array>
#include <atomic>
#include <mutex>
#include <stdexcept>
#include <string>
#include <utility>
namespace aethera::render_3d::detail {
struct Datoviz_Visual_Backend::Private : Prev_Private {
struct Frame_Target;
struct Frame_Targets;
struct External_Attribute {
std::string name{}; /* Datoviz attribute semantic owned by this binding. */
std::uint32_t stride{}; /* One planar attribute item in bytes. */
std::uint32_t capacity{}; /* Items per independently writable frame region. */
DvzSceneBuffer* scene_buffer{}; /* Scene-side stable resource label; Scene owns it. */
DvzBuffer* gpu_buffer{}; /* Three-region runtime buffer owned by this backend. */
std::uint8_t registered_targets{}; /* Runtime slots that have borrowed gpu_buffer. */
};
struct Visual_Instance {
Visual_Identity identity{}; /* Scene 注册的稳定身份。 */
Visual_Family family{Visual_Family::point}; /* 原生 Visual 的确定 family。 */
DvzVisual* visual{}; /* 由 Datoviz Scene 拥有。 */
DvzSampledField* field{}; /* 仅纹理和体数据 family 使用的 Scene 字段资源。 */
DvzFont* font{}; /* Glyph/Text 使用的 Scene 字体与可增长 atlas 来源。 */
DvzText* coordinate_text{}; /* Marker 的数据坐标 XYZ 标注。 */
std::array<std::uint32_t, 3> field_extent{}; /* field 当前样本尺寸。 */
std::uint64_t applied_revision{}; /* 此 Visual 已上传的 Prepare 版本。 */
std::array<std::uint64_t, 3> uploaded_data_revisions{}; /* 各物理帧区已写入的数据版本。 */
std::optional<Prepared_Visual> applied{}; /* 最近应用的元数据与不可变载荷所有权。 */
std::vector<External_Attribute> attributes{}; /* 每字段各自拥有三段动态载荷区域。 */
};
struct Runtime_Slot {
DvzDrp2Runtime* runtime{}; /* 只执行对应帧目标的命令流。 */
DvzFramePlanEmitter* emitter{}; /* 与 runtime 一一对应的保留语义状态。 */
};
Private();
~Private() override;
void initialize(std::uint32_t gpu_index, bool validation_enabled,
const std::vector<Visual_Registration>& visuals,
const Scene_3D_Parameters& initial_scene);
void create_scene(const std::vector<Visual_Registration>& visuals,
const Scene_3D_Parameters& initial_scene);
void apply_camera(const Camera_Descriptor& camera);
void apply_axes(const Scene_3D_Parameters& scene);
[[nodiscard]] bool matches_command_structure(
const Scene_3D_Parameters& scene,
const Prepared_Visual_Batch& visuals) const;
[[nodiscard]] std::uint64_t apply(
const Scene_3D_Parameters& scene,
const Prepared_Visual_Batch& visuals,
std::uint8_t target_index, bool bind_target);
[[nodiscard]] std::uint64_t apply_visual(
Visual_Instance& target, const Prepared_Visual& visual,
std::uint8_t target_index, bool bind_target);
void ensure_external_attributes(Visual_Instance& target,
const Prepared_Visual& visual);
[[nodiscard]] std::uint64_t upload_external_attributes(
Visual_Instance& target, const Prepared_Visual& visual,
std::uint8_t target_index);
void bind_external_attributes(Visual_Instance& target,
std::uint8_t target_index,
std::uint32_t item_count);
void register_external_attributes(const DvzDrp2CommandStream* stream,
std::uint8_t target_index);
[[nodiscard]] std::optional<Pending_Frame> reuse_recorded_target(
const Scene_3D_Parameters& scene,
const Prepared_Visual_Batch& visuals,
std::uint64_t frame_sequence, bool observe, bool readback);
[[nodiscard]] std::optional<Pending_Frame> prepare(
const Scene_3D_Parameters& scene,
const Prepared_Visual_Batch& visuals,
std::uint64_t frame_sequence, bool observe, bool readback);
[[nodiscard]] std::optional<Pending_Frame> try_prepare_reused(
const Scene_3D_Parameters& scene,
const Prepared_Visual_Batch& visuals,
std::uint64_t frame_sequence, bool observe, bool readback);
[[nodiscard]] DvzSceneFrameArtifact* emit(
const Scene_3D_Parameters& scene, std::uint8_t target_index);
[[nodiscard]] std::optional<std::uint8_t> acquire_target(Extent extent);
[[nodiscard]] Frame_Target& target(const Pending_Frame& pending);
void submit(Pending_Frame& pending);
[[nodiscard]] Completed_Frame collect(Pending_Frame pending);
void discard(Pending_Frame pending);
void quarantine(Pending_Frame pending) noexcept;
void dispatch_pointer(Event_Type type, float x, float y,
Mouse_Button button,
Keyboard_Modifier modifiers,
Extent viewport,
std::uint64_t occurred_at_ns);
void dispatch_wheel(float x, float y, float delta_x, float delta_y,
Keyboard_Modifier modifiers,
Extent viewport,
std::uint64_t occurred_at_ns);
void dispatch_key(const Key_Event& event);
void abandon_resources() noexcept;
void destroy();
std::shared_ptr<Datoviz_Render_Context> render_context_{}; /* 同一 GPU 上所有后端共享的 Device 与分配器。 */
mutable std::mutex target_mutex_{}; /* 当前 Scene 三个目标槽的唯一生命周期同步源。 */
std::array<Runtime_Slot, 3> runtime_slots_{}; /* 三套独立 runtime/emitter 状态机。 */
DvzScene* scene_{}; /* 本后端唯一拥有的 Datoviz Scene。 */
DvzFigure* figure_{}; /* 当前离屏 Figure。 */
DvzPanel* panel_{}; /* 承载全部业务 Visual 的全屏 Panel。 */
std::vector<Visual_Instance> visuals_{}; /* 按 Scene 稳定身份管理的原生 Visual。 */
std::vector<DvzBuffer*> external_buffers_{}; /* runtime 销毁前保持存活的借用缓冲。 */
DvzVisual* axes_visual_{}; /* 三维主轴、刻度和网格 Segment Visual。 */
DvzText* axes_text_{}; /* 随相机变换的三维刻度与轴标题。 */
DvzItemInteraction* item_interaction_{}; /* Datoviz 原生图元悬停与选择控制器。 */
DvzPinnedReadout* hover_readout_{}; /* 最近一次命中的 Datoviz 数据提示卡。 */
DvzController* camera_controller_{}; /* 当前绑定到 Panel 的原生相机控制器。 */
DvzInputRouter* input_router_{}; /* Scene 输入事件路由器。 */
DvzPointerGestureHandler* gesture_handler_{}; /* 指针手势解析器。 */
std::unique_ptr<Frame_Targets> targets_{}; /* 三个可并行处于准备、GPU、读回阶段的目标。 */
Extent figure_extent_{}; /* Figure 当前应用的像素尺寸。 */
std::uint64_t target_generation_{}; /* 每次重建目标时递增的资源代次。 */
std::uint64_t command_revision_{1}; /* 结构变化后递增的命令录制版本。 */
std::optional<Camera_Descriptor> applied_camera_{}; /* 已应用到 Panel 的 Camera 配置。 */
std::optional<std::array<plot::Axis_Descriptor, 3>> applied_axes_{}; /* 已应用到轴 Visual 的描述。 */
bool input_changed_{}; /* 输入是否产生尚未录入命令的资源变化。 */
std::atomic_bool quarantined_{}; /* GPU 异常后是否永久放弃销毁与复用。 */
};
template <typename Object>
Datoviz_Visual_Backend::Builder<Object>::Builder(
std::uint32_t gpu_index_value, bool validation_enabled_value,
std::vector<Visual_Registration> visuals_value,
Scene_3D_Parameters initial_scene_value)
: Base(),
gpu_index(gpu_index_value),
validation_enabled(validation_enabled_value),
visuals(std::move(visuals_value)),
initial_scene(std::move(initial_scene_value)) {}
template <typename Object>
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error>
Datoviz_Visual_Backend::Builder<Object>::build() {
if (visuals.empty())
throw std::invalid_argument(
"Datoviz backend requires at least one Visual registration");
auto result = Base::build();
if (!result) return std::unexpected(result.error());
auto backend = std::move(result).value();
auto& private_data = Base::private_access(backend.get())
.template get<Datoviz_Visual_Backend::Base_Tag>();
private_data.initialize(gpu_index, validation_enabled, visuals,
initial_scene);
return backend;
}
} // namespace aethera::render_3d::detail