7.1 KiB
7.1 KiB
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-8ReadOnlySpan<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:增量源生成器结构
- 步骤:
- 收集 AdditionalFiles(
gl.xml)。 - 解析→建模(CommandModel, EnumModel, FeatureModel)。
- 按版本/profile 过滤。
- Emit:分文件输出(
SourceProductionContext.AddSource)。
- 收集 AdditionalFiles(
- 配置建议:
LangVersion=preview(支持delegate* unmanaged[Stdcall]);仅引用必要的 XML 解析库。
阶段 6:兼容性与发布注意
- 不改动现有手写文件,仅追加 partial。
- 常量值需与现有
glConst保持一致,生成前检查重复。 - 大
gl.xml使用流式解析避免内存压力。 - Loader(
wglGetProcAddress/glXGetProcAddress/eglGetProcAddress)不在本轮生成,字段调用约定需与 loader 对齐。
下一步实施建议
- 将
gl.xml添加为 AdditionalFile。 - 搭建增量生成器骨架:Parse → Filter → Emit。
- 先生成 3.3 子集验证编译,再扩展到 4.6。
- 按需追加扩展(ARB/KHR),保持可配置启用列表。
本地评审输出
可把首个命令行参数作为输出目录:
dotnet run --project test\StgSharp.GenerateGL\GenerateGL.csproj -- test\StgSharp.GenerateGL\Generated