From 4ff2220e38ec99f414d0d30ad4fd5ed8bd5e364d Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Sat, 29 Aug 2026 14:00:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/kernel/frame.cpp | 48 +++++++ kernel/src/kernel/frame.hpp | 24 ++++ kernel/src/kernel/frame_statistics.hpp | 24 ++++ mcp/core/runtime/Plot.cpp | 32 ++++- mcp/tests/Control_Path_Benchmarks.cpp | 77 ++++++++++++ .../base/Datoviz_Frame_Observation.hpp | 29 ++++- render_3D/render_3D/scene/Render_Scene_3D.ipp | 63 +++++++++- .../scene/detail/Datoviz_Frame_Pipeline.ipp | 119 ++++++++++++++---- .../datoviz/include/datoviz/drp2/runtime.h | 18 +++ .../third_party/datoviz/src/drp2/_runtime.h | 6 +- .../third_party/datoviz/src/drp2/backend.c | 15 ++- .../third_party/datoviz/src/drp2/pipeline.c | 10 +- .../third_party/datoviz/src/drp2/runtime.c | 21 +++- .../datoviz/src/scene/runtime/render_pass.c | 26 +--- 14 files changed, 452 insertions(+), 60 deletions(-) diff --git a/kernel/src/kernel/frame.cpp b/kernel/src/kernel/frame.cpp index 2d64591..754c3d5 100644 --- a/kernel/src/kernel/frame.cpp +++ b/kernel/src/kernel/frame.cpp @@ -123,6 +123,30 @@ Frame_Statistics_Sample Render_Frame::statistics() const { Frame_Statistic::backend_apply_ms, Frame_Statistic::backend_plan_ms, Frame_Statistic::backend_execute_ms, + Frame_Statistic::backend_target_acquire_ms, + Frame_Statistic::backend_structure_check_ms, + Frame_Statistic::backend_query_ms, + Frame_Statistic::backend_runtime_plan_ms, + Frame_Statistic::backend_runtime_execute_ms, + Frame_Statistic::backend_mvp_update_ms, + Frame_Statistic::backend_frame_begin_ms, + Frame_Statistic::backend_frame_plan_ms, + Frame_Statistic::backend_external_register_ms, + Frame_Statistic::backend_frame_attach_ms, + Frame_Statistic::backend_frame_execute_ms, + Frame_Statistic::backend_frame_finish_ms, + Frame_Statistic::backend_drp_validation_ms, + Frame_Statistic::backend_drp_state_ms, + Frame_Statistic::backend_drp_buffer_create_ms, + Frame_Statistic::backend_drp_texture_create_ms, + Frame_Statistic::backend_drp_shader_create_ms, + Frame_Statistic::backend_drp_shader_compile_ms, + Frame_Statistic::backend_drp_shader_module_create_ms, + Frame_Statistic::backend_drp_pipeline_create_ms, + Frame_Statistic::backend_drp_binding_create_ms, + Frame_Statistic::backend_drp_upload_ms, + Frame_Statistic::backend_drp_transfer_ms, + Frame_Statistic::backend_drp_record_ms, Frame_Statistic::backend_submit_queue_ms, Frame_Statistic::backend_submit_ms, Frame_Statistic::gpu_completion_observation_ms, @@ -136,6 +160,30 @@ Frame_Statistics_Sample Render_Frame::statistics() const { Frame_Trace_Measurement::backend_apply_ns, Frame_Trace_Measurement::backend_plan_ns, Frame_Trace_Measurement::backend_execute_ns, + Frame_Trace_Measurement::backend_target_acquire_ns, + Frame_Trace_Measurement::backend_structure_check_ns, + Frame_Trace_Measurement::backend_query_ns, + Frame_Trace_Measurement::backend_runtime_plan_ns, + Frame_Trace_Measurement::backend_runtime_execute_ns, + Frame_Trace_Measurement::backend_mvp_update_ns, + Frame_Trace_Measurement::backend_frame_begin_ns, + Frame_Trace_Measurement::backend_frame_plan_ns, + Frame_Trace_Measurement::backend_external_register_ns, + Frame_Trace_Measurement::backend_frame_attach_ns, + Frame_Trace_Measurement::backend_frame_execute_ns, + Frame_Trace_Measurement::backend_frame_finish_ns, + Frame_Trace_Measurement::backend_drp_validation_ns, + Frame_Trace_Measurement::backend_drp_state_ns, + Frame_Trace_Measurement::backend_drp_buffer_create_ns, + Frame_Trace_Measurement::backend_drp_texture_create_ns, + Frame_Trace_Measurement::backend_drp_shader_create_ns, + Frame_Trace_Measurement::backend_drp_shader_compile_ns, + Frame_Trace_Measurement::backend_drp_shader_module_create_ns, + Frame_Trace_Measurement::backend_drp_pipeline_create_ns, + Frame_Trace_Measurement::backend_drp_binding_create_ns, + Frame_Trace_Measurement::backend_drp_upload_ns, + Frame_Trace_Measurement::backend_drp_transfer_ns, + Frame_Trace_Measurement::backend_drp_record_ns, Frame_Trace_Measurement::backend_submit_queue_ns, Frame_Trace_Measurement::backend_submit_ns, Frame_Trace_Measurement::gpu_completion_observation_ns, diff --git a/kernel/src/kernel/frame.hpp b/kernel/src/kernel/frame.hpp index bacef52..dcf5bfe 100644 --- a/kernel/src/kernel/frame.hpp +++ b/kernel/src/kernel/frame.hpp @@ -54,6 +54,30 @@ enum struct Frame_Trace_Measurement : std::uint8_t { backend_apply_ns, backend_plan_ns, backend_execute_ns, + backend_target_acquire_ns, + backend_structure_check_ns, + backend_query_ns, + backend_runtime_plan_ns, + backend_runtime_execute_ns, + backend_mvp_update_ns, + backend_frame_begin_ns, + backend_frame_plan_ns, + backend_external_register_ns, + backend_frame_attach_ns, + backend_frame_execute_ns, + backend_frame_finish_ns, + backend_drp_validation_ns, + backend_drp_state_ns, + backend_drp_buffer_create_ns, + backend_drp_texture_create_ns, + backend_drp_shader_create_ns, + backend_drp_shader_compile_ns, + backend_drp_shader_module_create_ns, + backend_drp_pipeline_create_ns, + backend_drp_binding_create_ns, + backend_drp_upload_ns, + backend_drp_transfer_ns, + backend_drp_record_ns, backend_submit_queue_ns, backend_submit_ns, gpu_completion_observation_ns, diff --git a/kernel/src/kernel/frame_statistics.hpp b/kernel/src/kernel/frame_statistics.hpp index 0ef8b2c..420dca7 100644 --- a/kernel/src/kernel/frame_statistics.hpp +++ b/kernel/src/kernel/frame_statistics.hpp @@ -19,6 +19,30 @@ enum struct Frame_Statistic : std::uint8_t { backend_apply_ms, backend_plan_ms, backend_execute_ms, + backend_target_acquire_ms, + backend_structure_check_ms, + backend_query_ms, + backend_runtime_plan_ms, + backend_runtime_execute_ms, + backend_mvp_update_ms, + backend_frame_begin_ms, + backend_frame_plan_ms, + backend_external_register_ms, + backend_frame_attach_ms, + backend_frame_execute_ms, + backend_frame_finish_ms, + backend_drp_validation_ms, + backend_drp_state_ms, + backend_drp_buffer_create_ms, + backend_drp_texture_create_ms, + backend_drp_shader_create_ms, + backend_drp_shader_compile_ms, + backend_drp_shader_module_create_ms, + backend_drp_pipeline_create_ms, + backend_drp_binding_create_ms, + backend_drp_upload_ms, + backend_drp_transfer_ms, + backend_drp_record_ms, backend_submit_queue_ms, backend_submit_ms, gpu_completion_observation_ms, diff --git a/mcp/core/runtime/Plot.cpp b/mcp/core/runtime/Plot.cpp index 1c860b8..a45fb51 100644 --- a/mcp/core/runtime/Plot.cpp +++ b/mcp/core/runtime/Plot.cpp @@ -354,9 +354,34 @@ nlohmann::json datoviz_observation_json( "queue_submit_wait", milliseconds(value.queue_submit_wait_ns) }, + {"target_acquire", milliseconds(value.target_acquire_ns)}, + {"structure_check", milliseconds(value.structure_check_ns)}, {"apply", milliseconds(value.apply_ns)}, - {"emit", milliseconds(value.emit_ns)}, - {"execute", milliseconds(value.execute_ns)}, + {"query", milliseconds(value.query_ns)}, + {"runtime_plan", milliseconds(value.runtime_plan_ns)}, + {"runtime_execute", milliseconds(value.runtime_execute_ns)}, + {"mvp_update", milliseconds(value.mvp_update_ns)}, + {"frame_begin", milliseconds(value.frame_begin_ns)}, + {"frame_plan", milliseconds(value.frame_plan_ns)}, + {"external_register", milliseconds(value.external_register_ns)}, + {"frame_attach", milliseconds(value.frame_attach_ns)}, + {"frame_execute", milliseconds(value.frame_execute_ns)}, + {"frame_finish", milliseconds(value.frame_finish_ns)}, + {"drp_validation", milliseconds(value.drp_validation_ns)}, + {"drp_state", milliseconds(value.drp_state_ns)}, + {"drp_buffer_create", milliseconds(value.drp_buffer_create_ns)}, + {"drp_texture_create", milliseconds(value.drp_texture_create_ns)}, + {"drp_shader_create", milliseconds(value.drp_shader_create_ns)}, + {"drp_shader_compile", milliseconds(value.drp_shader_compile_ns)}, + { + "drp_shader_module_create", + milliseconds(value.drp_shader_module_create_ns) + }, + {"drp_pipeline_create", milliseconds(value.drp_pipeline_create_ns)}, + {"drp_binding_create", milliseconds(value.drp_binding_create_ns)}, + {"drp_upload", milliseconds(value.drp_upload_ns)}, + {"drp_transfer", milliseconds(value.drp_transfer_ns)}, + {"drp_record", milliseconds(value.drp_record_ns)}, {"submit", milliseconds(value.submit_ns)}, { "gpu_completion_observation", @@ -372,7 +397,8 @@ nlohmann::json datoviz_observation_json( { "traffic", { {"uploaded_bytes", value.uploaded_bytes}, - {"readback_bytes", value.readback_bytes} + {"readback_bytes", value.readback_bytes}, + {"pipeline_create_count", value.drp_pipeline_create_count} } }, { diff --git a/mcp/tests/Control_Path_Benchmarks.cpp b/mcp/tests/Control_Path_Benchmarks.cpp index d3d6cf7..ff6372a 100644 --- a/mcp/tests/Control_Path_Benchmarks.cpp +++ b/mcp/tests/Control_Path_Benchmarks.cpp @@ -387,6 +387,44 @@ protected: statistic_value("backend_execute_ms", "p95"); state.counters[prefix + "backend_execute_max_ms"] = statistic_value("backend_execute_ms", "maximum"); + constexpr std::array detailed_backend_statistics{ + "backend_target_acquire_ms", + "backend_structure_check_ms", + "backend_query_ms", + "backend_runtime_plan_ms", + "backend_runtime_execute_ms", + "backend_mvp_update_ms", + "backend_frame_begin_ms", + "backend_frame_plan_ms", + "backend_external_register_ms", + "backend_frame_attach_ms", + "backend_frame_execute_ms", + "backend_frame_finish_ms"}; + constexpr std::array detailed_drp_statistics{ + "backend_drp_validation_ms", + "backend_drp_state_ms", + "backend_drp_buffer_create_ms", + "backend_drp_texture_create_ms", + "backend_drp_shader_create_ms", + "backend_drp_shader_compile_ms", + "backend_drp_shader_module_create_ms", + "backend_drp_pipeline_create_ms", + "backend_drp_binding_create_ms", + "backend_drp_upload_ms", + "backend_drp_transfer_ms", + "backend_drp_record_ms"}; + for (const std::string_view name : detailed_backend_statistics) { + state.counters[prefix + std::string{name} + "/p95"] = + statistic_value(name, "p95"); + state.counters[prefix + std::string{name} + "/max"] = + statistic_value(name, "maximum"); + } + for (const std::string_view name : detailed_drp_statistics) { + state.counters[prefix + std::string{name} + "/p95"] = + statistic_value(name, "p95"); + state.counters[prefix + std::string{name} + "/max"] = + statistic_value(name, "maximum"); + } state.counters[prefix + "backend_submit_queue_ms"] = statistic_value("backend_submit_queue_ms", "average"); state.counters[prefix + "backend_submit_queue_p95_ms"] = @@ -546,6 +584,45 @@ public: << std::setw(10) << counter(prefix + "slot_backpressure") << std::setw(9) << counter(prefix + "scene_rejected") << '\n'; + constexpr std::array detailed_backend_statistics{ + std::pair{"acquire", "backend_target_acquire_ms"}, + std::pair{"structure", "backend_structure_check_ms"}, + std::pair{"query", "backend_query_ms"}, + std::pair{"runtime-plan", "backend_runtime_plan_ms"}, + std::pair{"runtime-exec", "backend_runtime_execute_ms"}, + std::pair{"mvp", "backend_mvp_update_ms"}, + std::pair{"frame-begin", "backend_frame_begin_ms"}, + std::pair{"frame-plan", "backend_frame_plan_ms"}, + std::pair{"external", "backend_external_register_ms"}, + std::pair{"attach", "backend_frame_attach_ms"}, + std::pair{"frame-exec", "backend_frame_execute_ms"}, + std::pair{"finish", "backend_frame_finish_ms"}}; + output << " backend-detail " << id; + for (const auto& [label, statistic] : + detailed_backend_statistics) + output << " " << label << "95/max=" + << counter(prefix + statistic + "/p95") << "/" + << counter(prefix + statistic + "/max"); + output << '\n'; + constexpr std::array detailed_drp_statistics{ + std::pair{"validate", "backend_drp_validation_ms"}, + std::pair{"state", "backend_drp_state_ms"}, + std::pair{"buffer", "backend_drp_buffer_create_ms"}, + std::pair{"texture", "backend_drp_texture_create_ms"}, + std::pair{"shader", "backend_drp_shader_create_ms"}, + std::pair{"shader-compile", "backend_drp_shader_compile_ms"}, + std::pair{"shader-module", "backend_drp_shader_module_create_ms"}, + std::pair{"pipeline", "backend_drp_pipeline_create_ms"}, + std::pair{"binding", "backend_drp_binding_create_ms"}, + std::pair{"upload", "backend_drp_upload_ms"}, + std::pair{"transfer", "backend_drp_transfer_ms"}, + std::pair{"record", "backend_drp_record_ms"}}; + output << " drp-detail " << id; + for (const auto& [label, statistic] : detailed_drp_statistics) + output << " " << label << "95/max=" + << counter(prefix + statistic + "/p95") << "/" + << counter(prefix + statistic + "/max"); + output << '\n'; } output << "aggregate_fps=" << counter("aggregate_fps") << " min_fps=" << counter("minimum_plot_fps") diff --git a/render_3D/render_3D/base/Datoviz_Frame_Observation.hpp b/render_3D/render_3D/base/Datoviz_Frame_Observation.hpp index 6b621ea..877981f 100644 --- a/render_3D/render_3D/base/Datoviz_Frame_Observation.hpp +++ b/render_3D/render_3D/base/Datoviz_Frame_Observation.hpp @@ -31,9 +31,32 @@ struct Datoviz_Frame_Observation { bool controller_input_applied{}; /* 本帧是否把已提交输入应用到 Datoviz 控制器。 */ bool prepare_released_after_submission{}; /* 本帧实际提交后是否立即允许下一帧 Prepare。 */ std::uint64_t queue_submit_wait_ns{}; /* 获取共享 VkQueue 提交权的墙钟耗时。 */ - std::uint64_t apply_ns{}; /* 应用本帧 Visual 数据耗时。 */ - std::uint64_t emit_ns{}; /* 生成 Datoviz 帧计划耗时。 */ - std::uint64_t execute_ns{}; /* 执行 Datoviz 帧计划耗时。 */ + std::uint64_t target_acquire_ns{}; /* 查找或创建本帧三槽目标的墙钟耗时。 */ + std::uint64_t structure_check_ns{}; /* 判断命令结构是否变化的墙钟耗时。 */ + std::uint64_t apply_ns{}; /* 应用 Camera、Axes 和 Visual 数据的墙钟耗时。 */ + std::uint64_t query_ns{}; /* 处理 Datoviz 查询与悬浮读数的墙钟耗时。 */ + std::uint64_t runtime_plan_ns{}; /* 生成增量 Runtime 资源命令流的墙钟耗时。 */ + std::uint64_t runtime_execute_ns{}; /* 执行增量 Runtime 资源命令流的墙钟耗时。 */ + std::uint64_t mvp_update_ns{}; /* 更新可复用命令所引用 MVP 缓冲的墙钟耗时。 */ + std::uint64_t frame_begin_ns{}; /* 重置并开始目标命令缓冲录制的墙钟耗时。 */ + std::uint64_t frame_plan_ns{}; /* 生成完整 Datoviz 帧计划的墙钟耗时。 */ + std::uint64_t external_register_ns{}; /* 注册外部属性缓冲的墙钟耗时。 */ + std::uint64_t frame_attach_ns{}; /* 把借用目标附加到 DRP2 Runtime 的墙钟耗时。 */ + std::uint64_t frame_execute_ns{}; /* 执行完整帧命令流的墙钟耗时。 */ + std::uint64_t frame_finish_ns{}; /* 完成命令录制并建立提交描述的墙钟耗时。 */ + std::uint64_t drp_validation_ns{}; /* DRP2 语义验证与状态复制耗时。 */ + std::uint64_t drp_state_ns{}; /* DRP2 状态建立与提交耗时。 */ + std::uint64_t drp_buffer_create_ns{}; /* Vulkan Buffer 创建命令耗时。 */ + std::uint64_t drp_texture_create_ns{}; /* Vulkan Texture 创建命令耗时。 */ + std::uint64_t drp_shader_create_ns{}; /* Vulkan Shader Module 创建命令耗时。 */ + std::uint64_t drp_shader_compile_ns{}; /* Shader Module 命令中 GLSL 到 SPIR-V 的编译耗时。 */ + std::uint64_t drp_shader_module_create_ns{}; /* Shader Module 命令中 vkCreateShaderModule 的耗时。 */ + std::uint64_t drp_pipeline_create_ns{}; /* Vulkan Pipeline 创建命令耗时。 */ + std::uint64_t drp_binding_create_ns{}; /* Sampler、Layout 与 Bind Group 创建命令耗时。 */ + std::uint64_t drp_upload_ns{}; /* Buffer 与 Texture 写入命令耗时。 */ + std::uint64_t drp_transfer_ns{}; /* 显式 Copy 命令耗时。 */ + std::uint64_t drp_record_ns{}; /* Render/Compute Pass 录制命令耗时。 */ + std::uint32_t drp_pipeline_create_count{}; /* 本帧实际创建的图形/计算管线数。 */ std::uint64_t submit_ns{}; /* Vulkan 队列提交耗时。 */ std::uint64_t gpu_completion_observation_ns{}; /* 从 watch 到探测到 fence 完成的墙钟耗时。 */ std::uint64_t completion_task_queue_ns{}; /* 探测到 fence 完成后,Scene completion task 的排队耗时。 */ diff --git a/render_3D/render_3D/scene/Render_Scene_3D.ipp b/render_3D/render_3D/scene/Render_Scene_3D.ipp index 07d9952..bd95486 100644 --- a/render_3D/render_3D/scene/Render_Scene_3D.ipp +++ b/render_3D/render_3D/scene/Render_Scene_3D.ipp @@ -208,12 +208,67 @@ inline void publish_datoviz_observation( if (observation.apply_ns) frame->record(Frame_Trace_Measurement::backend_apply_ns, observation.apply_ns); - if (observation.emit_ns) + const auto plan_ns = observation.runtime_plan_ns + + observation.frame_plan_ns; + const auto execute_ns = observation.runtime_execute_ns + + observation.frame_attach_ns + observation.frame_execute_ns; + if (plan_ns) frame->record(Frame_Trace_Measurement::backend_plan_ns, - observation.emit_ns); - if (observation.execute_ns) + plan_ns); + if (execute_ns) frame->record(Frame_Trace_Measurement::backend_execute_ns, - observation.execute_ns); + execute_ns); + const std::array detailed_timings{ + std::pair{Frame_Trace_Measurement::backend_target_acquire_ns, + observation.target_acquire_ns}, + std::pair{Frame_Trace_Measurement::backend_structure_check_ns, + observation.structure_check_ns}, + std::pair{Frame_Trace_Measurement::backend_query_ns, + observation.query_ns}, + std::pair{Frame_Trace_Measurement::backend_runtime_plan_ns, + observation.runtime_plan_ns}, + std::pair{Frame_Trace_Measurement::backend_runtime_execute_ns, + observation.runtime_execute_ns}, + std::pair{Frame_Trace_Measurement::backend_mvp_update_ns, + observation.mvp_update_ns}, + std::pair{Frame_Trace_Measurement::backend_frame_begin_ns, + observation.frame_begin_ns}, + std::pair{Frame_Trace_Measurement::backend_frame_plan_ns, + observation.frame_plan_ns}, + std::pair{Frame_Trace_Measurement::backend_external_register_ns, + observation.external_register_ns}, + std::pair{Frame_Trace_Measurement::backend_frame_attach_ns, + observation.frame_attach_ns}, + std::pair{Frame_Trace_Measurement::backend_frame_execute_ns, + observation.frame_execute_ns}, + std::pair{Frame_Trace_Measurement::backend_frame_finish_ns, + observation.frame_finish_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_validation_ns, + observation.drp_validation_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_state_ns, + observation.drp_state_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_buffer_create_ns, + observation.drp_buffer_create_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_texture_create_ns, + observation.drp_texture_create_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_shader_create_ns, + observation.drp_shader_create_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_shader_compile_ns, + observation.drp_shader_compile_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_shader_module_create_ns, + observation.drp_shader_module_create_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_pipeline_create_ns, + observation.drp_pipeline_create_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_binding_create_ns, + observation.drp_binding_create_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_upload_ns, + observation.drp_upload_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_transfer_ns, + observation.drp_transfer_ns}, + std::pair{Frame_Trace_Measurement::backend_drp_record_ns, + observation.drp_record_ns}}; + for (const auto& [measurement, value] : detailed_timings) + if (value) frame->record(measurement, value); if (observation.queue_submit_wait_ns) frame->record(Frame_Trace_Measurement::backend_submit_queue_ns, observation.queue_submit_wait_ns); diff --git a/render_3D/render_3D/scene/detail/Datoviz_Frame_Pipeline.ipp b/render_3D/render_3D/scene/detail/Datoviz_Frame_Pipeline.ipp index 8231ccb..b59782d 100644 --- a/render_3D/render_3D/scene/detail/Datoviz_Frame_Pipeline.ipp +++ b/render_3D/render_3D/scene/detail/Datoviz_Frame_Pipeline.ipp @@ -6,6 +6,60 @@ namespace aethera::render_3d::detail { +namespace { +void accumulate_execution_timing( + const DvzDrp2ExecutionTiming& source, + Datoviz_Frame_Observation& target) noexcept { + const auto command = [&](DvzDrp2CommandType type) noexcept { + return source.command_ns[static_cast(type)]; + }; + const auto count = [&](DvzDrp2CommandType type) noexcept { + return source.command_count[static_cast(type)]; + }; + target.drp_validation_ns += source.validation_ns; + target.drp_state_ns += source.state_ensure_ns + source.state_commit_ns; + target.drp_buffer_create_ns += command(DVZ_DRP2_COMMAND_CREATE_BUFFER); + target.drp_texture_create_ns += command(DVZ_DRP2_COMMAND_CREATE_TEXTURE); + target.drp_shader_create_ns += command(DVZ_DRP2_COMMAND_CREATE_SHADER_MODULE); + target.drp_shader_compile_ns += source.shader_compile_ns; + target.drp_shader_module_create_ns += source.shader_module_create_ns; + target.drp_pipeline_create_ns += + command(DVZ_DRP2_COMMAND_CREATE_RENDER_PIPELINE) + + command(DVZ_DRP2_COMMAND_CREATE_COMPUTE_PIPELINE); + target.drp_pipeline_create_count += + count(DVZ_DRP2_COMMAND_CREATE_RENDER_PIPELINE) + + count(DVZ_DRP2_COMMAND_CREATE_COMPUTE_PIPELINE); + target.drp_binding_create_ns += + command(DVZ_DRP2_COMMAND_CREATE_SAMPLER) + + command(DVZ_DRP2_COMMAND_CREATE_BIND_GROUP_LAYOUT) + + command(DVZ_DRP2_COMMAND_CREATE_BIND_GROUP); + target.drp_upload_ns += command(DVZ_DRP2_COMMAND_WRITE_BUFFER) + + command(DVZ_DRP2_COMMAND_WRITE_TEXTURE); + target.drp_transfer_ns += + command(DVZ_DRP2_COMMAND_COPY_BUFFER_TO_BUFFER) + + command(DVZ_DRP2_COMMAND_COPY_BUFFER_TO_TEXTURE) + + command(DVZ_DRP2_COMMAND_COPY_TEXTURE_TO_BUFFER) + + command(DVZ_DRP2_COMMAND_COPY_TEXTURE_TO_TEXTURE); + constexpr std::array record_commands{ + DVZ_DRP2_COMMAND_BEGIN_RENDER_PASS, + DVZ_DRP2_COMMAND_BEGIN_COMPUTE_PASS, + DVZ_DRP2_COMMAND_SET_VIEWPORT, + DVZ_DRP2_COMMAND_SET_SCISSOR, + DVZ_DRP2_COMMAND_SET_PIPELINE, + DVZ_DRP2_COMMAND_SET_BIND_GROUP, + DVZ_DRP2_COMMAND_SET_VERTEX_BUFFER, + DVZ_DRP2_COMMAND_SET_INDEX_BUFFER, + DVZ_DRP2_COMMAND_DRAW, + DVZ_DRP2_COMMAND_DRAW_INDEXED, + DVZ_DRP2_COMMAND_DISPATCH_WORKGROUPS, + DVZ_DRP2_COMMAND_END_RENDER_PASS, + DVZ_DRP2_COMMAND_END_COMPUTE_PASS, + DVZ_DRP2_COMMAND_RESOURCE_BARRIER}; + for (const auto type : record_commands) + target.drp_record_ns += command(type); +} +} + /* Datoviz Scene 根据当前权威资源生成 DRP2 命令流描述,不提交 GPU。 */ DvzSceneFrameArtifact* Scene_Datoviz_State::emit( const Scene_3D_Parameters& scene, std::uint8_t target_index) { @@ -143,12 +197,6 @@ std::optional Scene_Datoviz_State::prepare( * VkQueue。它必须和 Render Domain 的显式 submit 使用同一外部同步域。 * 热路径的已录制目标复用在此锁之前返回,仍可在各 Scene 准备线程并行。 */ - std::optional target_index; - { - std::lock_guard resource_lock(target_mutex_); - target_index = acquire_target(scene.viewport); - } - if (!target_index) return std::nullopt; Datoviz_Frame_Observation observation; observation.render_sequence = frame_sequence; observation.path = Datoviz_Frame_Path::recorded; @@ -156,14 +204,26 @@ std::optional Scene_Datoviz_State::prepare( observation.readback_requested = readback; observation.controller_input_applied = input_changed_; std::uint64_t phase_started = trace_now_ns(); + std::optional target_index; + { + std::lock_guard resource_lock(target_mutex_); + target_index = acquire_target(scene.viewport); + } + observation.target_acquire_ns = trace_now_ns() - phase_started; + if (!target_index) return std::nullopt; + phase_started = trace_now_ns(); const bool content_changed = !matches_command_structure(scene, visuals); + observation.structure_check_ns = trace_now_ns() - phase_started; if (content_changed) ++command_revision_; auto& frame_target = *targets_->values[*target_index]; const bool bind_target = !frame_target.can_reuse_commands(command_revision_, readback); + phase_started = trace_now_ns(); observation.uploaded_bytes = apply( scene, visuals, *target_index, bind_target); + observation.apply_ns = trace_now_ns() - phase_started; bool query_changed_scene{}; + phase_started = trace_now_ns(); if (item_interaction_ != nullptr) { static_cast(dvz_figure_process_queries( figure_, runtime_slots_[*target_index].runtime, nullptr)); @@ -198,8 +258,8 @@ std::optional Scene_Datoviz_State::prepare( } } } + observation.query_ns = trace_now_ns() - phase_started; if (query_changed_scene) ++command_revision_; - observation.apply_ns = trace_now_ns() - phase_started; bool runtime_resources_updated{}; if (frame_target.can_reuse_commands(command_revision_, readback) && !target_runtime_resources_current(visuals, *target_index)) { @@ -220,7 +280,7 @@ std::optional Scene_Datoviz_State::prepare( &uploaded_bytes, &command_recording_valid, &report), &dvz_drp2_stream_destroy }; - observation.emit_ns += trace_now_ns() - phase_started; + observation.runtime_plan_ns = trace_now_ns() - phase_started; if (!update_stream) { std::string message = "failed to prepare Datoviz retained runtime resources"; @@ -233,11 +293,13 @@ std::optional Scene_Datoviz_State::prepare( phase_started = trace_now_ns(); DvzDrp2ValidationResult update_result{}; { - update_result = dvz_drp2_runtime_execute( + DvzDrp2ExecutionTiming timing{}; + update_result = dvz_drp2_runtime_execute_timed( runtime_slots_[*target_index].runtime, - update_stream.get()); + update_stream.get(), &timing); + accumulate_execution_timing(timing, observation); } - observation.execute_ns += trace_now_ns() - phase_started; + observation.runtime_execute_ns = trace_now_ns() - phase_started; if (!update_result.ok) throw std::runtime_error( "failed to execute Datoviz retained runtime resources"); @@ -252,6 +314,7 @@ std::optional Scene_Datoviz_State::prepare( * rebuilding the Figure artifact or re-recording commands. Structural Scene * changes keep using command_revision_ and fall through to full recording. */ bool mvp_updated{}; + phase_started = trace_now_ns(); if (frame_target.can_reuse_commands(command_revision_, readback) && !frame_target.can_reuse( command_revision_, controller_revision_, readback)) { @@ -265,6 +328,7 @@ std::optional Scene_Datoviz_State::prepare( mvp_updated = true; } } + observation.mvp_update_ns = trace_now_ns() - phase_started; if (frame_target.can_reuse( command_revision_, controller_revision_, readback)) { { @@ -284,9 +348,11 @@ std::optional Scene_Datoviz_State::prepare( }; } { + phase_started = trace_now_ns(); std::lock_guard recording_lock(target_mutex_); frame_target.begin( observe, readback, command_revision_, controller_revision_); + observation.frame_begin_ns = trace_now_ns() - phase_started; } struct Recording_Scope { Datoviz_Frame_Target& target; /* 异常退出时回收尚未发布的录制槽。 */ @@ -307,7 +373,7 @@ std::optional Scene_Datoviz_State::prepare( try { phase_started = trace_now_ns(); artifact.reset(emit(scene, *target_index)); - observation.emit_ns = trace_now_ns() - phase_started; + observation.frame_plan_ns = trace_now_ns() - phase_started; } catch (...) { raise_context("preparing Datoviz frame", std::current_exception()); @@ -322,21 +388,26 @@ std::optional Scene_Datoviz_State::prepare( } const DvzDrp2CommandStream* stream = dvz_scene_frame_artifact_stream(artifact.get()); - register_external_attributes(stream, *target_index); - const DvzStreamFrame target_frame = frame_target.stream_frame(); phase_started = trace_now_ns(); + register_external_attributes(stream, *target_index); + observation.external_register_ns = trace_now_ns() - phase_started; + const DvzStreamFrame target_frame = frame_target.stream_frame(); bool attached{}; DvzDrp2ValidationResult result{}; - { - attached = stream != nullptr && - dvz_drp2_runtime_attach_frame_target( - runtime_slots_[*target_index].runtime, - color_target_id, &target_frame); - if (attached) - result = dvz_drp2_runtime_execute( - runtime_slots_[*target_index].runtime, stream); + phase_started = trace_now_ns(); + attached = stream != nullptr && + dvz_drp2_runtime_attach_frame_target( + runtime_slots_[*target_index].runtime, + color_target_id, &target_frame); + observation.frame_attach_ns = trace_now_ns() - phase_started; + if (attached) { + phase_started = trace_now_ns(); + DvzDrp2ExecutionTiming timing{}; + result = dvz_drp2_runtime_execute_timed( + runtime_slots_[*target_index].runtime, stream, &timing); + accumulate_execution_timing(timing, observation); + observation.frame_execute_ns = trace_now_ns() - phase_started; } - observation.execute_ns = trace_now_ns() - phase_started; observation.validation_performed = true; observation.validation_ok = attached && result.ok; observation.validation_code = static_cast(result.code); @@ -364,8 +435,10 @@ std::optional Scene_Datoviz_State::prepare( } mark_target_runtime_resources_uploaded(*target_index); { + phase_started = trace_now_ns(); std::lock_guard recording_lock(target_mutex_); frame_target.finish_recording(); + observation.frame_finish_ns = trace_now_ns() - phase_started; } recording_scope.released = true; input_changed_ = false; diff --git a/render_3D/third_party/datoviz/include/datoviz/drp2/runtime.h b/render_3D/third_party/datoviz/include/datoviz/drp2/runtime.h index ac0b195..2ea5523 100644 --- a/render_3D/third_party/datoviz/include/datoviz/drp2/runtime.h +++ b/render_3D/third_party/datoviz/include/datoviz/drp2/runtime.h @@ -35,6 +35,7 @@ EXTERN_C_ON typedef struct DvzDrp2ValidationResult DvzDrp2ValidationResult; typedef struct DvzDrp2RuntimeConfig DvzDrp2RuntimeConfig; typedef struct DvzDrp2ExternalBufferDesc DvzDrp2ExternalBufferDesc; +typedef struct DvzDrp2ExecutionTiming DvzDrp2ExecutionTiming; typedef struct DvzDevice DvzDevice; typedef struct DvzStreamFrame DvzStreamFrame; typedef struct DvzVma DvzVma; @@ -72,6 +73,19 @@ struct DvzDrp2ExternalBufferDesc uint32_t usage; }; +#define DVZ_DRP2_COMMAND_TYPE_COUNT ((uint32_t)DVZ_DRP2_COMMAND_QUEUE_SUBMIT_REPLY + 1U) + +struct DvzDrp2ExecutionTiming +{ + uint64_t validation_ns; + uint64_t state_ensure_ns; + uint64_t shader_compile_ns; + uint64_t shader_module_create_ns; + uint64_t command_ns[DVZ_DRP2_COMMAND_TYPE_COUNT]; + uint32_t command_count[DVZ_DRP2_COMMAND_TYPE_COUNT]; + uint64_t state_commit_ns; +}; + /*************************************************************************************************/ @@ -202,6 +216,10 @@ dvz_drp2_validate_stream(const DvzDrp2CommandStream* stream); DVZ_EXPORT DvzDrp2ValidationResult dvz_drp2_runtime_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream); +DVZ_EXPORT DvzDrp2ValidationResult dvz_drp2_runtime_execute_timed( + DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream, + DvzDrp2ExecutionTiming* timing); + /** * Attach a borrowed stream frame as a runtime render target. diff --git a/render_3D/third_party/datoviz/src/drp2/_runtime.h b/render_3D/third_party/datoviz/src/drp2/_runtime.h index 928d4bf..3463c00 100644 --- a/render_3D/third_party/datoviz/src/drp2/_runtime.h +++ b/render_3D/third_party/datoviz/src/drp2/_runtime.h @@ -315,7 +315,8 @@ bool _vklite_attach_frame_target( bool _vklite_retire_frame_target_depth( Drp2VkliteState* state, Drp2VkliteObject* object); DvzDrp2ValidationResult _vklite_execute( - DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream); + DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream, + DvzDrp2ExecutionTiming* timing); VkImageView _vklite_object_image_view(const Drp2VkliteObject* object); void _vklite_state_cleanup(Drp2VkliteState* state); bool _vklite_defer_destroy_object( @@ -337,7 +338,8 @@ void _vklite_transition_image_access( bool _vklite_compile_glsl( const char* stage, const char* code, uint32_t** spv, uint64_t* spv_size); DvzDrp2ValidationResult _vklite_create_shader_module( - Drp2VkliteState* state, const DvzDrp2Command* command, uint32_t command_index); + Drp2VkliteState* state, const DvzDrp2Command* command, uint32_t command_index, + DvzDrp2ExecutionTiming* timing); DvzDrp2ValidationResult _vklite_create_sampler( Drp2VkliteState* state, const DvzDrp2Command* command, uint32_t command_index); DvzDrp2ValidationResult _vklite_create_bind_group_layout( diff --git a/render_3D/third_party/datoviz/src/drp2/backend.c b/render_3D/third_party/datoviz/src/drp2/backend.c index 7d4c09b..4532edb 100644 --- a/render_3D/third_party/datoviz/src/drp2/backend.c +++ b/render_3D/third_party/datoviz/src/drp2/backend.c @@ -23,6 +23,7 @@ #include "_assertions.h" #include "_runtime.h" #include "_stream.h" +#include "datoviz/common/functions.h" @@ -573,7 +574,9 @@ static DvzDrp2ValidationResult _vklite_destroy_shader_module( DvzDrp2ValidationResult -_vklite_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream) +_vklite_execute( + DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream, + DvzDrp2ExecutionTiming* timing) { ANN(runtime); ANN(stream); @@ -590,6 +593,7 @@ _vklite_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream) for (uint32_t i = 0; i < stream->count; i++) { const DvzDrp2Command* command = &stream->commands[i]; + const uint64_t command_started = timing != NULL ? dvz_time_monotonic_ns() : 0; switch (command->type) { case DVZ_DRP2_COMMAND_CREATE_BUFFER: @@ -607,7 +611,7 @@ _vklite_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream) state, command->u.destroy_texture.texture_id, DRP2_OBJECT_TEXTURE, i); break; case DVZ_DRP2_COMMAND_CREATE_SHADER_MODULE: - result = _vklite_create_shader_module(state, command, i); + result = _vklite_create_shader_module(state, command, i, timing); break; case DVZ_DRP2_COMMAND_DESTROY_SHADER_MODULE: result = _vklite_destroy_shader_module( @@ -712,6 +716,13 @@ _vklite_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream) break; } + if (timing != NULL && command->type < DVZ_DRP2_COMMAND_TYPE_COUNT) + { + timing->command_ns[command->type] += + dvz_time_monotonic_ns() - command_started; + timing->command_count[command->type]++; + } + if (!result.ok) break; } diff --git a/render_3D/third_party/datoviz/src/drp2/pipeline.c b/render_3D/third_party/datoviz/src/drp2/pipeline.c index 8e24f6f..7020855 100644 --- a/render_3D/third_party/datoviz/src/drp2/pipeline.c +++ b/render_3D/third_party/datoviz/src/drp2/pipeline.c @@ -34,6 +34,7 @@ typedef int shaderc_shader_kind; #include "_runtime.h" #include "_stream.h" #include "_vk_utils.h" +#include "datoviz/common/functions.h" @@ -444,7 +445,8 @@ bool _vklite_compile_glsl( * @return DRP2 validation result */ DvzDrp2ValidationResult _vklite_create_shader_module( - Drp2VkliteState* state, const DvzDrp2Command* command, uint32_t command_index) + Drp2VkliteState* state, const DvzDrp2Command* command, uint32_t command_index, + DvzDrp2ExecutionTiming* timing) { ANN(state); ANN(command); @@ -464,10 +466,13 @@ DvzDrp2ValidationResult _vklite_create_shader_module( if (is_glsl) { + const uint64_t compile_started = timing != NULL ? dvz_time_monotonic_ns() : 0; if (!_vklite_compile_glsl( command->u.create_shader_module.stage, command->u.create_shader_module.code, &spv_owned, &spv_size)) return _drp2_fail(DVZ_DRP2_VALIDATION_INVALID_ARGUMENT, command_index); + if (timing != NULL) + timing->shader_compile_ns += dvz_time_monotonic_ns() - compile_started; spv = spv_owned; } else @@ -499,7 +504,10 @@ DvzDrp2ValidationResult _vklite_create_shader_module( } object->shader = shader; + const uint64_t module_started = timing != NULL ? dvz_time_monotonic_ns() : 0; int out = dvz_shader(state->runtime->device, spv_size, spv, shader); + if (timing != NULL) + timing->shader_module_create_ns += dvz_time_monotonic_ns() - module_started; dvz_free(spv_owned); if (out != 0) return _vklite_fail_destroy_object( diff --git a/render_3D/third_party/datoviz/src/drp2/runtime.c b/render_3D/third_party/datoviz/src/drp2/runtime.c index 09342ac..344f4f5 100644 --- a/render_3D/third_party/datoviz/src/drp2/runtime.c +++ b/render_3D/third_party/datoviz/src/drp2/runtime.c @@ -28,6 +28,7 @@ #include "_log.h" #include "_overflow.h" #include "_runtime.h" +#include "datoviz/common/functions.h" #include "_stream.h" #include "datoviz/vk/gpu_ctx.h" @@ -509,25 +510,40 @@ bool _dvz_drp2_runtime_vklite_download_buffer( */ DvzDrp2ValidationResult dvz_drp2_runtime_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream) +{ + return dvz_drp2_runtime_execute_timed(runtime, stream, NULL); +} + +DvzDrp2ValidationResult dvz_drp2_runtime_execute_timed( + DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* stream, + DvzDrp2ExecutionTiming* timing) { if (runtime == NULL) return _drp2_fail(DVZ_DRP2_VALIDATION_INVALID_ARGUMENT, 0); if (stream == NULL) return _drp2_fail(DVZ_DRP2_VALIDATION_INVALID_ARGUMENT, 0); + if (timing != NULL) + *timing = (DvzDrp2ExecutionTiming){0}; + uint64_t phase_started = timing != NULL ? dvz_time_monotonic_ns() : 0; Drp2RuntimeState next_state = {0}; DvzDrp2ValidationResult result = _drp2_runtime_validate_stream(runtime, stream, &next_state); + if (timing != NULL) + timing->validation_ns = dvz_time_monotonic_ns() - phase_started; if (!result.ok) { _drp2_runtime_state_cleanup(&next_state); return result; } + phase_started = timing != NULL ? dvz_time_monotonic_ns() : 0; if (!_drp2_runtime_state_ensure(runtime)) { _drp2_runtime_state_cleanup(&next_state); return _drp2_fail(DVZ_DRP2_VALIDATION_INVALID_STATE, 0); } + if (timing != NULL) + timing->state_ensure_ns = dvz_time_monotonic_ns() - phase_started; if (runtime->semantic_only) { @@ -540,17 +556,20 @@ dvz_drp2_runtime_execute(DvzDrp2Runtime* runtime, const DvzDrp2CommandStream* st } #if DVZ_DRP2_HAS_VKLITE - DvzDrp2ValidationResult backend_result = _vklite_execute(runtime, stream); + DvzDrp2ValidationResult backend_result = _vklite_execute(runtime, stream, timing); if (!backend_result.ok) { _drp2_runtime_state_cleanup(&next_state); return backend_result; } + phase_started = timing != NULL ? dvz_time_monotonic_ns() : 0; if (!_drp2_runtime_state_commit(runtime, &next_state)) { _drp2_runtime_state_cleanup(&next_state); return _drp2_fail(DVZ_DRP2_VALIDATION_INVALID_STATE, 0); } + if (timing != NULL) + timing->state_commit_ns = dvz_time_monotonic_ns() - phase_started; return backend_result; #else _drp2_runtime_state_cleanup(&next_state); diff --git a/render_3D/third_party/datoviz/src/scene/runtime/render_pass.c b/render_3D/third_party/datoviz/src/scene/runtime/render_pass.c index 5cdab3e..f88bda1 100644 --- a/render_3D/third_party/datoviz/src/scene/runtime/render_pass.c +++ b/render_3D/third_party/datoviz/src/scene/runtime/render_pass.c @@ -57,23 +57,6 @@ static const char ENCODE_GLSL[] = " outColor = vec4(linearToSrgb(color.rgb), clamp(color.a, 0.0, 1.0));\n" "}\n"; -static const char ENCODE_WGSL[] = - "@group(0) @binding(0) var source_tex: texture_2d;\n" - "@group(0) @binding(1) var samp: sampler;\n" - "fn linear_to_srgb(linear_color: vec3f) -> vec3f {\n" - " let clipped = clamp(linear_color, vec3f(0.0), vec3f(1.0));\n" - " let lo = vec3f(12.92) * clipped;\n" - " let hi = vec3f(1.055) * pow(clipped, vec3f(1.0 / 2.4)) - vec3f(0.055);\n" - " return select(hi, lo, clipped <= vec3f(0.0031308));\n" - "}\n" - "@fragment fn main(@builtin(position) pos: vec4f) -> @location(0) vec4f {\n" - " let p = vec2i(pos.xy);\n" - " let color = textureLoad(source_tex, p, 0);\n" - " return vec4f(linear_to_srgb(color.rgb), clamp(color.a, 0.0, 1.0));\n" - "}\n"; - - - static bool _render_pass_external_target_needs_encode(const DvzFramePlanEmitConfig* cfg) { if (cfg != NULL && cfg->color_pipeline == DVZ_COLOR_PIPELINE_LEGACY_SRGB_BLEND) @@ -302,15 +285,16 @@ bool _render_pass_emit_final_encode( if (vs_id == 0) return false; if (ok && is_new) - ok = ok && _emit_shader(stream, vs_id, "VERTEX", _fullscreen_vertex_wgsl(), - _builtin_shader_glsl(DVZ_SCENE_BUILTIN_SHADER_WBOIT_RESOLVE, false), - cfg); + ok = ok && _emit_shader_spirv( + stream, vs_id, "VERTEX", "fullscreen_vert", + _builtin_shader_glsl(DVZ_SCENE_BUILTIN_SHADER_WBOIT_RESOLVE, false), cfg); uint64_t fs_id = _obj_id(emitter, fs_key, &is_new); if (fs_id == 0) return false; if (ok && is_new) - ok = ok && _emit_shader(stream, fs_id, "FRAGMENT", ENCODE_WGSL, ENCODE_GLSL, cfg); + ok = ok && _emit_shader_spirv( + stream, fs_id, "FRAGMENT", "final_srgb_encode_frag", ENCODE_GLSL, cfg); uint64_t pipe_id = _obj_id(emitter, pipe_key, &is_new); if (pipe_id == 0)