15 KiB
15 KiB
Phase 4: 调试器系统 (S12)
S12 - 调试器系统
调试模式激活方式
MIRAI 调试器提供多种激活方式:
// 调试器管理器
class debug_system {
public:
static debug_system& instance();
// 激活调试器
void enable();
void disable();
[[nodiscard]] bool is_enabled() const;
// 切换调试器显示状态
void toggle_inspector();
// 设置调试器根窗口
void set_root_window(widget_base* root);
private:
bool enabled_ = false;
debug_overlay* overlay_ = nullptr;
};
激活方式:
| 触发方式 | 快捷键/命令 | 说明 |
|---|---|---|
| 键盘快捷键 | F12 |
全局切换 |
| 鼠标手势 | 右键双击 | 在控件上激活 |
| 控制台命令 | debug.toggle() |
脚本调用 |
| 启动参数 | --debug |
程序启动时启用 |
| 环境变量 | MIRAI_DEBUG=1 |
编译时配置 |
使用示例:
// 启动参数解析
int main(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
if (std::strcmp(argv[i], "--debug") == 0) {
debug_system::instance().enable();
}
}
// 运行应用
run_application();
return 0;
}
// 控制台命令(游戏引擎集成)
void console_debug_toggle() {
debug_system::instance().toggle_inspector();
}
着色器热重载触发机制
// 着色器热重载管理器
class shader_hot_reloader {
public:
static shader_hot_reloader& instance();
// 启用/禁用热重载
void set_enabled(bool enabled);
[[nodiscard]] bool is_enabled() const;
// 添加监视的着色器文件
void watch(const std::filesystem::path& path);
void unwatch(const std::filesystem::path& path);
// 手动触发重载
void reload(const std::filesystem::path& path);
void reload_all();
// 事件回调
std::function<void(const std::filesystem::path&)> on_before_reload;
std::function<void(const std::filesystem::path&)> on_after_reload;
std::function<void(const std::filesystem::path&, const std::string&)> on_reload_failed;
// 轮询检查(在主循环中调用)
void poll();
// 触发方式
enum class trigger_mode {
auto_reload, // 自动检测并重载
auto_notify, // 自动检测,仅通知
manual_only, // 仅手动触发
};
void set_trigger_mode(trigger_mode mode);
private:
bool enabled_ = false;
trigger_mode mode_ = trigger_mode::auto_reload;
std::unordered_map<std::string, std::filesystem::file_time_type> file_times_;
};
热重载触发流程:
sequenceDiagram
participant S as Shader Watcher
participant F as File System
participant C as Shader Compiler
participant W as Widget
loop 每帧 poll()
S->>F: 检查文件修改时间
F-->>S: 修改时间戳
alt 文件已修改
S->>C: 重新编译着色器
C-->>S: 编译结果
alt 编译成功
S->>S: 备份当前资源
S->>W: on_before_reload
S->>W: 更新着色器管线
S->>W: on_after_reload
Note over W: 立即反映新效果
else 编译失败
S->>S: 回滚到备份
S->>W: on_reload_failed
end
end
end
配置选项:
| 选项 | 默认值 | 说明 |
|---|---|---|
MIRAI_HOT_RELOAD |
Debug: true, Release: false | 全局开关 |
MIRAI_RELOAD_DEBOUNCE_MS |
100 | 防抖动延迟 |
MIRAI_RELOAD_BACKUP |
true | 失败时回滚 |
任务 12.1: 性能监控器
前置依赖: 任务 2.1
系统: S12 - 调试器系统
目标: 实现性能指标收集
目录结构:
src/mirai/debug/
├── perf_monitor.hpp
└── perf_monitor.cpp
公共接口:
// perf_monitor.hpp
namespace mirai {
struct frame_stats {
f64 frame_time;
f64 update_time;
f64 layout_time;
f64 paint_time;
f64 gpu_time;
u32 draw_calls;
u32 vertices;
u64 memory_usage;
};
class perf_monitor {
public:
static perf_monitor& instance();
void begin_frame();
void end_frame();
void begin_section(std::string_view name);
void end_section(std::string_view name);
[[nodiscard]] const frame_stats& current_stats() const;
[[nodiscard]] f64 average_fps(u32 frame_count = 60) const;
[[nodiscard]] bool is_enabled() const;
void set_enabled(bool enabled);
private:
frame_stats current_stats_;
std::vector<frame_stats> history_;
std::unordered_map<std::string, f64> section_times_;
bool enabled_ = true;
};
} // namespace mirai
预期产出物:
src/mirai/debug/perf_monitor.hppsrc/mirai/debug/perf_monitor.cpptests/debug/test_perf_monitor.cpp
任务 12.2: Widget 树视图
前置依赖: 任务 11.1
系统: S12 - 调试器系统
目标: 实现 Widget 树可视化
目录结构:
src/mirai/debug/
├── widget_tree_view.hpp
└── widget_tree_view.cpp
公共接口:
// widget_tree_view.hpp
namespace mirai {
class widget_tree_view : public widget {
public:
widget_tree_view();
void set_root(widget_base* root);
void set_selected(widget_base* widget);
[[nodiscard]] widget_base* selected() const;
std::function<void(widget_base*)> on_selection_changed;
void paint(render_context& ctx) override;
bool on_mouse_event(const mouse_event& event) override;
private:
void paint_node(render_context& ctx, widget_base* node, u32 depth, f32& y);
widget_base* root_ = nullptr;
widget_base* selected_ = nullptr;
std::unordered_set<widget_base*> expanded_;
};
} // namespace mirai
预期产出物:
src/mirai/debug/widget_tree_view.hppsrc/mirai/debug/widget_tree_view.cpp
任务 12.3: 属性检查器
前置依赖: 任务 12.2
系统: S12 - 调试器系统
目标: 实现 Widget 属性编辑器
目录结构:
src/mirai/debug/
├── inspector.hpp
└── inspector.cpp
公共接口:
// inspector.hpp
namespace mirai {
class inspector : public widget {
public:
inspector();
void set_target(widget* target);
[[nodiscard]] widget* target() const;
void paint(render_context& ctx) override;
private:
void paint_property(render_context& ctx, std::string_view name, std::string_view value, f32& y);
// 专门用于绘制 shader 参数的编辑器
void paint_shader_parameter(render_context& ctx, const shader_parameter& param, f32& y);
widget* target_ = nullptr;
};
class debug_overlay : public widget {
public:
static debug_overlay& instance();
void toggle();
[[nodiscard]] bool is_visible() const;
void set_root(widget_base* root);
private:
widget_tree_view tree_view_;
inspector inspector_;
perf_monitor* perf_monitor_;
bool visible_ = false;
};
} // namespace mirai
预期产出物:
src/mirai/debug/inspector.hppsrc/mirai/debug/inspector.cpptests/debug/test_inspector.cpp
任务 12.4: Debug 模块 CMake 配置
前置依赖: 任务 12.1 - 12.3
系统: S12 - 调试器系统
CMakeLists.txt 内容:
project(mirai_debug)
simple_library(STATIC)
target_link_libraries(${PROJECT_NAME}
PUBLIC mirai_core mirai_ui mirai_loop
)
# 仅在 Debug 构建时启用
target_compile_definitions(${PROJECT_NAME} PUBLIC
$<$<CONFIG:Debug>:MIRAI_DEBUG_ENABLED>
)
预期产出物:
- `src/mirai/debug/CMakeLists.txt
附录: 文档索引
本文档拆分自原 任务分解.md,共分为以下7个独立文档:
| 文档 | 文件名 | 内容描述 |
|---|---|---|
| 1 | 01-project-structure.md |
项目目录结构设计、命名规范 |
| 2 | 02-phase0-infrastructure.md |
Phase 0: 基础设施 (S4,S1,S9) |
| 3 | 03-phase1a-rendering-core.md |
Phase 1A: 渲染核心 (S6,S10,S5) |
| 4 | 04-phase1b-text-input.md |
Phase 1B: 文本与输入 (S7,S8) |
| 5 | 05-phase2-reactive-system.md |
Phase 2: 响应式系统 (S3,S2) |
| 6 | 06-phase3-widget-system.md |
Phase 3: 控件系统 (S11) |
| 7 | 07-phase4-debugger.md |
Phase 4: 调试器系统 (S12) |
附录 A: 性能分析功能
A.1 帧时间分解
MIRAI 的性能监控系统将帧时间分解为以下阶段:
| 阶段 | 说明 | 包含操作 |
|---|---|---|
| input_processing | 输入处理时间 | SDL 事件处理、输入事件分发 |
| state_updates | 状态更新时间 | Signal 通知、Computed 更新 |
| layout_calculation | 布局计算时间 | Yoga 布局、Measure/Arrange |
| paint_commands | 绘制命令生成时间 | Widget paint、Layer 录制 |
| batch_flush | 批处理提交时间 | Command Buffer 提交 |
| gpu_execution | GPU 执行时间 | 渲染管线执行 |
| present | 呈现时间 | Swapchain 呈现 |
// 性能监控示例
void frame_profiler::begin_frame() {
frame_start_ = std::chrono::high_resolution_clock::now();
// 输入处理阶段
profile_section("input_processing", [&]() {
process_input_events();
});
}
void frame_profiler::render_widget(widget::ptr w) {
profile_section("paint_commands", [&]() {
w->paint(render_context_);
});
}
// 使用 Vulkan Timestamp Queries 测量 GPU 时间
void gpu_profiler::begin_timestamp(vk_command_buffer cmd, u32 query_id) {
vkCmdResetQueryPool(cmd, query_pool_, query_id * 2, 2);
vkCmdWriteTimestamp(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
query_pool_, query_id * 2);
}
void gpu_profiler::end_timestamp(vk_command_buffer cmd, u32 query_id) {
vkCmdWriteTimestamp(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
query_pool_, query_id * 2 + 1);
}
f64 gpu_profiler::get_timestamp_duration(u32 query_id) {
u64 begin_ts, end_ts;
vkGetQueryPoolResults(device_, query_pool_, query_id * 2, 1,
sizeof(u64), &begin_ts, 0, VK_QUERY_RESULT_64_BIT);
vkGetQueryPoolResults(device_, query_pool_, query_id * 2 + 1, 1,
sizeof(u64), &end_ts, 0, VK_QUERY_RESULT_64_BIT);
// 转换为毫秒
return (end_ts - begin_ts) * timestamp_period_ / 1'000'000.0;
}
A.2 控件级别性能分析
// 控件性能统计
struct widget_perf_stats {
widget* target;
f64 total_paint_time; // 累计绘制时间
u32 paint_count; // 绘制次数
f64 avg_paint_time; // 平均绘制时间
u32 child_count; // 子控件数量
f32 bounds_area; // 边界面积
bool is_dirty; // 是否脏标记
};
// 获取控件级别的性能数据
widget_perf_stats get_widget_perf_stats(widget* w) {
auto& tracker = widget_perf_tracker::instance();
return {
.target = w,
.total_paint_time = tracker.get_total_time(w),
.paint_count = tracker.get_paint_count(w),
.avg_paint_time = tracker.get_avg_time(w),
.child_count = w->child_count(),
.bounds_area = w->bounds().extent.width * w->bounds().extent.height,
.is_dirty = w->is_dirty()
};
}
// 性能热点分析
std::vector<widget_perf_stats> find_perf_hotspots(u32 top_n = 10) {
auto all_widgets = collect_all_widgets();
std::vector<widget_perf_stats> stats;
for (auto w : all_widgets) {
stats.push_back(get_widget_perf_stats(w));
}
// 按平均绘制时间排序
std::sort(stats.begin(), stats.end(),
[](const auto& a, const auto& b) {
return a.avg_paint_time > b.avg_paint_time;
});
return {stats.begin(), stats.begin() + std::min(top_n, (u32)stats.size())};
}
A.3 性能覆盖层显示
// 性能覆盖层配置
struct perf_overlay_config {
bool show_fps = true;
bool show_frame_time = true;
bool show_gpu_time = false;
bool show_draw_calls = true;
bool show_memory = true;
bool show_widget_count = false;
bool show_perf_graph = true;
f32 graph_height = 100;
u32 graph_history_size = 60; // 60 帧历史
};
// 性能覆盖层渲染
void perf_overlay::paint(render_context& ctx) {
auto& stats = perf_monitor::instance().current_stats();
// FPS 显示
if (config_.show_fps) {
draw_text(ctx, {10, 10},
std::format("FPS: {:.1f}", stats.fps),
colors::white);
}
// 帧时间条形图
if (config_.show_perf_graph) {
draw_graph(ctx, {10, 30}, stats.history, config_.graph_height);
}
// 详细信息
if (config_.show_frame_time) {
draw_text(ctx, {10, 150},
std::format("Frame: {:.2f}ms", stats.frame_time * 1000),
colors::white);
}
if (config_.show_draw_calls) {
draw_text(ctx, {10, 170},
std::format("Draw Calls: {}", stats.draw_calls),
colors::white);
}
}
附录 B: 着色器热重载详细配置
B.1 配置文件选项
{
"shader_hot_reload": {
"enabled": true,
"trigger_mode": "auto_reload",
"poll_interval_ms": 500,
"debounce_ms": 100,
"backup_on_error": true,
"show_notification": true,
"watch_patterns": ["**/*.slang"],
"exclude_paths": ["**/build/**", "**/.git/**"]
}
}
B.2 API 配置选项
| 选项 | 默认值 | 类型 | 说明 |
|---|---|---|---|
| enabled | Debug: true | bool | 是否启用热重载 |
| trigger_mode | auto_reload | enum | 触发模式 |
| poll_interval_ms | 500 | u32 | 文件检查间隔 |
| debounce_ms | 100 | u32 | 防抖动延迟 |
| backup_on_error | true | bool | 失败时回滚 |
| show_notification | true | bool | 显示通知 |
B.3 热重载事件处理
// 监听热重载事件
shader_hot_reloader::instance().on_before_reload = [](const auto& path) {
MIRAI_LOG_INFO("Reloading shader: {}", path.string());
};
shader_hot_reloader::instance().on_after_reload = [](const auto& path) {
// 刷新使用该着色器的所有控件
for (auto widget : get_widgets_using_shader(path)) {
widget->on_shader_reloaded();
}
// 显示成功通知
notification::show("Shader reloaded", path.filename().string());
};
shader_hot_reloader::instance().on_reload_failed = [](const auto& path, const auto& error) {
MIRAI_LOG_ERROR("Failed to reload shader {}: {}", path.string(), error);
// 显示错误通知
notification::show_error("Shader reload failed", error);
};
文档版本信息
| 版本 | 日期 | 更新内容 |
|---|---|---|
| 0.1.0 | 2024-01-15 | 初始版本 |
| 0.1.1 | 2024-01-20 | 添加性能分析功能、帧时间分解、GPU 时间测量、控件级别性能分析、着色器热重载详细配置 |
| <last_updated>2024-01-20</last_updated> | ||
| draft |