资讯动态

Slang 编译器入口点合法化测试束解析:coverage/legalize 的白盒表征测试体系

发布时间:2026/9/19 12:16:16 来源:尧图企业网站定制
Slang 编译器入口点合法化测试束解析coverage/legalize 的白盒表征测试体系【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang导读本文围绕 Slang 着色语言编译器仓库中的docs/generated/tests/coverage/legalize/README.md及其 23 个测试用例系统讲解编译器 IR 层面两个核心合法化器——GLSL/SPIR-V 入口点合法化器source/slang/slang-ir-glsl-legalize.cpp与变长参数varying parameter合法化器source/slang/slang-ir-legalize-varying-params.cpp——的实际行为。读者将理解从一条普通slangc命令行到最终着色器输出的过程中入口点参数如何被展平、系统值语义system-value semantic如何映射为各目标平台的 builtin、hull/mesh/ray-tracing 等特殊阶段经历了怎样的结构重写以及测试束如何通过 characterization表征方法把这些当前观察到的行为固化为可回归的断言。测试束定位白盒表征测试而非规范coverage/legalize测试束的定位非常明确它是针对入口点/变长参数合法化器的白盒表征测试white-box characterization tests固定的是当前观察到的合法化行为而非一份规范spec。所谓表征测试意味着这些测试不是为了定义正确的行为应该是什么而是把某个特定提交source_commit: 5634a0ea1b下、由 CLI 可达的入口点参数形态所产生的实际输出逐字记录pin下来一旦合法化器行为改变导致输出变化测试就会失败从而暴露回归。测试束的关键元数据约束见 README.md包括不验证、只固定映射遵循已文档化的 GLSL/Vulkan、Metal、WGSL builtin 命名因此全部视为已验证测试束内没有任何用例携带characterization-unverified标记下游可接受性对于文本 GLSL 目标生成的着色器还会通过 glslang 反向验证-target spirv -emit-spirv-via-glsl对于 SPIR-V 目标用SLANG_RUN_SPIRV_VALIDATION1做校验确保固定的输出不会被下游消费方拒绝不可达缺口单独处理凡是会产生下游消费者拒绝的输出形态都被从测试中剔除并记录为 findings详见不可达缺口一节。三路并进的覆盖策略README 记录了测试束第二轮本批次补齐的三类缺口这也是理解 23 个测试文件组织逻辑的主线1. 没有其他用例驱动的阶段0% 行覆盖率以下函数此前行覆盖率全部为 0只有 hull、domain、geometry、mesh、per-vertex fragment 和 ray-tracing 入口点才能从一条普通slangc调用抵达它们因此每个函数配一个探针probe用例函数所在文件探针用例invokePathConstantFuncInHullShaderslang-ir-glsl-legalize.cpp:1229hull-patch-constant-func-spirv.slanggetOrCreateBuiltinParamForHullShaderslang-ir-glsl-legalize.cpp:1121同上合成路径createPatchConstantFuncResultTypeLayoutslang-ir-glsl-legalize.cpp:1167同上legalizeMeshOutputParamslang-ir-glsl-legalize.cpp:3502mesh-shader-output-block-glsl.slanggetOrCreatePerVertexInputArrayslang-ir-glsl-legalize.cpp:3759pervertex-input-array-glsl.slangconsolidateParametersslang-ir-glsl-legalize.cpp:3040raytracing-multi-payload-consolidation-spirv.slangassignRayPayloadHitObjectAttributeLocationsslang-ir-glsl-legalize.cpp:4563raytracing-payload-location-assignment-spirv.slang2. GLSL 系统值表的长尾231 行未覆盖getGLSLSystemValueInfo是整个文件中最大的单点缺口231 行未覆盖。此前从未被触达的语义恰好是那些 GLSL 形态不是简单改名的条目数组值的SV_CoverageSV_DepthGreaterEqual的 layout 限定符对noperspective敏感的SV_Barycentrics分支int 类型的gl_BaseVertex/gl_BaseInstanceSV_PrimitiveID的输入/输出分离。这些语义按阶段归入三个探针用例fragment-coverage-depth-glsl.slang、fragment-barycentrics-layer-viewport-glsl.slang、geometry-shader-sysvals-glsl.slang。3. 非 Vulkan 的变长参数合法化器322 行未覆盖emitOptiXPayloadRead/emitOptiXPayloadWrite两者合计 322 行未覆盖、Metal 和 WGSL 各自的getSystemValueInfo表、Metal 的 amplification/mesh 重写。这些从纯文本发射-target cuda/metal/wgsl即可触达不依赖下游工具链因此所有用例都不做工具门控tool-gated。功能覆盖表21 条行为声明的完整清单README 的核心价值在于其 21 条 Claim → 意图 → 文档锚点 → 测试 的映射表。以下完整继承并整理意图均为 characterizationGLSL/SPIR-V 入口点合法化slang-ir-glsl-legalize.cpp行为声明文档锚点测试顶点入口点的 struct 型 varying 输入/输出展平为逐字段的 GLSLin/out全局变量SV_Position路由到gl_Positiondocs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlingvarying-struct-flatten-glsl.slangSPIR-V 变长参数合法化器把 struct 输入/输出拆成逐字段的 OpVariable 全局变量带顺序 Location 装饰SV_Position路由到 BuiltIn Position同上varying-struct-flatten-spirv.slang四个 compute thread-id 系统值映射到 GLSLgl_*builtindocs/design/target-pipelines/spirv.md#legalizeentrypointsforglsl-despite-the-namecompute-sysval-builtins-glsl.slangfragment 的SV_Position输入映射到gl_FragCoordSV_IsFrontFace映射到gl_FrontFacing同上fragment-position-frontface-glsl.slang无法识别的SV_*语义被 GLSL 入口点合法化器以 E49999 拒绝同上unknown-system-value-semantic.slangSV_VertexID/SV_InstanceID在 GLSL 中降级为gl_VertexIndex/gl_InstanceIndex并减去 base offset同上vertex-id-base-offset-glsl.slanghull 着色器的 patch-constant 函数被拼接进入口点置于控制屏障之后、invocation id 0守卫之内接收 InputPatch 参数并物化 OutputPatchdocs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlinghull-patch-constant-func-spirv.slangdomain 入口点把 OutputPatch 路由到 Location 输入SV_DomainLocation路由到 TessCoordpatch-constant struct 的SV_InsideTessFactor路由到 Patch 装饰的 TessLevelInner同上domain-shader-patch-input-spirv.slanggeometry 着色器中SV_PrimitiveID分裂为输入的gl_PrimitiveIDIn与输出的gl_PrimitiveIDSV_GSInstanceID变为gl_InvocationIDlayer/viewport 收窄为 intdocs/design/target-pipelines/spirv.md#legalizeentrypointsforglsl-despite-the-namegeometry-shader-sysvals-glsl.slangmesh 着色器的输出只重声明gl_MeshPerVertexEXT/gl_MeshPerPrimitiveEXT中被使用的成员索引放入独立的gl_PrimitiveTriangleIndicesEXT数组docs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlingmesh-shader-output-block-glsl.slang含两个及以上 inout varying 参数的 ray-tracing 入口点参数合并为一个 Location 0 的IncomingRayPayloadKHRstruct 变量docs/design/target-pipelines/spirv.md#legalizeentrypointsforglsl-despite-the-nameraytracing-multi-payload-consolidation-spirv.slang未显式声明 location 的 ray payload、callable payload 与 hit-object attributes从各自类型独立计数器中取最低空闲编号跳过被显式占用的位置同上raytracing-payload-location-assignment-spirv.slang同一 nointerpolation fragment 输入上重复的GetAttributeAtVertex共享一个记忆化的pervertexEXT三元素数组声明时不带插值限定符同上pervertex-input-array-glsl.slangSV_Coverage成为gl_SampleMaskIn/gl_SampleMask的 0 号元素并做 uint/int 转换SV_InnerCoverage变为 bool 的gl_FragFullyCoveredNVSV_DepthGreaterEqual变为layout(depth_greater)同上fragment-coverage-depth-glsl.slangSV_StartVertexLocation/SV_StartInstanceLocation映射到 int 的gl_BaseVertex/gl_BaseInstance并强制#version 460带索引的SV_ClipDistanceN共享同一个gl_ClipDistance数组同上vertex-base-location-clip-distance-glsl.slangSV_Barycentrics依据字段的noperspective修饰符选择gl_BaryCoordEXT或gl_BaryCoordNoPerspEXT连同 fragment 的 layer/viewport/sample/shading-rate 映射同上fragment-barycentrics-layer-viewport-glsl.slangCUDA/OptiX 变长参数合法化slang-ir-legalize-varying-params.cpp行为声明文档锚点测试混合位宽的 OptiX ray payload 被打包进 32 位 payload 寄存器子字sub-word字段通过 shift/mask 的 read-modify-write 共享一个寄存器聚合类型逐元素递归64 位字段占用一对寄存器docs/design/target-pipelines/cuda.md#legalizeentrypointvaryingparamsforcudaoptix-payload-register-packing-cuda.slang聚合 hit-attribute struct 按声明顺序每次取一个 32 位optixGetAttribute槽float 槽带__int_as_float整型槽不加转换同上optix-hit-attribute-fetch-cuda.slangMetal 变长参数合法化slang-ir-legalize-varying-params.cpp行为声明文档锚点测试Metal fragment 系统值表把SV_ViewID映射到[[amplification_id]]、SV_DepthGreaterEqual映射到[[depth(greater)]]输入 struct 展平为每字段一个带属性的参数docs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlingmetal-fragment-sysvals.slangMetal 上SV_GroupIndex没有属性由[[thread_position_in_threadgroup]]与[numthreads]范围合成其余 vertex/compute id 直接映射同上metal-vertex-compute-sysvals.slangMetal amplification 获得合成的_slang_mesh_payload/_slang_mgp参数DispatchMesh变为set_threadgroups_per_gridmesh 阶段把输出收敛进一个metal::mesh对象同上metal-mesh-amplification.slangWGSL 变长参数合法化slang-ir-legalize-varying-params.cpp行为声明文档锚点测试WGSL fragment 表把SV_Depth映射到builtin(frag_depth)、SV_Coverage映射到标量builtin(sample_mask)SV_Target变为location(0)docs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlingwgsl-fragment-sysvals.slangWGSL 表标记为不支持的语义以 E55202 报告诊断信息在声明处给出小写化的语义名而不是静默丢弃同上wgsl-unsupported-system-value-diag.slang源码级纵深三个最具代表性的重写细节hull 阶段的 patch-constant 拼接最大的结构重写Vulkan 没有独立的 patch constant 函数细分控制着色器必须自己、且每个 patch 只算一次细分因子。因此合法化器把入口点的return重写为跳转到新的尾块该尾块发射OpControlBarrier控制屏障把调用 id 与 0 比较OpIEqual ... %int_0形成OpSelectionMerge守卫在true分支内调用[patchconstantfunc]传入入口点自己的InputPatch参数和从逐控制点输出数组物化出的OutputPatch。测试 hull-patch-constant-func-spirv.slang 通过 SPIR-V 断言精确固定了这一形态OpControlBarrier、OpIEqual守卫、TessLevelOuter/TessLevelInner的Patch装饰以及SV_OutputControlPointID复用为InvocationIdbuiltin 并兼任是否控制点 0的谓词。OptiX payload 的 32 位寄存器打包OptiX 没有 payload 内存只有最多 32 个不透明的 32 位寄存器。因此inoutpayload struct 会在入口/出口被逐字段拆解为optixGetPayload_N/optixSetPayload_N对optix-payload-register-packing-cuda.slang 在一个 payload 中同时压测了所有字段路径bool、uint8_t、half、int16_t是子字字段多个共享一个寄存器读侧用 shift 0xFF/0xFFFF掩码提取写侧做 read-modify-write 以保护相邻字段uint直接占一个寄存器float需要位转换bit-castfloat3、float2x2、float[2]逐元素递归寄存器连续且按声明顺序double、int64_t各占两个寄存器以(high 32) | low重组。测试断言每个字段落位的寄存器索引与精确的提取/重组表达式从而固定打包器执行的字节偏移算术——字段对齐或顺序的任何变化都会移动索引并使测试失败。Metal amplification/mesh 的重写Metal 的 mesh 管线与 HLSL 完全不同amplification 着色器是[[object]]函数通过object_data指针写 payload通过mesh_grid_properties对象启动 mesh 网格——而这两个参数在用户源码中都不存在。metal-mesh-amplification.slang 固定了合法化器定位DispatchMesh调用后合成_slang_mesh_payload、_slang_mgp两个参数并把调用改写为set_threadgroups_per_grid消费侧的 mesh 合法化器则把payload参数重定型为object_data指针把三个输出数组收敛为一个metal::meshVertex_0, Prim_0, 3U, 1U, metal::topology::triangle对象并驱动set_vertex/set_index/set_primitive调用。测试驱动方式每个测试文件的头部//TEST:指令给出了精确的 CLI 驱动方式全部经由slangc直接可达GLSL 文本输出//TEST:SIMPLE(filecheckGLSL):-target glsl -entry main -stage vertex如 varying-struct-flatten-glsl.slang配合//GLSL-DAG:///GLSL:断言SPIR-V 汇编//TEST:SIMPLE(filecheckSPIRV):-target spirv-asm -entry chit -stage closesthit配合//SPIRV:///SPIRV-DAG:断言如 raytracing-multi-payload-consolidation-spirv.slangCUDA 文本//TEST:SIMPLE(filecheckCUDA):-target cuda -entry chit -stage closesthitMetal / WGSL 文本-target metal/-target wgslMetal 用例用两段 filecheck 分别检查 amplificationAMP与 meshMESH两个入口点诊断测试//DIAGNOSTIC_TEST:SIMPLE(diagCHECK):-target wgsl ...断言错误码与消息文本如 wgsl-unsupported-system-value-diag.slang 断言E55202与system value semantic sv_clipdistance is not supported for the current target.。文本 GLSL 目标的输出还会经 glslang 往返校验-target spirv -emit-spirv-via-glslSPIR-V 目标用SLANG_RUN_SPIRV_VALIDATION1验证从而保证测试固定的输出不会被下游消费方拒绝。不可达unreachable缺口清单README 详尽列出了那些从 CLI 无法驱动或不应固化的代码路径这是表征测试方法论中知道什么不测同样重要的部分invokePathConstantFuncInHullShader的SV_PrimitiveID/SV_OutputControlPointID分支slang-ir-glsl-legalize.cpp:1305-1315对 CLI 输入是死代码。patch-constant 函数的参数不带IRVarLayout:1299的if (!layout)守卫先行触发每个标量系统值参数在命名分支被查阅前就以 E57002 拒绝。已记为 findingglsl-hull-patch-constant-system-value-param-rejected只有修复该问题后分支才可达。getOrCreateBuiltinParamForHullShader的参数已存在路径:1128-1146原则可达但仅与上一条联合出现——它按系统值语义查找已有入口点参数而它被调用的两个语义恰是 patch-constant 路径拒绝的那两个。合成路径:1148-1165已由 hull-patch-constant-func-spirv.slang 覆盖。legalizeDynamicResourcesForGLSL:529592 行可达但已被手写测试 tests/slang-extension/dynamic-resource-gl.slang 完全驱动重复添加无新增价值唯一遗漏的AmbiguousReferenceIr分支动态资源参数在重写后仍有存活使用无法构造出前端保留的、无.asT()的使用形态。getGLSLSystemValueInfo的nv_x_right/nv_viewport_mask:879-924NVX 多视图每视图属性路径。源码注释将其记录为已知不完整的 hackThis doesnt seem to work correctly on its own between hlsl/glsl固化当前输出会固化编译器自己都不认为正确正确与否未获证实的行为。SV_StencilRefGLSL与SV_CullDistanceGLSL可达且易驱动但发射的#extension指令格式错误按方法论记为 findingglsl-legalize-extension-name-missing-gl-prefix而非测试。同理包括mesh 图元输出中的SV_ShadingRateglsl-mesh-shading-rate-block-member-type、用户语义的 patch-constant 输出hull-patch-constant-user-output-location-collides、hull 的整段文本 GLSL 形态glsl-hull-patch-constant-func-void-return、domain 的文本 GLSL 形态glsl-domain-shader-patch-input-array-size、带两个inout参数的 callable 着色器callable-shader-multi-inout-uses-ray-payload-storage。这就是为什么对应测试改用 SPIR-V 分支或省略该字段。基类兜底diagnoseUnsupportedSystemVal/diagnoseUnsupportedUserValslang-ir-legalize-varying-params.cpp:1042/:1053仍为 0%。每个具体目标上下文Metal、WGSL、CUDA、CPU都用自带的诊断覆盖了不支持路径wgsl-unsupported-system-value-diag.slang 固定的正是 WGSL 的覆盖版本基类版本只会在某目标上下文不覆盖时触发而目前 CLI 无法触达任何这种目标。CUDA 上下文超尺寸 hit-attribute 分支:2383可达hit-attribute struct 超过 32 字节但它报的是E99999内部错误而非用户诊断因此记为 findingoptix-oversized-hit-attributes-internal-error而不固化。handleSpecialSystemValue基类版本:2833与assign(IRBuilder, LegalizedVaryingVal, IRInst*)重载:3186防御性的基类体断言或空操作每个有特殊系统值的目标都覆盖了它们。上一轮遗留的slang-ir-legalize-types.cpp缺口UseOfUninitializedOpaqueHandle、CooperativeMatrixUnsupportedCapture已不在本批范围测试束的coverage_targets仅含slang-ir-glsl-legalize.cpp与slang-ir-legalize-varying-params.cpp。文档缺口doc gaps测试驱动文档补全测试束还反向指出了三处官方设计文档的不足每条都附带了具体的补充建议是读者理解合法化器行为的重要旁证HLSL 到 Vulkan 的索引重定基未被文档化文档提到 GLSL 合法化器尽管名字如此也跑在 SPIR-V 分支上但未说明它执行索引重定基——SV_VertexID变成gl_VertexIndex - gl_BaseVertexSV_InstanceID同理从而让用户代码保持 HLSL 的按 draw 从零开始的语义。因此发射值不是裸的gl_VertexIndex。SV_到 gl_映射表缺失**文档未枚举系统值语义到 gl_* builtin 的映射SV_DispatchThreadID→gl_GlobalInvocationID、fragmentSV_Position→gl_FragCoord、SV_IsFrontFace→gl_FrontFacing等也未提及未知SV_*语义会以错误 49999unknown system-value semantic拒绝。对应的行为断言见 unknown-system-value-semantic.slang。hull 与 ray-tracing 的结构重写未记载docs/design/pipeline/05-ir-passes.md的入口点参数处理一节未描述 hull 入口点被重写为内联调用[patchconstantfunc]含屏障与单调用守卫、OutputPatch 从控制点输出数组物化这一全 pass 最大的结构重写也未描述consolidateRayTracingParameters/assignRayPayloadHitObjectAttributeLocations这对函数何时合并、ray/callable/hit-attribute 位置如何独立编号。漂移审查drift review机制测试束自带周期性的漂移审查纪律README 记录了本批次审查结果在d592afa9b9对照生成基准ef1068b548期间有 16 个提交触及被监视路径watched paths全部 23 个既有测试仍然通过基准提交后新增了一个来自coverage_targets的诊断 E55214经不可内联调用抵达的着色器终止内建函数它已有手写测试 tests/cuda/optix-terminate-nested-recursion.slang故未新增测试一处引用漂移被修正nv_x_right/nv_viewport_mask分支的行号从:876-905更正为:879-924其余行号引用:518的sv_clipdistance、:543的sv_coverage复查后仍精确窗口内落入的5ed83a468c#12182CUDA/OptiX callable 着色器支持对 ray-tracing 入口点参数诊断的影响已在docs/design/pipeline/04c-layout-ir中由文档声明及其测试重定向处理。结语这套测试束的工程价值从coverage/legalize这套测试可以提炼出 Slang 编译器测试基础设施的三种方法论表征而非规范固定当前行为、暴露回归、下游可接受性校验GLSL 过 glslang、SPIR-V 过验证器、可测性边界纪律无法触达或会固化缺陷行为的路径以 findings 形式记录而非强行断言。对于希望深入 Slang 入口点合法化逻辑的读者推荐按以下路径继续探索docs/design/pipeline/05-ir-passes.mdIR pass 总览与入口点参数处理、docs/design/target-pipelines/spirv.mddespite the name 的 GLSL 合法化说明、docs/design/target-pipelines/cuda.mdCUDA 变长参数合法化以及两个核心实现文件 source/slang/slang-ir-glsl-legalize.cpp 与 source/slang/slang-ir-legalize-varying-params.cpp。【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价