diff --git a/docs/api-skill.md b/docs/api-skill.md index e4b22275..0827528b 100644 --- a/docs/api-skill.md +++ b/docs/api-skill.md @@ -2,15 +2,15 @@ ## 目标 -本规范用于为 `XCEngine` 生成和维护一套唯一的 canonical API 文档。 +本规范用于维护 `XCEngine` 的唯一正式 API 文档树,并约束后续所有模块级重构的工作方式。 硬性要求: -1. `docs/api/XCEngine/**` 必须与 `engine/include/XCEngine/**` 严格平行。 -2. 模块、子模块、类型、方法的命名必须稳定并贴近源码符号名。 -3. 不保留第二套正式文档树。历史文档只允许作为迁移过程中的临时材料,迁移完成后必须删除。 - -在编写任何 API 文档之前,必须先阅读对应头文件与相关实现,理解职责、边界、生命周期、线程语义、错误条件和依赖关系。禁止只根据函数名猜测含义。 +1. `docs/api/XCEngine/**` 必须与 `engine/include/XCEngine/**` 保持平行。 +2. canonical API 文档只保留一套;迁移完成后必须删除旧目录与旧入口。 +3. 每个 public header 对应一个独立文档目录,每个类型页都使用 `{TypeName}/{TypeName}.md`。 +4. 方法页优先使用源码中的原始函数名;不要改成 kebab-case、全小写或其它再命名形式。 +5. API 文档必须以源码、实现、测试和真实调用点为依据,禁止只根据名字猜测行为。 ## Canonical 目录结构 @@ -23,48 +23,43 @@ docs/api/ │ │ ├── Debug.md │ │ ├── Logger/ │ │ │ ├── Logger.md -│ │ │ ├── Log.md -│ │ │ ├── SetLevel.md -│ │ │ ├── Constructor.md -│ │ │ └── Destructor.md +│ │ │ ├── Get.md +│ │ │ ├── Initialize.md +│ │ │ └── Log.md │ │ └── RenderDocCapture/ │ │ ├── RenderDocCapture.md -│ │ └── TriggerCapture.md -│ ├── Core/ -│ │ ├── Core.md -│ │ ├── Asset/ -│ │ │ ├── Asset.md -│ │ │ └── ResourceManager/ -│ │ │ ├── ResourceManager.md -│ │ │ └── Load.md -│ │ └── Math/ -│ │ └── Math.md +│ │ └── BeginCapture.md │ └── ... -├── _meta/ -└── _tools/ +├── _guides/ +│ └── Debug/ +└── _meta/ ``` +说明: + +- `docs/api/XCEngine/**` 是唯一 canonical API 树。 +- `docs/api/_guides/**` 用于概念、教程、设计理念和工作流说明,不是第二套 API 树。 +- `README.md` 不用于 canonical 模块索引页;模块索引页统一使用 `{DirName}.md`。 + ## 强制命名规则 -### 1. 目录总览页 +### 1. 目录索引页 -- 根目录总览页必须是 `docs/api/XCEngine/XCEngine.md` -- 模块总览页必须使用 `{ModuleName}.md` -- 子模块总览页必须使用 `{SubmoduleName}.md` -- canonical 目录下禁止使用 `README.md` 作为模块或子模块总览页 +- 根索引页:`docs/api/XCEngine/XCEngine.md` +- 模块索引页:`docs/api/XCEngine/{ModuleName}/{ModuleName}.md` +- 子模块索引页:`docs/api/XCEngine/{ModuleName}/{SubmoduleName}/{SubmoduleName}.md` 示例: - `docs/api/XCEngine/Debug/Debug.md` - `docs/api/XCEngine/Core/Core.md` -- `docs/api/XCEngine/Core/Asset/Asset.md` - `docs/api/XCEngine/RHI/D3D12/D3D12.md` ### 2. 类型目录 -- 每个 public 类型或以 header 为单位的主声明,都必须是一个独立文件夹 -- 文件夹名必须与源码中的类型名或 header stem 保持一致 -- 保留原始大小写 +- 每个 public header 对应一个独立文件夹。 +- 文件夹名必须与 header stem 或主要类型名一致。 +- 保留源码中的大小写,不做风格改写。 示例: @@ -74,77 +69,225 @@ docs/api/ ### 3. 类型总览页 -- 类型总览页固定为 `{TypeName}/{TypeName}.md` -- 不允许把类型总览页直接平铺在模块目录下 +- 固定为 `{TypeName}/{TypeName}.md` +- 不允许把类型总览页直接平铺在模块目录中 ### 4. 方法详情页 -- 方法详情页必须放在所属类型文件夹内 -- 方法页文件名优先使用原函数名 -- 保留 PascalCase / camelCase / 全大写缩写 -- 禁止改成 lowercase kebab-case -- 同名重载共用一个方法页 +- 方法页放在所属类型目录内。 +- 文件名优先使用原函数名。 +- 重载共享同一页,在页内按签名分节说明。 示例: - `Get.md` -- `CreateBuffer.md` -- `SetRenderTarget.md` +- `Initialize.md` +- `SetCaptureFilePath.md` - `LoadSceneAsync.md` -- `GetCPUHandle.md` -### 5. 特殊方法命名 +### 5. 特殊命名 -- 构造函数使用 `Constructor.md` -- 析构函数使用 `Destructor.md` -- 运算符重载使用可读的 PascalCase 名称 +- 构造函数:`Constructor.md` +- 析构函数:`Destructor.md` +- 运算符使用可读的 PascalCase 名称 -推荐映射: +建议映射: - `operator=` -> `OperatorAssign.md` - `operator+=` -> `OperatorPlusAssign.md` - `operator[]` -> `OperatorSubscript.md` - `operator()` -> `OperatorCall.md` -- `operator bool` -> `OperatorBool.md` + +## 写作前的取证流程 + +在编写任何 API 页之前,必须完成下面的最小取证: + +1. 阅读对应 public header。 +2. 阅读对应 `.cpp` 或内联实现。 +3. 搜索测试、示例和真实调用点。 +4. 确认生命周期、线程语义、所有权、失败路径和平台限制。 + +至少回答以下问题后才能落文: + +- 这个类型解决什么问题,边界在哪里? +- 调用前需要什么前置条件? +- 调用失败时返回什么,或者会静默失败? +- 谁拥有对象,谁负责释放资源? +- 多线程下哪些调用安全,哪些只能在初始化阶段使用? +- 当前实现是不是完整的?有没有空实现、占位实现或只做轻量封装? + +禁止行为: + +- 只根据 `Get`、`Create`、`Set` 之类的前缀写模板句。 +- 把“设计意图”当成“当前实现行为”来写。 +- 把测试里假设成立的场景,误写成通用保证。 + +## 契约分层规则 + +文档必须明确区分下面三层信息: + +### 1. 接口契约 + +来自 public header,属于使用者可以依赖的 API 形状。 + +例如: + +- 函数签名 +- 参数和返回值 +- 可见的数据结构 +- 明确暴露的枚举值和宏 + +### 2. 当前实现行为 + +来自 `.cpp`、内联实现、测试和调用点,描述当前版本的真实行为。 + +例如: + +- 是否自动初始化 +- 是否加锁 +- 是否会写日志、刷新文件、拉起窗口焦点 +- 是否只是 no-op 或 stub + +这一层必须使用明确表述,例如: + +- “当前实现中……” +- “按 `engine/src/...` 的实现……” +- “当前版本会……” + +### 3. 合理推断 + +只在确实有必要时使用,而且必须标明是推断。 + +例如: + +- “从 API 形状看,设计上显然是为后续 Chrome Trace 导出预留扩展点。” + +如果不能证明,就不要写。 ## 页面职责 -### 1. 目录总览页 +### 1. 模块页 / 子模块页 负责: -- 说明模块或子模块的职责边界 -- 列出直接子目录 -- 列出当前目录下的 public headers 对应类型入口 -- 提供父级目录和 `docs/api/main.md` 的导航 +- 说明模块职责、边界和典型使用场景 +- 列出子目录与 public headers +- 给出与相邻模块的关系 +- 链接相关 guide 页 不负责: -- 展开详细方法级说明 -- 复制头文件全部声明 -- 保留迁移说明、旧入口跳转或双轨文档提示 +- 展开所有方法细节 +- 重复 header 全量声明 -### 2. 类型总览页 +### 2. 类型页 -负责: +必须包含: -- 标识命名空间、类型、头文件、职责 -- 给出声明概览 -- 列出公开字段、枚举值或公开方法 -- 作为该类型所有方法详情页的稳定入口 +- 命名空间 +- 类型分类 +- 头文件 +- 角色概述 +- 生命周期 +- 线程语义 +- 所有权 / 资源管理方式 +- 当前实现限制 +- 与相关方法页、guide 页的跳转 -### 3. 方法详情页 +如果类型是枚举或结构体,还应补充: -负责: +- 字段或枚举值说明 +- 值之间的语义关系 +- 典型使用方式 -- 给出准确签名 -- 按重载分节 -- 说明参数、返回值、生命周期、线程语义和关键约束 -- 给出最小但可信的示例 +### 3. 方法页 -## 推荐页面模板 +必须包含: -### 1. 目录总览页模板 +- 准确签名 +- 调用目的 +- 前置条件 +- 参数说明 +- 返回值说明 +- 副作用 +- 线程语义 +- 失败路径或 no-op 条件 +- 最小可信示例 + +方法页不能只写“获取对象”“设置状态”这种空描述。 + +## 内容深度要求 + +### 1. 解释“是什么” + +说明类型或方法的职责,而不是简单复述名字。 + +### 2. 解释“怎么用” + +给出最小可运行或最小可信的使用顺序,让用户知道放在初始化、运行时还是销毁阶段。 + +### 3. 解释“为什么这样设计” + +结合引擎架构解释: + +- 为什么做成 singleton、service、interface、sink、builder、handle +- 这样做的收益是什么 +- 有哪些代价或约束 + +### 4. 解释“当前实现做到哪一步” + +商业级 API 文档不能假装所有接口都同样成熟。 + +对于未完成能力,必须明确说明: + +- 当前是占位接口 +- 当前只有基础实现 +- 当前只覆盖某个平台 / 某条后端路径 + +## 教程与概念页规范 + +当某个模块仅靠 API 页不足以让用户理解时,应增加 `_guides` 页。 + +适合写 guide 的内容: + +- 前置知识 +- 架构设计理念 +- 推荐工作流 +- 和 Unity / Unreal / RenderDoc 等常见工具的概念对照 +- 最佳实践与反模式 + +guide 页不是第二套 API 参考,它们负责回答: + +- 为什么要这样组织模块 +- 用户第一次接触时该从哪里开始 +- 这套 API 与常见引擎的对应关系是什么 + +guide 页应尽量包含: + +- 问题背景 +- 设计目标 +- 推荐流程 +- 优点与代价 +- 与现有 API 页的链接 + +## Unity 风格的解释性要求 + +当模块涉及常见引擎概念时,可以增加 Unity 对照,但必须克制且准确。 + +推荐写法: + +- “可以把 `Logger` 理解为比 Unity Console 更底层的日志分发中心。” +- “当前 `Profiler` 只覆盖轻量 CPU 埋点,不等同于 Unity Profiler 的完整时间线分析。” +- “`RenderDocCapture` 更接近引擎内置的 RenderDoc 工作流桥接,而不是 Unity Frame Debugger 的替代品。” + +禁止写法: + +- “和 Unity 完全一样” +- “等价于某商业引擎的完整系统” + +## 页面模板 + +### 1. 模块页模板 ```markdown # {DirName} @@ -155,27 +298,26 @@ docs/api/ **描述**: {一句话说明当前目录职责} -## 概览 +## 概述 -{说明该目录在整个引擎中的职责边界、使用场景和与相邻模块的关系} +{解释职责边界、典型场景和相邻模块关系} -## 子目录 +## 设计要点 -- [ChildA](ChildA/ChildA.md) -- [ChildB](ChildB/ChildB.md) +- {要点 1} +- {要点 2} ## 头文件 - [TypeA](TypeA/TypeA.md) - `TypeA.h` - [TypeB](TypeB/TypeB.md) - `TypeB.h` -## 相关文档 +## 相关指南 -- [上级目录](../{ParentDir}.md) -- [API 总索引](../../main.md) +- [GuideA](../../_guides/.../GuideA.md) ``` -### 2. 类型总览页模板 +### 2. 类型页模板 ```markdown # {TypeName} @@ -188,29 +330,27 @@ docs/api/ **描述**: {一句话说明} -## 概览 +## 概述 -{描述该类型的职责、拥有关系、状态约束、典型使用方式} +{说明角色、状态、边界、典型使用方式} -## 声明概览 +## 生命周期 -| 声明 | 类型 | 说明 | -|------|------|------| -| `{TypeName}` | `class` | {说明} | +- {初始化与销毁方式} -## 公共方法 +## 线程语义 -| 方法 | 描述 | +- {线程安全说明} + +## 公开成员 + +| 成员 | 说明 | |------|------| -| [Initialize](Initialize.md) | {描述} | -| [Shutdown](Shutdown.md) | {描述} | - -## 相关文档 - -- [当前目录](../{DirName}.md) +| [Initialize](Initialize.md) | {说明} | +| [Shutdown](Shutdown.md) | {说明} | ``` -### 3. 方法详情页模板 +### 3. 方法页模板 ```markdown # {TypeName}::{MethodName} @@ -221,57 +361,37 @@ docs/api/ {完整签名} ``` -{方法行为说明,包括前置条件、后置条件、副作用和失败语义} +## 行为说明 + +{说明前置条件、后置状态、副作用和当前实现细节} + +## 参数 -**参数** - `param` - {描述} -**返回** +## 返回值 + - `{Type}` - {描述} -**线程语义** -- {线程安全 / 只能主线程 / 调用方同步等} +## 线程语义 -**示例** +- {线程安全、只建议初始化阶段调用、或必须同线程配对等} + +## 示例 ```cpp {最小可信示例} ``` - -## 相关文档 - -- [返回类型总览]({TypeName}.md) -- [返回模块目录](../{DirName}.md) ``` -## 文风与质量要求 - -- 使用工程化、可审阅、可维护的描述,不写空话 -- 描述职责边界,而不是复述函数名 -- 线程、生命周期、资源所有权、错误条件必须明确 -- 示例必须与当前 public API 一致,不允许伪代码式胡写 -- 信息应放在正确层级,避免模块页和类型页职责混淆 -- 禁止生成双轨入口或保留旧目录跳转 - -## 重构与生成流程 - -1. 扫描 `engine/include/XCEngine/**` -2. 建立与源码平行的 `docs/api/XCEngine/**` 目录树 -3. 为每个源码目录生成 `{DirName}.md` 目录总览页 -4. 为每个 public header 生成 `{TypeName}/{TypeName}.md` -5. 为每个公开方法生成 `{TypeName}/{MethodName}.md` -6. 清理旧的 lowercase kebab-case 方法页和旧的 flat header 页面 -7. 删除迁移完成后的历史文档 -8. 审计链接、头文件引用覆盖率和目录索引完整性 - ## 验收清单 -- `docs/api/XCEngine/**` 与 `engine/include/XCEngine/**` 目录结构平行 -- canonical 目录下没有模块级 `README.md` -- 每个类型都是一个独立文件夹 -- 每个类型总览页都是 `{TypeName}/{TypeName}.md` -- 方法页文件名使用原函数名或规范化运算符名 -- `docs/api/main.md` 指向 `docs/api/XCEngine/XCEngine.md` -- 所有 canonical `.md` 链接可解析 -- 所有 public headers 都有对应 canonical 文档入口 -- 仓库中不存在第二套正式 API 文档树 +- `docs/api/XCEngine/**` 与 `engine/include/XCEngine/**` 目录平行 +- canonical 树下没有模块级 `README.md` +- 每个 public header 都有对应类型目录 +- 每个类型总览页都位于 `{TypeName}/{TypeName}.md` +- 方法页使用原函数名或规范化运算符名 +- 所有链接都指向真实存在的 `.md` 页面 +- 文档中明确区分接口契约、当前实现和合理推断 +- 重要模块拥有必要的 guide 页 +- 重要限制、stub、平台条件和线程语义都已写清 diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/ConsoleLogSink.md b/docs/api/XCEngine/Debug/ConsoleLogSink/ConsoleLogSink.md index dcdc15e0..059a5d5f 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/ConsoleLogSink.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/ConsoleLogSink.md @@ -6,30 +6,50 @@ **头文件**: `XCEngine/Debug/ConsoleLogSink.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `ConsoleLogSink` public API。 +**描述**: 将日志输出到标准输出流,并在 Windows 上按级别着色。 ## 概述 -`ConsoleLogSink.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`ConsoleLogSink` 是最直接的调试输出目标,适合测试程序、命令行工具和开发期编辑器启动日志。它本身只关心“如何写到控制台”,不过滤 category,也不处理文件、函数名和时间戳格式化以外的元数据。 -## 声明概览 +当前实现中的关键行为: -| 声明 | 类型 | 说明 | -|------|------|------| -| `ConsoleLogSink` | `class` | 继承自 `ILogSink` 的公开声明。 | +- 日志格式固定为 `[LEVEL] [Category] message`。 +- 颜色输出只在 `_WIN32` 下生效;其它平台仍会输出文本,但不会着色。 +- sink 自身维护一个最小级别阈值,可在 `Logger` 的全局过滤之后再做一次本地过滤。 -## 公共方法 +## 生命周期 -| 方法 | 描述 | +- [Constructor](Constructor.md) 创建 sink,默认开启颜色输出,最小级别为 `Verbose`。 +- [Destructor](Destructor.md) 无额外资源释放逻辑。 +- [Flush](Flush.md) 手动刷新 `stdout`。 + +## 线程语义 + +- `ConsoleLogSink` 自身没有加锁。 +- 通过 `Logger` 调用时,实际输出发生在 `Logger` 的互斥区内,因此同一时刻只会有一个 sink 调用进入。 +- 如果绕过 `Logger` 直接从多个线程调用 `Log`,线程安全由调用方自己保证。 + +## 公开方法 + +| 方法 | 说明 | |------|------| -| [ConsoleLogSink()](Constructor.md) | 构造对象。 | -| [~ConsoleLogSink()](Destructor.md) | 销毁对象并释放相关资源。 | -| [Log](Log.md) | 公开方法,详见头文件声明。 | -| [Flush](Flush.md) | 公开方法,详见头文件声明。 | -| [SetColorOutput](SetColorOutput.md) | 设置相关状态或配置。 | -| [SetMinimumLevel](SetMinimumLevel.md) | 设置相关状态或配置。 | +| [Constructor](Constructor.md) | 构造一个控制台日志 sink。 | +| [Destructor](Destructor.md) | 析构 sink。 | +| [Log](Log.md) | 将一条日志格式化写入 `stdout`。 | +| [Flush](Flush.md) | 刷新 `stdout`。 | +| [SetColorOutput](SetColorOutput.md) | 开关 Windows 控制台颜色。 | +| [SetMinimumLevel](SetMinimumLevel.md) | 设置 sink 级别阈值。 | + +## 适用场景 + +- 单元测试与集成测试的即时输出。 +- 编辑器或工具进程启动阶段的可见日志。 +- 临时调试某个后端时,为 `Logger` 追加一个低成本输出目标。 ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [ILogSink](../ILogSink/ILogSink.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/Constructor.md b/docs/api/XCEngine/Debug/ConsoleLogSink/Constructor.md index 8a1dc18a..ecd8b79f 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/Constructor.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/Constructor.md @@ -1,28 +1,43 @@ -# ConsoleLogSink::ConsoleLogSink() +# ConsoleLogSink::Constructor -构造对象。 +构造一个面向控制台输出的日志 sink。 ```cpp ConsoleLogSink(); ``` -该方法声明于 `XCEngine/Debug/ConsoleLogSink.h`,当前页面用于固定 `ConsoleLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现中,构造函数不会打开额外资源,也不会访问控制台句柄。它只建立默认状态: -**返回:** `void` - 无返回值。 +- `m_colorOutput = true` +- `m_minimumLevel = LogLevel::Verbose` -**示例:** +也就是说,创建完成后该 sink 会接收所有级别日志,并在 Windows 上尝试使用彩色输出。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 构造阶段没有共享状态。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::ConsoleLogSink object; -} +auto sink = std::make_unique(); +Logger::Get().AddSink(std::move(sink)); ``` ## 相关文档 -- [返回类总览](ConsoleLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ConsoleLogSink.md) +- [SetColorOutput](SetColorOutput.md) +- [SetMinimumLevel](SetMinimumLevel.md) diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/Destructor.md b/docs/api/XCEngine/Debug/ConsoleLogSink/Destructor.md index 78b4c373..ace71a83 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/Destructor.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/Destructor.md @@ -1,29 +1,34 @@ -# ConsoleLogSink::~ConsoleLogSink() +# ConsoleLogSink::Destructor -销毁对象并释放相关资源。 +销毁控制台日志 sink。 ```cpp ~ConsoleLogSink() override; ``` -该方法声明于 `XCEngine/Debug/ConsoleLogSink.h`,当前页面用于固定 `ConsoleLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现中的析构函数是默认实现,不负责关闭控制台或回收外部句柄。通常不需要直接调用它,而是让 `Logger` 在移除 sink 或 `Shutdown` 时通过 `ILogSink` 基类指针自动析构。 -**返回:** `void` - 无返回值。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 应在对象不再被其它线程使用时销毁。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::ConsoleLogSink object; - // 对象离开作用域时会自动触发析构。 -} +Logger::Get().Shutdown(); ``` ## 相关文档 -- [返回类总览](ConsoleLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ConsoleLogSink.md) +- [ILogSink::Destructor](../ILogSink/Destructor.md) diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/Flush.md b/docs/api/XCEngine/Debug/ConsoleLogSink/Flush.md index 286a59aa..d652e9de 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/Flush.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/Flush.md @@ -1,30 +1,35 @@ # ConsoleLogSink::Flush -公开方法,详见头文件声明。 +刷新标准输出流,确保之前写入的控制台文本立即可见。 ```cpp void Flush() override; ``` -该方法声明于 `XCEngine/Debug/ConsoleLogSink.h`,当前页面用于固定 `ConsoleLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现直接调用 `fflush(stdout)`。如果你依赖实时控制台输出,例如在崩溃前或长帧分析时,希望日志立刻出现,可以显式调用该方法。 -**返回:** `void` - 无返回值。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- `ConsoleLogSink` 自身不加锁;通常通过 `Logger` 串行调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::ConsoleLogSink object; - // 根据上下文补齐参数后调用 ConsoleLogSink::Flush(...)。 - (void)object; -} +ConsoleLogSink sink; +sink.Flush(); ``` ## 相关文档 -- [返回类总览](ConsoleLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ConsoleLogSink.md) +- [Log](Log.md) diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/Log.md b/docs/api/XCEngine/Debug/ConsoleLogSink/Log.md index 77f05cc8..9a8cf7e0 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/Log.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/Log.md @@ -1,31 +1,58 @@ # ConsoleLogSink::Log -公开方法,详见头文件声明。 +将一条日志格式化后写到 `stdout`。 ```cpp void Log(const LogEntry& entry) override; ``` -该方法声明于 `XCEngine/Debug/ConsoleLogSink.h`,当前页面用于固定 `ConsoleLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `entry` - 参数语义详见头文件声明。 +当前实现分三步处理: -**返回:** `void` - 无返回值。 +1. 如果 `entry.level < m_minimumLevel`,直接返回。 +2. 在 Windows 且启用颜色输出时,根据 `entry.level` 设置控制台颜色。 +3. 按 `[LEVEL] [Category] message` 的固定格式调用 `printf` 输出一行文本,并在 Windows 上恢复默认颜色。 -**示例:** +它不会输出: + +- 时间戳 +- 文件路径 +- 行号 +- 函数名 +- 线程 ID + +如果你需要这些元数据,必须实现自己的 sink,或者扩展当前 sink 的格式化逻辑。 + +## 参数 + +- `entry` - 待输出的日志条目。 + +## 返回值 + +- 无。 + +## 线程语义 + +- sink 自身不加锁。 +- 通过 `Logger` 调用时,`Logger` 会在互斥区内串行分发。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::ConsoleLogSink object; - // 根据上下文补齐参数后调用 ConsoleLogSink::Log(...)。 - (void)object; -} +LogEntry entry{}; +entry.level = LogLevel::Info; +entry.category = LogCategory::General; +entry.message = "Hello from ConsoleLogSink"; + +ConsoleLogSink sink; +sink.Log(entry); ``` ## 相关文档 -- [返回类总览](ConsoleLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ConsoleLogSink.md) +- [Flush](Flush.md) +- [SetMinimumLevel](SetMinimumLevel.md) diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/SetColorOutput.md b/docs/api/XCEngine/Debug/ConsoleLogSink/SetColorOutput.md index b04b086a..989b6483 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/SetColorOutput.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/SetColorOutput.md @@ -1,31 +1,39 @@ # ConsoleLogSink::SetColorOutput -设置相关状态或配置。 +开启或关闭控制台颜色输出。 ```cpp void SetColorOutput(bool enable); ``` -该方法声明于 `XCEngine/Debug/ConsoleLogSink.h`,当前页面用于固定 `ConsoleLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `enable` - 参数语义详见头文件声明。 +该方法只修改内部开关 `m_colorOutput`。当前实现中: -**返回:** `void` - 无返回值。 +- 在 Windows 上,`enable = true` 时会在输出前后调用 `SetConsoleTextAttribute`。 +- 在非 Windows 平台上,即使设置为 `true`,也不会产生颜色效果,因为对应代码被 `_WIN32` 条件编译保护。 -**示例:** +## 参数 + +- `enable` - `true` 表示启用颜色输出,`false` 表示始终输出普通文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前实现没有加锁;更适合在初始化阶段配置,而不是在高频日志期间频繁切换。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::ConsoleLogSink object; - // 根据上下文补齐参数后调用 ConsoleLogSink::SetColorOutput(...)。 - (void)object; -} +auto sink = std::make_unique(); +sink->SetColorOutput(false); +XCEngine::Debug::Logger::Get().AddSink(std::move(sink)); ``` ## 相关文档 -- [返回类总览](ConsoleLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ConsoleLogSink.md) +- [SetMinimumLevel](SetMinimumLevel.md) diff --git a/docs/api/XCEngine/Debug/ConsoleLogSink/SetMinimumLevel.md b/docs/api/XCEngine/Debug/ConsoleLogSink/SetMinimumLevel.md index a3545481..26eb1f92 100644 --- a/docs/api/XCEngine/Debug/ConsoleLogSink/SetMinimumLevel.md +++ b/docs/api/XCEngine/Debug/ConsoleLogSink/SetMinimumLevel.md @@ -1,31 +1,43 @@ # ConsoleLogSink::SetMinimumLevel -设置相关状态或配置。 +设置该 sink 自己接受的最低日志级别。 ```cpp void SetMinimumLevel(LogLevel level); ``` -该方法声明于 `XCEngine/Debug/ConsoleLogSink.h`,当前页面用于固定 `ConsoleLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `level` - 参数语义详见头文件声明。 +这是 sink 级过滤,不是全局过滤。日志只有同时通过了: -**返回:** `void` - 无返回值。 +- `Logger` 的全局级别与 category 过滤; +- `ConsoleLogSink` 的本地级别过滤; -**示例:** +才会真正输出到控制台。 + +## 参数 + +- `level` - 该 sink 允许输出的最小级别。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前实现没有加锁;建议在把 sink 注册到 `Logger` 前完成配置。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::ConsoleLogSink object; - // 根据上下文补齐参数后调用 ConsoleLogSink::SetMinimumLevel(...)。 - (void)object; -} +auto sink = std::make_unique(); +sink->SetMinimumLevel(LogLevel::Warning); +Logger::Get().AddSink(std::move(sink)); ``` ## 相关文档 -- [返回类总览](ConsoleLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ConsoleLogSink.md) +- [Logger::SetMinimumLevel](../Logger/SetMinimumLevel.md) diff --git a/docs/api/XCEngine/Debug/Debug.md b/docs/api/XCEngine/Debug/Debug.md index ef5a0a87..a9cf2078 100644 --- a/docs/api/XCEngine/Debug/Debug.md +++ b/docs/api/XCEngine/Debug/Debug.md @@ -4,24 +4,47 @@ **类型**: `module` -**描述**: 日志、Profiler 与调试集成接口。 +**描述**: 提供日志分发、轻量级 CPU 埋点以及 RenderDoc 捕获集成。 -## 概览 +## 概述 -该目录与 `XCEngine/Debug` 对应的 public headers 保持平行,用于承载唯一的 canonical API 文档入口。 +`XCEngine::Debug` 是引擎运行时调试能力的入口模块。它把三个需求放在同一层中统一管理: + +- 运行日志:通过 `Logger` 将消息分发到控制台、文件或自定义 sink。 +- CPU 埋点:通过 `Profiler` 记录函数段或作用域的耗时。 +- GPU 抓帧:通过 `RenderDocCapture` 在图形测试和工具程序中触发 RenderDoc。 + +当前版本的成熟度并不一致: + +- `Logger` 与日志 sink 已经可以直接用于编辑器、测试和后端调试。 +- `Profiler` 的接口已经成形,但导出、标记和事件功能目前仍是占位实现。 +- `RenderDocCapture` 是 Windows 平台上的轻量封装,依赖可用的 `renderdoc.dll`。 + +## 设计要点 + +- 统一入口比散落的 `printf` 或后端专用日志更利于跨模块排查问题。 +- sink 模式允许同时输出到多个目标,而不会把输出策略写死在业务代码里。 +- `Profiler` 和 `RenderDocCapture` 都采用单例,目的是让工具、测试和引擎运行时共享一套调试入口。 +- 该模块偏开发期工具能力,不追求零侵入;一些 API 会主动写日志、刷新文件或拉起窗口焦点。 ## 头文件 -- [ConsoleLogSink](ConsoleLogSink/ConsoleLogSink.md) - `ConsoleLogSink.h` -- [Debug](Debug/Debug.md) - `Debug.h` -- [FileLogSink](FileLogSink/FileLogSink.md) - `FileLogSink.h` -- [ILogSink](ILogSink/ILogSink.md) - `ILogSink.h` -- [LogCategory](LogCategory/LogCategory.md) - `LogCategory.h` -- [LogEntry](LogEntry/LogEntry.md) - `LogEntry.h` -- [Logger](Logger/Logger.md) - `Logger.h` -- [LogLevel](LogLevel/LogLevel.md) - `LogLevel.h` -- [Profiler](Profiler/Profiler.md) - `Profiler.h` -- [RenderDocCapture](RenderDocCapture/RenderDocCapture.md) - `RenderDocCapture.h` +- [ConsoleLogSink](ConsoleLogSink/ConsoleLogSink.md) - `ConsoleLogSink.h`,面向 `stdout` 的日志输出 sink。 +- [Debug](Debug/Debug.md) - `Debug.h`,聚合调试模块所有 public header 的便利入口。 +- [FileLogSink](FileLogSink/FileLogSink.md) - `FileLogSink.h`,将日志追加写入文件。 +- [ILogSink](ILogSink/ILogSink.md) - `ILogSink.h`,日志输出目标接口。 +- [LogCategory](LogCategory/LogCategory.md) - `LogCategory.h`,日志功能分类枚举。 +- [LogEntry](LogEntry/LogEntry.md) - `LogEntry.h`,日志记录载体。 +- [Logger](Logger/Logger.md) - `Logger.h`,全局日志分发中心。 +- [LogLevel](LogLevel/LogLevel.md) - `LogLevel.h`,日志严重级别枚举。 +- [Profiler](Profiler/Profiler.md) - `Profiler.h`,轻量级 CPU 埋点入口。 +- [RenderDocCapture](RenderDocCapture/RenderDocCapture.md) - `RenderDocCapture.h`,RenderDoc 封装。 + +## 相关指南 + +- [Logging Architecture](../../_guides/Debug/Logging-Architecture.md) - 日志系统的角色划分、推荐接线方式和与 Unity 的概念对照。 +- [Profiler Workflow](../../_guides/Debug/Profiler-Workflow.md) - 当前埋点能力的适用边界、典型流程与限制。 +- [RenderDoc Capture Workflow](../../_guides/Debug/RenderDoc-Capture-Workflow.md) - 在图形测试中接入 RenderDoc 的推荐步骤。 ## 相关文档 diff --git a/docs/api/XCEngine/Debug/Debug/Debug.md b/docs/api/XCEngine/Debug/Debug/Debug.md index 9abd25e1..1c8a8813 100644 --- a/docs/api/XCEngine/Debug/Debug/Debug.md +++ b/docs/api/XCEngine/Debug/Debug/Debug.md @@ -1,18 +1,46 @@ # Debug -**命名空间**: `XCEngine` +**命名空间**: `XCEngine::Debug` -**类型**: `header` +**类型**: `header-umbrella` **头文件**: `XCEngine/Debug/Debug.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `Debug` public API。 +**描述**: 聚合调试模块主要 public header 的便利包含入口。 ## 概述 -`Debug.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`Debug.h` 自身不定义新的核心类型,它的主要作用是把调试子系统的常用头文件集中包含进来,方便工具程序、测试程序或示例快速接入调试能力。 + +当前头文件会聚合: + +- `LogLevel.h` +- `LogCategory.h` +- `LogEntry.h` +- `ILogSink.h` +- `ConsoleLogSink.h` +- `FileLogSink.h` +- `Logger.h` +- `Profiler.h` +- `RenderDocCapture.h` +- `../Core/FileWriter.h` + +## 设计建议 + +- 对于快速原型、测试或示例程序,直接包含 `Debug.h` 比逐个包含更方便。 +- 对于大型模块或编译敏感代码,建议只包含真正需要的具体头文件,避免不必要的编译依赖扩散。 +- `Logger.h` 与 `Profiler.h` 中定义的重要宏分别是 `XE_LOG`、`XE_ASSERT`、`XE_PROFILE_BEGIN`、`XE_PROFILE_END` 和 `XE_PROFILE_FUNCTION`。 + +## 声明概览 + +| 声明 | 类型 | 说明 | +|------|------|------| +| `Debug.h` | umbrella header | 调试模块的快速入口,而不是独立运行时对象。 | ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [Profiler](../Profiler/Profiler.md) +- [RenderDocCapture](../RenderDocCapture/RenderDocCapture.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/FileLogSink/Constructor.md b/docs/api/XCEngine/Debug/FileLogSink/Constructor.md index a436d7d7..271f5ecd 100644 --- a/docs/api/XCEngine/Debug/FileLogSink/Constructor.md +++ b/docs/api/XCEngine/Debug/FileLogSink/Constructor.md @@ -1,29 +1,36 @@ -# FileLogSink::FileLogSink() +# FileLogSink::Constructor -构造对象。 +构造一个把日志追加写入文件的 sink。 ```cpp FileLogSink(const Containers::String& filePath); ``` -该方法声明于 `XCEngine/Debug/FileLogSink.h`,当前页面用于固定 `FileLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `filePath` - 参数语义详见头文件声明。 +当前实现会保存 `filePath`,并立即尝试通过 `Core::FileWriter` 以追加模式打开该文件。即使第一次打开失败,对象仍然会保留路径,后续在 `Log` 时继续重试打开。 -**返回:** `void` - 无返回值。 +## 参数 -**示例:** +- `filePath` - 日志文件路径。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 构造本身不加锁;通常在启动阶段创建并交给 `Logger` 持有。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::FileLogSink object; -} +Logger::Get().AddSink(std::make_unique("editor.log")); ``` ## 相关文档 -- [返回类总览](FileLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](FileLogSink.md) +- [Log](Log.md) diff --git a/docs/api/XCEngine/Debug/FileLogSink/Destructor.md b/docs/api/XCEngine/Debug/FileLogSink/Destructor.md index 275aeafe..3ed4bd73 100644 --- a/docs/api/XCEngine/Debug/FileLogSink/Destructor.md +++ b/docs/api/XCEngine/Debug/FileLogSink/Destructor.md @@ -1,29 +1,34 @@ -# FileLogSink::~FileLogSink() +# FileLogSink::Destructor -销毁对象并释放相关资源。 +销毁文件日志 sink 并关闭底层文件。 ```cpp ~FileLogSink() override; ``` -该方法声明于 `XCEngine/Debug/FileLogSink.h`,当前页面用于固定 `FileLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现直接调用 `m_writer.Close()`。如果该 sink 仍由 `Logger` 持有,通常会在 `Logger::Shutdown` 清空 sink 列表时自动触发析构。 -**返回:** `void` - 无返回值。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 应在对象不再参与日志分发后销毁。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::FileLogSink object; - // 对象离开作用域时会自动触发析构。 -} +XCEngine::Debug::Logger::Get().Shutdown(); ``` ## 相关文档 -- [返回类总览](FileLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](FileLogSink.md) +- [ILogSink::Destructor](../ILogSink/Destructor.md) diff --git a/docs/api/XCEngine/Debug/FileLogSink/FileLogSink.md b/docs/api/XCEngine/Debug/FileLogSink/FileLogSink.md index 6d8e86f9..79601af1 100644 --- a/docs/api/XCEngine/Debug/FileLogSink/FileLogSink.md +++ b/docs/api/XCEngine/Debug/FileLogSink/FileLogSink.md @@ -6,28 +6,56 @@ **头文件**: `XCEngine/Debug/FileLogSink.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `FileLogSink` public API。 +**描述**: 将日志追加写入文件,并在失败时回退到 `stderr`。 ## 概述 -`FileLogSink.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`FileLogSink` 负责把 `LogEntry` 序列化成文本并落盘。它适合编辑器、集成测试和长时间运行的工具程序,因为这类场景通常需要保留会话级日志以便复盘。 -## 声明概览 +当前实现中的关键行为: -| 声明 | 类型 | 说明 | -|------|------|------| -| `FileLogSink` | `class` | 继承自 `ILogSink` 的公开声明。 | +- 构造时尝试以追加模式打开目标文件。 +- 每次写入后立即 `Flush`,优先保证可追溯性,而不是吞吐量。 +- 如果文件句柄不可用,会在 `Log` 时尝试重新打开。 +- 如果重新打开或写入失败,会把错误和原始日志内容写到 `stderr`。 -## 公共方法 +## 生命周期 -| 方法 | 描述 | +- [Constructor](Constructor.md) 保存目标路径并尝试打开文件。 +- [Destructor](Destructor.md) 关闭底层 `FileWriter`。 +- [Flush](Flush.md) 将缓冲区刷到磁盘。 + +## 线程语义 + +- `FileLogSink` 自身没有显式加锁。 +- 通过 `Logger` 使用时,调用会被 `Logger` 串行化。 +- 当前实现使用 `std::localtime` 生成时间文本;如果绕过 `Logger` 并发调用,线程安全性由调用方承担。 + +## 输出格式 + +当前实现输出格式为: + +```text +[YYYY-MM-DD HH:MM:SS] [LEVEL] [Category] message +``` + +注意: + +- 使用的是 `LogEntry::timestamp` 的本地时间表示。 +- 当前不会把 `file`、`line`、`function` 或 `threadId` 写入文件。 + +## 公开方法 + +| 方法 | 说明 | |------|------| -| [FileLogSink()](Constructor.md) | 构造对象。 | -| [~FileLogSink()](Destructor.md) | 销毁对象并释放相关资源。 | -| [Log](Log.md) | 公开方法,详见头文件声明。 | -| [Flush](Flush.md) | 公开方法,详见头文件声明。 | +| [Constructor](Constructor.md) | 构造文件日志 sink。 | +| [Destructor](Destructor.md) | 析构 sink 并关闭文件。 | +| [Log](Log.md) | 将日志条目写入文件。 | +| [Flush](Flush.md) | 刷新底层文件。 | ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [ILogSink](../ILogSink/ILogSink.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/FileLogSink/Flush.md b/docs/api/XCEngine/Debug/FileLogSink/Flush.md index 0d52daf2..8234b8e5 100644 --- a/docs/api/XCEngine/Debug/FileLogSink/Flush.md +++ b/docs/api/XCEngine/Debug/FileLogSink/Flush.md @@ -1,30 +1,37 @@ # FileLogSink::Flush -公开方法,详见头文件声明。 +把底层文件缓冲区刷新到磁盘。 ```cpp void Flush() override; ``` -该方法声明于 `XCEngine/Debug/FileLogSink.h`,当前页面用于固定 `FileLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现直接转发到 `Core::FileWriter::Flush()`。如果文件尚未成功打开,`FileWriter` 会返回 `false`,但 `FileLogSink::Flush` 本身不会上报错误。 -**返回:** `void` - 无返回值。 +需要注意的是,当前 `FileLogSink::Log` 在每次写入后已经主动调用一次 `Flush`,因此手动调用更多是为了表达语义,而不是补齐缺失步骤。 -**示例:** +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 通过 `Logger` 使用时通常是串行的。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::FileLogSink object; - // 根据上下文补齐参数后调用 FileLogSink::Flush(...)。 - (void)object; -} +XCEngine::Debug::FileLogSink sink("engine.log"); +sink.Flush(); ``` ## 相关文档 -- [返回类总览](FileLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](FileLogSink.md) +- [Log](Log.md) diff --git a/docs/api/XCEngine/Debug/FileLogSink/Log.md b/docs/api/XCEngine/Debug/FileLogSink/Log.md index 457bf031..1f584720 100644 --- a/docs/api/XCEngine/Debug/FileLogSink/Log.md +++ b/docs/api/XCEngine/Debug/FileLogSink/Log.md @@ -1,31 +1,51 @@ # FileLogSink::Log -公开方法,详见头文件声明。 +将日志条目写入文件,并在失败时回退到 `stderr`。 ```cpp void Log(const LogEntry& entry) override; ``` -该方法声明于 `XCEngine/Debug/FileLogSink.h`,当前页面用于固定 `FileLogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `entry` - 参数语义详见头文件声明。 +当前实现流程如下: -**返回:** `void` - 无返回值。 +1. 如果文件未打开,先尝试按保存的路径重新打开。 +2. 如果打开失败,把错误和原始日志写到 `stderr`,然后返回。 +3. 把 `entry.timestamp` 按本地时间格式化为 `YYYY-MM-DD HH:MM:SS`。 +4. 以 `[时间] [级别] [分类] message` 的形式写入文件。 +5. 写入后立即 `Flush`。 -**示例:** +当前不会写入: + +- `file` +- `line` +- `function` +- `threadId` + +## 参数 + +- `entry` - 待落盘的日志条目。 + +## 返回值 + +- 无。 + +## 线程语义 + +- sink 自身无锁。 +- 通过 `Logger` 分发时为串行调用。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::FileLogSink object; - // 根据上下文补齐参数后调用 FileLogSink::Log(...)。 - (void)object; -} +Logger::Get().AddSink(std::make_unique("runtime.log")); +Logger::Get().Info(LogCategory::General, "Runtime started"); ``` ## 相关文档 -- [返回类总览](FileLogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](FileLogSink.md) +- [Flush](Flush.md) diff --git a/docs/api/XCEngine/Debug/ILogSink/Destructor.md b/docs/api/XCEngine/Debug/ILogSink/Destructor.md index 6b8252b2..0d5f668a 100644 --- a/docs/api/XCEngine/Debug/ILogSink/Destructor.md +++ b/docs/api/XCEngine/Debug/ILogSink/Destructor.md @@ -1,29 +1,35 @@ -# ILogSink::~ILogSink() +# ILogSink::Destructor -销毁对象并释放相关资源。 +以基类指针安全销毁日志 sink。 ```cpp virtual ~ILogSink() = default; ``` -该方法声明于 `XCEngine/Debug/ILogSink.h`,当前页面用于固定 `ILogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +这是一个虚析构函数,目的是保证 `Logger` 通过 `std::unique_ptr` 释放派生类对象时,能够正确调用派生类析构逻辑。 -**返回:** `void` - 无返回值。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 销毁前应确保对象不再被并发调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::ILogSink object; - // 对象离开作用域时会自动触发析构。 -} +XCEngine::Debug::Logger::Get().Shutdown(); ``` ## 相关文档 -- [返回类总览](ILogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ILogSink.md) +- [ConsoleLogSink::Destructor](../ConsoleLogSink/Destructor.md) +- [FileLogSink::Destructor](../FileLogSink/Destructor.md) diff --git a/docs/api/XCEngine/Debug/ILogSink/Flush.md b/docs/api/XCEngine/Debug/ILogSink/Flush.md index 0303be53..80fe9d68 100644 --- a/docs/api/XCEngine/Debug/ILogSink/Flush.md +++ b/docs/api/XCEngine/Debug/ILogSink/Flush.md @@ -1,30 +1,43 @@ # ILogSink::Flush -公开方法,详见头文件声明。 +刷新 sink 内部缓冲。 ```cpp virtual void Flush() = 0; ``` -该方法声明于 `XCEngine/Debug/ILogSink.h`,当前页面用于固定 `ILogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +这是纯虚接口。不同 sink 对“刷新”的含义不同: -**返回:** `void` - 无返回值。 +- `ConsoleLogSink` 刷新 `stdout` +- `FileLogSink` 刷新底层文件句柄 -**示例:** +如果你的自定义 sink 持有网络缓冲、内存队列或异步批处理器,也应在这里提供显式落地语义。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 由具体实现决定。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::ILogSink object; - // 根据上下文补齐参数后调用 ILogSink::Flush(...)。 - (void)object; -} +class MySink final : public XCEngine::Debug::ILogSink { +public: + void Log(const XCEngine::Debug::LogEntry& entry) override {} + void Flush() override {} +}; ``` ## 相关文档 -- [返回类总览](ILogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ILogSink.md) +- [Log](Log.md) diff --git a/docs/api/XCEngine/Debug/ILogSink/ILogSink.md b/docs/api/XCEngine/Debug/ILogSink/ILogSink.md index 5011b777..16654b83 100644 --- a/docs/api/XCEngine/Debug/ILogSink/ILogSink.md +++ b/docs/api/XCEngine/Debug/ILogSink/ILogSink.md @@ -6,27 +6,45 @@ **头文件**: `XCEngine/Debug/ILogSink.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `ILogSink` public API。 +**描述**: 定义日志输出目标的最小接口。 ## 概述 -`ILogSink.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`ILogSink` 把“日志生产”与“日志落地”分离开来。`Logger` 只负责构造 `LogEntry`、做全局过滤并分发,而真正的输出策略交给 sink 实现决定。 -## 声明概览 +这类接口的意义在于: -| 声明 | 类型 | 说明 | -|------|------|------| -| `ILogSink` | `class` | 头文件中的公开声明。 | +- 可以同时输出到控制台、文件、编辑器面板或远程通道。 +- 不需要让业务模块直接依赖具体输出媒介。 +- 便于在测试中插入自定义 sink 验证日志行为。 -## 公共方法 +## 契约 -| 方法 | 描述 | +- [Log](Log.md) 必须接收一条已经构造好的 `LogEntry` 并执行输出。 +- [Flush](Flush.md) 用于把 sink 内部缓冲显式落地。 +- [Destructor](Destructor.md) 必须为虚析构,以便通过基类指针安全释放派生对象。 + +## 线程语义 + +- `ILogSink` 不承诺任何线程安全保证。 +- 具体线程语义由实现类与调用方共同决定。 +- 在 XCEngine 当前实现中,`Logger` 会在互斥区内调用 sink,因此“通过 `Logger` 分发”是串行的。 + +## 已知实现 + +- [ConsoleLogSink](../ConsoleLogSink/ConsoleLogSink.md) +- [FileLogSink](../FileLogSink/FileLogSink.md) + +## 公开方法 + +| 方法 | 说明 | |------|------| -| [~ILogSink()](Destructor.md) | 销毁对象并释放相关资源。 | -| [Log](Log.md) | 公开方法,详见头文件声明。 | -| [Flush](Flush.md) | 公开方法,详见头文件声明。 | +| [Destructor](Destructor.md) | 虚析构函数。 | +| [Log](Log.md) | 输出一条日志记录。 | +| [Flush](Flush.md) | 刷新 sink 内部缓冲。 | ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/ILogSink/Log.md b/docs/api/XCEngine/Debug/ILogSink/Log.md index 05ccf487..717ff1f7 100644 --- a/docs/api/XCEngine/Debug/ILogSink/Log.md +++ b/docs/api/XCEngine/Debug/ILogSink/Log.md @@ -1,31 +1,51 @@ # ILogSink::Log -公开方法,详见头文件声明。 +输出一条已经构造完成的日志记录。 ```cpp virtual void Log(const LogEntry& entry) = 0; ``` -该方法声明于 `XCEngine/Debug/ILogSink.h`,当前页面用于固定 `ILogSink` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `entry` - 参数语义详见头文件声明。 +这是纯虚接口。`Logger` 负责创建 `LogEntry`、做全局过滤和序列化分发,sink 实现只需要关心如何消费这条记录。 -**返回:** `void` - 无返回值。 +常见实现策略包括: -**示例:** +- 控制台打印 +- 文件写入 +- 编辑器面板缓存 +- 远程调试通道转发 + +## 参数 + +- `entry` - 已构造完成的日志记录。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 由具体实现决定。 +- 在当前引擎实现中,通过 `Logger` 分发时通常是串行调用。 + +## 示例 ```cpp -#include +class CountingSink final : public XCEngine::Debug::ILogSink { +public: + void Log(const XCEngine::Debug::LogEntry& entry) override { + ++count; + } -void Example() { - XCEngine::Debug::ILogSink object; - // 根据上下文补齐参数后调用 ILogSink::Log(...)。 - (void)object; -} + void Flush() override {} + + int count = 0; +}; ``` ## 相关文档 -- [返回类总览](ILogSink.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](ILogSink.md) +- [Logger::AddSink](../Logger/AddSink.md) diff --git a/docs/api/XCEngine/Debug/LogCategory/LogCategory.md b/docs/api/XCEngine/Debug/LogCategory/LogCategory.md index 727ab33d..6f9fe37e 100644 --- a/docs/api/XCEngine/Debug/LogCategory/LogCategory.md +++ b/docs/api/XCEngine/Debug/LogCategory/LogCategory.md @@ -6,35 +6,44 @@ **头文件**: `XCEngine/Debug/LogCategory.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `LogCategory` public API。 +**描述**: 表示日志的功能域分类,用于按模块过滤与检索。 ## 概述 -`LogCategory.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`LogCategory` 用于回答“这条日志属于哪个子系统”。与 `LogLevel` 负责表达严重程度不同,category 更像是日志的归属标签。 -## 声明概览 +当前版本中的 category 同时用于: -| 声明 | 类型 | 说明 | -|------|------|------| -| `LogCategory` | `enum class` | 头文件中的公开声明。 | +- sink 输出中的分类文本。 +- `Logger::SetCategoryEnabled` 的运行时开关。 +- 编辑器控制台和测试日志的筛选依据。 ## 枚举值 -| 枚举值 | 数值 | 描述 | -|--------|------|------| -| `General` | - | 枚举项。 | -| `Rendering` | - | 枚举项。 | -| `Physics` | - | 枚举项。 | -| `Audio` | - | 枚举项。 | -| `Scripting` | - | 枚举项。 | -| `Network` | - | 枚举项。 | -| `Memory` | - | 枚举项。 | -| `Threading` | - | 枚举项。 | -| `FileSystem` | - | 枚举项。 | -| `RenderDoc` | - | 枚举项。 | -| `Custom` | - | 枚举项。 | +| 值 | 说明 | +|------|------| +| `General` | 通用运行信息、不明确属于单一子系统的日志。 | +| `Rendering` | 渲染、图形后端、截图与渲染流程相关日志。 | +| `Physics` | 物理系统日志。 | +| `Audio` | 音频系统日志。 | +| `Scripting` | 脚本或运行时绑定日志。 | +| `Network` | 网络系统日志。 | +| `Memory` | 内存分配、回收与调试日志。 | +| `Threading` | 线程、任务和同步原语相关日志。 | +| `FileSystem` | 资源加载、文件读写和路径处理日志。 | +| `RenderDoc` | RenderDoc 抓帧或图形诊断相关日志。 | +| `Custom` | 预留给调用方的自定义类别。 | + +## 当前实现说明 + +- `Logger` 内部使用固定长度为 11 的启用表管理 category 开关。 +- 这意味着当前枚举值数量与 `Logger` 的实现保持强耦合;如果扩展枚举,必须同步更新 `Logger` 的过滤数组与边界检查。 +- `LogCategoryToString` 提供稳定的显示名称,控制台和文件 sink 都依赖它。 ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [LogLevel](../LogLevel/LogLevel.md) +- [LogEntry](../LogEntry/LogEntry.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/LogEntry/LogEntry.md b/docs/api/XCEngine/Debug/LogEntry/LogEntry.md index d7fa8750..ae206112 100644 --- a/docs/api/XCEngine/Debug/LogEntry/LogEntry.md +++ b/docs/api/XCEngine/Debug/LogEntry/LogEntry.md @@ -6,32 +6,34 @@ **头文件**: `XCEngine/Debug/LogEntry.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `LogEntry` public API。 +**描述**: 承载单条日志记录的结构体。 ## 概述 -`LogEntry.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`LogEntry` 是 `Logger` 与各类 sink 之间传递日志数据的统一载体。调用方通常不会手动构造它,而是通过 `Logger::Log` 或便捷方法间接生成;sink 实现则读取其中的字段决定如何格式化输出。 -## 声明概览 +## 字段说明 -| 声明 | 类型 | 说明 | +| 字段 | 类型 | 说明 | |------|------|------| -| `LogEntry` | `struct` | 头文件中的公开声明。 | +| `level` | `LogLevel` | 日志严重级别。 | +| `category` | `LogCategory` | 日志功能域。 | +| `message` | `Containers::String` | 最终日志文本。 | +| `file` | `Containers::String` | 源文件路径;只有显式传入时才有值。 | +| `line` | `int32_t` | 源码行号;便捷方法通常保留为 `0`。 | +| `function` | `Containers::String` | 源函数名;只有显式传入时才有值。 | +| `timestamp` | `uint64_t` | 当前实现中为 Unix epoch 秒数。 | +| `threadId` | `uint32_t` | 当前实现中为 `std::thread::id` 哈希后的 32 位值。 | -## 结构体成员 +## 当前实现说明 -| 成员 | 类型 | 描述 | 默认值 | -|------|------|------|--------| -| `level` | `LogLevel` | 结构体公开字段。 | - | -| `category` | `LogCategory` | 结构体公开字段。 | - | -| `message` | `Containers::String` | 结构体公开字段。 | - | -| `file` | `Containers::String` | 结构体公开字段。 | - | -| `line` | `int32_t` | 结构体公开字段。 | - | -| `function` | `Containers::String` | 结构体公开字段。 | - | -| `timestamp` | `uint64_t` | 结构体公开字段。 | - | -| `threadId` | `uint32_t` | 结构体公开字段。 | - | +- `Logger::Log` 会为 `timestamp` 与 `threadId` 自动填值。 +- `Logger::Verbose`、`Info` 等便捷方法调用的是带默认参数的 `Log`,因此默认不会填充 `file`、`line` 和 `function`。 +- 如果希望保留源码位置,推荐使用 `XE_LOG` 宏而不是直接调用这些便捷方法。 ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [ILogSink](../ILogSink/ILogSink.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/LogLevel/LogLevel.md b/docs/api/XCEngine/Debug/LogLevel/LogLevel.md index a4418532..67446054 100644 --- a/docs/api/XCEngine/Debug/LogLevel/LogLevel.md +++ b/docs/api/XCEngine/Debug/LogLevel/LogLevel.md @@ -6,30 +6,34 @@ **头文件**: `XCEngine/Debug/LogLevel.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `LogLevel` public API。 +**描述**: 表示日志严重程度,并定义过滤时使用的优先级顺序。 ## 概述 -`LogLevel.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`LogLevel` 负责回答“这条日志有多严重”。它同时被 `Logger` 的全局阈值和 `ConsoleLogSink` 的本地阈值使用,因此其枚举顺序本身就是过滤规则的一部分。 -## 声明概览 - -| 声明 | 类型 | 说明 | -|------|------|------| -| `LogLevel` | `enum class` | 头文件中的公开声明。 | +当前实现使用“数值越大,严重程度越高”的顺序,比较方式是直接使用 `<`。 ## 枚举值 -| 枚举值 | 数值 | 描述 | -|--------|------|------| -| `Verbose` | `0` | 枚举项。 | -| `Debug` | `1` | 枚举项。 | -| `Info` | `2` | 枚举项。 | -| `Warning` | `3` | 枚举项。 | -| `Error` | `4` | 枚举项。 | -| `Fatal` | `5` | 枚举项。 | +| 值 | 当前数值 | 说明 | +|------|------|------| +| `Verbose` | `0` | 最细粒度的调试输出。 | +| `Debug` | `1` | 面向开发者的调试信息。 | +| `Info` | `2` | 重要但正常的运行信息。 | +| `Warning` | `3` | 可恢复或需关注的问题。 | +| `Error` | `4` | 明确的失败或异常路径。 | +| `Fatal` | `5` | 最严重级别;当前实现仍只负责记录日志。 | + +## 当前实现说明 + +- `LogLevelToString` 会把枚举值转换为大写文本,例如 `INFO`、`ERROR`。 +- `Logger` 和 `ConsoleLogSink` 都通过比较 `entry.level < minimumLevel` 过滤日志。 +- `Fatal` 目前没有额外控制流语义;它不是“崩溃即将发生”的语言级保证,只是最高等级日志。 ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Logger](../Logger/Logger.md) +- [LogCategory](../LogCategory/LogCategory.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/Logger/AddSink.md b/docs/api/XCEngine/Debug/Logger/AddSink.md index 6de782a6..d1c6d226 100644 --- a/docs/api/XCEngine/Debug/Logger/AddSink.md +++ b/docs/api/XCEngine/Debug/Logger/AddSink.md @@ -1,31 +1,43 @@ # Logger::AddSink -添加元素或建立关联。 +把一个日志输出目标注册到全局 `Logger`。 ```cpp void AddSink(std::unique_ptr sink); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `sink` - 参数语义详见头文件声明。 +当前实现会在互斥区内把 `sink` 移入内部 `std::vector>`。注册后: -**返回:** `void` - 无返回值。 +- `Logger` 接管对象生命周期。 +- 之后的每次 `Log` 都会把日志分发给该 sink。 +- 不会因为未初始化而失败;`AddSink` 本身不依赖 `Initialize`。 -**示例:** +## 参数 + +- `sink` - 新的日志输出目标,所有权会转移给 `Logger`。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前实现对 sink 列表写入加锁。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::AddSink(...)。 - (void)object; -} +Logger::Get().Initialize(); +Logger::Get().AddSink(std::make_unique()); +Logger::Get().AddSink(std::make_unique("engine.log")); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [RemoveSink](RemoveSink.md) +- [ILogSink](../ILogSink/ILogSink.md) diff --git a/docs/api/XCEngine/Debug/Logger/Debug.md b/docs/api/XCEngine/Debug/Logger/Debug.md index e5a36dfe..2532e6f8 100644 --- a/docs/api/XCEngine/Debug/Logger/Debug.md +++ b/docs/api/XCEngine/Debug/Logger/Debug.md @@ -1,32 +1,46 @@ # Logger::Debug -公开方法,详见头文件声明。 +以 `Debug` 级别记录一条日志。 ```cpp void Debug(LogCategory category, const Containers::String& message); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +这是 `Logger::Log` 的便捷封装,等价于: ```cpp -#include +Log(LogLevel::Debug, category, message); +``` -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Debug(...)。 - (void)object; -} +它不会自动填充 `file`、`line` 或 `function`。如果你需要源码位置,请改用 `XE_LOG` 宏或直接调用 `Log` 的完整签名。 + +## 参数 + +- `category` - 日志分类。 +- `message` - 日志文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 与 [Log](Log.md) 相同。 + +## 示例 + +```cpp +XCEngine::Debug::Logger::Get().Debug( + XCEngine::Debug::LogCategory::Rendering, + "Pipeline state updated" +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Log](Log.md) +- [Verbose](Verbose.md) +- [Info](Info.md) diff --git a/docs/api/XCEngine/Debug/Logger/Error.md b/docs/api/XCEngine/Debug/Logger/Error.md index 14e73c1c..5acb82a3 100644 --- a/docs/api/XCEngine/Debug/Logger/Error.md +++ b/docs/api/XCEngine/Debug/Logger/Error.md @@ -1,32 +1,45 @@ # Logger::Error -公开方法,详见头文件声明。 +以 `Error` 级别记录一条日志。 ```cpp void Error(LogCategory category, const Containers::String& message); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +这是 `Logger::Log` 的便捷封装,等价于: ```cpp -#include +Log(LogLevel::Error, category, message); +``` -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Error(...)。 - (void)object; -} +当前实现只记录错误,不会抛异常或改变控制流。 + +## 参数 + +- `category` - 日志分类。 +- `message` - 错误文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 与 [Log](Log.md) 相同。 + +## 示例 + +```cpp +XCEngine::Debug::Logger::Get().Error( + XCEngine::Debug::LogCategory::FileSystem, + "Failed to open asset file" +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Log](Log.md) +- [Fatal](Fatal.md) diff --git a/docs/api/XCEngine/Debug/Logger/Fatal.md b/docs/api/XCEngine/Debug/Logger/Fatal.md index d8da183c..21f3dc88 100644 --- a/docs/api/XCEngine/Debug/Logger/Fatal.md +++ b/docs/api/XCEngine/Debug/Logger/Fatal.md @@ -1,32 +1,45 @@ # Logger::Fatal -公开方法,详见头文件声明。 +以 `Fatal` 级别记录一条日志。 ```cpp void Fatal(LogCategory category, const Containers::String& message); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +这是 `Logger::Log` 的便捷封装,等价于: ```cpp -#include +Log(LogLevel::Fatal, category, message); +``` -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Fatal(...)。 - (void)object; -} +需要特别注意:在当前版本中,`Fatal` 只是最高严重级别的日志,不会自动终止程序、触发断言中断或抛出异常。`XE_ASSERT` 也是基于这个行为实现的。 + +## 参数 + +- `category` - 日志分类。 +- `message` - 致命错误文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 与 [Log](Log.md) 相同。 + +## 示例 + +```cpp +XCEngine::Debug::Logger::Get().Fatal( + XCEngine::Debug::LogCategory::General, + "Unexpected unrecoverable state" +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Log](Log.md) +- [Error](Error.md) diff --git a/docs/api/XCEngine/Debug/Logger/Get.md b/docs/api/XCEngine/Debug/Logger/Get.md index d5a48ac2..c601d1b3 100644 --- a/docs/api/XCEngine/Debug/Logger/Get.md +++ b/docs/api/XCEngine/Debug/Logger/Get.md @@ -1,29 +1,44 @@ # Logger::Get -获取相关状态或对象。 +获取进程级全局 `Logger` 实例。 ```cpp static Logger& Get(); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 - -**返回:** `Logger&` - 返回值语义详见头文件声明。 - -**示例:** +当前实现使用函数内静态对象保存单例: ```cpp -#include +static Logger instance; +``` -void Example() { - auto& instance = XCEngine::Debug::Logger::Get(); - (void)instance; -} +因此: + +- 你拿到的是同一个 `Logger` 实例引用。 +- 该方法本身不会自动初始化 sink,也不会重置过滤配置。 + +## 参数 + +- 无。 + +## 返回值 + +- `Logger&` - 全局日志分发器引用。 + +## 线程语义 + +- C++ 对函数内静态对象初始化提供线程安全保证,但 `Logger` 的后续配置和使用仍需遵守各自方法的线程语义。 + +## 示例 + +```cpp +XCEngine::Debug::Logger& logger = XCEngine::Debug::Logger::Get(); +logger.Initialize(); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/Logger/Info.md b/docs/api/XCEngine/Debug/Logger/Info.md index 8fbf2cb2..3ee7698f 100644 --- a/docs/api/XCEngine/Debug/Logger/Info.md +++ b/docs/api/XCEngine/Debug/Logger/Info.md @@ -1,32 +1,45 @@ # Logger::Info -公开方法,详见头文件声明。 +以 `Info` 级别记录一条日志。 ```cpp void Info(LogCategory category, const Containers::String& message); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +这是 `Logger::Log` 的便捷封装,等价于: ```cpp -#include +Log(LogLevel::Info, category, message); +``` -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Info(...)。 - (void)object; -} +它适合记录重要但正常的运行事件,例如启动完成、资源路径、当前设备信息等。 + +## 参数 + +- `category` - 日志分类。 +- `message` - 日志文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 与 [Log](Log.md) 相同。 + +## 示例 + +```cpp +XCEngine::Debug::Logger::Get().Info( + XCEngine::Debug::LogCategory::General, + "Editor Application starting..." +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Log](Log.md) +- [Warning](Warning.md) diff --git a/docs/api/XCEngine/Debug/Logger/Initialize.md b/docs/api/XCEngine/Debug/Logger/Initialize.md index 647eef39..8f03908c 100644 --- a/docs/api/XCEngine/Debug/Logger/Initialize.md +++ b/docs/api/XCEngine/Debug/Logger/Initialize.md @@ -1,30 +1,49 @@ # Logger::Initialize -初始化内部状态。 +把 `Logger` 标记为已初始化。 ```cpp void Initialize(); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现是幂等的: -**返回:** `void` - 无返回值。 +- 如果已经初始化,直接返回。 +- 如果尚未初始化,仅把内部 `m_initialized` 设为 `true`。 -**示例:** +它不会做以下事情: + +- 不会添加默认 sink。 +- 不会清空已有 sink。 +- 不会重置最小级别或 category 开关。 + +因此,推荐把它理解为“进入可用状态”的轻量标记,而不是完整的日志系统自举流程。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前实现没有显式同步初始化流程;如果多线程首次同时写日志,`Log` 的自动初始化路径虽然通常能工作,但仍建议在启动阶段显式调用一次。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Initialize(...)。 - (void)object; -} +Logger::Get().Initialize(); +Logger::Get().AddSink(std::make_unique()); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Shutdown](Shutdown.md) +- [Log](Log.md) diff --git a/docs/api/XCEngine/Debug/Logger/Log.md b/docs/api/XCEngine/Debug/Logger/Log.md index 0acc4d42..50df1fb2 100644 --- a/docs/api/XCEngine/Debug/Logger/Log.md +++ b/docs/api/XCEngine/Debug/Logger/Log.md @@ -1,36 +1,77 @@ # Logger::Log -公开方法,详见头文件声明。 +构造一条 `LogEntry` 并把它分发给所有已注册 sink。 ```cpp -void Log(LogLevel level, LogCategory category, const Containers::String& message, const char* file = nullptr, int32_t line = 0, const char* function = nullptr); +void Log( + LogLevel level, + LogCategory category, + const Containers::String& message, + const char* file = nullptr, + int32_t line = 0, + const char* function = nullptr +); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `level` - 参数语义详见头文件声明。 -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 -- `file` - 参数语义详见头文件声明。 -- `line` - 参数语义详见头文件声明。 -- `function` - 参数语义详见头文件声明。 +当前实现依次执行以下步骤: -**返回:** `void` - 无返回值。 +1. 如果 `Logger` 尚未初始化,先调用 `Initialize()`。 +2. 如果 `level < m_minimumLevel`,直接丢弃日志。 +3. 如果 category 对应的启用位为关闭状态,直接丢弃日志。 +4. 构造 `LogEntry`,填充: + - `level` + - `category` + - `message` + - `file` + - `line` + - `function` + - 当前秒级时间戳 + - 当前线程哈希值 +5. 在互斥区内遍历所有 sink 并调用其 `Log(entry)`。 -**示例:** +需要注意: + +- 如果没有注册任何 sink,日志会被静默丢弃。 +- 当前时间戳粒度是“秒”,不是毫秒或微秒。 +- 当前线程 ID 是哈希结果,不保证与系统线程号一致。 + +## 参数 + +- `level` - 日志级别。 +- `category` - 日志分类。 +- `message` - 日志文本。 +- `file` - 可选的源文件路径。 +- `line` - 可选的源码行号。 +- `function` - 可选的函数名。 + +## 返回值 + +- 无。 + +## 线程语义 + +- sink 分发过程在互斥区内执行。 +- `SetMinimumLevel` 和 `SetCategoryEnabled` 当前无锁,因此在高并发日志期间动态修改配置时要自行承担竞争风险。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Log(...)。 - (void)object; -} +Logger::Get().Log( + LogLevel::Warning, + LogCategory::General, + "Fallback code path selected", + __FILE__, + __LINE__, + __FUNCTION__ +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Verbose](Verbose.md) +- [XE_LOG 宏所在类型页](Logger.md) diff --git a/docs/api/XCEngine/Debug/Logger/Logger.md b/docs/api/XCEngine/Debug/Logger/Logger.md index 4d3063a3..fe1f87a3 100644 --- a/docs/api/XCEngine/Debug/Logger/Logger.md +++ b/docs/api/XCEngine/Debug/Logger/Logger.md @@ -6,38 +6,79 @@ **头文件**: `XCEngine/Debug/Logger.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `Logger` public API。 +**描述**: 构造日志记录、应用全局过滤并把日志分发到多个 sink。 ## 概述 -`Logger.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`Logger` 是 XCEngine 当前日志系统的中心节点。业务代码、测试程序和工具层并不直接操作控制台或文件,而是先把消息交给 `Logger`,再由它把统一格式的 `LogEntry` 分发给已注册的 `ILogSink`。 -## 声明概览 +这类设计的好处是: -| 声明 | 类型 | 说明 | -|------|------|------| -| `Logger` | `class` | 头文件中的公开声明。 | +- 输出目标可以随运行环境变化,而业务日志调用点保持不变。 +- 全局级别过滤和 category 开关只需要维护一份。 +- 可以在编辑器、命令行测试和文件日志之间复用同一条日志链路。 -## 公共方法 +## 生命周期 -| 方法 | 描述 | +- [Get](Get.md) 返回进程级单例。 +- [Initialize](Initialize.md) 只设置初始化标志,不会自动添加默认 sink。 +- [Shutdown](Shutdown.md) 会 `Flush` 所有 sink 并清空 sink 列表。 +- [Log](Log.md) 在第一次被调用时会自动调用 `Initialize`。 + +推荐做法: + +- 在程序启动阶段显式 `Initialize` 并注册 sink。 +- 在受控退出阶段调用 `Shutdown`,避免与其它线程仍在写日志时并发销毁。 + +## 线程语义 + +- `AddSink`、`RemoveSink` 和 `Log` 通过内部 `Mutex` 保护 sink 列表访问。 +- `SetMinimumLevel` 和 `SetCategoryEnabled` 当前没有加锁,更适合作为初始化阶段配置,而不是高频热更新开关。 +- `Shutdown` 当前也没有在锁内遍历 sink;应在其它线程不再写日志时调用。 + +## 所有权 + +- `AddSink` 接收 `std::unique_ptr`,所有权转移给 `Logger`。 +- `RemoveSink` 只按裸指针匹配已注册对象;如果调用方未来需要移除某个 sink,必须在移交所有权前保留一份原始指针。 + +## 宏与便捷接口 + +- `XE_LOG(category, level, message)` 会把 `__FILE__`、`__LINE__` 和 `__FUNCTION__` 一并传给 `Logger::Log`。 +- `XE_ASSERT(condition, message)` 在条件失败时只记录一条 `Fatal` 级别日志;当前实现不会中断程序、抛异常或触发调试断点。 +- `Verbose`、`Debug`、`Info`、`Warning`、`Error`、`Fatal` 都是 `Log` 的便捷封装,但默认不带源码位置信息。 + +## 公开方法 + +| 方法 | 说明 | |------|------| -| [Get](Get.md) | 获取相关状态或对象。 | -| [Initialize](Initialize.md) | 初始化内部状态。 | -| [Shutdown](Shutdown.md) | 关闭并清理内部状态。 | -| [AddSink](AddSink.md) | 添加元素或建立关联。 | -| [RemoveSink](RemoveSink.md) | 移除元素或解除关联。 | -| [Log](Log.md) | 公开方法,详见头文件声明。 | -| [Verbose](Verbose.md) | 公开方法,详见头文件声明。 | -| [Debug](Debug.md) | 公开方法,详见头文件声明。 | -| [Info](Info.md) | 公开方法,详见头文件声明。 | -| [Warning](Warning.md) | 公开方法,详见头文件声明。 | -| [Error](Error.md) | 公开方法,详见头文件声明。 | -| [Fatal](Fatal.md) | 公开方法,详见头文件声明。 | -| [SetMinimumLevel](SetMinimumLevel.md) | 设置相关状态或配置。 | -| [SetCategoryEnabled](SetCategoryEnabled.md) | 设置相关状态或配置。 | +| [Get](Get.md) | 获取全局 `Logger` 实例。 | +| [Initialize](Initialize.md) | 初始化日志系统状态。 | +| [Shutdown](Shutdown.md) | 刷新并移除所有 sink。 | +| [AddSink](AddSink.md) | 注册一个新的日志输出目标。 | +| [RemoveSink](RemoveSink.md) | 根据原始指针移除 sink。 | +| [Log](Log.md) | 构造 `LogEntry` 并分发到所有 sink。 | +| [Verbose](Verbose.md) | 发送 `Verbose` 级日志。 | +| [Debug](Debug.md) | 发送 `Debug` 级日志。 | +| [Info](Info.md) | 发送 `Info` 级日志。 | +| [Warning](Warning.md) | 发送 `Warning` 级日志。 | +| [Error](Error.md) | 发送 `Error` 级日志。 | +| [Fatal](Fatal.md) | 发送 `Fatal` 级日志。 | +| [SetMinimumLevel](SetMinimumLevel.md) | 设置全局最小日志级别。 | +| [SetCategoryEnabled](SetCategoryEnabled.md) | 打开或关闭某个日志分类。 | + +## 真实使用位置 + +当前代码库中,`Logger` 已经被用于: + +- 编辑器启动流程,为控制台、编辑器面板和文件同时输出日志。 +- RHI 集成测试,为控制台和文件记录帧调试信息。 +- `RenderDocCapture`、截图工具和资源管理等低层模块的错误与警告输出。 ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [ILogSink](../ILogSink/ILogSink.md) +- [ConsoleLogSink](../ConsoleLogSink/ConsoleLogSink.md) +- [FileLogSink](../FileLogSink/FileLogSink.md) +- [LogEntry](../LogEntry/LogEntry.md) +- [Logging Architecture](../../../_guides/Debug/Logging-Architecture.md) diff --git a/docs/api/XCEngine/Debug/Logger/RemoveSink.md b/docs/api/XCEngine/Debug/Logger/RemoveSink.md index 8b399f36..51f8975f 100644 --- a/docs/api/XCEngine/Debug/Logger/RemoveSink.md +++ b/docs/api/XCEngine/Debug/Logger/RemoveSink.md @@ -1,31 +1,47 @@ # Logger::RemoveSink -移除元素或解除关联。 +按原始指针移除一个已注册的 sink。 ```cpp void RemoveSink(ILogSink* sink); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `sink` - 参数语义详见头文件声明。 +当前实现会在互斥区内线性扫描 sink 列表,找到第一个 `it->get() == sink` 的元素后将其删除并停止遍历。 -**返回:** `void` - 无返回值。 +删除后: -**示例:** +- sink 对象会立刻析构。 +- 对应指针立即失效。 + +如果传入空指针或未找到匹配项,当前实现会静默返回。 + +## 参数 + +- `sink` - 之前注册到 `Logger` 的 sink 原始指针。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前实现对移除操作加锁。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::RemoveSink(...)。 - (void)object; -} +auto sink = std::make_unique(); +ConsoleLogSink* sinkPtr = sink.get(); + +Logger::Get().AddSink(std::move(sink)); +Logger::Get().RemoveSink(sinkPtr); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [AddSink](AddSink.md) diff --git a/docs/api/XCEngine/Debug/Logger/SetCategoryEnabled.md b/docs/api/XCEngine/Debug/Logger/SetCategoryEnabled.md index e93ed6e9..92fb8ab3 100644 --- a/docs/api/XCEngine/Debug/Logger/SetCategoryEnabled.md +++ b/docs/api/XCEngine/Debug/Logger/SetCategoryEnabled.md @@ -1,32 +1,43 @@ # Logger::SetCategoryEnabled -设置相关状态或配置。 +打开或关闭某个日志分类。 ```cpp void SetCategoryEnabled(LogCategory category, bool enabled); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `enabled` - 参数语义详见头文件声明。 +当前实现会把 `category` 对应的启用位直接写入内部数组。之后所有 `Log` 调用都会先检查这个开关,再决定是否分发该分类日志。 -**返回:** `void` - 无返回值。 +这是一种非常轻量的 category 过滤方式,但也意味着: -**示例:** +- 当前实现没有加锁。 +- 枚举值数量与数组长度耦合。 + +## 参数 + +- `category` - 需要开关的日志分类。 +- `enabled` - `true` 表示启用,`false` 表示禁用。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在初始化阶段配置,而不是在多个线程持续写日志时频繁修改。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::SetCategoryEnabled(...)。 - (void)object; -} +Logger::Get().SetCategoryEnabled(LogCategory::Rendering, false); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [SetMinimumLevel](SetMinimumLevel.md) +- [LogCategory](../LogCategory/LogCategory.md) diff --git a/docs/api/XCEngine/Debug/Logger/SetMinimumLevel.md b/docs/api/XCEngine/Debug/Logger/SetMinimumLevel.md index d0ccf943..0bcf707e 100644 --- a/docs/api/XCEngine/Debug/Logger/SetMinimumLevel.md +++ b/docs/api/XCEngine/Debug/Logger/SetMinimumLevel.md @@ -1,31 +1,40 @@ # Logger::SetMinimumLevel -设置相关状态或配置。 +设置全局日志分发的最小级别。 ```cpp void SetMinimumLevel(LogLevel level); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `level` - 参数语义详见头文件声明。 +当前实现直接把内部 `m_minimumLevel` 赋值为 `level`。之后所有 `Log` 调用都会先比较 `entry.level < m_minimumLevel`,不满足要求的日志在构造 sink 输出前就会被丢弃。 -**返回:** `void` - 无返回值。 +这属于全局过滤;sink 仍然可以在此基础上继续做自己的本地过滤。 -**示例:** +## 参数 + +- `level` - 允许继续分发的最低级别。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前实现没有加锁。 +- 更适合作为启动配置,而不是高频运行时热更新项。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::SetMinimumLevel(...)。 - (void)object; -} +Logger::Get().SetMinimumLevel(LogLevel::Warning); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [SetCategoryEnabled](SetCategoryEnabled.md) +- [ConsoleLogSink::SetMinimumLevel](../ConsoleLogSink/SetMinimumLevel.md) diff --git a/docs/api/XCEngine/Debug/Logger/Shutdown.md b/docs/api/XCEngine/Debug/Logger/Shutdown.md index 18694864..ff7650df 100644 --- a/docs/api/XCEngine/Debug/Logger/Shutdown.md +++ b/docs/api/XCEngine/Debug/Logger/Shutdown.md @@ -1,30 +1,45 @@ # Logger::Shutdown -关闭并清理内部状态。 +刷新并移除所有已注册 sink。 ```cpp void Shutdown(); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现依次做三件事: -**返回:** `void` - 无返回值。 +1. 遍历所有 sink 并调用 `Flush()`。 +2. 清空 sink 列表。 +3. 把 `m_initialized` 设回 `false`。 -**示例:** +需要特别注意: + +- 当前不会重置 `m_minimumLevel`。 +- 当前不会重置 category 启用表。 +- 当前没有在锁内执行整个关闭流程,因此应在受控停机阶段调用。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 请在其它线程不再调用 `Log` 后执行 `Shutdown`。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Shutdown(...)。 - (void)object; -} +XCEngine::Debug::Logger::Get().Shutdown(); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Initialize](Initialize.md) +- [AddSink](AddSink.md) diff --git a/docs/api/XCEngine/Debug/Logger/Verbose.md b/docs/api/XCEngine/Debug/Logger/Verbose.md index b6162d4a..72918e45 100644 --- a/docs/api/XCEngine/Debug/Logger/Verbose.md +++ b/docs/api/XCEngine/Debug/Logger/Verbose.md @@ -1,32 +1,45 @@ # Logger::Verbose -公开方法,详见头文件声明。 +以 `Verbose` 级别记录一条日志。 ```cpp void Verbose(LogCategory category, const Containers::String& message); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +这是 `Logger::Log` 的便捷封装,等价于: ```cpp -#include +Log(LogLevel::Verbose, category, message); +``` -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Verbose(...)。 - (void)object; -} +适合输出高频、细粒度的开发期调试信息。默认不带源码位置信息。 + +## 参数 + +- `category` - 日志分类。 +- `message` - 日志文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 与 [Log](Log.md) 相同。 + +## 示例 + +```cpp +XCEngine::Debug::Logger::Get().Verbose( + XCEngine::Debug::LogCategory::Threading, + "Worker thread woke up" +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Log](Log.md) +- [Debug](Debug.md) diff --git a/docs/api/XCEngine/Debug/Logger/Warning.md b/docs/api/XCEngine/Debug/Logger/Warning.md index 53bca2ce..7864d427 100644 --- a/docs/api/XCEngine/Debug/Logger/Warning.md +++ b/docs/api/XCEngine/Debug/Logger/Warning.md @@ -1,32 +1,45 @@ # Logger::Warning -公开方法,详见头文件声明。 +以 `Warning` 级别记录一条日志。 ```cpp void Warning(LogCategory category, const Containers::String& message); ``` -该方法声明于 `XCEngine/Debug/Logger.h`,当前页面用于固定 `Logger` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `category` - 参数语义详见头文件声明。 -- `message` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +这是 `Logger::Log` 的便捷封装,等价于: ```cpp -#include +Log(LogLevel::Warning, category, message); +``` -void Example() { - XCEngine::Debug::Logger object; - // 根据上下文补齐参数后调用 Logger::Warning(...)。 - (void)object; -} +它适合记录“当前还能继续运行,但状态值得关注”的情况。 + +## 参数 + +- `category` - 日志分类。 +- `message` - 警告文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 与 [Log](Log.md) 相同。 + +## 示例 + +```cpp +XCEngine::Debug::Logger::Get().Warning( + XCEngine::Debug::LogCategory::General, + "Created OpenGL context without debug bit" +); ``` ## 相关文档 -- [返回类总览](Logger.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Logger.md) +- [Log](Log.md) +- [Error](Error.md) diff --git a/docs/api/XCEngine/Debug/Profiler/BeginFrame.md b/docs/api/XCEngine/Debug/Profiler/BeginFrame.md index 3ac53719..65522417 100644 --- a/docs/api/XCEngine/Debug/Profiler/BeginFrame.md +++ b/docs/api/XCEngine/Debug/Profiler/BeginFrame.md @@ -1,30 +1,37 @@ # Profiler::BeginFrame -公开方法,详见头文件声明。 +标记一帧 profiling 周期的开始。 ```cpp void BeginFrame(); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现只记录当前微秒时间到内部 `m_frameStartTime`,不会创建样本,也不会清空已有数据。 -**返回:** `void` - 无返回值。 +这说明它目前更像是为后续“按帧汇总”能力预留入口,而不是已经完整实现的帧级 profiler 边界。 -**示例:** +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 无同步保护;建议在主线程或统一的 profiling 线程中调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::BeginFrame(...)。 - (void)object; -} +auto& profiler = XCEngine::Debug::Profiler::Get(); +profiler.BeginFrame(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [EndFrame](EndFrame.md) diff --git a/docs/api/XCEngine/Debug/Profiler/BeginProfile.md b/docs/api/XCEngine/Debug/Profiler/BeginProfile.md index e6df05c9..3395d1c7 100644 --- a/docs/api/XCEngine/Debug/Profiler/BeginProfile.md +++ b/docs/api/XCEngine/Debug/Profiler/BeginProfile.md @@ -1,31 +1,51 @@ # Profiler::BeginProfile -公开方法,详见头文件声明。 +开始一个具名 profile 区段。 ```cpp void BeginProfile(const char* name); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `name` - 参数语义详见头文件声明。 +当前实现会把一个新的 `ProfileNode` 压入内部栈,记录: -**返回:** `void` - 无返回值。 +- `name` +- 当前微秒时间 +- 当前线程哈希值 -**示例:** +它不会检查: + +- `Profiler` 是否已经 `Initialize` +- `name` 是否为空 +- 是否来自同一线程 + +因此当前 API 更适合“明确受控、单线程成对调用”的埋点场景。 + +## 参数 + +- `name` - 区段名称,通常使用固定字符串或函数名。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 必须与 [EndProfile](EndProfile.md) 在同一线程、按栈顺序配对使用。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::BeginProfile(...)。 - (void)object; -} +Profiler::Get().BeginProfile("ShadowPass"); +// ... CPU work ... +Profiler::Get().EndProfile(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [EndProfile](EndProfile.md) +- [Profiler Workflow](../../../_guides/Debug/Profiler-Workflow.md) diff --git a/docs/api/XCEngine/Debug/Profiler/EndFrame.md b/docs/api/XCEngine/Debug/Profiler/EndFrame.md index 81067f75..73cc63a2 100644 --- a/docs/api/XCEngine/Debug/Profiler/EndFrame.md +++ b/docs/api/XCEngine/Debug/Profiler/EndFrame.md @@ -1,30 +1,42 @@ # Profiler::EndFrame -公开方法,详见头文件声明。 +结束当前帧的 profiling 周期。 ```cpp void EndFrame(); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现会直接清空内部 `m_samples` 数组,而不会导出、返回或持久化这些样本。 -**返回:** `void` - 无返回值。 +这意味着当前版本里: -**示例:** +- `BeginProfile` / `EndProfile` 采集到的数据是短暂的。 +- 如果你在同一帧内没有其它方式读取样本,调用 `EndFrame` 后这些数据就会被丢弃。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 无同步保护;建议与 [BeginFrame](BeginFrame.md) 在同一线程调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::EndFrame(...)。 - (void)object; -} +auto& profiler = XCEngine::Debug::Profiler::Get(); +profiler.BeginFrame(); +// ... +profiler.EndFrame(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [BeginFrame](BeginFrame.md) diff --git a/docs/api/XCEngine/Debug/Profiler/EndProfile.md b/docs/api/XCEngine/Debug/Profiler/EndProfile.md index 8b128fda..c00dd4eb 100644 --- a/docs/api/XCEngine/Debug/Profiler/EndProfile.md +++ b/docs/api/XCEngine/Debug/Profiler/EndProfile.md @@ -1,30 +1,48 @@ # Profiler::EndProfile -公开方法,详见头文件声明。 +结束最近一次开始的 profile 区段,并记录其耗时。 ```cpp void EndProfile(); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现会: -**返回:** `void` - 无返回值。 +1. 检查内部栈是否为空;为空则直接返回。 +2. 读取当前微秒时间作为结束时间。 +3. 弹出最近一个 `ProfileNode`。 +4. 计算区段耗时并把结果追加到内部 `m_samples`。 -**示例:** +当前不会: + +- 验证开始与结束是否发生在同一线程。 +- 提供读取样本的公开 API。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 必须与 [BeginProfile](BeginProfile.md) 形成正确的 LIFO 配对。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::EndProfile(...)。 - (void)object; -} +Profiler::Get().BeginProfile("FrameBuild"); +// ... +Profiler::Get().EndProfile(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [BeginProfile](BeginProfile.md) diff --git a/docs/api/XCEngine/Debug/Profiler/ExportChromeTracing.md b/docs/api/XCEngine/Debug/Profiler/ExportChromeTracing.md index 44aed86e..3223116e 100644 --- a/docs/api/XCEngine/Debug/Profiler/ExportChromeTracing.md +++ b/docs/api/XCEngine/Debug/Profiler/ExportChromeTracing.md @@ -1,31 +1,36 @@ # Profiler::ExportChromeTracing -公开方法,详见头文件声明。 +将采样结果导出为 Chrome Tracing 格式文件。 ```cpp void ExportChromeTracing(const Containers::String& filePath); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `filePath` - 参数语义详见头文件声明。 +当前实现是空函数,不会创建文件,也不会导出任何样本。 -**返回:** `void` - 无返回值。 +从 API 形状可以推断,这个接口是为后续接入 Chrome Trace 或 Perfetto 类工具预留的;但在当前版本中,调用它不会产生可见效果。 -**示例:** +## 参数 + +- `filePath` - 预期的输出文件路径。当前实现不会实际使用该参数。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前为空实现,无额外线程语义。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::ExportChromeTracing(...)。 - (void)object; -} +XCEngine::Debug::Profiler::Get().ExportChromeTracing("trace.json"); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [Profiler Workflow](../../../_guides/Debug/Profiler-Workflow.md) diff --git a/docs/api/XCEngine/Debug/Profiler/Get.md b/docs/api/XCEngine/Debug/Profiler/Get.md index 4b2a0b40..02c582fa 100644 --- a/docs/api/XCEngine/Debug/Profiler/Get.md +++ b/docs/api/XCEngine/Debug/Profiler/Get.md @@ -1,29 +1,35 @@ # Profiler::Get -获取相关状态或对象。 +获取进程级全局 `Profiler` 实例。 ```cpp static Profiler& Get(); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现使用函数内静态对象保存单例,整个进程只存在一个 `Profiler` 实例。它不会在 `Get()` 时自动初始化或清空样本。 -**返回:** `Profiler&` - 返回值语义详见头文件声明。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- `Profiler&` - 全局 profiler 引用。 + +## 线程语义 + +- 单例构造本身由 C++ 保证线程安全;后续使用仍需遵守当前 profiler 不支持并发埋点的限制。 + +## 示例 ```cpp -#include - -void Example() { - auto& instance = XCEngine::Debug::Profiler::Get(); - (void)instance; -} +XCEngine::Debug::Profiler& profiler = XCEngine::Debug::Profiler::Get(); +profiler.Initialize(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/Profiler/Initialize.md b/docs/api/XCEngine/Debug/Profiler/Initialize.md index cdaacfb0..f54eafde 100644 --- a/docs/api/XCEngine/Debug/Profiler/Initialize.md +++ b/docs/api/XCEngine/Debug/Profiler/Initialize.md @@ -1,30 +1,39 @@ # Profiler::Initialize -初始化内部状态。 +把 `Profiler` 标记为已初始化。 ```cpp void Initialize(); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现是幂等的: -**返回:** `void` - 无返回值。 +- 如果已经初始化,直接返回。 +- 如果尚未初始化,仅把 `m_initialized` 设为 `true`。 -**示例:** +它不会分配新资源,也不会清理旧样本。更准确地说,当前 `Initialize` 只是一个状态标记,而不是完整自举流程。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前没有同步逻辑;建议在单线程启动阶段调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::Initialize(...)。 - (void)object; -} +XCEngine::Debug::Profiler::Get().Initialize(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [Shutdown](Shutdown.md) diff --git a/docs/api/XCEngine/Debug/Profiler/MarkEvent.md b/docs/api/XCEngine/Debug/Profiler/MarkEvent.md index 6fdf900e..521bd273 100644 --- a/docs/api/XCEngine/Debug/Profiler/MarkEvent.md +++ b/docs/api/XCEngine/Debug/Profiler/MarkEvent.md @@ -1,33 +1,38 @@ # Profiler::MarkEvent -公开方法,详见头文件声明。 +记录一个带时间戳的事件标记。 ```cpp void MarkEvent(const char* name, uint64_t timestamp, uint32_t threadId); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `name` - 参数语义详见头文件声明。 -- `timestamp` - 参数语义详见头文件声明。 -- `threadId` - 参数语义详见头文件声明。 +当前实现是空函数,不会保存事件,也不会产生输出。 -**返回:** `void` - 无返回值。 +从接口形状看,它原本应该用于把离散事件插入时间线上,但这一能力目前尚未接入内部样本系统。 -**示例:** +## 参数 + +- `name` - 事件名称。当前实现不会使用。 +- `timestamp` - 事件时间戳。当前实现不会使用。 +- `threadId` - 事件线程 ID。当前实现不会使用。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前为空实现,无额外线程语义。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::MarkEvent(...)。 - (void)object; -} +XCEngine::Debug::Profiler::Get().MarkEvent("GPUSubmit", 0, 0); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [SetMarker](SetMarker.md) diff --git a/docs/api/XCEngine/Debug/Profiler/Profiler.md b/docs/api/XCEngine/Debug/Profiler/Profiler.md index 8cd60d5e..3851bbee 100644 --- a/docs/api/XCEngine/Debug/Profiler/Profiler.md +++ b/docs/api/XCEngine/Debug/Profiler/Profiler.md @@ -6,34 +6,60 @@ **头文件**: `XCEngine/Debug/Profiler.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `Profiler` public API。 +**描述**: 提供轻量级 CPU 埋点入口,用于记录成对的 profile 区段。 ## 概述 -`Profiler.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`Profiler` 的 API 形状明显面向“开发期埋点”和“后续时间线导出”场景,但当前实现仍处于非常早期的阶段。它已经能够记录一组成对的 `BeginProfile` / `EndProfile` 调用时长,却还没有提供读取样本、可视化时间线或导出 Chrome Trace 的完整工作流。 -## 声明概览 +可以把它理解为: -| 声明 | 类型 | 说明 | -|------|------|------| -| `Profiler` | `class` | 头文件中的公开声明。 | +- 设计方向上类似轻量版的引擎内 CPU 埋点器; +- 但当前能力远不等同于 Unity Profiler 这类成熟的分析器。 -## 公共方法 +## 当前实现能力 -| 方法 | 描述 | +- [BeginProfile](BeginProfile.md) / [EndProfile](EndProfile.md) 会把区段时长记录到内部样本数组。 +- [BeginFrame](BeginFrame.md) 只记录一帧开始时间。 +- [EndFrame](EndFrame.md) 当前会直接清空样本数组。 +- [MarkEvent](MarkEvent.md)、[SetMarker](SetMarker.md) 和 [ExportChromeTracing](ExportChromeTracing.md) 目前都是空实现。 + +## 生命周期 + +- [Get](Get.md) 返回进程级单例。 +- [Initialize](Initialize.md) 只设置初始化标志。 +- [Shutdown](Shutdown.md) 清空样本与栈状态。 + +## 线程语义 + +- 当前实现没有任何锁,也不是按线程分桶存储。 +- `m_profileStack` 是单个全局栈,因此 `BeginProfile` / `EndProfile` 只应在同一线程、同一调用栈上成对使用。 +- 如果多个线程并发使用同一个 `Profiler`,样本次序和栈配对都可能被破坏。 + +## 宏 + +- `XE_PROFILE_BEGIN(name)` 开始一个具名区段。 +- `XE_PROFILE_END()` 结束最近一次开始的区段。 +- `XE_PROFILE_FUNCTION()` 使用当前函数名作为区段名。 + +这些宏是最适合当前实现的接入方式,因为它们几乎不引入额外样板代码。 + +## 公开方法 + +| 方法 | 说明 | |------|------| -| [Get](Get.md) | 获取相关状态或对象。 | -| [Initialize](Initialize.md) | 初始化内部状态。 | -| [Shutdown](Shutdown.md) | 关闭并清理内部状态。 | -| [BeginProfile](BeginProfile.md) | 公开方法,详见头文件声明。 | -| [EndProfile](EndProfile.md) | 公开方法,详见头文件声明。 | -| [BeginFrame](BeginFrame.md) | 公开方法,详见头文件声明。 | -| [EndFrame](EndFrame.md) | 公开方法,详见头文件声明。 | -| [MarkEvent](MarkEvent.md) | 公开方法,详见头文件声明。 | -| [SetMarker](SetMarker.md) | 设置相关状态或配置。 | -| [ExportChromeTracing](ExportChromeTracing.md) | 公开方法,详见头文件声明。 | +| [Get](Get.md) | 获取全局 `Profiler` 实例。 | +| [Initialize](Initialize.md) | 初始化 profiler 状态。 | +| [Shutdown](Shutdown.md) | 清空内部记录。 | +| [BeginProfile](BeginProfile.md) | 开始一个 profile 区段。 | +| [EndProfile](EndProfile.md) | 结束最近一个区段并记录时长。 | +| [BeginFrame](BeginFrame.md) | 标记帧开始。 | +| [EndFrame](EndFrame.md) | 结束当前帧并清空当前样本。 | +| [MarkEvent](MarkEvent.md) | 预留的事件标记接口。 | +| [SetMarker](SetMarker.md) | 预留的 marker 接口。 | +| [ExportChromeTracing](ExportChromeTracing.md) | 预留的导出接口。 | ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [Profiler Workflow](../../../_guides/Debug/Profiler-Workflow.md) diff --git a/docs/api/XCEngine/Debug/Profiler/SetMarker.md b/docs/api/XCEngine/Debug/Profiler/SetMarker.md index 56c7a37a..e907ac52 100644 --- a/docs/api/XCEngine/Debug/Profiler/SetMarker.md +++ b/docs/api/XCEngine/Debug/Profiler/SetMarker.md @@ -1,32 +1,37 @@ # Profiler::SetMarker -设置相关状态或配置。 +设置一个可视化 marker。 ```cpp void SetMarker(const char* name, uint32_t color); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `name` - 参数语义详见头文件声明。 -- `color` - 参数语义详见头文件声明。 +当前实现是空函数,不会保存 marker,也不会改变任何采样结果。 -**返回:** `void` - 无返回值。 +从接口设计看,这更像是为后续调试 UI 或时间线着色预留的扩展点,而不是现阶段可依赖的功能。 -**示例:** +## 参数 + +- `name` - marker 名称。当前实现不会使用。 +- `color` - marker 颜色。当前实现不会使用。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 当前为空实现,无额外线程语义。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::SetMarker(...)。 - (void)object; -} +XCEngine::Debug::Profiler::Get().SetMarker("ShadowPass", 0xff00ff00u); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [MarkEvent](MarkEvent.md) diff --git a/docs/api/XCEngine/Debug/Profiler/Shutdown.md b/docs/api/XCEngine/Debug/Profiler/Shutdown.md index 9015ff18..76321ecf 100644 --- a/docs/api/XCEngine/Debug/Profiler/Shutdown.md +++ b/docs/api/XCEngine/Debug/Profiler/Shutdown.md @@ -1,30 +1,40 @@ # Profiler::Shutdown -关闭并清理内部状态。 +清空 profiler 内部状态。 ```cpp void Shutdown(); ``` -该方法声明于 `XCEngine/Debug/Profiler.h`,当前页面用于固定 `Profiler` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现会: -**返回:** `void` - 无返回值。 +- 清空 `m_samples` +- 清空 `m_profileStack` +- 把 `m_initialized` 设为 `false` -**示例:** +它不会导出当前样本,也不会保留历史结果。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 应在不再有 profile 区段写入时调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::Profiler object; - // 根据上下文补齐参数后调用 Profiler::Shutdown(...)。 - (void)object; -} +XCEngine::Debug::Profiler::Get().Shutdown(); ``` ## 相关文档 -- [返回类总览](Profiler.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](Profiler.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/BeginCapture.md b/docs/api/XCEngine/Debug/RenderDocCapture/BeginCapture.md index 02df77fc..29013da6 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/BeginCapture.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/BeginCapture.md @@ -1,31 +1,52 @@ # RenderDocCapture::BeginCapture -公开方法,详见头文件声明。 +开始一次手动 RenderDoc 抓帧。 ```cpp bool BeginCapture(const char* title = nullptr); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `title` - 参数语义详见头文件声明。 +当前实现会在开始抓帧前依次检查: -**返回:** `bool` - 返回值语义详见头文件声明。 +1. RenderDoc 是否已加载。 +2. 当前是否已经处于抓帧中。 +3. `m_device` 与 `m_window` 是否都非空。 -**示例:** +任一条件不满足时都会记录警告并返回 `false`。 + +如果检查通过,当前实现会: + +- 如果 `title` 非空,则调用 `SetCaptureTitle(title)`。 +- 调用 `SetForegroundWindow` 和 `SetFocus`,把目标窗口切到前台。 +- 调用 `SetActiveWindow(m_device, m_window)`。 +- 调用 `StartFrameCapture(m_device, m_window)`。 + +## 参数 + +- `title` - 可选的 capture 标题。 + +## 返回值 + +- `bool` - `true` 表示已向 RenderDoc 发出开始抓帧请求;`false` 表示前置条件不满足。 + +## 线程语义 + +- 建议在拥有目标窗口与图形设备上下文的主线程调用。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::BeginCapture(...)。 - (void)object; +if (RenderDocCapture::Get().BeginCapture("D3D12_Triangle_Test")) { + Logger::Get().Info(LogCategory::RenderDoc, "Capture started"); } ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [EndCapture](EndCapture.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/EndCapture.md b/docs/api/XCEngine/Debug/RenderDocCapture/EndCapture.md index d02e1cfd..48e82920 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/EndCapture.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/EndCapture.md @@ -1,30 +1,48 @@ # RenderDocCapture::EndCapture -公开方法,详见头文件声明。 +结束当前正在进行的 RenderDoc 抓帧。 ```cpp bool EndCapture(); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现会先检查: -**返回:** `bool` - 返回值语义详见头文件声明。 +- RenderDoc 是否已加载。 +- 当前是否确实处于抓帧状态。 -**示例:** +如果任一条件不成立,会记录警告并返回 `false`。条件成立时会调用: ```cpp -#include +m_api->EndFrameCapture(m_device, m_window); +``` -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::EndCapture(...)。 - (void)object; +## 参数 + +- 无。 + +## 返回值 + +- `bool` - `true` 表示已发出结束抓帧请求;`false` 表示当前没有可结束的抓帧。 + +## 线程语义 + +- 应与 [BeginCapture](BeginCapture.md) 在同一渲染工作流中配对调用。 + +## 示例 + +```cpp +if (XCEngine::Debug::RenderDocCapture::Get().EndCapture()) { + XCEngine::Debug::Logger::Get().Info( + XCEngine::Debug::LogCategory::RenderDoc, + "Capture ended" + ); } ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [BeginCapture](BeginCapture.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/Get.md b/docs/api/XCEngine/Debug/RenderDocCapture/Get.md index a8d55b4f..7572e94b 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/Get.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/Get.md @@ -1,29 +1,35 @@ # RenderDocCapture::Get -获取相关状态或对象。 +获取进程级全局 `RenderDocCapture` 实例。 ```cpp static RenderDocCapture& Get(); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现使用函数内静态对象保存单例。`Get()` 本身不会加载 RenderDoc,也不会自动设置 `device` 或 `window`。 -**返回:** `RenderDocCapture&` - 返回值语义详见头文件声明。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- `RenderDocCapture&` - 全局 RenderDoc 封装对象引用。 + +## 线程语义 + +- 单例构造由 C++ 保证线程安全;后续抓帧 API 仍建议在主线程统一使用。 + +## 示例 ```cpp -#include - -void Example() { - auto& instance = XCEngine::Debug::RenderDocCapture::Get(); - (void)instance; -} +auto& capture = XCEngine::Debug::RenderDocCapture::Get(); +capture.Initialize(nullptr, hwnd); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/GetCapture.md b/docs/api/XCEngine/Debug/RenderDocCapture/GetCapture.md index dc55d280..9b8c5192 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/GetCapture.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/GetCapture.md @@ -1,32 +1,52 @@ # RenderDocCapture::GetCapture -获取相关状态或对象。 +读取指定 capture 的元数据。 ```cpp bool GetCapture(uint32_t index, RenderDocCaptureInfo* info) const; ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `index` - 参数语义详见头文件声明。 -- `info` - 参数语义详见头文件声明。 +当前实现要求: -**返回:** `bool` - 返回值语义详见头文件声明。 +- RenderDoc 已加载。 +- `info` 非空。 -**示例:** +满足条件后,它会调用底层 RenderDoc API,把结果写入 `info->filename`、`info->length` 和 `info->timestamp`。如果底层返回值等于 `1`,则方法返回 `true`。 + +注意当前包装层的一个实现细节: + +- `RenderDocCaptureInfo::filename` 是固定 256 字节数组。 +- XCEngine 直接把这块缓冲区传给 RenderDoc。 + +因此调用方不应假设超长路径总能被完整保留。 + +## 参数 + +- `index` - capture 索引。 +- `info` - 输出缓冲区,成功时会被填充。 + +## 返回值 + +- `bool` - `true` 表示成功读取该 capture 的元数据。 + +## 线程语义 + +- 无显式同步;通常在抓帧结束后的主线程诊断阶段调用。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::GetCapture(...)。 - (void)object; +RenderDocCaptureInfo info{}; +if (RenderDocCapture::Get().GetCapture(0, &info)) { + Logger::Get().Info(LogCategory::RenderDoc, info.filename); } ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [GetNumCaptures](GetNumCaptures.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/GetNumCaptures.md b/docs/api/XCEngine/Debug/RenderDocCapture/GetNumCaptures.md index aa3dc758..ab46a492 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/GetNumCaptures.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/GetNumCaptures.md @@ -1,30 +1,34 @@ # RenderDocCapture::GetNumCaptures -获取相关状态或对象。 +查询当前可访问的 capture 数量。 ```cpp uint32_t GetNumCaptures() const; ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +如果 RenderDoc 尚未加载,当前实现返回 `0`。否则直接转发到底层 `GetNumCaptures()`。 -**返回:** `uint32_t` - 返回值语义详见头文件声明。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- `uint32_t` - 当前 capture 数量;RenderDoc 未加载时为 `0`。 + +## 线程语义 + +- 无显式同步;通常在主线程诊断阶段调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::GetNumCaptures(...)。 - (void)object; -} +uint32_t count = XCEngine::Debug::RenderDocCapture::Get().GetNumCaptures(); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [GetCapture](GetCapture.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/Initialize.md b/docs/api/XCEngine/Debug/RenderDocCapture/Initialize.md index 422d5243..f2dc7fd0 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/Initialize.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/Initialize.md @@ -1,32 +1,54 @@ # RenderDocCapture::Initialize -初始化内部状态。 +加载 `renderdoc.dll` 并初始化当前抓帧上下文。 ```cpp bool Initialize(void* device = nullptr, void* window = nullptr); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `device` - 参数语义详见头文件声明。 -- `window` - 参数语义详见头文件声明。 +当前实现是幂等的: -**返回:** `bool` - 返回值语义详见头文件声明。 +- 如果已经初始化,直接返回 `true`。 +- 注意:在“已经初始化”的情况下,新的 `device` 和 `window` 参数不会写回内部状态。 -**示例:** +首次初始化时,当前实现会: + +1. 保存 `device` 与 `window` 指针。 +2. 在可执行文件所在目录查找并加载 `renderdoc.dll`。 +3. 获取 RenderDoc 1.7.0 API。 +4. 额外设置三个默认 U32 capture 选项:`2`、`8`、`9` 都设为 `1`。 +5. 记录一条初始化成功日志。 + +当前 API 允许在初始化时传空指针;这种情况下只要 DLL 可用,初始化仍可成功,但之后 [BeginCapture](BeginCapture.md) 仍要求设备和窗口已补齐。 + +## 参数 + +- `device` - 可选的图形设备指针。 +- `window` - 可选的窗口句柄。 + +## 返回值 + +- `bool` - `true` 表示 RenderDoc 已成功加载并可继续配置;`false` 表示加载或 API 获取失败。 + +## 线程语义 + +- 建议在创建窗口后、图形后端初始化期间由主线程调用。 + +## 示例 ```cpp -#include +using namespace XCEngine::Debug; -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::Initialize(...)。 - (void)object; +if (RenderDocCapture::Get().Initialize(nullptr, hwnd)) { + RenderDocCapture::Get().SetDevice(devicePtr); } ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [SetDevice](SetDevice.md) +- [SetWindow](SetWindow.md) +- [RenderDoc Capture Workflow](../../../_guides/Debug/RenderDoc-Capture-Workflow.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/IsCapturing.md b/docs/api/XCEngine/Debug/RenderDocCapture/IsCapturing.md index 301b3996..809c8e26 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/IsCapturing.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/IsCapturing.md @@ -1,30 +1,36 @@ # RenderDocCapture::IsCapturing -查询当前状态。 +查询当前是否处于 RenderDoc 抓帧状态。 ```cpp bool IsCapturing() const; ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +如果 RenderDoc 尚未加载或 API 指针无效,当前实现返回 `false`。否则会调用底层 `IsFrameCapturing()`,并把非零结果解释为 `true`。 -**返回:** `bool` - 返回值语义详见头文件声明。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- `bool` - `true` 表示当前正在抓帧。 + +## 线程语义 + +- 无显式同步;通常与 [BeginCapture](BeginCapture.md) / [EndCapture](EndCapture.md) 在同一线程使用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::IsCapturing(...)。 - (void)object; +if (XCEngine::Debug::RenderDocCapture::Get().IsCapturing()) { + // ... } ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [IsLoaded](IsLoaded.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/IsLoaded.md b/docs/api/XCEngine/Debug/RenderDocCapture/IsLoaded.md index aa03cc29..5ba49922 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/IsLoaded.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/IsLoaded.md @@ -1,30 +1,36 @@ # RenderDocCapture::IsLoaded -查询当前状态。 +查询 RenderDoc 是否已成功加载。 ```cpp bool IsLoaded() const; ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +这是一个内联查询函数,直接返回内部布尔值 `m_isLoaded`。它不验证 `device`、`window` 或当前是否处于抓帧状态,因此“已加载”只表示 RenderDoc API 已获取成功。 -**返回:** `bool` - 返回值语义详见头文件声明。 +## 参数 -**示例:** +- 无。 + +## 返回值 + +- `bool` - `true` 表示 RenderDoc DLL 和 API 已可用。 + +## 线程语义 + +- 只读查询;当前实现没有额外同步。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::IsLoaded(...)。 - (void)object; +if (!XCEngine::Debug::RenderDocCapture::Get().IsLoaded()) { + // RenderDoc unavailable } ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/LaunchReplayUI.md b/docs/api/XCEngine/Debug/RenderDocCapture/LaunchReplayUI.md index 96e2245f..4a6c79c0 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/LaunchReplayUI.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/LaunchReplayUI.md @@ -1,32 +1,40 @@ # RenderDocCapture::LaunchReplayUI -公开方法,详见头文件声明。 +请求启动 RenderDoc Replay UI。 ```cpp bool LaunchReplayUI(uint32_t connect = 1, const char* cmdline = nullptr); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `connect` - 参数语义详见头文件声明。 -- `cmdline` - 参数语义详见头文件声明。 +如果 RenderDoc 尚未加载,当前实现会记录警告并返回 `false`。否则会直接调用底层 `LaunchReplayUI(connect, cmdline)` 并返回 `true`。 -**返回:** `bool` - 返回值语义详见头文件声明。 +注意: -**示例:** +- 底层 RenderDoc 函数本身没有返回值。 +- 因此 XCEngine 无法确认 Replay UI 最终是否真的成功启动。 + +## 参数 + +- `connect` - 是否尝试连接到目标实例。 +- `cmdline` - 传给 Replay UI 的可选命令行。 + +## 返回值 + +- `bool` - `true` 表示已发出启动请求;`false` 表示 RenderDoc 未加载。 + +## 线程语义 + +- 建议在工具线程或主线程的诊断分支中调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::LaunchReplayUI(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().LaunchReplayUI(); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [GetCapture](GetCapture.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/RenderDocCapture.md b/docs/api/XCEngine/Debug/RenderDocCapture/RenderDocCapture.md index 1a16b794..2d90075e 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/RenderDocCapture.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/RenderDocCapture.md @@ -6,41 +6,70 @@ **头文件**: `XCEngine/Debug/RenderDocCapture.h` -**描述**: 定义 `XCEngine/Debug` 子目录中的 `RenderDocCapture` public API。 +**描述**: 在 Windows 上动态加载 RenderDoc,并为引擎或测试程序提供抓帧入口。 ## 概述 -`RenderDocCapture.h` 是 `XCEngine/Debug` 子目录 下的 public header,当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。 +`RenderDocCapture` 把外部 GPU 调试工具接入到引擎运行流程中。它的价值不在于替代 RenderDoc,而在于让测试程序、后端样例和编辑器工具可以用统一代码主动触发捕获。 + +当前实现的关键事实: + +- 公共头文件直接依赖 `windows.h`,因此它是明显的 Windows 专用 API。 +- 运行时会尝试从当前可执行文件目录加载 `renderdoc.dll`。 +- 初始化时可以先只传入 `window` 或者都传 `nullptr`,稍后再通过 [SetDevice](SetDevice.md) / [SetWindow](SetWindow.md) 补齐。 +- 抓帧前要求 RenderDoc 已加载,且 `device` 与 `window` 都不为空。 + +## 当前实现边界 + +- 只封装了 RenderDoc 1.7.0 API 中的一小部分函数。 +- `Initialize` 是幂等的;如果已经初始化,再次调用不会刷新 `device` 和 `window` 参数。 +- `LaunchReplayUI` 的底层 RenderDoc 调用没有返回值,XCEngine 只能报告“请求已发出”,不能证明 UI 一定成功启动。 +- `SetCaptureComments` 当前直接把 `nullptr` 作为 capture file path 传给 RenderDoc。 + +## 线程语义 + +- 当前实现没有显式同步机制。 +- 典型使用方式是在创建窗口和图形设备的主线程上完成初始化、抓帧和关闭。 +- `BeginCapture` 和 `TriggerCapture` 会尝试把窗口设为前台并设置焦点,这属于有副作用的 UI 行为。 ## 声明概览 | 声明 | 类型 | 说明 | |------|------|------| -| `RenderDocCaptureInfo` | `struct` | 头文件中的公开声明。 | -| `RenderDocCapture` | `class` | 头文件中的公开声明。 | +| `RenderDocCaptureInfo` | `struct` | 保存单个 capture 的文件名、长度和时间戳。 | +| `RenderDocCapture` | `class` | RenderDoc 封装与抓帧控制入口。 | -## 公共方法 +## 公开方法 -| 方法 | 描述 | +| 方法 | 说明 | |------|------| -| [Get](Get.md) | 获取相关状态或对象。 | -| [Initialize](Initialize.md) | 初始化内部状态。 | -| [Shutdown](Shutdown.md) | 关闭并清理内部状态。 | -| [SetDevice](SetDevice.md) | 设置相关状态或配置。 | -| [SetWindow](SetWindow.md) | 设置相关状态或配置。 | -| [IsLoaded](IsLoaded.md) | 查询当前状态。 | -| [IsCapturing](IsCapturing.md) | 查询当前状态。 | -| [GetNumCaptures](GetNumCaptures.md) | 获取相关状态或对象。 | -| [GetCapture](GetCapture.md) | 获取相关状态或对象。 | -| [BeginCapture](BeginCapture.md) | 公开方法,详见头文件声明。 | -| [EndCapture](EndCapture.md) | 公开方法,详见头文件声明。 | -| [TriggerCapture](TriggerCapture.md) | 公开方法,详见头文件声明。 | -| [SetCaptureFilePath](SetCaptureFilePath.md) | 设置相关状态或配置。 | -| [SetCaptureComments](SetCaptureComments.md) | 设置相关状态或配置。 | -| [SetCaptureOptionU32](SetCaptureOptionU32.md) | 设置相关状态或配置。 | -| [LaunchReplayUI](LaunchReplayUI.md) | 公开方法,详见头文件声明。 | +| [Get](Get.md) | 获取全局 `RenderDocCapture` 实例。 | +| [Initialize](Initialize.md) | 加载 RenderDoc 并记录设备/窗口句柄。 | +| [Shutdown](Shutdown.md) | 结束抓帧并卸载 RenderDoc。 | +| [SetDevice](SetDevice.md) | 更新当前活动图形设备指针。 | +| [SetWindow](SetWindow.md) | 更新当前活动窗口句柄。 | +| [IsLoaded](IsLoaded.md) | 查询 RenderDoc 是否成功加载。 | +| [IsCapturing](IsCapturing.md) | 查询当前是否处于抓帧中。 | +| [GetNumCaptures](GetNumCaptures.md) | 查询可访问的 capture 数量。 | +| [GetCapture](GetCapture.md) | 读取指定 capture 的元数据。 | +| [BeginCapture](BeginCapture.md) | 开始一次手动抓帧。 | +| [EndCapture](EndCapture.md) | 结束当前抓帧。 | +| [TriggerCapture](TriggerCapture.md) | 请求 RenderDoc 触发一次 capture。 | +| [SetCaptureFilePath](SetCaptureFilePath.md) | 设置 capture 文件路径模板。 | +| [SetCaptureComments](SetCaptureComments.md) | 设置 capture 注释。 | +| [SetCaptureOptionU32](SetCaptureOptionU32.md) | 以原始 option id 设置 U32 选项。 | +| [LaunchReplayUI](LaunchReplayUI.md) | 请求启动 RenderDoc Replay UI。 | + +## 真实使用位置 + +当前代码库已经在多个 D3D12 / OpenGL 集成测试中使用它: + +- 先创建窗口。 +- 调用 `Initialize(nullptr, hwnd)`。 +- 图形设备初始化完成后调用 `SetDevice(...)`。 +- 在目标帧前后调用 `BeginCapture` / `EndCapture`。 ## 相关文档 -- [当前目录](../Debug.md) - 返回 `Debug` 平行目录 -- [API 总索引](../../../main.md) - 返回顶层索引 +- [当前模块](../Debug.md) +- [RenderDoc Capture Workflow](../../../_guides/Debug/RenderDoc-Capture-Workflow.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureComments.md b/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureComments.md index 45ee1a80..a5019e32 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureComments.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureComments.md @@ -1,31 +1,40 @@ # RenderDocCapture::SetCaptureComments -设置相关状态或配置。 +设置 capture 注释文本。 ```cpp void SetCaptureComments(const char* comments); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `comments` - 参数语义详见头文件声明。 - -**返回:** `void` - 无返回值。 - -**示例:** +如果 RenderDoc 尚未加载,当前实现直接返回。否则会调用: ```cpp -#include +m_api->SetCaptureFileComments(nullptr, comments); +``` -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::SetCaptureComments(...)。 - (void)object; -} +这意味着 XCEngine 当前没有显式指定 capture 文件路径,而是把 `nullptr` 传给 RenderDoc。注释最终如何关联到具体 capture,取决于 RenderDoc 对该调用形式的处理。 + +## 参数 + +- `comments` - 注释文本。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 无显式同步;通常在抓帧前后由主线程调用。 + +## 示例 + +```cpp +XCEngine::Debug::RenderDocCapture::Get().SetCaptureComments("Frame 30 validation capture"); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [SetCaptureFilePath](SetCaptureFilePath.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureFilePath.md b/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureFilePath.md index cf4d1cd0..4d66a670 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureFilePath.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureFilePath.md @@ -1,31 +1,36 @@ # RenderDocCapture::SetCaptureFilePath -设置相关状态或配置。 +设置 capture 文件路径模板。 ```cpp void SetCaptureFilePath(const char* path); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `path` - 参数语义详见头文件声明。 +如果 RenderDoc 尚未加载,当前实现直接返回。否则会把 `path` 转发给底层 `SetCaptureFilePathTemplate`。 -**返回:** `void` - 无返回值。 +这个路径通常在抓帧前配置,用于决定生成的 `.rdc` 文件落到哪里,以及以什么名前缀生成。 -**示例:** +## 参数 + +- `path` - capture 文件路径模板。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在开始抓帧前完成配置。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::SetCaptureFilePath(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().SetCaptureFilePath(".\\triangle_frame30"); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [SetCaptureComments](SetCaptureComments.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureOptionU32.md b/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureOptionU32.md index a342aacc..998eacdd 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureOptionU32.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/SetCaptureOptionU32.md @@ -1,32 +1,37 @@ # RenderDocCapture::SetCaptureOptionU32 -设置相关状态或配置。 +以原始 option id 设置一个 32 位 RenderDoc capture 选项。 ```cpp void SetCaptureOptionU32(uint32_t option, uint32_t value); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `option` - 参数语义详见头文件声明。 -- `value` - 参数语义详见头文件声明。 +如果 RenderDoc 尚未加载,当前实现直接返回。否则会把 `option` 和 `value` 原样传给底层 `SetCaptureOptionU32`。 -**返回:** `void` - 无返回值。 +当前公共头文件没有为这些 option id 提供命名常量,因此调用方需要自行保证 option 编号与目标 RenderDoc 版本匹配。 -**示例:** +## 参数 + +- `option` - RenderDoc 选项编号。 +- `value` - 对应的 U32 值。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在初始化阶段或抓帧前配置。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::SetCaptureOptionU32(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().SetCaptureOptionU32(2, 1); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/SetDevice.md b/docs/api/XCEngine/Debug/RenderDocCapture/SetDevice.md index 163bd5a2..bd109c42 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/SetDevice.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/SetDevice.md @@ -1,31 +1,40 @@ # RenderDocCapture::SetDevice -设置相关状态或配置。 +更新当前用于抓帧的图形设备指针。 ```cpp void SetDevice(void* device); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `device` - 参数语义详见头文件声明。 +当前实现只是把 `device` 原样写入内部成员 `m_device`,不做类型检查、平台检查或合法性验证。 -**返回:** `void` - 无返回值。 +这个方法通常用于这样的流程: -**示例:** +1. 先在创建窗口后调用 [Initialize](Initialize.md)。 +2. 图形后端初始化完成后,把真实设备指针补给 `RenderDocCapture`。 + +## 参数 + +- `device` - 底层图形设备指针。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在图形设备创建线程中配置,并在抓帧前保持稳定。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::SetDevice(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().SetDevice(gDevice.GetDevice()); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [SetWindow](SetWindow.md) +- [Initialize](Initialize.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/SetWindow.md b/docs/api/XCEngine/Debug/RenderDocCapture/SetWindow.md index a71e057c..17fcb781 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/SetWindow.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/SetWindow.md @@ -1,31 +1,34 @@ # RenderDocCapture::SetWindow -设置相关状态或配置。 +更新当前用于抓帧的窗口句柄。 ```cpp void SetWindow(void* window); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** -- `window` - 参数语义详见头文件声明。 +当前实现只是把 `window` 原样写入内部成员 `m_window`,不做任何合法性检查。之后 [BeginCapture](BeginCapture.md) 与 [TriggerCapture](TriggerCapture.md) 可能会把它转换为 `HWND` 并尝试设置前台窗口与焦点。 -**返回:** `void` - 无返回值。 +## 参数 -**示例:** +- `window` - 目标窗口指针;在 Windows 平台上通常是 `HWND`。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在窗口所属线程或主线程设置。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::SetWindow(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().SetWindow(hwnd); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [SetDevice](SetDevice.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/Shutdown.md b/docs/api/XCEngine/Debug/RenderDocCapture/Shutdown.md index b8c8efce..2c78ff6e 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/Shutdown.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/Shutdown.md @@ -1,30 +1,42 @@ # RenderDocCapture::Shutdown -关闭并清理内部状态。 +结束抓帧并卸载 RenderDoc。 ```cpp void Shutdown(); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +当前实现只有在 `m_initialized` 为 `true` 时才执行关闭逻辑。关闭流程包括: -**返回:** `void` - 无返回值。 +1. 如果当前仍在抓帧,先调用 [EndCapture](EndCapture.md)。 +2. 卸载 `renderdoc.dll`。 +3. 清空 API 指针并把 `m_isLoaded` 设为 `false`。 +4. 把 `m_initialized` 设为 `false`。 -**示例:** +当前不会清空 `m_device` 与 `m_window` 指针,但下次 `Initialize` 会用新的参数覆盖它们。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在图形设备和窗口销毁前、主线程受控退出阶段调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::Shutdown(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().Shutdown(); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [Initialize](Initialize.md) +- [EndCapture](EndCapture.md) diff --git a/docs/api/XCEngine/Debug/RenderDocCapture/TriggerCapture.md b/docs/api/XCEngine/Debug/RenderDocCapture/TriggerCapture.md index e1636632..9fc7a49f 100644 --- a/docs/api/XCEngine/Debug/RenderDocCapture/TriggerCapture.md +++ b/docs/api/XCEngine/Debug/RenderDocCapture/TriggerCapture.md @@ -1,30 +1,39 @@ # RenderDocCapture::TriggerCapture -公开方法,详见头文件声明。 +请求 RenderDoc 触发一次 capture。 ```cpp void TriggerCapture(); ``` -该方法声明于 `XCEngine/Debug/RenderDocCapture.h`,当前页面用于固定 `RenderDocCapture` 类目录下的方法级 canonical 路径。 +## 行为说明 -**参数:** 无。 +如果 RenderDoc 尚未加载,当前实现直接返回。否则: -**返回:** `void` - 无返回值。 +- 如果 `m_window` 非空,会先把窗口设为前台并设置焦点。 +- 调用底层 `TriggerCapture()` 请求 RenderDoc 执行一次捕获。 -**示例:** +与 [BeginCapture](BeginCapture.md) / [EndCapture](EndCapture.md) 相比,这个方法更适合交给 RenderDoc 自己决定具体捕获时机。 + +## 参数 + +- 无。 + +## 返回值 + +- 无。 + +## 线程语义 + +- 建议在拥有目标窗口焦点控制权的线程调用。 + +## 示例 ```cpp -#include - -void Example() { - XCEngine::Debug::RenderDocCapture object; - // 根据上下文补齐参数后调用 RenderDocCapture::TriggerCapture(...)。 - (void)object; -} +XCEngine::Debug::RenderDocCapture::Get().TriggerCapture(); ``` ## 相关文档 -- [返回类总览](RenderDocCapture.md) -- [返回模块目录](../Debug.md) +- [返回类型总览](RenderDocCapture.md) +- [BeginCapture](BeginCapture.md) diff --git a/docs/api/_guides/Debug/Logging-Architecture.md b/docs/api/_guides/Debug/Logging-Architecture.md new file mode 100644 index 00000000..0a6adb52 --- /dev/null +++ b/docs/api/_guides/Debug/Logging-Architecture.md @@ -0,0 +1,107 @@ +# Logging Architecture + +## 这套日志系统解决什么问题 + +在游戏引擎里,日志不是单纯的输出文本,而是跨模块诊断链路。渲染后端、资源系统、编辑器工具和自动化测试都需要记录问题,但它们不应该各自决定“写到哪里、以什么格式写、是否需要同时写文件和控制台”。 + +`XCEngine::Debug::Logger` 采用中心分发 + sink 的结构,就是为了把这两类职责拆开: + +- 业务层负责说明“发生了什么”。 +- `Logger` 负责说明“这条记录如何统一过滤和分发”。 +- sink 负责说明“最终落到哪里”。 + +## 为什么不是 everywhere `printf` + +直接 `printf` 的问题是: + +- 输出目的地写死在调用点里。 +- 无法统一按级别和分类过滤。 +- 很难同时输出到控制台、文件和编辑器 UI。 +- 工具层很难在不修改业务代码的前提下插入额外日志通道。 + +sink 模式的好处是,业务代码只需要依赖: + +```cpp +Logger::Get().Info(LogCategory::General, "..."); +``` + +至于这条日志最终是进入控制台、文件还是编辑器面板,可以由启动阶段自由拼装。 + +## 当前架构中的角色分工 + +### `Logger` + +- 维护全局最小级别。 +- 维护 category 开关。 +- 生成 `LogEntry`。 +- 把日志广播给已注册 sink。 + +### `ILogSink` + +- 定义输出目标的最小契约。 +- 允许扩展出控制台、文件、内存缓存或远程诊断通道。 + +### `ConsoleLogSink` + +- 面向“立即可见”的输出。 +- 最适合测试程序、命令行工具和开发期启动日志。 + +### `FileLogSink` + +- 面向“事后复盘”的输出。 +- 最适合编辑器、长时间运行工具和自动化测试。 + +## 推荐接线方式 + +启动阶段推荐做三件事: + +1. 显式 `Logger::Get().Initialize()`。 +2. 注册至少一个可见 sink,例如 `ConsoleLogSink`。 +3. 如果程序有会话级价值,再追加 `FileLogSink`。 + +示例: + +```cpp +using namespace XCEngine::Debug; + +Logger::Get().Initialize(); +Logger::Get().AddSink(std::make_unique()); +Logger::Get().AddSink(std::make_unique("editor.log")); +Logger::Get().SetMinimumLevel(LogLevel::Debug); +``` + +这也是当前编辑器和多个集成测试采用的基本模式。 + +## 和 Unity 的对照 + +可以把这套结构理解为: + +- 比 Unity Console 更底层,因为它先解决日志分发,再决定是否显示在 UI。 +- 比单纯的 `Debug.Log` 更偏引擎层,因为它允许接多个输出目标。 + +但它又明显没有 Unity 那么完整: + +- 还没有统一的上下文对象、堆栈追踪或富文本格式化。 +- `XE_ASSERT` 当前也只会记一条 `Fatal` 日志,并不会中断执行。 + +## 当前版本最重要的限制 + +- `Logger::SetMinimumLevel` 和 `SetCategoryEnabled` 当前没有加锁,最好在初始化阶段配置。 +- `Shutdown` 不应和其它线程的 `Log` 并发执行。 +- 便捷方法 `Info`、`Warning` 等默认不带源码位置信息;需要文件和行号时,应优先使用 `XE_LOG`。 +- `FileLogSink` 会每次写入后立刻刷新文件,诊断友好,但吞吐量不是最优。 + +## 推荐实践 + +- 引擎启动、设备创建、资源加载失败这类关键路径,用 `Info` / `Warning` / `Error` 做结构化记录。 +- 高频噪声日志放到 `Verbose` 或 `Debug`,并通过最小级别统一控制。 +- category 要按子系统区分,不要把所有信息都塞到 `General`。 +- 如果未来需要编辑器控制台过滤、远程日志或测试断言统计,优先加 sink,不要让业务代码直接分叉输出逻辑。 + +## 相关 API + +- [Debug](../../XCEngine/Debug/Debug.md) +- [Logger](../../XCEngine/Debug/Logger/Logger.md) +- [ILogSink](../../XCEngine/Debug/ILogSink/ILogSink.md) +- [ConsoleLogSink](../../XCEngine/Debug/ConsoleLogSink/ConsoleLogSink.md) +- [FileLogSink](../../XCEngine/Debug/FileLogSink/FileLogSink.md) diff --git a/docs/api/_guides/Debug/Profiler-Workflow.md b/docs/api/_guides/Debug/Profiler-Workflow.md new file mode 100644 index 00000000..98391477 --- /dev/null +++ b/docs/api/_guides/Debug/Profiler-Workflow.md @@ -0,0 +1,109 @@ +# Profiler Workflow + +## 先说结论 + +`XCEngine::Debug::Profiler` 当前不是成熟的分析器,而是一个“轻量级 CPU 埋点接口壳”。它已经能表示 profile 区段,但还没有形成完整的数据消费闭环。 + +这不是坏事,但文档和使用方式必须诚实: + +- 它适合做早期埋点。 +- 它不适合被描述成 Unity Profiler 那种完整时间线工具。 + +## 现在真正能做什么 + +当前实现中,`BeginProfile` / `EndProfile` 会记录: + +- 区段名 +- 开始时间 +- 结束时间 +- 线程哈希 + +这证明设计方向是对的:接口已经在向“作用域埋点”靠拢。 + +但是同一时间,以下能力还没打通: + +- 没有公开的样本读取 API。 +- `MarkEvent`、`SetMarker`、`ExportChromeTracing` 仍是空实现。 +- `EndFrame` 会直接清空样本。 + +所以当前更合理的定位是: + +- 先把埋点位置和调用习惯稳定下来; +- 再逐步补数据导出、可视化和多线程时间线。 + +## 为什么先做成单例 + +对调试工具而言,单例有一个现实优势:调用点成本极低。 + +```cpp +XE_PROFILE_FUNCTION(); +``` + +这种接法非常适合逐步给引擎关键路径加埋点,而不需要把 profiler 对象层层传递。 + +代价也很明显: + +- 当前实现只有一个全局栈。 +- 如果多个线程同时写入,栈结构和样本语义都会混乱。 + +这就是为什么文档必须明确写“当前只适合受控单线程埋点”。 + +## 推荐工作流 + +当前阶段推荐把 `Profiler` 用在下面这些场景: + +1. 主线程 CPU 热路径粗测。 +2. 某个函数或阶段的进入/退出埋点。 +3. 为未来时间线导出预留稳定的区段命名。 + +推荐写法: + +```cpp +using namespace XCEngine::Debug; + +Profiler::Get().Initialize(); +Profiler::Get().BeginFrame(); + +XE_PROFILE_BEGIN("SceneUpdate"); +// ... +XE_PROFILE_END(); + +Profiler::Get().EndFrame(); +``` + +## 和 Unity Profiler 的差异 + +可以把它理解为“还在早期形态的引擎内 CPU 埋点接口”,而不是 Unity Profiler 的直接对标物。 + +Unity Profiler 已经提供: + +- 完整的帧时间线 +- 多线程可视化 +- 统计聚合 +- UI 分析工具 + +XCEngine 当前的 `Profiler` 还没有这些能力。它更像是先把“埋点 API”立住,再逐步扩展后端。 + +## 当前使用时最该注意的事 + +- `BeginProfile` / `EndProfile` 必须按栈顺序配对。 +- 不要跨线程共享同一条 profile 栈。 +- 不要指望 `ExportChromeTracing` 现在就会产出文件。 +- 如果你在 `EndFrame` 之后再找样本,当前实现里它们已经被清掉了。 + +## 下一阶段最值得补的能力 + +如果继续把这个模块做实,最有价值的方向通常是: + +1. 暴露只读样本访问接口。 +2. 把样本按线程分桶。 +3. 实现 Chrome Trace / Perfetto 导出。 +4. 在编辑器里增加最小时间线浏览能力。 + +## 相关 API + +- [Debug](../../XCEngine/Debug/Debug.md) +- [Profiler](../../XCEngine/Debug/Profiler/Profiler.md) +- [BeginProfile](../../XCEngine/Debug/Profiler/BeginProfile.md) +- [EndProfile](../../XCEngine/Debug/Profiler/EndProfile.md) +- [ExportChromeTracing](../../XCEngine/Debug/Profiler/ExportChromeTracing.md) diff --git a/docs/api/_guides/Debug/RenderDoc-Capture-Workflow.md b/docs/api/_guides/Debug/RenderDoc-Capture-Workflow.md new file mode 100644 index 00000000..87cc85e8 --- /dev/null +++ b/docs/api/_guides/Debug/RenderDoc-Capture-Workflow.md @@ -0,0 +1,88 @@ +# RenderDoc Capture Workflow + +## 为什么要把 RenderDoc 接进引擎 + +对图形引擎来说,GPU 调试不是“出了问题再临时打开工具”的事,而应该是测试与验证流程的一部分。 + +`RenderDocCapture` 的意义就在这里: + +- D3D12 和 OpenGL 集成测试可以在目标帧自动开始和结束抓帧。 +- 调试流程可以和测试用例、窗口创建、设备初始化保持同一套代码路径。 +- 不需要依赖人工热键或临时手动附加。 + +## 推荐接入顺序 + +当前代码库里的典型流程是: + +1. 创建窗口。 +2. 调用 `RenderDocCapture::Get().Initialize(nullptr, hwnd)`。 +3. 初始化图形设备。 +4. 调用 `SetDevice(...)` 补齐真实设备指针。 +5. 在目标帧前调用 `BeginCapture(...)`。 +6. 在目标帧后调用 `EndCapture()`。 +7. 程序结束前调用 `Shutdown()`。 + +示例: + +```cpp +using namespace XCEngine::Debug; + +RenderDocCapture::Get().Initialize(nullptr, hwnd); +RenderDocCapture::Get().SetCaptureFilePath(".\\triangle_frame30"); +RenderDocCapture::Get().SetDevice(devicePtr); + +if (frameCount == 29) { + RenderDocCapture::Get().BeginCapture("Triangle_Test"); +} + +if (frameCount == 30) { + RenderDocCapture::Get().EndCapture(); +} +``` + +## 为什么允许先不传 device + +窗口通常比图形设备更早创建。当前 `Initialize` 支持先传 `window`、后传 `device`,就是为了对齐真实的引擎启动顺序。 + +这点在图形测试里尤其重要,因为: + +- 有时必须先拿到 `HWND` 才能初始化后端。 +- 但 RenderDoc 的目标窗口又应该尽早绑定好。 + +## 这套设计的好处 + +- 把“抓帧时机”从人工操作变成代码可控流程。 +- D3D12 / OpenGL 可以复用同一套抓帧入口。 +- 自动化测试更容易固定在某一帧抓取稳定结果。 + +## 当前限制 + +- 这是 Windows 专用封装。 +- `renderdoc.dll` 必须位于可执行文件目录。 +- `BeginCapture` 会尝试把窗口切到前台,这对自动化环境可能是有副作用的。 +- `LaunchReplayUI` 只能确认“请求已发出”,不能确认 UI 一定成功启动。 +- 头文件暴露的是原始 `void*` 设备和窗口指针,没有类型安全包装。 + +## 和 Unity 的对照 + +它更接近“把外部 RenderDoc 工作流内嵌到引擎测试流程”,而不是 Unity Frame Debugger 那种引擎内逐 draw-call 可视化工具。 + +换句话说: + +- Unity Frame Debugger 侧重引擎自己解释渲染步骤。 +- `RenderDocCapture` 侧重让 RenderDoc 在正确的时机抓到正确的帧。 + +## 实战建议 + +- 把抓帧逻辑放在测试场景最稳定的关键帧,而不是随机运行时。 +- 在调用 `BeginCapture` 前确保设备和窗口都已设置完成。 +- 用 `SetCaptureFilePath` 给不同测试用例设置可区分的输出前缀。 +- 如果要写自动化诊断流程,优先把 capture 的开始/结束时机做成和帧数、状态机绑定,而不是临时热键。 + +## 相关 API + +- [Debug](../../XCEngine/Debug/Debug.md) +- [RenderDocCapture](../../XCEngine/Debug/RenderDocCapture/RenderDocCapture.md) +- [Initialize](../../XCEngine/Debug/RenderDocCapture/Initialize.md) +- [BeginCapture](../../XCEngine/Debug/RenderDocCapture/BeginCapture.md) +- [EndCapture](../../XCEngine/Debug/RenderDocCapture/EndCapture.md) diff --git a/docs/api/_meta/rebuild-status.md b/docs/api/_meta/rebuild-status.md index 43c2f9ae..128365c7 100644 --- a/docs/api/_meta/rebuild-status.md +++ b/docs/api/_meta/rebuild-status.md @@ -1,12 +1,12 @@ # API 文档重构状态 -**生成时间**: `2026-03-26 16:41:41` +**生成时间**: `2026-03-26 17:20:45` **来源**: `docs/api/_tools/audit_api_docs.py` ## 摘要 -- Markdown 页面数(全部): `2440` +- Markdown 页面数(全部): `2443` - Markdown 页面数(canonical): `2437` - Public headers 数: `185` - 有效头文件引用数(全部): `185`