加所有权之前

This commit is contained in:
2026-08-28 12:14:15 +08:00
parent 81d3d50966
commit 0bc281b6b9
86 changed files with 12167 additions and 427 deletions
@@ -27,6 +27,8 @@ struct Datoviz_Frame_Observation {
Datoviz_Frame_Path path{Datoviz_Frame_Path::recorded}; /* 本帧录制命令或复用既有命令。 */
bool gpu_timing_requested{}; /* 本帧是否读取已录制的 GPU 时间戳。 */
bool readback_requested{}; /* 本帧是否请求最终 RGBA 读回。 */
bool controller_input_applied{}; /* 本帧是否把已提交输入应用到 Datoviz 控制器。 */
bool prepare_released_after_submission{}; /* 本帧实际提交后是否立即允许下一帧 Prepare。 */
std::uint64_t render_domain_queue_wait_ns{}; /* 唯一 GPU 提交域排队耗时。 */
std::uint64_t apply_ns{}; /* 应用本帧 Visual 数据耗时。 */
std::uint64_t emit_ns{}; /* 生成 Datoviz 帧计划耗时。 */
@@ -111,7 +111,7 @@ struct Async_Render_Backend::Implementation
std::atomic_bool completion_enqueued{}; /* reservation 与提交失败只允许一个退休事实。 */
};
struct Gpu_Completion {
std::shared_ptr<Pending> pending{}; /* 完成前保持帧目标和回调集合存活。 */
std::shared_ptr<Pending> pending{}; /* 完成前保持后台目标、借用地址和回调集合。 */
std::optional<Gpu_Completion_Service::Result> result{}; /* fence 正常交付时的结果。 */
std::exception_ptr failure{}; /* 提交域或完成服务的 Unknown Failure。 */
};
@@ -368,6 +368,8 @@ void Async_Render_Backend::Implementation::submit_prepared(
std::shared_ptr<Pending> pending) {
pending->backend_frame.observation.render_domain_queue_wait_ns =
pending->domain_queue_wait_ns;
pending->backend_frame.observation.prepare_released_after_submission =
overlaps_gpu;
pending->output->mark(Frame_Trace_Marker::backend_submit_queued);
backend->submit(pending->backend_frame);
pending->submitted.store(true, std::memory_order_release);
@@ -484,7 +486,8 @@ void Async_Render_Backend::Implementation::dispatch(
wheel->angle_delta_x_value()),
wheel_step(wheel->pixel_delta_y_value(),
wheel->angle_delta_y_value()),
pointer->keyboard_modifiers(), viewport);
pointer->keyboard_modifiers(), viewport,
event->occurred_at.nanoseconds);
}
else if (pointer_valid &&
(event->type == Event_Type::pointer_move ||
@@ -497,7 +500,8 @@ void Async_Render_Backend::Implementation::dispatch(
event->type == Event_Type::pointer_move
? held_button(pointer->pointer_buttons())
: pointer->pointer_button(),
pointer->keyboard_modifiers(), viewport);
pointer->keyboard_modifiers(), viewport,
event->occurred_at.nanoseconds);
}
else if (key) backend->dispatch_key(*key);
if ((wheel && pointer_valid) || pointer_valid || key) event->accept();
@@ -2052,7 +2052,8 @@ std::uint64_t Datoviz_Visual_Backend::Private::apply_visual(
void Datoviz_Visual_Backend::Private::dispatch_pointer(
::aethera::Event_Type event, float x, float y,
::aethera::Mouse_Button mouse_button,
::aethera::Keyboard_Modifier keyboard_modifiers, Extent viewport) {
::aethera::Keyboard_Modifier keyboard_modifiers, Extent viewport,
std::uint64_t occurred_at_ns) {
std::lock_guard api_lock(render_context_->api_mutex());
input_changed_ = true;
if (applied_camera_ && applied_camera_->controller == Camera_Controller::turntable) {
@@ -2075,11 +2076,12 @@ void Datoviz_Visual_Backend::Private::dispatch_pointer(
dvz_pointer_emit_position(input_router_, type, x, y, width, height,
button(mouse_button),
modifiers(keyboard_modifiers), 1.0F,
dvz_input_timestamp_ns(), nullptr);
occurred_at_ns, nullptr);
}
void Datoviz_Visual_Backend::Private::dispatch_wheel(
float x, float y, float delta_x, float delta_y,
::aethera::Keyboard_Modifier keyboard_modifiers, Extent viewport) {
::aethera::Keyboard_Modifier keyboard_modifiers, Extent viewport,
std::uint64_t occurred_at_ns) {
std::lock_guard api_lock(render_context_->api_mutex());
input_changed_ = true;
if (applied_camera_ &&
@@ -2089,7 +2091,7 @@ void Datoviz_Visual_Backend::Private::dispatch_wheel(
dvz_pointer_emit_wheel(
input_router_, x, y, static_cast<float>(viewport.width),
static_cast<float>(viewport.height), delta_x, delta_y,
modifiers(keyboard_modifiers), 1.0F, dvz_input_timestamp_ns(), nullptr);
modifiers(keyboard_modifiers), 1.0F, occurred_at_ns, nullptr);
}
void Datoviz_Visual_Backend::Private::dispatch_key(
const ::aethera::Key_Event& event) {
@@ -2269,6 +2271,7 @@ Datoviz_Visual_Backend::Private::prepare(
observation.path = Datoviz_Frame_Path::recorded;
observation.gpu_timing_requested = observe;
observation.readback_requested = readback;
observation.controller_input_applied = input_changed_;
std::uint64_t phase_started = trace_now_ns();
const bool content_changed = !matches_command_structure(scene, visuals);
if (content_changed) ++command_revision_;
@@ -2566,16 +2569,18 @@ void Datoviz_Visual_Backend::quarantine(Pending_Frame pending) noexcept {
void Datoviz_Visual_Backend::dispatch_pointer(
Event_Type type, float x, float y, Mouse_Button button,
Keyboard_Modifier modifiers, Extent viewport) {
Keyboard_Modifier modifiers, Extent viewport,
std::uint64_t occurred_at_ns) {
static_cast<Private&>(*d).dispatch_pointer(
type, x, y, button, modifiers, viewport);
type, x, y, button, modifiers, viewport, occurred_at_ns);
}
void Datoviz_Visual_Backend::dispatch_wheel(
float x, float y, float delta_x, float delta_y,
Keyboard_Modifier modifiers, Extent viewport) {
Keyboard_Modifier modifiers, Extent viewport,
std::uint64_t occurred_at_ns) {
static_cast<Private&>(*d).dispatch_wheel(
x, y, delta_x, delta_y, modifiers, viewport);
x, y, delta_x, delta_y, modifiers, viewport, occurred_at_ns);
}
void Datoviz_Visual_Backend::dispatch_key(const Key_Event& event) {
@@ -85,10 +85,12 @@ struct Datoviz_Visual_Backend final
void dispatch_pointer(Event_Type type, float x, float y,
Mouse_Button button,
Keyboard_Modifier modifiers,
Extent viewport);
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);
Extent viewport,
std::uint64_t occurred_at_ns);
void dispatch_key(const Key_Event& event);
};
@@ -100,10 +100,12 @@ struct Datoviz_Visual_Backend::Private : Prev_Private {
void dispatch_pointer(Event_Type type, float x, float y,
Mouse_Button button,
Keyboard_Modifier modifiers,
Extent viewport);
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);
Extent viewport,
std::uint64_t occurred_at_ns);
void dispatch_key(const Key_Event& event);
void abandon_resources() noexcept;
void destroy();
@@ -58,9 +58,11 @@ struct Render_Scene_3D : Def<Render_Scene_3D, Scene> {
[[nodiscard]] Render_Result render(Frame_3D* frame);
void set_frame_callback(Frame_Callback callback);
void set_submitted_frame_callback(Submitted_Frame_Callback callback);
/* 无等待提交到调用方拥有的帧;最多三个帧槽,资源能力决定提交或完成释放。 */
/* GPU 实际提交并释放下一次 Prepare 时调用;bool 表示是否与 GPU 重叠。 */
/* 安装完成帧回调;completion graph 收口后传回同一外部帧。 */
/*
* FrameScene
* CPU PrepareGPU
*/
/* GPU 实际提交并释放下一次 Prepare 时调用;仅用于调用方继续驱动帧策略。 */
/*
* GPU Taskflow
* Scene emplace/erase/clear
+11 -11
View File
@@ -47,11 +47,10 @@ struct Render_Scene_3D::Private : Prev_Private {
* Prepare,使 CPU(N+1)、GPU(N) 和读回(N-1) 能够重叠。
* 3. Image/Text/Volume 等仍共享 Datoviz Scene 资源的 Visual 不在提交点
* 提前释放,而在 GPU 退休后释放;这是一条明确能力边界,不是 fallback。
* 4. GPU fence 回调只发布 gpu_completed 事实。completion_busy 选择一个
* 已完成帧执行 completion_graph该图结束后才归还槽。因此 Scene 和
* Renderable State、Plot 发布及用户 callback 始终保持唯一完成写者。
* 5. 全路径不等待 GPU、不复制组件状态、不创建帧外统计副本。帧身份、
* 像素、Trace 和完成事实都留在其 Frame_Context/Frame 本身。
* 4. GPU fence 回调只结束当前借用。completion_busy 选择一个已完成帧执行
* completion_graphScene 清除全部借用引用后,以唯一完成回调通知帧策略。
* 5. Scene 从不拥有 Frame,也不决定其复用时机。全路径不等待 GPU、不复制
* 组件状态、不创建帧外统计副本,物理事实始终写入调用方拥有的 Frame。
*/
static constexpr std::size_t frame_capacity{3};
std::array<Frame_Context, frame_capacity> frame_contexts{};
@@ -199,12 +198,12 @@ void Render_Scene_3D::Private::complete_frame(
Object*, Frame_Context* context) {
auto* frame = context->frame;
const auto callback = frame_callback.load(std::memory_order_acquire);
frame->mark(Frame_Trace_Marker::callback_started);
if (callback && *callback) (*callback)(frame);
frame->mark(Frame_Trace_Marker::callback_finished);
frame->mark(Frame_Trace_Marker::frame_ready);
if (context->trace_started)
aethera::detail::finish_taskflow_trace(*frame);
/* Scene 仅借用外部 Frame。完成通知前必须先清除所有借用引用并开放
* Frame_Context;回调之后是否发布、统计或复用只由调用方帧策略决定。 */
context->frame = nullptr;
context->events.clear();
context->failure = {};
@@ -214,6 +213,7 @@ void Render_Scene_3D::Private::complete_frame(
context->gpu_submitted.store(false, std::memory_order_relaxed);
context->gpu_completed.store(false, std::memory_order_relaxed);
context->phase.store(Frame_Phase::available, std::memory_order_release);
if (callback && *callback) (*callback)(frame);
}
inline Render_Scene_3D::Private::Frame_Context*
@@ -392,7 +392,7 @@ void Render_Scene_3D::Private::ensure_frame_taskflow(Object* object) {
auto* frame_context = context_for(submitted);
if (!frame_context)
throw std::logic_error(
"3D backend submitted an unowned Scene frame");
"3D backend submitted a frame not borrowed by Scene");
frame_context->overlaps_gpu = overlaps_gpu;
frame_context->gpu_submitted.store(
true, std::memory_order_release);
@@ -403,7 +403,7 @@ void Render_Scene_3D::Private::ensure_frame_taskflow(Object* object) {
auto* frame_context = context_for(completed);
if (!frame_context)
throw std::logic_error(
"3D backend completed an unowned Scene frame");
"3D backend completed a frame not borrowed by Scene");
frame_context->failure = std::move(failure);
if (frame_context->failure &&
!frame_context->gpu_submitted.load(
@@ -471,7 +471,7 @@ Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Object* object,
};
try {
/*
* Plot 在 render() 前写入 viewportVisual 也可能在同一帧更新属性。
* 调用方在 render() 前写入 viewportVisual 也可能在同一帧更新属性。
* 在创建或执行 frame_taskflow 前一次性推进完整 Scene,确保公共
* Render_Graph_Tag 已构建并且 frame DAG 引用的是同一权威运行图。
*/