
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 個測試用例系統(tǒng)講解編譯器 IR 層面兩個核心合法化器——GLSL/SPIR-V 入口點合法化器source/slang/slang-ir-glsl-legalize.cpp與變長參數(shù)varying parameter合法化器source/slang/slang-ir-legalize-varying-params.cpp——的實際行為。讀者將理解從一條普通slangc命令行到最終著色器輸出的過程中入口點參數(shù)如何被展平、系統(tǒng)值語義system-value semantic如何映射為各目標平臺的 builtin、hull/mesh/ray-tracing 等特殊階段經(jīng)歷了怎樣的結(jié)構(gòu)重寫以及測試束如何通過 characterization表征方法把這些當前觀察到的行為固化為可回歸的斷言。測試束定位白盒表征測試而非規(guī)范coverage/legalize測試束的定位非常明確它是針對入口點/變長參數(shù)合法化器的白盒表征測試white-box characterization tests固定的是當前觀察到的合法化行為而非一份規(guī)范spec。所謂表征測試意味著這些測試不是為了定義正確的行為應該是什么而是把某個特定提交source_commit: 5634a0ea1b下、由 CLI 可達的入口點參數(shù)形態(tài)所產(chǎn)生的實際輸出逐字記錄pin下來一旦合法化器行為改變導致輸出變化測試就會失敗從而暴露回歸。測試束的關(guān)鍵元數(shù)據(jù)約束見 README.md包括不驗證、只固定映射遵循已文檔化的 GLSL/Vulkan、Metal、WGSL builtin 命名因此全部視為已驗證測試束內(nèi)沒有任何用例攜帶characterization-unverified標記下游可接受性對于文本 GLSL 目標生成的著色器還會通過 glslang 反向驗證-target spirv -emit-spirv-via-glsl對于 SPIR-V 目標用SLANG_RUN_SPIRV_VALIDATION1做校驗確保固定的輸出不會被下游消費方拒絕不可達缺口單獨處理凡是會產(chǎn)生下游消費者拒絕的輸出形態(tài)都被從測試中剔除并記錄為 findings詳見不可達缺口一節(jié)。三路并進的覆蓋策略README 記錄了測試束第二輪本批次補齊的三類缺口這也是理解 23 個測試文件組織邏輯的主線1. 沒有其他用例驅(qū)動的階段0% 行覆蓋率以下函數(shù)此前行覆蓋率全部為 0只有 hull、domain、geometry、mesh、per-vertex fragment 和 ray-tracing 入口點才能從一條普通slangc調(diào)用抵達它們因此每個函數(shù)配一個探針probe用例函數(shù)所在文件探針用例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 系統(tǒng)值表的長尾231 行未覆蓋getGLSLSystemValueInfo是整個文件中最大的單點缺口231 行未覆蓋。此前從未被觸達的語義恰好是那些 GLSL 形態(tài)不是簡單改名的條目數(shù)組值的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 的變長參數(shù)合法化器322 行未覆蓋emitOptiXPayloadRead/emitOptiXPayloadWrite兩者合計 322 行未覆蓋、Metal 和 WGSL 各自的getSystemValueInfo表、Metal 的 amplification/mesh 重寫。這些從純文本發(fā)射-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 變長參數(shù)合法化器把 struct 輸入/輸出拆成逐字段的 OpVariable 全局變量帶順序 Location 裝飾SV_Position路由到 BuiltIn Position同上varying-struct-flatten-spirv.slang四個 compute thread-id 系統(tǒng)值映射到 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 函數(shù)被拼接進入口點置于控制屏障之后、invocation id 0守衛(wèi)之內(nèi)接收 InputPatch 參數(shù)并物化 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變?yōu)間l_InvocationIDlayer/viewport 收窄為 intdocs/design/target-pipelines/spirv.md#legalizeentrypointsforglsl-despite-the-namegeometry-shader-sysvals-glsl.slangmesh 著色器的輸出只重聲明gl_MeshPerVertexEXT/gl_MeshPerPrimitiveEXT中被使用的成員索引放入獨立的gl_PrimitiveTriangleIndicesEXT數(shù)組docs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlingmesh-shader-output-block-glsl.slang含兩個及以上 inout varying 參數(shù)的 ray-tracing 入口點參數(shù)合并為一個 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從各自類型獨立計數(shù)器中取最低空閑編號跳過被顯式占用的位置同上raytracing-payload-location-assignment-spirv.slang同一 nointerpolation fragment 輸入上重復的GetAttributeAtVertex共享一個記憶化的pervertexEXT三元素數(shù)組聲明時不帶插值限定符同上pervertex-input-array-glsl.slangSV_Coverage成為gl_SampleMaskIn/gl_SampleMask的 0 號元素并做 uint/int 轉(zhuǎn)換SV_InnerCoverage變?yōu)?bool 的gl_FragFullyCoveredNVSV_DepthGreaterEqual變?yōu)閘ayout(depth_greater)同上fragment-coverage-depth-glsl.slangSV_StartVertexLocation/SV_StartInstanceLocation映射到 int 的gl_BaseVertex/gl_BaseInstance并強制#version 460帶索引的SV_ClipDistanceN共享同一個gl_ClipDistance數(shù)組同上vertex-base-location-clip-distance-glsl.slangSV_Barycentrics依據(jù)字段的noperspective修飾符選擇gl_BaryCoordEXT或gl_BaryCoordNoPerspEXT連同 fragment 的 layer/viewport/sample/shading-rate 映射同上fragment-barycentrics-layer-viewport-glsl.slangCUDA/OptiX 變長參數(shù)合法化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整型槽不加轉(zhuǎn)換同上optix-hit-attribute-fetch-cuda.slangMetal 變長參數(shù)合法化slang-ir-legalize-varying-params.cpp行為聲明文檔錨點測試Metal fragment 系統(tǒng)值表把SV_ViewID映射到[[amplification_id]]、SV_DepthGreaterEqual映射到[[depth(greater)]]輸入 struct 展平為每字段一個帶屬性的參數(shù)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參數(shù)DispatchMesh變?yōu)閟et_threadgroups_per_gridmesh 階段把輸出收斂進一個metal::mesh對象同上metal-mesh-amplification.slangWGSL 變長參數(shù)合法化slang-ir-legalize-varying-params.cpp行為聲明文檔錨點測試WGSL fragment 表把SV_Depth映射到builtin(frag_depth)、SV_Coverage映射到標量builtin(sample_mask)SV_Target變?yōu)閘ocation(0)docs/design/pipeline/05-ir-passes.md#entry-point-and-parameter-handlingwgsl-fragment-sysvals.slangWGSL 表標記為不支持的語義以 E55202 報告診斷信息在聲明處給出小寫化的語義名而不是靜默丟棄同上wgsl-unsupported-system-value-diag.slang源碼級縱深三個最具代表性的重寫細節(jié)hull 階段的 patch-constant 拼接最大的結(jié)構(gòu)重寫Vulkan 沒有獨立的 patch constant 函數(shù)細分控制著色器必須自己、且每個 patch 只算一次細分因子。因此合法化器把入口點的return重寫為跳轉(zhuǎn)到新的尾塊該尾塊發(fā)射OpControlBarrier控制屏障把調(diào)用 id 與 0 比較OpIEqual ... %int_0形成OpSelectionMerge守衛(wèi)在true分支內(nèi)調(diào)用[patchconstantfunc]傳入入口點自己的InputPatch參數(shù)和從逐控制點輸出數(shù)組物化出的OutputPatch。測試 hull-patch-constant-func-spirv.slang 通過 SPIR-V 斷言精確固定了這一形態(tài)OpControlBarrier、OpIEqual守衛(wèi)、TessLevelOuter/TessLevelInner的Patch裝飾以及SV_OutputControlPointID復用為InvocationIdbuiltin 并兼任是否控制點 0的謂詞。OptiX payload 的 32 位寄存器打包OptiX 沒有 payload 內(nèi)存只有最多 32 個不透明的 32 位寄存器。因此inoutpayload struct 會在入口/出口被逐字段拆解為optixGetPayload_N/optixSetPayload_N對optix-payload-register-packing-cuda.slang 在一個 payload 中同時壓測了所有字段路徑bool、uint8_t、half、int16_t是子字字段多個共享一個寄存器讀側(cè)用 shift 0xFF/0xFFFF掩碼提取寫側(cè)做 read-modify-write 以保護相鄰字段uint直接占一個寄存器float需要位轉(zhuǎn)換bit-castfloat3、float2x2、float[2]逐元素遞歸寄存器連續(xù)且按聲明順序double、int64_t各占兩個寄存器以(high 32) | low重組。測試斷言每個字段落位的寄存器索引與精確的提取/重組表達式從而固定打包器執(zhí)行的字節(jié)偏移算術(shù)——字段對齊或順序的任何變化都會移動索引并使測試失敗。Metal amplification/mesh 的重寫Metal 的 mesh 管線與 HLSL 完全不同amplification 著色器是[[object]]函數(shù)通過object_data指針寫 payload通過mesh_grid_properties對象啟動 mesh 網(wǎng)格——而這兩個參數(shù)在用戶源碼中都不存在。metal-mesh-amplification.slang 固定了合法化器定位DispatchMesh調(diào)用后合成_slang_mesh_payload、_slang_mgp兩個參數(shù)并把調(diào)用改寫為set_threadgroups_per_grid消費側(cè)的 mesh 合法化器則把payload參數(shù)重定型為object_data指針把三個輸出數(shù)組收斂為一個metal::meshVertex_0, Prim_0, 3U, 1U, metal::topology::triangle對象并驅(qū)動set_vertex/set_index/set_primitive調(diào)用。測試驅(qū)動方式每個測試文件的頭部//TEST:指令給出了精確的 CLI 驅(qū)動方式全部經(jīng)由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 目標的輸出還會經(jīng) glslang 往返校驗-target spirv -emit-spirv-via-glslSPIR-V 目標用SLANG_RUN_SPIRV_VALIDATION1驗證從而保證測試固定的輸出不會被下游消費方拒絕。不可達unreachable缺口清單README 詳盡列出了那些從 CLI 無法驅(qū)動或不應固化的代碼路徑這是表征測試方法論中知道什么不測同樣重要的部分invokePathConstantFuncInHullShader的SV_PrimitiveID/SV_OutputControlPointID分支slang-ir-glsl-legalize.cpp:1305-1315對 CLI 輸入是死代碼。patch-constant 函數(shù)的參數(shù)不帶IRVarLayout:1299的if (!layout)守衛(wèi)先行觸發(fā)每個標量系統(tǒng)值參數(shù)在命名分支被查閱前就以 E57002 拒絕。已記為 findingglsl-hull-patch-constant-system-value-param-rejected只有修復該問題后分支才可達。getOrCreateBuiltinParamForHullShader的參數(shù)已存在路徑:1128-1146原則可達但僅與上一條聯(lián)合出現(xiàn)——它按系統(tǒng)值語義查找已有入口點參數(shù)而它被調(diào)用的兩個語義恰是 patch-constant 路徑拒絕的那兩個。合成路徑:1148-1165已由 hull-patch-constant-func-spirv.slang 覆蓋。legalizeDynamicResourcesForGLSL:529592 行可達但已被手寫測試 tests/slang-extension/dynamic-resource-gl.slang 完全驅(qū)動重復添加無新增價值唯一遺漏的AmbiguousReferenceIr分支動態(tài)資源參數(shù)在重寫后仍有存活使用無法構(gòu)造出前端保留的、無.asT()的使用形態(tài)。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可達且易驅(qū)動但發(fā)射的#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 形態(tài)glsl-hull-patch-constant-func-void-return、domain 的文本 GLSL 形態(tài)glsl-domain-shader-patch-input-array-size、帶兩個inout參數(shù)的 callable 著色器callable-shader-multi-inout-uses-ray-payload-storage。這就是為什么對應測試改用 SPIR-V 分支或省略該字段?;惗档譫iagnoseUnsupportedSystemVal/diagnoseUnsupportedUserValslang-ir-legalize-varying-params.cpp:1042/:1053仍為 0%。每個具體目標上下文Metal、WGSL、CUDA、CPU都用自帶的診斷覆蓋了不支持路徑wgsl-unsupported-system-value-diag.slang 固定的正是 WGSL 的覆蓋版本基類版本只會在某目標上下文不覆蓋時觸發(fā)而目前 CLI 無法觸達任何這種目標。CUDA 上下文超尺寸 hit-attribute 分支:2383可達hit-attribute struct 超過 32 字節(jié)但它報的是E99999內(nèi)部錯誤而非用戶診斷因此記為 findingoptix-oversized-hit-attributes-internal-error而不固化。handleSpecialSystemValue基類版本:2833與assign(IRBuilder, LegalizedVaryingVal, IRInst*)重載:3186防御性的基類體斷言或空操作每個有特殊系統(tǒng)值的目標都覆蓋了它們。上一輪遺留的slang-ir-legalize-types.cpp缺口UseOfUninitializedOpaqueHandle、CooperativeMatrixUnsupportedCapture已不在本批范圍測試束的coverage_targets僅含slang-ir-glsl-legalize.cpp與slang-ir-legalize-varying-params.cpp。文檔缺口doc gaps測試驅(qū)動文檔補全測試束還反向指出了三處官方設(shè)計文檔的不足每條都附帶了具體的補充建議是讀者理解合法化器行為的重要旁證HLSL 到 Vulkan 的索引重定基未被文檔化文檔提到 GLSL 合法化器盡管名字如此也跑在 SPIR-V 分支上但未說明它執(zhí)行索引重定基——SV_VertexID變成gl_VertexIndex - gl_BaseVertexSV_InstanceID同理從而讓用戶代碼保持 HLSL 的按 draw 從零開始的語義。因此發(fā)射值不是裸的gl_VertexIndex。SV_到 gl_映射表缺失**文檔未枚舉系統(tǒng)值語義到 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 的結(jié)構(gòu)重寫未記載docs/design/pipeline/05-ir-passes.md的入口點參數(shù)處理一節(jié)未描述 hull 入口點被重寫為內(nèi)聯(lián)調(diào)用[patchconstantfunc]含屏障與單調(diào)用守衛(wèi)、OutputPatch 從控制點輸出數(shù)組物化這一全 pass 最大的結(jié)構(gòu)重寫也未描述consolidateRayTracingParameters/assignRayPayloadHitObjectAttributeLocations這對函數(shù)何時合并、ray/callable/hit-attribute 位置如何獨立編號。漂移審查drift review機制測試束自帶周期性的漂移審查紀律README 記錄了本批次審查結(jié)果在d592afa9b9對照生成基準ef1068b548期間有 16 個提交觸及被監(jiān)視路徑watched paths全部 23 個既有測試仍然通過基準提交后新增了一個來自coverage_targets的診斷 E55214經(jīng)不可內(nèi)聯(lián)調(diào)用抵達的著色器終止內(nèi)建函數(shù)它已有手寫測試 tests/cuda/optix-terminate-nested-recursion.slang故未新增測試一處引用漂移被修正nv_x_right/nv_viewport_mask分支的行號從:876-905更正為:879-924其余行號引用:518的sv_clipdistance、:543的sv_coverage復查后仍精確窗口內(nèi)落入的5ed83a468c#12182CUDA/OptiX callable 著色器支持對 ray-tracing 入口點參數(shù)診斷的影響已在docs/design/pipeline/04c-layout-ir中由文檔聲明及其測試重定向處理。結(jié)語這套測試束的工程價值從coverage/legalize這套測試可以提煉出 Slang 編譯器測試基礎(chǔ)設(shè)施的三種方法論表征而非規(guī)范固定當前行為、暴露回歸、下游可接受性校驗GLSL 過 glslang、SPIR-V 過驗證器、可測性邊界紀律無法觸達或會固化缺陷行為的路徑以 findings 形式記錄而非強行斷言。對于希望深入 Slang 入口點合法化邏輯的讀者推薦按以下路徑繼續(xù)探索docs/design/pipeline/05-ir-passes.mdIR pass 總覽與入口點參數(shù)處理、docs/design/target-pipelines/spirv.mddespite the name 的 GLSL 合法化說明、docs/design/target-pipelines/cuda.mdCUDA 變長參數(shù)合法化以及兩個核心實現(xiàn)文件 source/slang/slang-ir-glsl-legalize.cpp 與 source/slang/slang-ir-legalize-varying-params.cpp?!久赓M下載鏈接】slangMaking it easier to work with shaders項目地址: https://gitcode.com/GitHub_Trending/sl/slang創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考