加所有权之前
This commit is contained in:
@@ -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 收口后传回同一外部帧。 */
|
||||
/*
|
||||
* 无等待写入调用方拥有的 Frame;Scene 始终只借用地址。最多三个借用可在
|
||||
* CPU Prepare、GPU 和读回阶段重叠,完成全部写入并清除借用后调用唯一完成回调。
|
||||
*/
|
||||
/* GPU 实际提交并释放下一次 Prepare 时调用;仅用于调用方继续驱动帧策略。 */
|
||||
/*
|
||||
* 返回 GPU 完成并回读像素后、帧回调前执行的直接 Taskflow。
|
||||
* 只能在 Scene 没有运行时修改该图;禁止在执行期间 emplace/erase/clear。
|
||||
|
||||
@@ -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_graph;Scene 清除全部借用引用后,以唯一完成回调通知帧策略。
|
||||
* 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() 前写入 viewport,Visual 也可能在同一帧更新属性。
|
||||
* 调用方在 render() 前写入 viewport,Visual 也可能在同一帧更新属性。
|
||||
* 在创建或执行 frame_taskflow 前一次性推进完整 Scene,确保公共
|
||||
* Render_Graph_Tag 已构建并且 frame DAG 引用的是同一权威运行图。
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user