diff --git a/src/StgSharp.RegularAnalysis/Text/TextRegex.cs b/src/StgSharp.RegularAnalysis/Text/TextRegex.cs
index d14bddc3..3b4cdbc1 100644
--- a/src/StgSharp.RegularAnalysis/Text/TextRegex.cs
+++ b/src/StgSharp.RegularAnalysis/Text/TextRegex.cs
@@ -84,21 +84,21 @@ namespace StgSharp.RegularAnalysis.Text
/// .
///
///
- /// /// This method operates on a single , and therefore /// on
- /// a single UTF-16 code unit rather than on a complete Unicode scalar /// value.
- /// /// /// Characters in the Unicode Basic Multilingual Plane are
- /// classified /// normally. A supplementary-plane character is represented by a ///
- /// surrogate pair and is therefore presented to this method as two /// separate surrogate
- /// code units. Neither surrogate is independently /// treated as a word character. This
- /// follows the char-based behavior of /// the corresponding .NET Regex helper. ///
- /// /// For ASCII input, the Unicode-category lookup is avoided. In ASCII, /// the
- /// accepted set is exactly: /// [A-Za-z0-9_] . /// /// This method
+ /// /// This method operates on a single , and therefore /// on a
+ /// single UTF-16 code unit rather than on a complete Unicode scalar /// value. ///
+ /// /// Characters in the Unicode Basic Multilingual Plane are classified
+ /// /// normally. A supplementary-plane character is represented by a /// surrogate pair
+ /// and is therefore presented to this method as two /// separate surrogate code units.
+ /// Neither surrogate is independently /// treated as a word character. This follows the
+ /// char-based behavior of /// the corresponding .NET Regex helper. /// ///
+ /// For ASCII input, the Unicode-category lookup is avoided. In ASCII, /// the accepted
+ /// set is exactly: /// [A-Za-z0-9_] . /// /// This method
/// implements ordinary .NET \w semantics. It does /// not implement the ASCII-
- /// oriented behavior enabled by /// RegexOptions.ECMAScript . ///
+ /// oriented behavior enabled by /// RegexOptions.ECMAScript . ///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected static bool IsCharWord(
- char value
+ protected internal static bool IsCharWord(
+ char value
)
{
/*
diff --git a/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs b/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs
index 2c8eb44c..dd022e3c 100644
--- a/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs
+++ b/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs
@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp;
using StgSharp.RegularAnalysis.Abstraction;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -82,6 +83,36 @@ namespace StgSharp.RegularAnalysis.Text
return SyntaxFactory.Literal(value).Text;
}
+ private static string GenerateCharSetExpression(
+ RegexCharSet set
+ )
+ {
+ string remainSpan = SourceGenContext._remain_span;
+ string accept = set.Accept ? string.Empty : "!";
+ switch (set.Type)
+ {
+ case RegexCharSetType.Single:
+ return $"{accept}({FormatStringLiteral(set.Value)}.{nameof(MemoryExtensions.Contains)}({remainSpan}[0]))";
+ case RegexCharSetType.Range:
+ return $"{accept}({remainSpan}[0] >= {FormatCharLiteral(set.Value[0])} && {remainSpan}[0] <= {FormatCharLiteral(set.Value[1])})";
+ case RegexCharSetType.Set:
+ switch (set.Value[0])
+ {
+ case 's':
+ return $"{accept}char.IsWhiteSpace({remainSpan}[0])";
+ case 'w':
+ return $"{accept}{nameof(TextRegex.IsCharWord)}({remainSpan}[0])";
+ case 'd':
+ return $"{accept}char.IsDigit({remainSpan}[0])";
+ default:
+ break;
+ }
+ goto default;
+ default:
+ return string.Empty;
+ }
+ }
+
private static bool IsNamedFind(
RegexAstNode node
)
@@ -131,15 +162,37 @@ namespace StgSharp.RegularAnalysis.Text
case RegexElementLabel.UNIT:
_ = sc.AppendLine(@$"if({context.RemainSpan}[0] == {FormatCharLiteral(code[0])})")
.AppendLine("{")
+ .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine($@"goto {exit_label};")
.AppendLine("}");
break;
case RegexElementLabel.UNIT_SET:
- IReadOnlyList split = current.PayloadAs()
- .Set;
- RegexCharSet first_set = split[0];
- for (int i = 1; i < split.Count - 1; i++) { }
- RegexCharSet last_set = split[^1];
+ RegexCharSetPayload payload = current.PayloadAs();
+ IReadOnlyList split = payload.Set;
+ bool accept = payload.Accept;
+ RegexCharSet _set = split[0];
+ _ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
+ for (int i = 1; i < split.Count - 1; i++)
+ {
+ _set = split[i];
+ _ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
+ }
+ _set = split[^1];
+ _ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}")
+ .AppendLine("{")
+ .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
+ .AppendLine($@"goto {exit_label};")
+ .AppendLine("}");
+ break;
+ case RegexElementLabel.UNIT_SPAN:
+ _ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({FormatStringLiteral(code)}))")
+ .AppendLine("{")
+ .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
+ .AppendLine($@"goto {exit_label};")
+ .AppendLine("}");
+
+ break;
+ default:
break;
}
} else
diff --git a/test/StgSharp.GenerateGL/Docs/ArchitectureAssessment.md b/test/StgSharp.GenerateGL/Docs/ArchitectureAssessment.md
new file mode 100644
index 00000000..5a4dfc70
--- /dev/null
+++ b/test/StgSharp.GenerateGL/Docs/ArchitectureAssessment.md
@@ -0,0 +1,666 @@
+# GenerateGL 与 StgSharp.Graphics OpenGL 绑定架构评估
+
+评估日期:2026-08-24
+
+## 1. 评估目的
+
+本文评估 `StgSharp.GenerateGL` 与 `src/StgSharp.Graphics` 当前 OpenGL 绑定代码之间的关系,重点回答以下问题:
+
+- GenerateGL 为什么会生成大量保留 C 命名风格的方法;
+- Uniform 系列应如何生成符合 C# 使用习惯的方法重载;
+- 现有手写封装散落在哪些文件中;
+- 修改生成器时还需要同步调整哪些类型、加载器和调用方;
+- 如何在保留现有功能的前提下逐步完成迁移。
+
+本次评估基于静态代码检查,不包含代码重构或 API 变更。
+
+## 2. 总体结论
+
+当前 GenerateGL 完成的是“将 Khronos OpenGL C API 转换为可调用的 C# 代码”,尚未建立从 C API 函数族到惯用 C# API 的语义映射。
+
+`glUniform1f`、`glUniform2f`、`glUniform4fv` 等名称中的数字和后缀分别编码了分量数、元素类型和指针形式。当前生成器只删除 `gl` 前缀,因此得到的仍然是 C 风格方法,而不是 C# 重载。
+
+解决该问题不能只修改方法命名。当前 OpenGL 代码同时存在以下结构性问题:
+
+1. 原始函数指针、自动生成的薄封装和手写高级封装没有清晰分层;
+2. `Uniform.cs` 同时定义 Uniform 类型和 `partial OpenGLFunction` 方法;
+3. `ShaderStruct.cs` 绕过 `OpenGLFunction`,直接调用原始函数指针;
+4. uniform location 被建模为通用 `GlHandle`,语义不正确;
+5. Context、ContextShadow、Loader 和 Wrapper 分别维护,已经出现函数清单漂移;
+6. OpenGL 版本能力判断存在错误,可能加载当前上下文不支持的函数;
+7. GenerateGL 文档描述的是增量源生成器,但当前实现是独立控制台代码生成程序。
+
+建议将架构拆分为四个明确层次:
+
+1. Registry 模型层:解析 `gl.xml` 并建立函数、版本和类型模型;
+2. ABI 层:生成原始函数指针和加载代码;
+3. Raw API 层:提供与 OpenGL 一一对应的薄封装;
+4. Idiomatic API 层:按函数族生成 C# 重载,并使用 StgSharp 的向量、矩阵和资源类型。
+
+## 3. 当前 GenerateGL 行为
+
+### 3.1 输入
+
+GenerateGL 从 `xml/gl.xml` 读取 Khronos OpenGL Registry。
+
+当前解析内容包括:
+
+- `` 中的函数名、返回值和参数;
+- `` 中各 OpenGL 版本新增的命令;
+- Core Profile 中删除的命令。
+
+当前未完整实现:
+
+- 枚举和常量生成;
+- 扩展 API 生成;
+- Roslyn Incremental Generator;
+- 自动写入或接入 `StgSharp.Graphics` 项目。
+
+### 3.2 输出
+
+当前生成器针对 OpenGL 3.3 至 4.6 生成:
+
+- 分版本 `OpenglContext` 函数指针字段;
+- 分版本 `OpenGLFunction` 薄封装方法;
+- 合并后的 `glContext.cs`;
+- OpenGL 命令新增和删除历史。
+
+输出目录为 GenerateGL 可执行文件所在目录下的 `Generated`,而不是 `src/StgSharp.Graphics`。
+
+### 3.3 当前生成策略的限制
+
+生成器对公开方法的处理主要包括:
+
+- 删除 `gl` 前缀;
+- 将部分 `GLuint` 参数启发式转换为 `GlHandle`;
+- 将部分 `const T*` 转换为 `ReadOnlySpan`;
+- 对 C# 保留字进行转义。
+
+它没有分析 OpenGL 函数族,因此下列函数会被当作互不相关的方法:
+
+```text
+glUniform1f
+glUniform2f
+glUniform3f
+glUniform4f
+glUniform1fv
+glUniform2fv
+glUniform3fv
+glUniform4fv
+```
+
+## 4. StgSharp.Graphics 当前代码分布
+
+### 4.1 原始函数指针
+
+`src/StgSharp.Graphics/OpenGL/glContext.cs` 定义 `OpenglContext`,当前包含 657 个函数指针字段。
+
+这些字段是 OpenGL ABI 的核心,应完全由生成器维护,不应与手写高级 API 混合。
+
+### 4.2 ContextShadow
+
+`src/StgSharp.Graphics/OpenGL/glContextShadow.cs` 使用 657 个 `IntPtr` 字段镜像 `OpenglContext`。
+
+加载器将 `OpenglContext*` 强制转换为 `glContextShadow*` 后写入函数地址。因此两个结构体必须始终满足:
+
+- 字段数量一致;
+- 字段顺序一致;
+- 每个字段占用相同大小。
+
+当前两者字段数量和顺序一致,但这种设计非常脆弱。生成器目前不生成 ContextShadow,任何一侧发生变化都可能破坏内存布局。
+
+### 4.3 函数加载器
+
+`src/StgSharp.Graphics/OpenGL/glApiManager.Load.cs` 按 OpenGL 版本加载函数。
+
+静态检查结果:
+
+- `OpenglContext` 字段数:657;
+- `glContextShadow` 字段数:657;
+- 实际 Loader 赋值数:655。
+
+当前未被实际加载的字段:
+
+- `glGetPointerv`;
+- `glVertexAttribLFormat`。
+
+这说明 Context、Shadow 和 Loader 已经发生漂移。
+
+### 4.4 自动生成的公开薄封装
+
+以下文件定义 `partial OpenGLFunction`:
+
+- `glFunction.v3_3.cs`;
+- `glFunction.v4_0.cs`;
+- `glFunction.v4_1.cs`;
+- `glFunction.v4_2.cs`;
+- `glFunction.v4_3.cs`;
+- `glFunction.v4_4.cs`;
+- `glFunction.v4_5.cs`;
+- `glFunction.v4_6.cs`。
+
+这些文件合计约 656 个公开方法。它们已经进行了一部分 C# 类型转换,但函数名和参数模型仍基本对应 C API。
+
+这使它们处于不稳定的中间层:
+
+- 不再是完全精确的 Raw ABI;
+- 又没有形成惯用的 C# API;
+- `count` 与 `ReadOnlySpan` 长度可能不一致;
+- `byte`、裸 `uint` 和裸指针仍大量暴露;
+- 资源句柄识别依赖参数名启发式规则。
+
+### 4.5 手写 OpenGLFunction 方法
+
+`src/StgSharp.Graphics/OpenGL/glFunction.cs` 约 795 行,包含约 55 个手写公开方法,职责包括:
+
+- Context 与 `OpenGLFunction` 实例管理;
+- Buffer 创建、删除和数据上传;
+- Texture 创建和上传;
+- Framebuffer 和 Renderbuffer 操作;
+- Shader 创建、源码上传和状态检查;
+- Draw 调用;
+- 错误检查;
+- Vertex Attribute 配置。
+
+这些方法与版本文件中的公开方法并存。例如同时存在:
+
+- `ActiveTextureUnit` 与 `ActiveTexture`;
+- `BindFrameBuffer` 与 `BindFramebuffer`;
+- `FrameBufferTexture2d` 与 `FramebufferTexture2D`;
+- `TextureImage2d` 与 `TexImage2D`;
+- `SetBufferData` 与 `BufferData`。
+
+这种重复不是编译错误,但会让调用者无法判断哪一层是推荐 API,也会妨碍生成器安全地产生新重载。
+
+### 4.6 Uniform 类型与方法
+
+`src/StgSharp.Graphics/OpenGL/ShaderEdit/Uniform.cs` 同时包含:
+
+- `Uniform` 基类;
+- `Uniform`;
+- `Uniform`;
+- `Uniform`;
+- `Uniform`;
+- `partial OpenGLFunction` 的 `SetUniformValue` 重载。
+
+代码位置本身不影响编译,但该文件跨越了两个职责边界:
+
+- Uniform 数据模型;
+- OpenGL 命令封装。
+
+这会导致生成器无法拥有 Uniform 方法的明确输出区域。
+
+### 4.7 Shader 相关代码
+
+`src/StgSharp.Graphics/OpenGL/ShaderEdit/Shader.cs` 同时定义:
+
+- `partial glRender` 的 Shader 工厂方法;
+- `Shader`;
+- `ShaderStatus`;
+- `ShaderProgram`;
+- `ShaderProgram.GetUniform`。
+
+此外还存在 `src/StgSharp.Graphics/ShaderEdit`,其中包含另一套 Shader 抽象。`OpenGL/ShaderEdit/IglConvertable.cs` 的文件路径位于 OpenGL 子目录,但命名空间是 `StgSharp.Graphics.ShaderEdit`。
+
+当前文件位置和命名空间没有形成一致边界。
+
+### 4.8 绕过公开封装的调用
+
+除 Loader 和绑定实现外,发现 `src/StgSharp.Graphics/ShaderEdit/ShaderStruct.cs` 直接获取:
+
+```csharp
+OpenglContext* gl =
+ (OpenglContext*)OpenGLFunction.CurrentGL.ContextHandle;
+```
+
+随后直接调用 `glUniform*`。
+
+这是高级代码对 ABI 层的越层依赖。新的 Uniform API 建立后,这里应只调用 `OpenGLFunction.SetUniformValue` 或对应的 Uniform 对象方法。
+
+## 5. 已确认的正确性问题
+
+### 5.1 Vec4 使用了错误的 OpenGL 函数
+
+当前 `Uniform.cs` 中,`Vec4` 被传给:
+
+```csharp
+glUniform1fv(location, 4, pointer);
+```
+
+该调用表示上传 4 个标量 uniform,而不是上传 1 个四分量向量。
+
+正确调用应为:
+
+```csharp
+glUniform4fv(location, 1, pointer);
+```
+
+### 5.2 整数 Uniform 调用了浮点函数
+
+`ShaderStruct.SetAllUniforms` 的整数分支调用 `glUniform1f`,应调用 `glUniform1i`。
+
+### 5.3 Uniform location 被错误建模为 GlHandle
+
+OpenGL uniform location 的原始类型是有符号 `GLint`,并允许 `-1` 表示未找到。
+
+当前实现使用 `GlHandle` 保存 uniform location。`GlHandle` 同时被用于 Buffer、Texture、Program 和 Shader 等 `GLuint` 对象名称,因此无法表达 uniform location 的不同语义和有效性规则。
+
+建议引入:
+
+```csharp
+public readonly record struct UniformLocation(int Value)
+{
+ public bool IsValid => Value >= 0;
+}
+```
+
+### 5.4 版本判断错误
+
+`glManager.CheckCoreVersion` 当前使用类似以下判断:
+
+```csharp
+majorVersion >= 4 ||
+(majorVersion == 4 && minorVersion == requiredMinor)
+```
+
+当上下文版本为 OpenGL 4.0 时,`majorVersion >= 4` 对 4.1 至 4.6 的检查也全部为真。
+
+正确判断应为:
+
+```csharp
+majorVersion > requiredMajor ||
+(majorVersion == requiredMajor && minorVersion >= requiredMinor)
+```
+
+版本和扩展能力还应保存在每个 OpenGL context 中,而不是静态全局字段中。
+
+### 5.5 上下文内存没有完整清零
+
+`glRender.InitializeContext` 通过 `Marshal.AllocHGlobal` 分配 `OpenglContext`,但只将 `glGetString` 设置为零。
+
+如果当前版本不加载某些较新函数,其字段可能保留未初始化值。公开版本方法仍然存在,错误调用时可能跳转到无效地址。
+
+上下文分配后应完整清零,并通过 capability 检查限制不受支持的方法调用。
+
+### 5.6 函数指针调用约定需要统一审计
+
+GLFW 返回的是非托管函数地址。当前 `OpenglContext` 多数使用 `delegate*<...>`,没有显式标记 `unmanaged` 调用约定。
+
+生成器应根据目标平台统一生成并验证函数指针调用约定,例如:
+
+```csharp
+delegate* unmanaged<...>
+```
+
+或在确有需要时生成平台对应的显式调用约定。
+
+## 6. Uniform 函数族的推荐建模
+
+### 6.1 函数名解析
+
+生成器应将以下函数族解析为结构化模型:
+
+```text
+glUniform{1|2|3|4}{f|d|i|ui}{v?}
+glProgramUniform{1|2|3|4}{f|d|i|ui}{v?}
+glUniformMatrix{2|3|4|2x3|2x4|3x2|3x4|4x2|4x3}{f|d}v
+glProgramUniformMatrix{...}{f|d}v
+```
+
+建议模型至少包含:
+
+```text
+Operation = Uniform | ProgramUniform
+Shape = Scalar | Vector | Matrix
+Columns = 1..4
+Rows = 1..4
+ElementType = Float | Double | Int | UInt
+InputForm = Components | Array
+NativeCommand = glUniform4fv 等原始名称
+IntroducedIn = OpenGL 版本
+```
+
+不要直接在字符串 emitter 中通过多组 `StartsWith` 和 `EndsWith` 拼接逻辑。应先完成函数族识别,再根据统一模型生成代码。
+
+### 6.2 推荐的 Uniform 类型
+
+建议保留单泛型参数:
+
+```csharp
+public readonly struct Uniform where T : unmanaged
+{
+ public UniformLocation Location { get; }
+}
+```
+
+向量和矩阵形状由 `T` 表达:
+
+```text
+Uniform
+Uniform
+Uniform
+Uniform
+Uniform
+```
+
+不建议继续使用 `Uniform` 表达四分量值。
+
+要完整支持 `double`、`int` 和 `uint` 向量,数学库还需要提供对应的向量类型,或者 OpenGL 层需要定义布局稳定的专用值类型,例如:
+
+```text
+DVec2 / DVec3 / DVec4
+IVec2 / IVec3 / IVec4
+UVec2 / UVec3 / UVec4
+```
+
+### 6.3 推荐重载
+
+标量与向量:
+
+```csharp
+void SetUniformValue(Uniform uniform, float value);
+void SetUniformValue(Uniform uniform, Vec2 value);
+void SetUniformValue(Uniform uniform, Vec3 value);
+void SetUniformValue(Uniform uniform, Vec4 value);
+```
+
+数组:
+
+```csharp
+void SetUniformValue(
+ Uniform uniform,
+ ReadOnlySpan values);
+
+void SetUniformValue(
+ Uniform uniform,
+ ReadOnlySpan values);
+```
+
+矩阵:
+
+```csharp
+void SetUniformValue(
+ Uniform uniform,
+ in GraphicsMatrix value,
+ bool transpose = false);
+```
+
+调用者不应手工传入 `count`。生成方法应根据 Span 长度和元素形状计算 OpenGL 的 `count` 参数。
+
+### 6.4 Raw API 的处理
+
+建议保留与 OpenGL 一一对应的 Raw 方法,至少在迁移期内不要立即删除。
+
+可选策略:
+
+1. 将 Raw 方法改为 `internal`;
+2. 放入单独的 `OpenGLRaw` 类型;
+3. 暂时保持 `public`,但使用 `EditorBrowsable(Never)` 降低 IntelliSense 噪音;
+4. 为旧 API 提供一个兼容周期,再逐步弃用。
+
+Idiomatic API 不应与 Raw API 写入同一生成文件。
+
+## 7. 推荐目录结构
+
+```text
+src/StgSharp.Graphics/OpenGL/
+ Generated/
+ OpenglContext.g.cs
+ OpenglLoader.v33.g.cs
+ OpenGLFunction.Raw.v33.g.cs
+ OpenGLFunction.Raw.v40.g.cs
+ OpenGLFunction.Uniform.g.cs
+ OpenGLFunction.ProgramUniform.g.cs
+
+ Api/
+ OpenGLFunction.Context.cs
+ OpenGLFunction.Diagnostics.cs
+ OpenGLFunction.Buffer.cs
+ OpenGLFunction.Texture.cs
+ OpenGLFunction.Drawing.cs
+ OpenGLFunction.Shader.cs
+
+ Objects/
+ Uniform.cs
+ UniformLocation.cs
+ Shader.cs
+ ShaderProgram.cs
+ ShaderStatus.cs
+ Buffer/
+ Texture/
+
+ Rendering/
+ GlRender.cs
+ GlRender.Resources.cs
+ GlRender.Threading.cs
+```
+
+具体目录名称可以调整,但必须保持以下边界:
+
+- `Generated` 中的文件可以被完整覆盖;
+- 手写文件永远不写入 `Generated`;
+- Uniform 类型定义和 Uniform 调用方法分离;
+- Shader 资源对象不直接访问 `OpenglContext*`;
+- Loader 与 Context 来自同一个生成模型。
+
+## 8. 建议的文件迁移
+
+### 8.1 `Uniform.cs`
+
+保留:
+
+- `Uniform`;
+- uniform location;
+- 与 uniform 数据模型直接相关的成员。
+
+移出:
+
+- 所有 `partial OpenGLFunction` 方法。
+
+### 8.2 `Shader.cs`
+
+拆分为:
+
+- `Shader.cs`;
+- `ShaderProgram.cs`;
+- `ShaderStatus.cs`;
+- `ShaderProgram.Uniform.cs`;
+- `GlRender.ShaderFactory.cs`。
+
+### 8.3 `ShaderStruct.cs`
+
+移除:
+
+- `ContextHandle` 访问;
+- `OpenglContext*` 转换;
+- 直接 `glUniform*` 调用。
+
+改为通过类型安全的 Uniform API 分发。
+
+### 8.4 `glFunction.cs`
+
+保留 Context 生命周期和实例管理,然后按功能拆分手写便利方法:
+
+```text
+OpenGLFunction.Context.cs
+OpenGLFunction.Diagnostics.cs
+OpenGLFunction.Buffer.cs
+OpenGLFunction.Texture.cs
+OpenGLFunction.Framebuffer.cs
+OpenGLFunction.Drawing.cs
+OpenGLFunction.Shader.cs
+```
+
+### 8.5 `glFunction.SourceManager.cs`
+
+该文件实际管理 Texture Unit,而不是 Source。建议重命名为:
+
+```text
+OpenGLFunction.TextureUnits.cs
+```
+
+进一步可以将 Texture Unit 分配状态移出函数绑定类,放入每个 Render Context 的资源管理对象。
+
+### 8.6 `IglConvertable.cs`
+
+该文件位于 `OpenGL/ShaderEdit`,命名空间却是 `StgSharp.Graphics.ShaderEdit`。应移动到与命名空间一致的 `ShaderEdit` 目录。
+
+## 9. GenerateGL 推荐内部结构
+
+建议将当前单一 `Generator` 拆分为以下阶段。
+
+### 9.1 Registry 解析
+
+```text
+GlXmlParser
+ -> RegistryModel
+```
+
+负责准确保留:
+
+- C 类型;
+- 指针层级;
+- const;
+- 参数组信息;
+- feature/profile/version;
+- alias;
+- enum group。
+
+### 9.2 ABI 类型映射
+
+```text
+RegistryModel
+ -> AbiCommandModel
+```
+
+这里只做精确映射,不做 `GlHandle`、Span 或 ShaderType 等高级推断。
+
+### 9.3 函数族分析
+
+```text
+AbiCommandModel
+ -> CommandFamilyModel
+```
+
+由专门规则识别:
+
+- Uniform;
+- ProgramUniform;
+- UniformMatrix;
+- VertexAttrib;
+- TexParameter;
+- Get 系列;
+- Gen/Delete/Create 系列。
+
+无法识别的命令仍可生成 Raw API,但不得用不确定的启发式规则擅自改变资源类型。
+
+### 9.4 Emitters
+
+建议拆分:
+
+```text
+ContextEmitter
+LoaderEmitter
+RawFunctionEmitter
+UniformEmitter
+ProgramUniformEmitter
+ConstantEmitter
+HistoryEmitter
+```
+
+每个 emitter 只负责一种输出,便于单独进行 golden-file 测试。
+
+## 10. 迁移计划
+
+### 阶段一:建立安全的生成边界
+
+1. 新增 `OpenGL/Generated`;
+2. 所有生成文件使用 `.g.cs` 后缀;
+3. 生成器直接生成 `OpenglContext` 和 Loader;
+4. 移除或自动生成 `glContextShadow`;
+5. 增加函数数量、名称和版本一致性测试。
+
+此阶段不改变现有公开 API。
+
+### 阶段二:修复 Uniform 模型
+
+1. 新增 `UniformLocation`;
+2. 将 `GetUniformLocation` 返回类型改为 `UniformLocation`;
+3. 将 Uniform 简化为 `Uniform`;
+4. 修复 Vec4 和整数 uniform 的错误调用;
+5. 迁移 Camera、ShaderProgram 和 ShaderStruct。
+
+### 阶段三:生成 Uniform 重载
+
+1. 实现 Uniform 函数族解析;
+2. 生成 scalar/vector/matrix overload;
+3. 自动计算 Span 对应的 count;
+4. 生成 ProgramUniform 对应重载;
+5. 使用 golden-file 测试验证每个原始命令映射到正确 overload。
+
+### 阶段四:整理其他手写便利 API
+
+1. 拆分 `glFunction.cs`;
+2. 统一 Buffer、Texture、Framebuffer 方法命名;
+3. 明确 Raw API 的可见性和兼容策略;
+4. 逐步为 VertexAttrib、TexParameter 等函数族生成重载。
+
+### 阶段五:清理旧 API
+
+1. 标记旧 C 风格 public wrapper 为 obsolete 或隐藏;
+2. 提供迁移说明;
+3. 在约定的兼容版本后删除旧入口。
+
+## 11. 测试与验收标准
+
+### 11.1 Registry 一致性
+
+- 每个 Context 字段必须有对应 Loader 赋值;
+- 每个 Raw wrapper 必须对应一个 Context 字段;
+- 不允许 Loader 引用不存在的字段;
+- Context、Loader 和 Wrapper 的版本归属必须一致。
+
+### 11.2 Uniform golden tests
+
+至少验证:
+
+```text
+float -> glUniform1f
+Vec2 -> glUniform2fv(count = 1)
+Vec3 -> glUniform3fv(count = 1)
+Vec4 -> glUniform4fv(count = 1)
+ReadOnlySpan -> glUniform4fv(count = span.Length)
+GraphicsMatrix -> glUniformMatrix4fv(count = 1)
+```
+
+同时覆盖 `double`、`int`、`uint`、非方阵矩阵和 ProgramUniform。
+
+### 11.3 API 约束
+
+- 高级代码不得访问 `OpenglContext*`;
+- 高级代码不得手工传入可由 Span 推导的 count;
+- uniform location 不得使用 `GlHandle`;
+- 生成文件不得包含手写区域;
+- 手写文件不得依赖生成字段的布局顺序;
+- 不支持的 OpenGL 版本方法不得调用未初始化函数指针。
+
+### 11.4 构建验证
+
+GenerateGL 当前可以成功构建,但存在代码分析警告。
+
+本次检查中,单独构建 `StgSharp.Graphics` 时,MSBuild 在项目引用 `StgSharp.Mathematics` 的 `GetTargetFrameworks` 阶段失败,最终显示 0 个 C# 错误和 0 个警告。该失败发生在 C# 编译前,因此本次评估不将其视为 Graphics 源码编译结果。
+
+## 12. 推荐的第一批实际改动
+
+为了控制改动规模,第一批建议只完成以下内容:
+
+1. 新增 `UniformLocation`;
+2. 将 `Uniform` 收敛到 `Uniform`;
+3. 把 `SetUniformValue` 从 `Uniform.cs` 移到独立 partial 文件;
+4. 修复 `Vec4` 与整数 uniform 调用;
+5. 让 `ShaderStruct` 不再访问 `OpenglContext*`;
+6. 给 GenerateGL 增加 `UniformFamilyModel` 和 `UniformEmitter`;
+7. 同时生成 Context 与 Loader,并消除 ContextShadow 的手工同步;
+8. 增加 Context/Loader/Wrapper 集合一致性测试。
+
+完成这一批后,再决定是否立即重构全部 `glFunction.cs`。这样可以先解决 Uniform API 和生成同步问题,同时避免一次性扩大到整个 Graphics 框架。