Files
stgsharp/test/StgSharp.GenerateGL/Docs/SourceGenerator.md
T

94 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# StgSharp.GenerateGL 源生成器技术文档
## 目标与范围
- **输入**:Khronos OpenGL Registry `gl.xml`(Core Profile 为主,版本 3.3→4.6,可选扩展)。
- **输出**:合并的 partial `OpenglContext`(`delegate*` 字段)、分版本 `OpenGLFunction` 薄包装方法,以及按版本生成的 Uniform 语义重载。生成结果最终对应 `src\StgSharp.Graphics\OpenGL\Generated\`,评审时可以通过命令行参数输出到独立目录。
- **风格**:保持现有函数指针字段 + 薄封装方法模式;兼容现有命名和类型定义(如 `GlHandle`)。
---
## 阶段 1:输入解析(XML 读取与过滤)
- 将 `gl.xml` 作为 AdditionalFile 或 EmbeddedResource,使用 `XmlReader` 流式解析。
- 解析节点:
- `<commands><command>`:函数名、返回类型、参数。
- `<enums>`:常量。
- `<feature profile="core">`:按 `version` 收录命令/常量。
- `<extensions>`:可选扩展(ARB/KHR/EXT/NV)。
- 过滤策略:仅 Core Profile 且版本 ≥ 3.3(3.3→4.6 递进);扩展按启用列表追加。
---
## 阶段 2:类型映射与句柄规则
- 整数:`GLenum`/`GLbitfield`→`uint`;`GLint`/`GLsizei`/`GLfixed`→`int`;`GLuint`→`uint`;`GLboolean`→`byte`(包装层可 bool→byte)。
- 浮点:`GLfloat`→`float`;`GLdouble`→`double`。
- 指针与尺寸:`void*`/`const void*`→`void*`;`GLintptr`、`GLsizeiptr`→`nint`;`GLsync`→现有 `glSync` 包装。`GLint64`/`GLuint64` 分别映射为 `long`/`ulong`。回调类型 `GLDEBUGPROC` 暂以指针大小的 `IntPtr` 表示。
- 未知 C 类型直接终止生成,不再静默回退为 `IntPtr`。这可以防止 typedef 漏映射后生成 ABI 不兼容的函数指针。
- 字符串:函数表中的 `GLchar*` 保持 `byte*` ABI;包装层的 const 单指针使用 UTF-8 `ReadOnlySpan<byte>`,后续可另行提供 `string` 重载。
- 参数长度:解析并保留 registry `<param len="...">`。包装层以该表达式判断数组方向、固定长度和关联的 `count`/`bufSize` 参数;底层函数表不使用这些托管规则。
- 调用约定:OpenGL APIENTRY 通常 stdcall(Windows);保持与现有 `glContext` 字段一致(`delegate* unmanaged[Stdcall]` 或 `unmanaged[Cdecl]`,需与 loader 对齐)。
- 句柄识别:包含 program/shader/buffer/texture/framebuffer/renderbuffer/vertexarray/query/sampler/transformfeedback 等对象名的 `GLuint` 参数 → 包装层使用 `GlHandle`,内部传 `handle.Value`。`glCreateProgram`、`glCreateShader` 等明确返回 object name 的命令返回 `GlHandle`。
- `GLenum` 不再仅凭参数名 `type` 推断为 `ShaderType`;低层包装保持 `uint`,避免把像素类型、索引类型等无关参数错误分类。
- glGet* 输出:保留指针签名,或另行生成 unsafe Span/stackalloc 适配器;核心先生成指针版。
---
## 阶段 3:版本分组与文件组织
- 目标目录:`src\StgSharp.Graphics\OpenGL\Generated\`
- Context 生成一个合并文件:
- `OpenglContext.g.cs`:所有目标 Core 版本需要的 `delegate*` 字段。
- Raw 包装按版本生成独立 partial:
- `OpenGLFunction.Raw.v3_3.g.cs`, …:包装方法 `public void Foo(...) => Context.glFoo(...);`
- Uniform 重载按首次引入版本生成:
- `OpenGLFunction.Uniform.v3_3.g.cs`、`v4_0`、`v4_1`。
- 不再同时生成分版本 Context 与合并 Context,避免同一字段被 partial struct 重复定义。
- 常量/枚举:`glConst.generated.cs`(或分版本补丁),避免与现有重复,先查已有定义再生成。
- 命名空间:`StgSharp.Graphics.OpenGL`;类声明:`partial struct/partial class glContext`(按现有定义),`partial class OpenGLFunction`。
---
## 阶段 4:生成规则(函数表与包装)
- `OpenglContext` 字段:`internal unsafe delegate*<converted_sig> glFoo;`
- `OpenGLFunction` 包装:薄封装直接转发;句柄参数用 `GlHandle`,内部传 `handle.Value`;`bool` 参数按底层 `GLboolean` 需要转换为 `byte/uint`。
- 指针包装:带长度的 `const T*` 生成 `ReadOnlySpan<T>`,输出 `T*` 生成 `Span<T>`,`len="1"` 的输出生成 `out T`。可由单个 Span 唯一决定的 `count`/`n`/`bufSize` 从 `Span.Length` 推导;共享同一长度的输入 Span 会检查长度一致。简单常量、乘法和除法长度表达式会生成下限检查。
- registry 中省略 `len` 的零结尾 const 字符指针仍生成 `ReadOnlySpan<byte>`;省略 `len` 的 `glGet*` 数值单指针按未知长度输出生成 `Span<T>`。`void*`、二级指针、驱动拥有的返回指针以及表示 Buffer 偏移的指针继续保留原始形式。
- 可重载的 C 类型尾缀会折叠为同一 C# 方法名,例如 `TexParameterf/i/fv/iv` → `TexParameter(...)`,`BlendEquation/BlendEquationi` → `BlendEquation(...)`。生成器以最终 C# 参数签名检测冲突;无法区分时保留最少的维度或语义尾缀。
- `glUniform1/2/3/4[f|i|ui|d][v]` 和 `glProgramUniform*` 不再作为一组公开的 C 风格方法生成,而是生成 `SetUniformValue(...)` 重载。location 从 `Uniform<T...>.id.SignedValue` 取得;数组版本接受 `ReadOnlySpan<T>` 并自动计算 count。
- float vector 额外生成 `Vec2`、`Vec3`、`Vec4` 重载,4×4 float matrix 生成 `GraphicsMatrix` 重载。所有 uniform setter(包括 matrix)都不进入 Raw wrapper;项目暂时没有对应托管类型的其他矩阵形状只保留底层 `OpenglContext` 函数指针,待类型齐备后再生成公开重载。
- `glVertexAttribN*v` 若存在对应的标量命令 `glVertexAttribN*`,不再生成重复的 Span wrapper;公开 API 使用 `VertexAttrib(index, x, y, z, w)` 形式的固定分量重载。只有不存在标量等价命令的特殊整数/归一化形式才暂时保留独立入口。
- `FramebufferTexture1D/2D/3D` 表示不同 OpenGL API,不参与维度重载归并。
- 去重:若同名字段/方法已存在,跳过或比对签名避免重复生成。
---
## 阶段 5:增量源生成器结构
- 步骤:
1. 收集 AdditionalFiles(`gl.xml`)。
2. 解析→建模(CommandModel, EnumModel, FeatureModel)。
3. 按版本/profile 过滤。
4. Emit:分文件输出(`SourceProductionContext.AddSource`)。
- 配置建议:`LangVersion=preview`(支持 `delegate* unmanaged[Stdcall]`);仅引用必要的 XML 解析库。
---
## 阶段 6:兼容性与发布注意
- 不改动现有手写文件,仅追加 partial。
- 常量值需与现有 `glConst` 保持一致,生成前检查重复。
- 大 `gl.xml` 使用流式解析避免内存压力。
- Loader(`wglGetProcAddress/glXGetProcAddress/eglGetProcAddress`)不在本轮生成,字段调用约定需与 loader 对齐。
---
## 下一步实施建议
1. 将 `gl.xml` 添加为 AdditionalFile。
2. 搭建增量生成器骨架:Parse → Filter → Emit。
3. 先生成 3.3 子集验证编译,再扩展到 4.6。
4. 按需追加扩展(ARB/KHR),保持可配置启用列表。
## 本地评审输出
可把首个命令行参数作为输出目录:
```powershell
dotnet run --project test\StgSharp.GenerateGL\GenerateGL.csproj -- test\StgSharp.GenerateGL\Generated
```