@carbonenginejs/runtime-resource 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (541) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +32 -32
  3. package/README.md +129 -108
  4. package/dist/CjsMotherLode.js +1271 -1271
  5. package/dist/CjsResMan.js +3858 -3494
  6. package/dist/CjsResMan.js.map +1 -1
  7. package/dist/CjsResManFetchProvider.js +94 -94
  8. package/dist/CjsResManWorkQueue.js +301 -301
  9. package/dist/_virtual/_rollupPluginBabelHelpers.js +150 -150
  10. package/dist/format/CjsBlueReader.js +358 -358
  11. package/dist/format/CjsByteReader.js +310 -310
  12. package/dist/format/CjsByteWriter.js +242 -242
  13. package/dist/format/CjsFormat.js +223 -223
  14. package/dist/format/CjsFormatError.js +41 -41
  15. package/dist/format/CjsReader.js +22 -22
  16. package/dist/format/CjsResourceProbe.js +279 -279
  17. package/dist/format/CjsStringTable.js +268 -268
  18. package/dist/format/carbonEffect/CjsCarbonEffectReader.js +408 -361
  19. package/dist/format/carbonEffect/CjsCarbonEffectReader.js.map +1 -1
  20. package/dist/format/carbonEffect/CjsCarbonEffectWriter.js +373 -373
  21. package/dist/format/carbonEffect/buildCarbonEffectContainer.js +182 -0
  22. package/dist/format/carbonEffect/buildCarbonEffectContainer.js.map +1 -0
  23. package/dist/format/carbonEffect/carbonEffectBackendBlock.js +321 -427
  24. package/dist/format/carbonEffect/carbonEffectBackendBlock.js.map +1 -1
  25. package/dist/format/carbonEffect/carbonEffectRecords.js +1147 -955
  26. package/dist/format/carbonEffect/carbonEffectRecords.js.map +1 -1
  27. package/dist/format/carbonEffect/carbonEffectResourceTransform.js +197 -0
  28. package/dist/format/carbonEffect/carbonEffectResourceTransform.js.map +1 -0
  29. package/dist/format/compareUtf8.js +36 -36
  30. package/dist/format/effect/effectBodyInventory.js +146 -0
  31. package/dist/format/effect/effectBodyInventory.js.map +1 -0
  32. package/dist/format/effect/effectPermutationGraph.js +257 -257
  33. package/dist/format/effect/effectPermutationGraph.js.map +1 -1
  34. package/dist/format/effect/sha256.js +114 -114
  35. package/dist/format/index.js +11 -11
  36. package/dist/format/payloadContract.js +193 -193
  37. package/dist/formats/black/CjsBlackFormat.js +310 -292
  38. package/dist/formats/black/CjsBlackFormat.js.map +1 -1
  39. package/dist/formats/black/core/CjsBlackBinaryReader.js +260 -260
  40. package/dist/formats/black/core/CjsBlackPropertyReaders.js +448 -448
  41. package/dist/formats/black/core/CjsBlackReader.js +764 -764
  42. package/dist/formats/black/core/CjsBlackSchemaRegistry.js +540 -540
  43. package/dist/formats/black/core/black-schema-v1-2026-07-23.json.js +4 -4
  44. package/dist/formats/black/core/blackConstants.js +7 -7
  45. package/dist/formats/black/core/blackDefinitions.js +10 -10
  46. package/dist/formats/black/core/blackEnums.js +6 -6
  47. package/dist/formats/black/core/blackSchema.js +3 -3
  48. package/dist/formats/black/core/blackVersion.js +22 -22
  49. package/dist/formats/black/core/helpers.js +199 -199
  50. package/dist/formats/black/core/schema.js +4 -4
  51. package/dist/formats/black/index.js +2 -2
  52. package/dist/formats/bnk/CjsBnkFormat.js +175 -156
  53. package/dist/formats/bnk/CjsBnkFormat.js.map +1 -1
  54. package/dist/formats/bnk/core/busNodes.js +252 -0
  55. package/dist/formats/bnk/core/busNodes.js.map +1 -0
  56. package/dist/formats/bnk/core/effectNodes.js +147 -0
  57. package/dist/formats/bnk/core/effectNodes.js.map +1 -0
  58. package/dist/formats/bnk/core/eventAction.js +416 -305
  59. package/dist/formats/bnk/core/eventAction.js.map +1 -1
  60. package/dist/formats/bnk/core/globalSettings.js +215 -0
  61. package/dist/formats/bnk/core/globalSettings.js.map +1 -0
  62. package/dist/formats/bnk/core/graph.js +137 -137
  63. package/dist/formats/bnk/core/helpers.js +512 -480
  64. package/dist/formats/bnk/core/helpers.js.map +1 -1
  65. package/dist/formats/bnk/core/musicNodes.js +533 -509
  66. package/dist/formats/bnk/core/musicNodes.js.map +1 -1
  67. package/dist/formats/bnk/core/nodeBase.js +553 -532
  68. package/dist/formats/bnk/core/nodeBase.js.map +1 -1
  69. package/dist/formats/bnk/core/sfxNodes.js +632 -632
  70. package/dist/formats/bnk/core/soundbanksInfo.js +209 -209
  71. package/dist/formats/bnk/index.js +2 -2
  72. package/dist/formats/cmf/CjsCmfFormat.js +497 -497
  73. package/dist/formats/cmf/core/binary.js +194 -194
  74. package/dist/formats/cmf/core/buffers.js +237 -237
  75. package/dist/formats/cmf/core/constants.js +47 -47
  76. package/dist/formats/cmf/core/gr2Anim.js +453 -453
  77. package/dist/formats/cmf/core/helpers.js +318 -318
  78. package/dist/formats/cmf/core/pack.js +276 -276
  79. package/dist/formats/cmf/core/schema.js +374 -374
  80. package/dist/formats/cmf/core/shared.js +277 -277
  81. package/dist/formats/cmf/core/writer.js +571 -571
  82. package/dist/formats/cmf/index.js +2 -2
  83. package/dist/formats/dds/CjsDdsFormat.js +200 -200
  84. package/dist/formats/dds/core/bc6h.js +298 -298
  85. package/dist/formats/dds/core/bc7.js +272 -272
  86. package/dist/formats/dds/core/helpers.js +862 -862
  87. package/dist/formats/dds/index.js +2 -2
  88. package/dist/formats/dxbc/CjsDxbcFormat.js +142 -142
  89. package/dist/formats/dxbc/core/DxbcReader.js +266 -266
  90. package/dist/formats/dxbc/core/container.js +169 -169
  91. package/dist/formats/dxbc/core/decoder.js +789 -789
  92. package/dist/formats/dxbc/core/errors.js +19 -19
  93. package/dist/formats/dxbc/core/helpers.js +220 -220
  94. package/dist/formats/dxbc/core/opcodes.js +45 -45
  95. package/dist/formats/dxbc/core/program.js +91 -91
  96. package/dist/formats/dxbc/core/signature.js +172 -172
  97. package/dist/formats/dxbc/index.js +2 -2
  98. package/dist/formats/fbx/CjsFbxFormat.js +266 -266
  99. package/dist/formats/fbx/core/helpers.js +3932 -3932
  100. package/dist/formats/fbx/index.js +2 -2
  101. package/dist/formats/flac/CjsFlacFormat.js +142 -142
  102. package/dist/formats/flac/core/helpers.js +315 -315
  103. package/dist/formats/flac/index.js +2 -2
  104. package/dist/formats/gif/CjsGifFormat.js +141 -141
  105. package/dist/formats/gif/core/helpers.js +380 -380
  106. package/dist/formats/gif/index.js +2 -2
  107. package/dist/formats/gltf/CjsGltfFormat.js +290 -290
  108. package/dist/formats/gltf/core/helpers.js +307 -307
  109. package/dist/formats/gltf/core/json.js +79 -79
  110. package/dist/formats/gltf/core/parser.js +679 -679
  111. package/dist/formats/gltf/core/targets.js +173 -173
  112. package/dist/formats/gltf/index.js +2 -2
  113. package/dist/formats/gr2/CjsGr2Format.js +289 -289
  114. package/dist/formats/gr2/core/bitknit2.js +282 -282
  115. package/dist/formats/gr2/core/curves.js +1047 -1047
  116. package/dist/formats/gr2/core/gsf.js +72 -72
  117. package/dist/formats/gr2/core/helpers.js +352 -352
  118. package/dist/formats/gr2/core/json.js +622 -622
  119. package/dist/formats/gr2/core/oodle1.js +388 -388
  120. package/dist/formats/gr2/core/tangents.js +48 -48
  121. package/dist/formats/gr2/core/targets.js +361 -361
  122. package/dist/formats/gr2/index.js +2 -2
  123. package/dist/formats/hlsl/CjsHlslFormat.js +254 -254
  124. package/dist/formats/hlsl/core/HlslBinaryUtils.js +15 -15
  125. package/dist/formats/hlsl/core/HlslEffectReadError.js +19 -19
  126. package/dist/formats/hlsl/core/HlslEffectStateManager.js +130 -130
  127. package/dist/formats/hlsl/core/HlslRenderStateSetup.js +37 -37
  128. package/dist/formats/hlsl/core/HlslResourceSetDescription.js +94 -94
  129. package/dist/formats/hlsl/core/HlslShaderBytecode.js +44 -44
  130. package/dist/formats/hlsl/core/analysis.js +51 -51
  131. package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js +850 -781
  132. package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js.map +1 -1
  133. package/dist/formats/hlsl/core/detailMapFamily.js +128 -0
  134. package/dist/formats/hlsl/core/detailMapFamily.js.map +1 -0
  135. package/dist/formats/hlsl/core/helpers.js +270 -270
  136. package/dist/formats/hlsl/core/json.js +284 -284
  137. package/dist/formats/hlsl/core/localLightFamily.js +133 -0
  138. package/dist/formats/hlsl/core/localLightFamily.js.map +1 -0
  139. package/dist/formats/hlsl/core/metadata.js +327 -327
  140. package/dist/formats/hlsl/core/render-states.js +280 -280
  141. package/dist/formats/hlsl/core/tr2/HlslRenderContextEnum.js +43 -43
  142. package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +320 -314
  143. package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js.map +1 -1
  144. package/dist/formats/hlsl/core/tr2/resources/HlslShaderPermutation.js +33 -33
  145. package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js +416 -416
  146. package/dist/formats/hlsl/core/tr2/shader/HlslEffectConstant.js +40 -40
  147. package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js +62 -742
  148. package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js.map +1 -1
  149. package/dist/formats/hlsl/core/tr2/shader/HlslEffectLibrary.js +52 -52
  150. package/dist/formats/hlsl/core/tr2/shader/HlslEffectParameterAnnotation.js +38 -38
  151. package/dist/formats/hlsl/core/tr2/shader/HlslEffectResource.js +50 -50
  152. package/dist/formats/hlsl/core/tr2/shader/HlslEffectStageInput.js +86 -86
  153. package/dist/formats/hlsl/core/tr2/shader/HlslEffectTechnique.js +31 -31
  154. package/dist/formats/hlsl/core/tr2/shader/HlslPass.js +42 -42
  155. package/dist/formats/hlsl/core/tr2/shader/HlslSamplerDescription.js +55 -55
  156. package/dist/formats/hlsl/core/tr2/shader/HlslSamplerSetup.js +29 -29
  157. package/dist/formats/hlsl/core/tr2/shader/HlslShader.js +220 -220
  158. package/dist/formats/hlsl/core/tr2/shader/HlslShaderOption.js +30 -30
  159. package/dist/formats/hlsl/index.js +3 -3
  160. package/dist/formats/index.js +33 -31
  161. package/dist/formats/index.js.map +1 -1
  162. package/dist/formats/jpeg/CjsJpegFormat.js +212 -212
  163. package/dist/formats/jpeg/core/helpers.js +402 -402
  164. package/dist/formats/jpeg/core/jpeg.js +480 -480
  165. package/dist/formats/jpeg/index.js +2 -2
  166. package/dist/formats/mp3/CjsMp3Format.js +197 -197
  167. package/dist/formats/mp3/core/helpers.js +375 -375
  168. package/dist/formats/mp3/index.js +2 -2
  169. package/dist/formats/mp4/CjsMp4Format.js +197 -197
  170. package/dist/formats/mp4/core/helpers.js +484 -484
  171. package/dist/formats/mp4/index.js +2 -2
  172. package/dist/formats/obj/CjsObjFormat.js +253 -253
  173. package/dist/formats/obj/core/helpers.js +573 -573
  174. package/dist/formats/obj/core/json.js +64 -64
  175. package/dist/formats/obj/core/parser.js +321 -321
  176. package/dist/formats/obj/index.js +2 -2
  177. package/dist/formats/ogg/CjsOggFormat.js +143 -143
  178. package/dist/formats/ogg/core/helpers.js +410 -410
  179. package/dist/formats/ogg/core/imdct.js +178 -178
  180. package/dist/formats/ogg/core/vorbis.js +1017 -1017
  181. package/dist/formats/ogg/index.js +2 -2
  182. package/dist/formats/pickle/CjsPickleFormat.js +214 -0
  183. package/dist/formats/pickle/CjsPickleFormat.js.map +1 -0
  184. package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js +551 -0
  185. package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js.map +1 -0
  186. package/dist/formats/pickle/index.js +2 -0
  187. package/dist/formats/pickle/index.js.map +1 -0
  188. package/dist/formats/png/CjsPngFormat.js +201 -201
  189. package/dist/formats/png/core/helpers.js +635 -635
  190. package/dist/formats/png/index.js +2 -2
  191. package/dist/formats/red/CjsRedFormat.js +263 -263
  192. package/dist/formats/red/core/CjsRedReader.js +246 -246
  193. package/dist/formats/red/core/blackDefinitions.js +3 -3
  194. package/dist/formats/red/core/helpers.js +158 -158
  195. package/dist/formats/red/core/redGraph.js +71 -68
  196. package/dist/formats/red/core/redGraph.js.map +1 -1
  197. package/dist/formats/red/core/schema.js +4 -4
  198. package/dist/formats/red/index.js +2 -2
  199. package/dist/formats/stl/CjsStlFormat.js +365 -365
  200. package/dist/formats/stl/core/helpers.js +261 -261
  201. package/dist/formats/stl/core/json.js +51 -51
  202. package/dist/formats/stl/core/stl.js +642 -642
  203. package/dist/formats/stl/core/targets.js +173 -173
  204. package/dist/formats/stl/index.js +2 -2
  205. package/dist/formats/tga/CjsTgaFormat.js +197 -197
  206. package/dist/formats/tga/core/helpers.js +493 -493
  207. package/dist/formats/tga/index.js +2 -2
  208. package/dist/formats/wav/CjsWavFormat.js +198 -198
  209. package/dist/formats/wav/core/helpers.js +365 -365
  210. package/dist/formats/wav/index.js +2 -2
  211. package/dist/formats/webgl/CjsWebglFormat.js +199 -221
  212. package/dist/formats/webgl/CjsWebglFormat.js.map +1 -1
  213. package/dist/formats/webgl/core/buildGlslEffectContainer.js +70 -0
  214. package/dist/formats/webgl/core/buildGlslEffectContainer.js.map +1 -0
  215. package/dist/formats/webgl/core/effectPackage.js +900 -792
  216. package/dist/formats/webgl/core/effectPackage.js.map +1 -1
  217. package/dist/formats/webgl/core/errors.js +27 -27
  218. package/dist/formats/webgl/core/errors.js.map +1 -1
  219. package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js +2820 -2678
  220. package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js.map +1 -1
  221. package/dist/formats/webgl/core/glsl/DxbcGlslHelpers.js +89 -89
  222. package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js +486 -428
  223. package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js.map +1 -1
  224. package/dist/formats/webgl/core/glsl/packedLightFixups.js +98 -0
  225. package/dist/formats/webgl/core/glsl/packedLightFixups.js.map +1 -0
  226. package/dist/formats/webgl/core/glslBackendBlock.js +552 -0
  227. package/dist/formats/webgl/core/glslBackendBlock.js.map +1 -0
  228. package/dist/formats/webgl/core/glslBackendBodySet.js +243 -0
  229. package/dist/formats/webgl/core/glslBackendBodySet.js.map +1 -0
  230. package/dist/formats/webgl/core/{cewgCompleteness.js → glslEffectCompleteness.js} +85 -81
  231. package/dist/formats/webgl/core/glslEffectCompleteness.js.map +1 -0
  232. package/dist/formats/webgl/core/helpers.js +167 -306
  233. package/dist/formats/webgl/core/helpers.js.map +1 -1
  234. package/dist/formats/webgl/core/inspectGlslEffectContainer.js +122 -0
  235. package/dist/formats/webgl/core/inspectGlslEffectContainer.js.map +1 -0
  236. package/dist/formats/webgl/core/readGlslEffectContainer.js +303 -0
  237. package/dist/formats/webgl/core/readGlslEffectContainer.js.map +1 -0
  238. package/dist/formats/webgl/index.js +2 -2
  239. package/dist/formats/webgpu/CjsWebgpuFormat.js +357 -357
  240. package/dist/formats/webgpu/CjsWebgpuFormat.js.map +1 -1
  241. package/dist/formats/webgpu/core/buildCarbonEffectContainer.js +89 -197
  242. package/dist/formats/webgpu/core/buildCarbonEffectContainer.js.map +1 -1
  243. package/dist/formats/webgpu/core/{cewgpu/CewgpuContainer.js → carbonWebgpu/CarbonWebgpuContainer.js} +354 -368
  244. package/dist/formats/webgpu/core/carbonWebgpu/CarbonWebgpuContainer.js.map +1 -0
  245. package/dist/formats/webgpu/core/{cewgpu → carbonWebgpu}/containerViews.js +355 -355
  246. package/dist/formats/webgpu/core/carbonWebgpu/containerViews.js.map +1 -0
  247. package/dist/formats/webgpu/core/{cewgpu → carbonWebgpu}/validateContainer.js +90 -90
  248. package/dist/formats/webgpu/core/carbonWebgpu/validateContainer.js.map +1 -0
  249. package/dist/formats/webgpu/core/effectAnalysis.js +82 -82
  250. package/dist/formats/webgpu/core/effectBackendBodySet.js +289 -289
  251. package/dist/formats/webgpu/core/effectBackendBodySet.js.map +1 -1
  252. package/dist/formats/webgpu/core/errors.js +20 -20
  253. package/dist/formats/webgpu/core/errors.js.map +1 -1
  254. package/dist/formats/webgpu/core/helpers.js +443 -443
  255. package/dist/formats/webgpu/core/helpers.js.map +1 -1
  256. package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js +212 -212
  257. package/dist/formats/webgpu/core/ir/buildControlFlow.js +220 -220
  258. package/dist/formats/webgpu/core/ir/indexableTemps.js +137 -137
  259. package/dist/formats/webgpu/core/ir/inferValueTypes.js +449 -449
  260. package/dist/formats/webgpu/core/ir/lowerDxbcToIr.js +494 -494
  261. package/dist/formats/webgpu/core/ir/resolveRegisterFlow.js +177 -177
  262. package/dist/formats/webgpu/core/ir/sourceLanes.js +61 -61
  263. package/dist/formats/webgpu/core/packageEffect.js +381 -385
  264. package/dist/formats/webgpu/core/packageEffect.js.map +1 -1
  265. package/dist/formats/webgpu/core/packageEffectSelection.js +164 -164
  266. package/dist/formats/webgpu/core/packageEffectSelection.js.map +1 -1
  267. package/dist/formats/webgpu/core/packageMetadata.js +17 -17
  268. package/dist/formats/webgpu/core/schema.js +4 -4
  269. package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +263 -263
  270. package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js.map +1 -1
  271. package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js +172 -172
  272. package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +320 -320
  273. package/dist/formats/webgpu/core/wgsl/buildWgslSet.js.map +1 -1
  274. package/dist/formats/webgpu/core/wgsl/emitWgsl.js +356 -356
  275. package/dist/formats/webgpu/core/wgsl/hoistEscapingValues.js +77 -77
  276. package/dist/formats/webgpu/core/wgsl/lowerBindingLayout.js +451 -451
  277. package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js +735 -735
  278. package/dist/formats/webgpu/core/wgsl/lowerCreateHistogramsComputeProgram.js +457 -457
  279. package/dist/formats/webgpu/core/wgsl/lowerFragmentProgram.js +1572 -1572
  280. package/dist/formats/webgpu/core/wgsl/lowerMergeHistogramsComputeProgram.js +659 -659
  281. package/dist/formats/webgpu/core/wgsl/lowerParticleClearComputePrograms.js +734 -734
  282. package/dist/formats/webgpu/core/wgsl/lowerParticleEmitComputeProgram.js +583 -583
  283. package/dist/formats/webgpu/core/wgsl/lowerSkinVerticesComputeProgram.js +621 -621
  284. package/dist/formats/webgpu/core/wgsl/lowerSortComputeProgram.js +824 -824
  285. package/dist/formats/webgpu/core/wgsl/lowerSortInnerComputeProgram.js +697 -697
  286. package/dist/formats/webgpu/core/wgsl/lowerSortStepComputeProgram.js +559 -559
  287. package/dist/formats/webgpu/core/wgsl/lowerVertexProgram.js +1328 -1328
  288. package/dist/formats/webgpu/core/wgsl/particleEmitSemanticDigest.js +110 -110
  289. package/dist/formats/webgpu/core/wgsl/precisionControls.js +55 -55
  290. package/dist/formats/webgpu/core/wgsl/selectionPlans.js +717 -717
  291. package/dist/formats/webgpu/core/wgsl/uniformity.js +78 -78
  292. package/dist/formats/webgpu/core/wgsl/validateExactComputeIr.js +196 -196
  293. package/dist/formats/webgpu/core/wgsl/validateHandleOperand.js +37 -37
  294. package/dist/formats/webgpu/index.js +2 -2
  295. package/dist/formats/webm/CjsWebmFormat.js +197 -197
  296. package/dist/formats/webm/core/helpers.js +572 -572
  297. package/dist/formats/webm/index.js +2 -2
  298. package/dist/formats/webp/CjsWebpFormat.js +140 -140
  299. package/dist/formats/webp/core/helpers.js +237 -237
  300. package/dist/formats/webp/index.js +2 -2
  301. package/dist/formats/wem/CjsWemFormat.js +250 -250
  302. package/dist/formats/wem/core/bitStream.js +261 -261
  303. package/dist/formats/wem/core/codebookLibrary.js +164 -164
  304. package/dist/formats/wem/core/helpers.js +437 -437
  305. package/dist/formats/wem/core/packedCodebooksAotuv603.js +30 -30
  306. package/dist/formats/wem/core/ptadpcm.js +77 -77
  307. package/dist/formats/wem/core/resolve.js +121 -121
  308. package/dist/formats/wem/core/wemToOgg.js +485 -485
  309. package/dist/formats/wem/index.js +2 -2
  310. package/dist/formats/yaml/CjsYamlFormat.js +134 -134
  311. package/dist/formats/yaml/CjsYamlFormat.js.map +1 -1
  312. package/dist/formats/yaml/core/CjsYamlReader.js +400 -402
  313. package/dist/formats/yaml/core/CjsYamlReader.js.map +1 -1
  314. package/dist/formats/yaml/core/helpers.js +196 -170
  315. package/dist/formats/yaml/core/helpers.js.map +1 -1
  316. package/dist/formats/yaml/index.js +2 -2
  317. package/dist/index.js +64 -62
  318. package/dist/index.js.map +1 -1
  319. package/dist/resource/CjsLoadingObject.js +19 -0
  320. package/dist/resource/CjsLoadingObject.js.map +1 -0
  321. package/dist/resource/CjsResource.js +801 -797
  322. package/dist/resource/CjsResource.js.map +1 -1
  323. package/dist/resource/ResourceHandlerMode.js +14 -0
  324. package/dist/resource/ResourceHandlerMode.js.map +1 -0
  325. package/dist/resource/Tr2LightProfileRes.js +32 -32
  326. package/dist/resource/audio/AudioGeometryResData.js +47 -47
  327. package/dist/resource/audio/CjsAudioBufferRes.js +86 -86
  328. package/dist/resource/audio/CjsAudioRes.js +213 -213
  329. package/dist/resource/audio/index.js +4 -4
  330. package/dist/resource/geometry/MeshDecalData.js +37 -37
  331. package/dist/resource/geometry/MeshDecalLodData.js +34 -34
  332. package/dist/resource/geometry/TriGeometryRes.js +675 -675
  333. package/dist/resource/geometry/TriGeometryResAreaData.js +59 -59
  334. package/dist/resource/geometry/TriGeometryResJointData.js +38 -38
  335. package/dist/resource/geometry/TriGeometryResLodData.js +88 -88
  336. package/dist/resource/geometry/TriGeometryResMeshData.js +63 -63
  337. package/dist/resource/geometry/TriGeometryResSkeletonData.js +34 -34
  338. package/dist/resource/geometry/TriJointBinding.js +38 -38
  339. package/dist/resource/geometry/TriMorphTargetGeometryConstants.js +46 -46
  340. package/dist/resource/geometry/TriRtGeometryConstants.js +88 -88
  341. package/dist/resource/geometry/granny/GStateBindingCallbackData.js +31 -31
  342. package/dist/resource/geometry/granny/Tr2GrannyIntersectionResult.js +60 -60
  343. package/dist/resource/geometry/granny/Tr2GrannyStateRes.js +36 -36
  344. package/dist/resource/geometry/granny/TriGrannyRes.js +35 -35
  345. package/dist/resource/geometry/granny/enums.js +10 -10
  346. package/dist/resource/geometry/granny/index.js +6 -6
  347. package/dist/resource/geometry/index.js +17 -17
  348. package/dist/resource/index.js +54 -52
  349. package/dist/resource/index.js.map +1 -1
  350. package/dist/resource/resourceBoundary.js +64 -64
  351. package/dist/resource/shader/Tr2EffectRes.js +336 -431
  352. package/dist/resource/shader/Tr2EffectRes.js.map +1 -1
  353. package/dist/resource/shader/Tr2MaterialArea.js +31 -31
  354. package/dist/resource/shader/Tr2MaterialMesh.js +27 -27
  355. package/dist/resource/shader/Tr2MaterialRes.js +31 -31
  356. package/dist/resource/shader/Tr2Shader.js +283 -261
  357. package/dist/resource/shader/Tr2Shader.js.map +1 -1
  358. package/dist/resource/shader/Tr2ShaderPermutation.js +43 -43
  359. package/dist/resource/shader/index.js +17 -17
  360. package/dist/resource/shader/reflection/Tr2EffectConstant.js +143 -135
  361. package/dist/resource/shader/reflection/Tr2EffectConstant.js.map +1 -1
  362. package/dist/resource/shader/reflection/Tr2EffectDefine.js +30 -30
  363. package/dist/resource/shader/reflection/Tr2EffectDescription.js +114 -109
  364. package/dist/resource/shader/reflection/Tr2EffectDescription.js.map +1 -1
  365. package/dist/resource/shader/reflection/Tr2EffectLibrary.js +168 -147
  366. package/dist/resource/shader/reflection/Tr2EffectLibrary.js.map +1 -1
  367. package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +125 -105
  368. package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js.map +1 -1
  369. package/dist/resource/shader/reflection/Tr2EffectResource.js +120 -86
  370. package/dist/resource/shader/reflection/Tr2EffectResource.js.map +1 -1
  371. package/dist/resource/shader/reflection/Tr2EffectStageInput.js +372 -241
  372. package/dist/resource/shader/reflection/Tr2EffectStageInput.js.map +1 -1
  373. package/dist/resource/shader/reflection/Tr2EffectTechnique.js +78 -68
  374. package/dist/resource/shader/reflection/Tr2EffectTechnique.js.map +1 -1
  375. package/dist/resource/shader/reflection/Tr2Pass.js +168 -111
  376. package/dist/resource/shader/reflection/Tr2Pass.js.map +1 -1
  377. package/dist/resource/shader/reflection/carbonRecordFields.js +159 -0
  378. package/dist/resource/shader/reflection/carbonRecordFields.js.map +1 -0
  379. package/dist/resource/shader/reflection/shaderStage.js +22 -0
  380. package/dist/resource/shader/reflection/shaderStage.js.map +1 -0
  381. package/dist/resource/shader/sampler/Tr2SamplerSetup.js +135 -77
  382. package/dist/resource/shader/sampler/Tr2SamplerSetup.js.map +1 -1
  383. package/dist/resource/texture/CjsTextureArrayRes.js +472 -472
  384. package/dist/resource/texture/CjsTextureArrayResParameterProxy.js +179 -179
  385. package/dist/resource/texture/Tr2ImageRes.js +120 -120
  386. package/dist/resource/texture/Tr2TextureLodManager.js +82 -82
  387. package/dist/resource/texture/Tr2TextureLodUpdateRequest.js +37 -37
  388. package/dist/resource/texture/Tr2TexturePackChannel.js +37 -37
  389. package/dist/resource/texture/Tr2TexturePipeline.js +54 -54
  390. package/dist/resource/texture/Tr2TexturePipelineParams.js +34 -34
  391. package/dist/resource/texture/Tr2TexturePipelineStepCompress.js +40 -40
  392. package/dist/resource/texture/Tr2TexturePipelineStepGenerateMips.js +22 -22
  393. package/dist/resource/texture/Tr2TexturePipelineStepLimitSize.js +34 -34
  394. package/dist/resource/texture/Tr2TexturePipelineStepLoad.js +31 -31
  395. package/dist/resource/texture/Tr2TexturePipelineStepPack.js +43 -43
  396. package/dist/resource/texture/TriTextureRes.js +359 -359
  397. package/dist/resource/texture/index.js +15 -15
  398. package/dist/resource/texture/texturePipelineBehavior.js +308 -308
  399. package/dist/worker/CjsResManMainThreadLoader.js +89 -87
  400. package/dist/worker/CjsResManMainThreadLoader.js.map +1 -1
  401. package/dist/worker/CjsResManWorker.js +218 -217
  402. package/dist/worker/CjsResManWorker.js.map +1 -1
  403. package/dist/worker/CjsResManWorkerLoader.js +437 -434
  404. package/dist/worker/CjsResManWorkerLoader.js.map +1 -1
  405. package/dist/worker/protocol.js +12 -12
  406. package/docs/README.md +98 -98
  407. package/docs/architecture.md +118 -109
  408. package/docs/concepts/resource-lifecycle.md +226 -225
  409. package/docs/concepts/shader-resource-model.md +111 -114
  410. package/docs/concepts/writing-an-engine-adapter.md +115 -115
  411. package/docs/formats/README.md +138 -136
  412. package/docs/formats/carbon-effect-container.md +553 -452
  413. package/docs/formats/dxbc/README.md +68 -68
  414. package/docs/formats/dxbc/architecture.md +80 -80
  415. package/docs/formats/dxbc/reference/api.md +77 -77
  416. package/docs/formats/dxbc/reference/classes/README.md +9 -9
  417. package/docs/formats/dxbc/reference/decoded-output.md +122 -122
  418. package/docs/formats/gr2.md +160 -160
  419. package/docs/formats/hlsl/README.md +54 -54
  420. package/docs/formats/hlsl/architecture.md +65 -67
  421. package/docs/formats/hlsl/guides/hydrating-json-output.md +60 -62
  422. package/docs/formats/hlsl/guides/reading-effects.md +64 -64
  423. package/docs/formats/hlsl/reference/advanced-analysis.md +61 -66
  424. package/docs/formats/hlsl/reference/api.md +92 -98
  425. package/docs/formats/hlsl/reference/classes/README.md +11 -11
  426. package/docs/formats/hlsl/reference/json-graph.md +97 -100
  427. package/docs/formats/pickle.md +82 -0
  428. package/docs/formats/provenance.md +196 -196
  429. package/docs/formats/stl.md +37 -37
  430. package/docs/formats/webgl/README.md +115 -57
  431. package/docs/formats/webgl/architecture.md +69 -70
  432. package/docs/formats/webgl/carbon-constant-layouts.md +326 -326
  433. package/docs/formats/webgl/decl-io.md +1234 -1234
  434. package/docs/formats/webgl/memory-structured.md +890 -871
  435. package/docs/formats/webgl/reference/classes/README.md +9 -9
  436. package/docs/formats/webgl/texture-sample.md +964 -964
  437. package/docs/formats/webgpu/README.md +84 -84
  438. package/docs/formats/webgpu/architecture.md +95 -96
  439. package/docs/formats/webgpu/formats/{cewgpu.md → carbon-webgpu.md} +215 -216
  440. package/docs/formats/webgpu/guides/effect-packaging.md +189 -191
  441. package/docs/formats/webgpu/reference/api.md +196 -197
  442. package/docs/formats/webgpu/reference/classes/README.md +9 -9
  443. package/docs/formats/webgpu/reference/wgsl-compatibility.md +1546 -1543
  444. package/docs/formats/wwise.md +146 -85
  445. package/docs/reference/classes/README.md +35 -35
  446. package/docs/reference/classes/audio.md +30 -30
  447. package/docs/reference/classes/core.md +216 -206
  448. package/docs/reference/classes/dropped.md +46 -46
  449. package/docs/reference/classes/formats.md +944 -952
  450. package/docs/reference/classes/resources.md +456 -456
  451. package/docs/reference/classes/texture.md +26 -26
  452. package/docs/reference/events.md +117 -117
  453. package/docs/reference/motherlode-cache.md +275 -275
  454. package/docs/reference/queues.md +194 -110
  455. package/docs/reference/reload.md +107 -107
  456. package/docs/reference/texture-arrays.md +113 -113
  457. package/docs/reference/texture-pipeline.md +53 -53
  458. package/docs/reference/workers.md +142 -135
  459. package/docs/roadmap.md +150 -150
  460. package/format-notices/black/LICENSE +21 -21
  461. package/format-notices/black/NOTICE +47 -47
  462. package/format-notices/bnk/LICENSE +21 -21
  463. package/format-notices/bnk/NOTICE +21 -21
  464. package/format-notices/cmf/LICENSE +21 -21
  465. package/format-notices/cmf/NOTICE +36 -36
  466. package/format-notices/dds/LICENSE +21 -21
  467. package/format-notices/dds/NOTICE +14 -14
  468. package/format-notices/dxbc/LICENSE +21 -21
  469. package/format-notices/dxbc/NOTICE +20 -20
  470. package/format-notices/fbx/LICENSE +21 -21
  471. package/format-notices/fbx/NOTICE +14 -14
  472. package/format-notices/flac/LICENSE +21 -21
  473. package/format-notices/flac/NOTICE +14 -14
  474. package/format-notices/gif/LICENSE +21 -21
  475. package/format-notices/gif/NOTICE +14 -14
  476. package/format-notices/gltf/LICENSE +21 -21
  477. package/format-notices/gltf/NOTICE +27 -27
  478. package/format-notices/gr2/LICENSE +21 -21
  479. package/format-notices/gr2/NOTICE +60 -60
  480. package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -93
  481. package/format-notices/hlsl/LICENSE +21 -21
  482. package/format-notices/hlsl/NOTICE +25 -25
  483. package/format-notices/jpeg/LICENSE +21 -21
  484. package/format-notices/jpeg/NOTICE +14 -14
  485. package/format-notices/mp3/LICENSE +21 -21
  486. package/format-notices/mp3/NOTICE +14 -14
  487. package/format-notices/mp4/LICENSE +21 -21
  488. package/format-notices/mp4/NOTICE +14 -14
  489. package/format-notices/obj/LICENSE +21 -21
  490. package/format-notices/obj/NOTICE +26 -26
  491. package/format-notices/ogg/LICENSE +21 -21
  492. package/format-notices/ogg/NOTICE +28 -28
  493. package/format-notices/png/LICENSE +21 -21
  494. package/format-notices/png/NOTICE +14 -14
  495. package/format-notices/red/LICENSE +21 -21
  496. package/format-notices/red/NOTICE +31 -31
  497. package/format-notices/stl/LICENSE +21 -21
  498. package/format-notices/stl/NOTICE +21 -21
  499. package/format-notices/tga/LICENSE +21 -21
  500. package/format-notices/tga/NOTICE +14 -14
  501. package/format-notices/wav/LICENSE +21 -21
  502. package/format-notices/wav/NOTICE +14 -14
  503. package/format-notices/webgl/LICENSE +21 -21
  504. package/format-notices/webgl/NOTICE +35 -35
  505. package/format-notices/webgpu/LICENSE +21 -21
  506. package/format-notices/webgpu/NOTICE +31 -31
  507. package/format-notices/webm/LICENSE +21 -21
  508. package/format-notices/webm/NOTICE +14 -14
  509. package/format-notices/webp/LICENSE +21 -21
  510. package/format-notices/webp/NOTICE +14 -14
  511. package/format-notices/wem/LICENSE +57 -57
  512. package/format-notices/wem/NOTICE +33 -33
  513. package/format-notices/yaml/LICENSE +21 -21
  514. package/format-notices/yaml/NOTICE +44 -44
  515. package/package.json +63 -63
  516. package/dist/format/carbonEffect/carbonDescriptionFromPortable.js +0 -372
  517. package/dist/format/carbonEffect/carbonDescriptionFromPortable.js.map +0 -1
  518. package/dist/format/effect/effectReflectionPackage.js +0 -636
  519. package/dist/format/effect/effectReflectionPackage.js.map +0 -1
  520. package/dist/formats/hlsl/core/HlslReader.js +0 -16
  521. package/dist/formats/hlsl/core/HlslReader.js.map +0 -1
  522. package/dist/formats/hlsl/core/portableReflection.js +0 -848
  523. package/dist/formats/hlsl/core/portableReflection.js.map +0 -1
  524. package/dist/formats/hlsl/portable.js +0 -2
  525. package/dist/formats/hlsl/portable.js.map +0 -1
  526. package/dist/formats/webgl/core/cewg/CewgPackage.js +0 -340
  527. package/dist/formats/webgl/core/cewg/CewgPackage.js.map +0 -1
  528. package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js +0 -104
  529. package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js.map +0 -1
  530. package/dist/formats/webgl/core/cewg/binary.js +0 -19
  531. package/dist/formats/webgl/core/cewg/binary.js.map +0 -1
  532. package/dist/formats/webgl/core/cewgCompleteness.js.map +0 -1
  533. package/dist/formats/webgl/core/effectPackageValidation.js +0 -331
  534. package/dist/formats/webgl/core/effectPackageValidation.js.map +0 -1
  535. package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js.map +0 -1
  536. package/dist/formats/webgpu/core/cewgpu/containerViews.js.map +0 -1
  537. package/dist/formats/webgpu/core/cewgpu/validateContainer.js.map +0 -1
  538. package/dist/resource/shader/portable.js +0 -33
  539. package/dist/resource/shader/portable.js.map +0 -1
  540. package/docs/formats/hlsl/reference/portable-reflection.md +0 -141
  541. package/docs/formats/webgl/effect-reflection.md +0 -127
@@ -1,871 +1,890 @@
1
- # DXBC → GLSL ES 3.00 Lowering Spec: Memory-Structured Family
2
-
3
- Status: Evolving
4
- Scope: `@carbonenginejs/runtime-resource/formats/webgl` structured-memory lowering
5
- Audience: Shader translator maintainers and reviewers
6
- Summary: Defines bounded WebGL2 adaptations for DXBC structured-memory operations.
7
-
8
- Family key: `memory-structured`
9
- Target: GLSL ES 3.00 (WebGL2), vertex + pixel stages only (no compute, no SSBOs).
10
- Register model: every DXBC register is stored by the emitter as a `float` `vec4`; all
11
- integer/unsigned reads and writes go through `floatBitsToInt` / `floatBitsToUint` /
12
- `intBitsToFloat` / `uintBitsToFloat` at the use site, mirroring HLSLcc's own
13
- `GetBitcastOp` (`vendor/HLSLcc/src/toGLSLOperand.cpp:327-353`) and
14
- `AddOpAssignToDestWithMask` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:28-153`)
15
- machinery, which HLSLcc itself falls back to whenever static data-type analysis is
16
- unavailable (exactly the reflection-stripped situation this fork runs in per
17
- `vendor/HLSLcc/CARBONENGINEJS-FORK.md:34-52`).
18
-
19
- Corpus counts (450k-instruction sweep, 1611 EVE Online DX11 effects):
20
-
21
- | Opcode | Count | Stage reality |
22
- |---|---:|---|
23
- | `ld_structured` | 4014 | vs (BoneTransforms skinning) + ps (LightBuffer/LightIndexBuffer-style tbuffer reads) |
24
- | `store_structured` | 930 | compute-only in D3D11 (requires a UAV write target); **not observed as reachable in vs/ps stages actually shipped to WebGL2** — see per-opcode note |
25
- | `store_uav_typed` | 642 | compute-only in practice for this corpus (UAV write) |
26
- | `sync` | 183 | compute-only (`sync` only has meaning with `dcl_thread_group`) |
27
- | `ld_raw` | 54 | no confirmed vs/ps corpus example found (see per-opcode note); same SSBO problem as `ld_structured` if it does appear in vs/ps |
28
- | `store_raw` | 54 | compute-only in practice (RWByteAddressBuffer write) |
29
- | `atomic_iadd` | 27 | **confirmed present in a pixel shader** (`lensflareoccludert.sm_depth`, `stageName: "pixel"` in `dx11-instruction-coverage.json`'s `initialCandidateOpcodeExamples`) — not compute-only, see per-opcode note |
30
- | `imm_atomic_iadd` | 24 | compute-only (UAV atomic with previous-value return) |
31
- | `ld_uav_typed` | 18 | compute-only in this corpus — sampled instance is `measureexposure.sm_depth` (tone-mapping luminance compute pass), **not** `lensflareoccludert` (that file's confirmed opcode is `atomic_iadd`/`dcl_unordered_access_view_typed`, per `TRANSPILING-GAPS.md:100-114`); see per-opcode note |
32
- | `imm_atomic_exch` | 9 | compute-only |
33
- | `atomic_umax` | 6 | compute-only |
34
- | `atomic_umin` | 3 | compute-only |
35
- | `bufinfo` | 0 | not observed in this corpus; specified for completeness only |
36
-
37
- **Central WebGL2 constraint** (governs every opcode below): GLSL ES 3.00 has **no
38
- shader storage buffers** (`buffer` blocks require `#version 310 es` or GL 4.3+), **no
39
- image load/store types** (`image2D`/`imageLoad`/`imageStore` require ES 3.10+), and
40
- **no atomic-memory built-ins outside compute shaders** (`atomicAdd`/`imageAtomicAdd`
41
- etc. and `barrier()`/`memoryBarrier()` are ES 3.10 compute-shader built-ins, not part
42
- of the ES 3.00 vertex/fragment built-in set). Every HLSLcc GLSL template shown below
43
- is therefore **reference material for what desktop/Vulkan/Metal HLSLcc emits**, not
44
- directly compilable WebGL2 output. The one opcode with a proven, shipping WebGL2
45
- lowering is `ld_structured` restricted to the `BoneTransforms` skinning case, via the
46
- package-time `cb3` rewrite described in its section below.
47
-
48
- ---
49
-
50
- ## Shared machinery referenced by this family
51
-
52
- - `HaveUnsignedTypes(eLang)` and `HaveBitEncodingOps(eLang)`
53
- (`vendor/HLSLcc/src/internal_includes/languages.h:156-180`) both return `1` for
54
- every target except `LANG_ES_100`/`LANG_120`. `LANG_ES_300` (this project's
55
- target) has unsigned integer types and bit-encoding intrinsics
56
- (`floatBitsToInt`/`floatBitsToUint`/`intBitsToFloat`/`uintBitsToFloat`) available,
57
- so all the `TO_FLAG_UNSIGNED_INTEGER` / bitcast branches below are live for our
58
- target.
59
- - `AddAssignToDest` / `AddAssignPrologue`
60
- (`vendor/HLSLcc/src/toGLSLInstruction.cpp:155-171`) write the destination operand,
61
- the write mask, `= `, and the correct number of constructor/bitcast open-parens;
62
- `AddAssignPrologue` closes them and appends `;\n`. This is the generic
63
- "assign-with-implicit-bitcast" pattern the emitter must reproduce for `ld_structured`,
64
- `ld_raw`, `ld_uav_typed`, and `bufinfo`.
65
- - `_sat` (saturate) is applied **generically, after the main switch**, only to
66
- operand 0 (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4821-4844`): it re-clamps
67
- `dest = clamp(dest, 0.0, 1.0)` (with an Adreno `min(max(dest,0.0),1.0)` workaround
68
- path gated behind `#ifdef UNITY_ADRENO_ES3`, since `eTargetLanguage == LANG_ES_300`
69
- triggers the workaround branch). This only matters for opcodes that write a
70
- register destination — i.e. `ld_structured`, `ld_raw`, `ld_uav_typed`, `bufinfo`,
71
- `imm_atomic_*` (previous-value destination). Store/`sync`/non-`imm_` atomics have
72
- no float destination and DXBC does not encode `_sat` for them in practice.
73
- - Structured/raw buffer declaration (`DeclareBufferVariable`,
74
- `vendor/HLSLcc/src/toGLSLDeclaration.cpp:1027-1092`) is the HLSLcc reference
75
- declaration these instructions index into:
76
- ```glsl
77
- struct t0_type { uint[<stride/4>] value; };
78
- layout(std430, binding = N) readonly buffer t0 { t0_type t0_buf[]; };
79
- ```
80
- (raw buffers use `uint t0_buf[]` / `int t0_buf[]` directly, no wrapper struct,
81
- selected by `HaveUnsignedTypes`). This declaration is unusable in GLSL ES 3.00 —
82
- documented here only because the per-instruction `t0_buf[...]` indexing expression
83
- it feeds is the exact text pattern the package-time `cb3` rewrite (see
84
- `ld_structured`) pattern-matches against.
85
-
86
- ---
87
-
88
- ## `ld_structured` (4014 instances) — highest priority in this family
89
-
90
- ### Semantics
91
- Loads a structured-buffer element: given a structure index (operand 1) and a
92
- byte offset within the structure (operand 2), reads one or more 32-bit components
93
- from resource operand 3 (a `t#`/`u#` structured buffer) into the destination
94
- register, per D3D11 `ld_structured` semantics (index-then-byte-offset addressing
95
- into an array of fixed-stride structures).
96
-
97
- ### GLSL lowering — A. HLSLcc reference (desktop/Vulkan/Metal SSBO path)
98
- `TranslateShaderStorageLoad`, case `OPCODE_LD_STRUCTURED`
99
- (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1585-1683`, dispatched at
100
- `toGLSLInstruction.cpp:4256-4264`). Operands: `psDest=asOperands[0]`,
101
- `psSrcAddr=asOperands[1]` (struct index), `psSrcByteOff=asOperands[2]` (byte
102
- offset), `psSrc=asOperands[3]` (resource).
103
-
104
- For each destination component `c` present in the destination write mask:
105
- ```glsl
106
- <bitcast_open><resourceName>_buf[<structIndexExpr>].value[(<byteOffExpr> >> 2u) + <swz>u]<bitcast_close>
107
- ```
108
- where `<swz>` is `psSrc->aui32Swizzle[c]` if the resource operand carries an
109
- explicit swizzle (`OPERAND_4_COMPONENT_SWIZZLE_MODE`), else `c` itself
110
- (`toGLSLInstruction.cpp:1673`) — i.e. the *resource* operand's own swizzle can
111
- remap which dword of the structure element component `c` reads from. All such
112
- per-component expressions are joined by `AddAssignToDest`/constructor into:
113
- ```glsl
114
- dest.mask = <ctor>(comp0, comp1, ...);
115
- ```
116
- (`toGLSLInstruction.cpp:1623-1682`).
117
-
118
- `<bitcast_open>`/`<bitcast_close>` depend on `destDataType = psDest->GetDataType()`
119
- (`toGLSLInstruction.cpp:1642-1654`):
120
- - `SVT_FLOAT` → `uintBitsToFloat(...)` (since `HaveBitEncodingOps` is true for ES
121
- 3.00); the code falls back to `float(...)` only for pre-bit-encoding targets.
122
- - `SVT_INT`/`SVT_INT16`/`SVT_INT12` → `int(...)`.
123
- - `SVT_UINT` → no wrapper at all (`addedBitcast` stays `0`) because the backing
124
- `t0_type.value` array element type is always `uint` — "always uint array atm"
125
- (`toGLSLInstruction.cpp:1641`).
126
-
127
- The struct-index operand is translated with **both** `TO_FLAG_UNSIGNED_INTEGER |
128
- TO_FLAG_INTEGER` set simultaneously (`toGLSLInstruction.cpp:1664`) — reproduce
129
- this by picking whichever the index operand's own declared type implies (uint by
130
- default on ES 3.00). The byte-offset operand's flag (`srcOffFlag`) is
131
- `TO_FLAG_UNSIGNED_INTEGER` unless the target lacks unsigned types or the operand's
132
- own `SVT_INT`/`SVT_INT16`/`SVT_INT12` type forces `TO_FLAG_INTEGER`
133
- (`toGLSLInstruction.cpp:1618-1621`); when unsigned, both the `>> 2` and the `+
134
- <swz>` component addend get a trailing `u` suffix (`toGLSLInstruction.cpp:1669-1675`).
135
-
136
- ### GLSL lowering — B. WebGL2 `cb3` joint-matrix rewrite contract (the shipping path)
137
- This is the **only** `ld_structured` lowering this emitter must actually produce
138
- runnable WebGL2 GLSL for, restricted to the `BoneTransforms` skinning case
139
- (vertex stage). It is a two-stage pipeline:
140
-
141
- 1. Emit HLSLcc's reference SSBO GLSL exactly as in section A (this project's
142
- HLSLcc fork already tolerates missing `RDEF` bindings for
143
- `dcl_resource_structured` by falling back to the DXBC declaration's encoded
144
- stride — see `CARBONENGINEJS-FORK.md:41-44` and
145
- `TRANSPILING-GAPS.md:51-54`), producing text of the exact shape:
146
- ```glsl
147
- struct t0_type { uint[1] value; };
148
- layout(std430, binding = 0) readonly buffer t0 { t0_type t0_buf[]; };
149
- ...
150
- dest = vec4(uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 0]),
151
- uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 1]),
152
- uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 2]),
153
- uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 3]));
154
- ```
155
- Verified against an actual generated fixture
156
- (`../shaderdiscovery/artifacts/ab-shader-set/work/skinned_fxdirectionalv5/skinned_fxdirectionalv5.sm_hi.dxbc_29291f5662ed6781.vertex.es300.glsl:60-64`):
157
- all four components of one row share the **same** byte offset (row 0 uses
158
- `0`, row 1 uses `16`, row 2 uses `32` — i.e. the row's base byte offset, not
159
- a per-component offset of `0/4/8/12`), differing only in the trailing
160
- `+ 0/1/2/3` dword index, and **without** a `u` suffix on either the shift or
161
- the addend. The missing `u` is not a formatting nit: in this corpus the
162
- byte-offset operand is declared `SVT_INT` (not `SVT_UINT`), so
163
- `srcOffFlag` resolves to `TO_FLAG_INTEGER`
164
- (`toGLSLInstruction.cpp:1618-1621`), which suppresses the `u` suffix
165
- entirely (see `printImmediate32`, `toGLSLOperand.cpp:371-387` vs. `388-395`).
166
- This also matters functionally: `lowerStructuredBoneLoad`'s regex
167
- (`packageTr2WebglEffect.js:875`) matches literal `(\d+)\s*>>\s*2\s*\)` with
168
- no `u` tolerance, and its 4-component agreement check requires all four
169
- loads to share one `byteOffset` — a per-component-varying offset of
170
- `0/4/8/12` would both fail to match the regex *and* fail the "same
171
- byteOffset" agreement check, silently no-opping the rewrite. The previous
172
- worked example here was internally inconsistent with the very rewrite
173
- contract it was illustrating.
174
- 2. A package-time rewrite pass (`scripts/packageTr2WebglEffect.js`,
175
- functions `lowerWebgl2SkinningAbi` at lines 826-864 and
176
- `lowerStructuredBoneLoad` at lines 873-902) runs over that generated GLSL text
177
- and performs, **in this exact order**:
178
- 1. Strip the `#ifdef GL_ARB_shader_storage_buffer_object` /
179
- `GL_ARB_shader_image_load_store` extension guard blocks (regexes at
180
- `packageTr2WebglEffect.js:832-833`).
181
- 2. Strip the `struct t0_type { uint[1] value; };` declaration (regex at
182
- `packageTr2WebglEffect.js:834`, matches only the 1-word/4-byte stride
183
- shape).
184
- 3. Strip the `layout(std430, binding = 0) readonly buffer t0 { t0_type
185
- t0_buf[]; };` declaration (regex at `packageTr2WebglEffect.js:835`).
186
- 4. Grow the vertex stage's `ConstantBuffer3` (`cb3`) declaration to
187
- `vec4 data[max(existingSize, 200)]` (`packageTr2WebglEffect.js:836-839`)
188
- this is where `JointMat` lives at `cb3.data[26..199]` per the ccpwgl runtime
189
- ABI (`cb3[26..199]`, 58 joints × 12 floats = 696 floats,
190
- `AGENT-FINDINGS/decisions/016-cewg-skinning-abi-lowering-for-ccpwgl-2026-06-30.md`
191
- and `015-joint-matrix-jointmat-findings-ccpwgl-runtime-truth.md`).
192
- 5. Convert `uvec4`/`ivec4` (or `uvec2/3`, `ivec2/3`) `in_BLENDINDICES<n>` vertex
193
- inputs to plain `vec<N>` (regex at `packageTr2WebglEffect.js:840-843`)
194
- ccpwgl binds GR2 mesh blend indices as float attributes via
195
- `vertexAttribPointer`, not `vertexAttribIPointer`
196
- (`AGENT-FINDINGS/decisions/028-cewg-skinned-blend-index-abi-lowering.md`).
197
- 6. Strip the DX11 global bone-offset add HLSLcc emits when combining
198
- `in_BLENDINDICES0` with a `cb3.data[26]` offset uniform (two regex forms at
199
- `packageTr2WebglEffect.js:845-852`, covering both the scalar `int(...) +
200
- floatBitsToInt(cb3.data[26].x)` shape and the vector `(i)uvec/ivec(...) +
201
- floatBitsToInt(cb3.data[26].<swz>)` shape) ccpwgl's `cb3.data[26]` slot is
202
- reused for `JointMat`, not the native bone-ring-buffer offset, so this add
203
- must be removed entirely rather than merely rewired.
204
- 7. Rewrite each 4-component `t0_buf[...]` row-load expression
205
- (`vec4(t0_buf[idx].value[(byteOff>>2)+0], ...)`, all 4 components required,
206
- `lowerStructuredBoneLoad`) into:
207
- ```glsl
208
- cb3.data[26 + (<idx>) * 3 + <row>]
209
- ```
210
- where `<row> = floor(byteOff / 16)` and must be in `{0,1,2}` (a `Float4x3`
211
- bone matrix is 3 `vec4` rows); if any of the 4 component sub-expressions
212
- disagree on `idx`/`byteOff`, or `row` falls outside `0..2`, or the swizzle
213
- is anything but the identity `xyzw`/`.xyzw` is stripped when default,
214
- **the rewrite silently no-ops and leaves the un-lowered `t0_buf` text in
215
- place** (`packageTr2WebglEffect.js:886,890,895,898` all `return match`) —
216
- this is a silent-failure edge case the implementing engineer must guard
217
- against (add a diagnostic) rather than trust to fail loudly.
218
- 8. If any rewrite happened, inject a `// CEWG: BoneTransforms lowered to cb3
219
- JointMat rows.` marker comment after `#version 300 es`
220
- (`packageTr2WebglEffect.js:859-861`).
221
-
222
- ### GLSL lowering C. `ld_structured` in pixel stage / non-skinning resources
223
- The corpus also uses `ld_structured` on `t#` "packed tbuffer" resources unrelated
224
- to skinning e.g. `LightBuffer`/`LightIndexBuffer` reads in pixel shaders such as
225
- `decalcylindricv5.sm_depth` (`AGENT-FINDINGS/decisions/005-structured-resource-only-opcodes-2026-06-26.md`).
226
- **No `cb3`-style *functional* ABI rewrite exists for these** they hit the same
227
- SSBO-unavailability wall as section A. The emitter's default path lowers them to
228
- pixel `usampler2D` data textures (see `DxbcGlslEmitter.js` `dcl_resource_structured`
229
- pixel branch), which compiles but consumes a texture unit each; on real drivers
230
- the `_depth` quad variants overflow `MAX_TEXTURE_IMAGE_UNITS`(16).
231
-
232
- **Resolution (2026-07-08)stub, not rewrite.** Since CEWG does not support this
233
- tiled lighting, the packager can DROP it instead of lowering it. Run
234
- `packageTr2WebglEffect.js --stub-light-resources`: it resolves the light resource
235
- names (`LightBuffer`, `LightIndexBuffer`, `LightProfileArray`) to `t#` registers
236
- from the Carbon `.sm` reflection (RDEF is stripped, so names live only there —
237
- and the registers vary per permutation, so this is name-driven, not fixed to
238
- sb11/sb12/s13) and passes them to `emitGlsl` as `stubResourceRegisters`. The
239
- emitter then drops their decl+binding and lowers reads to `uintBitsToFloat(0u)`
240
- (structured) / `vec4(0.0)` (sampled) zeroing the per-tile light count makes the
241
- light loop dead. The packager also strips those `resource` bindings from the
242
- manifest JSON (`stripLightResourcesFromManifest`) so the CEWG runtime does not
243
- synthesize a texture def (glType 0 "Invalid shader texture definition") for the
244
- now-undeclared light buffers. Opt-in, default off; every other package is
245
- unchanged. A functional light constant-buffer path remains possible but was not
246
- built.
247
-
248
- Tested by `test/glsl-emitter.test.js` (synthetic pixel shaders with a structured
249
- buffer / sampler2DArray: declared by default, dropped + no binding when the
250
- register is in `stubResourceRegisters`, and only listed registers dropped) and
251
- `test/stub-light-resources.test.js` (the packager's `resolveStubLightRegisters`
252
- name→register resolution and `stripLightResourcesFromManifest` manifest filter,
253
- in `scripts/stubLightResources.js`).
254
-
255
- ### Type rules
256
- - Struct index operand: read as int/uint (both flags set in HLSLcc; pick uint by
257
- default for ES 3.00).
258
- - Byte-offset operand: uint unless the operand's own declared type is signed int.
259
- - Result component type follows the *destination* register's inferred type
260
- (float `uintBitsToFloat`, int `int(...)`, uint passthrough), **not** the
261
- source resource's declared return type this is purely dest-driven, matching
262
- the "everything is `float vec4`, bitcast at use" register model this project
263
- already commits to.
264
- - This is a data-movement instruction, not a comparison it does not produce a
265
- 0xFFFFFFFF/0 mask.
266
-
267
- ### Helpers needed
268
- - `structuredLoadComponent(bufName, structIndex, byteOffset, component, destType)`
269
- reference-only (HLSLcc SSBO shape), needed if the emitter ever targets a
270
- non-WebGL2 backend or documents the pre-rewrite intermediate form.
271
- - `lowerBoneTransformsToCb3` (package-time text pass; port of
272
- `lowerWebgl2SkinningAbi` + `lowerStructuredBoneLoad`).
273
- - `lowerBlendIndicesToFloatAttribute` (package-time text pass, part of the same
274
- rewrite; port of the `in_BLENDINDICES` regex).
275
- - `refuseNonSkinningStructuredLoad` (detection helper for section C).
276
-
277
- ### Edge cases
278
- - NaN/inf: none introduced by the load itself; `uintBitsToFloat` is a pure
279
- bit-reinterpret, so any NaN bit pattern already in the buffer round-trips as
280
- NaN.
281
- - The resource-operand swizzle indirection (`psSrc->aui32Swizzle[component]`)
282
- means component `c` of the destination is not guaranteed to read structure
283
- dword `c` verify this against real corpus DXBC before assuming identity
284
- swizzle always holds.
285
- - The row/index-agreement check in `lowerStructuredBoneLoad` requires **all 4**
286
- components to share the same `idx`/`byteOffset`; a destination write mask
287
- narrower than `.xyzw` (e.g. `.xy`) will not match the 4-load regex and will
288
- silently fail to rewrite this is plausible for shaders that only need part of
289
- a bone row and needs explicit test coverage.
290
- - `bSaturate` on `ld_structured` is legal per the generic post-switch handling
291
- but is not expected to appear in real bone/light-buffer loads; still must be
292
- implemented for correctness if the corpus is ever re-scanned with `_sat`
293
- detection.
294
-
295
- ### WebGL2 notes
296
- - SSBOs (`buffer` blocks) do not exist in GLSL ES 3.00 at all; section A's
297
- output is fundamentally uncompilable in WebGL2 and must never reach the
298
- final package unless rewritten by section B.
299
- - `layout(std430, binding=N)` is likewise unavailable in ES 3.00 (`std430` and UBO
300
- binding indices exist, but SSBO binding does not).
301
-
302
- ### Confidence
303
- **High** for the `BoneTransforms`/`cb3` path (validated end-to-end:
304
- `336/336` and `240/240` WebGL2 program links per
305
- `TRANSPILING-GAPS.md:60-63` and `016-cewg-skinning-abi-lowering-for-ccpwgl-2026-06-30.md`).
306
- **Low** for non-skinning `ld_structured` in pixel stages no validated WebGL2
307
- lowering exists; treat as blocked pending a decision.
308
-
309
- ---
310
-
311
- ## `store_structured` (930 instances)
312
-
313
- ### Semantics
314
- Writes one or more 32-bit components of a structured-buffer element addressed by
315
- a structure index and byte offset, per D3D11 `store_structured` (the inverse of
316
- `ld_structured`; only valid against a UAV, since D3D11 `structured buffer`
317
- read-only resources cannot be written).
318
-
319
- ### GLSL lowering
320
- `TranslateShaderStorageStore`, case `OPCODE_STORE_STRUCTURED`
321
- (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1500-1583`, dispatched at
322
- `toGLSLInstruction.cpp:4348-4357`). Operands: `psDest=asOperands[0]` (the UAV
323
- resource, carrying the write mask via `OPERAND_4_COMPONENT_MASK_MODE`),
324
- `psDestAddr=asOperands[1]` (struct index), `psDestByteOff=asOperands[2]` (byte
325
- offset), `psSrc=asOperands[3]` (value to store).
326
-
327
- For each component present in `psDest->ui32CompMask`:
328
- ```glsl
329
- <name>_buf[<structIndexExpr>].value[(<byteOffExpr> >> 2u) + <comp>u] = <uint-or-int-cast>(src.<swz-or-x>);
330
- ```
331
- (`toGLSLInstruction.cpp:1534-1582`). `dstOffFlag` follows the same
332
- unsigned-unless-signed-typed rule as `ld_structured`. The source cast (`srcFlag`)
333
- is `TO_FLAG_UNSIGNED_INTEGER` by default, flipped to `TO_FLAG_INTEGER` only when
334
- `DeclareRWStructuredBufferTemplateTypeAsInteger` reports the target buffer as a
335
- single-`int`-typed `RWStructuredBuffer<int4>` (the "avoid calling the wrong
336
- `AtomicMin` overload" special case, `toGLSLDeclaration.cpp:998-1025`) — otherwise
337
- the destination array element type is always `uint` (`toGLSLInstruction.cpp:1569-1572`).
338
- Source components are consumed left-to-right via an incrementing `srcComponent`
339
- counter if the source operand has more than one swizzle element, else always
340
- `.x` (`toGLSLInstruction.cpp:1575-1578`).
341
-
342
- ### Type rules
343
- - Destination index/byte-offset: same int/uint rule as `ld_structured`.
344
- - Source value: bitcast to uint (default) or int (special RWStructuredBuffer<int>
345
- case) before storing — never stored as float, consistent with "backing array is
346
- always uint".
347
-
348
- ### Helpers needed
349
- - `structuredStoreComponent(bufName, structIndex, byteOffset, component, value,
350
- srcType)` — reference-only; no WebGL2 target exists for this opcode (see below).
351
-
352
- ### Edge cases
353
- - No destination register write, so `_sat` never applies (DXBC does not attach
354
- `_sat` to store instructions).
355
- - Per-component write masking must exactly follow `psDest->ui32CompMask`
356
- (`OPERAND_4_COMPONENT_MASK_MODE`), not the source operand's own mask.
357
-
358
- ### WebGL2 notes
359
- `store_structured` requires a writable UAV, which in turn requires an SSBO
360
- (`buffer`, not `readonly buffer`) — completely unavailable in GLSL ES 3.00. No
361
- package-time rewrite analogous to the `cb3` skinning path exists for writes
362
- (there is no ccpwgl uniform target that plausibly receives a per-invocation
363
- compute-style scatter write). **This opcode is out of scope for the WebGL2
364
- emitter.** The 930 corpus instances should be treated as evidence this opcode
365
- occurs in DX11 stages that are not shipped to the current WebGL2 vs/ps target
366
- (the sampled corpus instance is `createhistograms.sm_depth`, tagged
367
- `stageName: "geometry"` in `dx11-instruction-coverage.json` but much more
368
- plausibly a mislabeled compute shader given the histogram-building workload
369
- and its co-occurring `sync`/`dcl_thread_group`-shaped instruction in the same
370
- file — see the `atomic_iadd` section for the one confirmed **non**-compute
371
- counterexample in this family, `lensflareoccludert`, which is a pixel shader,
372
- not compute); the emitter should detect and refuse rather than attempt
373
- emission.
374
-
375
- ### Confidence
376
- **Medium** on the HLSLcc reference lowering itself (directly read from source);
377
- **high** on the WebGL2-scope conclusion (no counter-evidence of a vs/ps
378
- `store_structured` shipping shader was found in the decision corpus, and the
379
- project's own draft transpiler already special-cases the sibling UAV write
380
- opcode `store_uav_typed` as a target blocker see that section).
381
-
382
- ---
383
-
384
- ## `store_uav_typed` (642 instances)
385
-
386
- ### Semantics
387
- Writes a full-precision (or format-converted) texel/element to a typed UAV
388
- (`RWTexture*`/`RWBuffer`) at an integer address, per D3D11 `store_uav_typed`.
389
-
390
- ### GLSL lowering
391
- Case `OPCODE_STORE_UAV_TYPED` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4359-4415`):
392
- ```glsl
393
- imageStore(<uavName>, <addr-expr-by-dimension>, <value-cast-by-return-type>);
394
- ```
395
- The address component mask and any `TO_AUTO_EXPAND_TO_VEC{2,3,4}` flag are chosen
396
- from the UAV's reflected `REFLECT_RESOURCE_DIMENSION_*`
397
- (`toGLSLInstruction.cpp:4382-4407`): 1D/Buffer `.x` only; 2D/1DArray/2DMS
398
- `.xy` with `TO_AUTO_EXPAND_TO_VEC2`; 2DArray/3D/2DMSArray/Cube `.xyz` with
399
- `TO_AUTO_EXPAND_TO_VEC3`; CubeArray `TO_AUTO_EXPAND_TO_VEC4`. The stored value
400
- is translated with `ResourceReturnTypeToFlag(psRes->ui32ReturnType)` — i.e. cast
401
- to match the UAV's declared return type (float/int/uint).
402
-
403
- ### Type rules
404
- Value operand bitcast is driven entirely by the UAV's reflected return type
405
- (`RETURN_TYPE_FLOAT`/`SINT`/`UINT`/`UNORM`/`SNORM`), not by any DXBC instruction
406
- flag this requires resource-binding reflection, which per
407
- `CARBONENGINEJS-FORK.md:34-39` is frequently stripped in this project's shipped
408
- DXBC and falls back to register-stable naming only (no return-type recovery
409
- implied by that fallback).
410
-
411
- ### Helpers needed
412
- None for the WebGL2 emitter proper — see WebGL2 notes. Reference-only helper:
413
- `imageStoreTyped(uav, addr, value, returnType)`.
414
-
415
- ### Edge cases
416
- - `imageStore` swizzle/expansion must match the UAV's declared dimensionality
417
- exactly, or GLSL will reject a texel with the wrong component count.
418
- - Missing `RDEF` reflection (this project's normal stripped-DXBC case) leaves the
419
- return type unrecoverable, which independently blocks this opcode even before
420
- the SSBO/image-type gap is considered.
421
-
422
- ### WebGL2 notes
423
- `image2D`/`imageBuffer` UAV types and `imageStore` are GLSL ES 3.10+ built-ins,
424
- not part of ES 3.00. **Fully out of scope for the WebGL2 emitter.** This matches
425
- the project's own draft-transpiler decision, which already lists
426
- `store_uav_typed` as a hard `TARGET_BLOCKER_OPCODES` entry
427
- (`../shaderdiscovery/src/core/transpiler/gles/Dx11GlesDraftTranspiler.js:130`) and
428
- the `TRANSPILING-GAPS.md:100-114` "UAV and atomic path... blocked for current
429
- WebGL2 target" decision. The emitter must detect `dcl_unordered_access_view_*`
430
- declarations plus this opcode and refuse the stage (or the whole effect) with an
431
- explicit diagnostic, never attempt best-effort emission.
432
-
433
- ### Confidence
434
- **High** corroborated independently by HLSLcc source, the draft transpiler's
435
- explicit blocker list, and the shaderdiscovery decision log.
436
-
437
- ---
438
-
439
- ## `sync` (183 instances)
440
-
441
- ### Semantics
442
- A compute-shader thread-group synchronization barrier. DXBC encodes which memory
443
- domains/threads to synchronize via `ui32SyncFlags`: `SYNC_THREAD_GROUP_SHARED_MEMORY`,
444
- `SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP`/`_GLOBAL`, and `SYNC_THREADS_IN_GROUP`.
445
- It only has defined meaning inside a compute shader with a `dcl_thread_group` size.
446
-
447
- ### GLSL lowering
448
- Case `OPCODE_SYNC` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:3958-3984`):
449
- ```glsl
450
- if (flags & SYNC_THREAD_GROUP_SHARED_MEMORY) memoryBarrierShared();
451
- if (flags & (SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP|_GLOBAL)) memoryBarrier();
452
- if (flags & SYNC_THREADS_IN_GROUP) barrier();
453
- ```
454
- Each condition independently emits its statement (not mutually exclusive; a
455
- single `sync` instruction can emit all three lines).
456
-
457
- ### Type rules
458
- N/A no operands, no data type.
459
-
460
- ### Helpers needed
461
- None this opcode has no GLSL ES 3.00 equivalent to helper-wrap; see WebGL2
462
- notes.
463
-
464
- ### Edge cases
465
- None beyond the flag decoding itself (a bitmask, not an enum — must check all
466
- three bits independently, not `switch`/`else if`).
467
-
468
- ### WebGL2 notes
469
- `barrier()`, `memoryBarrier()`, and `memoryBarrierShared()` are **compute-shader-
470
- only** built-ins in GLSL ES (introduced with ES 3.10 compute shaders); they do
471
- not exist in the ES 3.00 vertex/fragment built-in set at all, and vertex/fragment
472
- shaders have no thread-group concept regardless of GLSL version. **Fully out of
473
- scope for the WebGL2 emitter.** Detect `sync` (and its precondition,
474
- `dcl_thread_group`) and refuse the stage.
475
-
476
- ### Confidence
477
- **High**the DXBC semantics and the compute-only nature of `barrier`/
478
- `memoryBarrier` in GLSL ES are unambiguous.
479
-
480
- ---
481
-
482
- ## `ld_raw` (54 instances)
483
-
484
- ### Semantics
485
- Reads one or more 32-bit components from a raw (`ByteAddressBuffer`) resource at
486
- a byte offset, per D3D11 `ld_raw` — same addressing model as `ld_structured` but
487
- without a structure index (flat byte-addressed array).
488
-
489
- ### GLSL lowering
490
- Same function as `ld_structured`, `TranslateShaderStorageLoad`, case
491
- `OPCODE_LD_RAW` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1602-1606`, dispatched
492
- at `toGLSLInstruction.cpp:4416-4425`). Operands: `psDest=asOperands[0]`,
493
- `psSrcByteOff=asOperands[1]`, `psSrc=asOperands[2]` no `psSrcAddr`, so the
494
- `TranslateShaderStorageLoad` body skips the `[<idx>].value` indirection
495
- entirely (`toGLSLInstruction.cpp:1661-1666`, gated on `if (psSrcAddr)`), producing:
496
- ```glsl
497
- <bitcast_open><name>_buf[(<byteOffExpr> >> 2u) + <comp>u]<bitcast_close>
498
- ```
499
- against a flat `uint`/`int` array (`vendor/HLSLcc/src/toGLSLDeclaration.cpp:1078-1088`,
500
- `isRaw` branch: `uint <name>_buf[];` or `int <name>_buf[];` chosen by
501
- `HaveUnsignedTypes`), not a `_type` struct array.
502
-
503
- ### Type rules
504
- Identical bitcast-by-destination-type rule as `ld_structured` (float
505
- `uintBitsToFloat`, int `int(...)`, uint passthrough).
506
-
507
- ### Helpers needed
508
- - `rawLoadComponent(bufName, byteOffset, component, destType)` — reference-only;
509
- see WebGL2 notes for scope.
510
-
511
- ### Edge cases
512
- Same swizzle-indirection caveat as `ld_structured` (component addressing follows
513
- the resource operand's own swizzle if present).
514
-
515
- ### WebGL2 notes
516
- Same SSBO unavailability as `ld_structured` section A/C. No `cb3`-style rewrite
517
- is known or defined for raw-buffer reads — the `BoneTransforms` rewrite is
518
- specific to the structured-buffer `t0_buf[idx].value[...]` shape, not the flat
519
- `t0_buf[...]` raw shape. **Out of scope for the WebGL2 emitter** unless/until a
520
- specific raw-buffer resource is proven to need a package-time ABI rewrite
521
- analogous to skinning.
522
-
523
- The corpus table's "vs/ps" stage claim was overreach: the only sampled
524
- instance in `dx11-instruction-coverage.json`'s `allOpcodeExamples` is
525
- `graphics\effect.dx11\managed\space\specialfx\particles\gpu\emit.sm_depth`
526
- tagged `stageName: "geometry"`, paired with the sibling `store_raw` opcode in
527
- the exact same file/technique (also tagged `"geometry"`)a GPU particle
528
- emission pass, which is much more plausibly a compute-style workload than a
529
- genuine vertex/pixel `ByteAddressBuffer` read. Do not assume `ld_raw` is
530
- `vs/ps`-reachable without a concrete counter-example (unlike `atomic_iadd`,
531
- which has one see that section).
532
-
533
- ### Confidence
534
- **Medium** HLSLcc source lowering is directly read and clear, but no shipping
535
- corpus evidence of `ld_raw` reaching a WebGL2-validated vs/ps program was found
536
- (only 54 instances total, none flagged in the skinning/JointMat decision
537
- trail); the sole sampled corpus example is paired with `store_raw` in a
538
- likely-compute GPU-particle-emission shader, not a vs/ps stage.
539
-
540
- ---
541
-
542
- ## `store_raw` (54 instances)
543
-
544
- ### Semantics
545
- Writes one or more 32-bit components to a raw UAV (`RWByteAddressBuffer`) at a
546
- byte offset, per D3D11 `store_raw` — inverse of `ld_raw`.
547
-
548
- ### GLSL lowering
549
- Same function as `store_structured`, `TranslateShaderStorageStore`, case
550
- `OPCODE_STORE_RAW` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1519-1523`,
551
- dispatched at `toGLSLInstruction.cpp:4338-4346`). Operands: `psDest=asOperands[0]`,
552
- `psDestByteOff=asOperands[1]`, `psSrc=asOperands[2]` — no `psDestAddr`, so no
553
- `[<idx>].value` indirection (`toGLSLInstruction.cpp:1546-1551`, gated on `if
554
- (psDestAddr)`):
555
- ```glsl
556
- <name>_buf[(<byteOffExpr> >> 2u) + <comp>u] = <uint-or-int-cast>(src.<swz-or-x>);
557
- ```
558
-
559
- ### Type rules
560
- Same as `store_structured`: uint by default, int only for the special
561
- single-int `RWStructuredBuffer<int4>`-shaped buffer detection (which does not
562
- actually apply to raw buffers in practice, since that check is structured-buffer
563
- specific, but the code path is shared).
564
-
565
- ### Helpers needed
566
- - `rawStoreComponent(bufName, byteOffset, component, value, srcType)` —
567
- reference-only.
568
-
569
- ### Edge cases
570
- No destination register, so `_sat` never applies.
571
-
572
- ### WebGL2 notes
573
- Requires a writable UAV/SSBO — unavailable in ES 3.00. **Out of scope for the
574
- WebGL2 emitter**; treat identically to `store_structured` (detect and refuse).
575
-
576
- ### Confidence
577
- **Medium** — same reasoning as `ld_raw`; low corpus volume (54) with no
578
- known vs/ps shipping path.
579
-
580
- ---
581
-
582
- ## `atomic_iadd` (27) / `imm_atomic_iadd` (24) / `imm_atomic_exch` (9) / `atomic_umax` (6) / `atomic_umin` (3)
583
-
584
- Grouped: all five are handled by the single `TranslateAtomicMemOp` function and
585
- differ only in GLSL function name and whether a previous-value destination
586
- exists.
587
-
588
- ### Semantics
589
- - `atomic_iadd` / `imm_atomic_iadd`: atomically add a value to a UAV or
590
- groupshared (TGSM) memory location; the `imm_` form additionally returns the
591
- pre-add value into a destination register, the non-`imm_` form discards it.
592
- - `imm_atomic_exch`: atomically replace the memory location's value and return
593
- the previous value (exchange has no non-`imm_` counterpart in DXBC).
594
- - `atomic_umax` / `atomic_umin`: atomically store `max`/`min` of the current
595
- value and the source value (unsigned comparison), discarding the previous
596
- value (no `imm_` variants observed in this corpus, though DXBC defines
597
- `imm_atomic_umax`/`umin` too).
598
-
599
- ### GLSL lowering
600
- `TranslateAtomicMemOp` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1685-2087`,
601
- dispatched at `toGLSLInstruction.cpp:4428-4450`). Per-opcode operand layout and
602
- GLSL function name selected at the top of the function
603
- (`toGLSLInstruction.cpp:1700-1935`):
604
-
605
- | Opcode | `func` | operands (dest addr order) |
606
- |---|---|---|
607
- | `imm_atomic_iadd` | `"Add"` | `[0]=previousValue, [1]=dest, [2]=destAddr, [3]=src` |
608
- | `atomic_iadd` | `"Add"` | `[0]=dest, [1]=destAddr, [2]=src` (no previousValue) |
609
- | `imm_atomic_exch` | `"Exchange"` | `[0]=previousValue, [1]=dest, [2]=destAddr, [3]=src` |
610
- | `atomic_umin` | `"Min"` | `[0]=dest, [1]=destAddr, [2]=src` |
611
- | `atomic_umax` | `"Max"` | `[0]=dest, [1]=destAddr, [2]=src` |
612
-
613
- Resource-kind detection (`toGLSLInstruction.cpp:1968-2011`): if `dest` is not
614
- `OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY`, look up its UAV binding.
615
- `RTYPE_UAV_RWTYPED` `isUint = (returnType == RETURN_TYPE_UINT)` and derive
616
- `texDim` (1/2/3) from the UAV's resource dimension; `RTYPE_UAV_RWSTRUCTURED` →
617
- `isUint=false, ui32DstDataTypeFlag |= TO_FLAG_INTEGER` only if
618
- `DeclareRWStructuredBufferTemplateTypeAsInteger` says so; TGSM defaults to
619
- `isUint=true, texDim=0`. Then:
620
- ```glsl
621
- ui32DataTypeFlag = isUint ? (TO_FLAG_UNSIGNED_INTEGER|TO_AUTO_BITCAST_TO_UINT)
622
- : (TO_FLAG_INTEGER|TO_AUTO_BITCAST_TO_INT);
623
- ```
624
- (`toGLSLInstruction.cpp:2013-2016`). If `previousValue` exists, it's assigned via
625
- `AddAssignToDest(previousValue, isUint?SVT_UINT:SVT_INT, 1, ...)` **before** the
626
- atomic call text is emitted (`toGLSLInstruction.cpp:2018-2019`). Final emitted
627
- shape (`toGLSLInstruction.cpp:2021-2086`):
628
- - Typed-UAV (image) form (`texDim>0`):
629
- ```glsl
630
- [prev =] imageAtomic<Func>(<uavName>, <addr>.<xy|xyz|x>, <src-cast>);
631
- ```
632
- - Buffer/TGSM form (`texDim==0`):
633
- ```glsl
634
- [prev =] atomic<Func>(<name>[_buf][<addr> >> 2u], <src-cast>);
635
- ```
636
- where `<name>_buf[<addr>]` gains an extra `.value[<addrY> >> 2u]` indirection
637
- if the destAddr operand carries **two** swizzle components (X and Y) — "structured
638
- buf if we have both x & y swizzles" (`toGLSLInstruction.cpp:2055-2062`) — vs. a
639
- raw buffer's single-component addressing.
640
- - No trailing `;` is appended when `previousValue` is set (the assignment prologue
641
- handles closing parens/semicolon via `AddAssignPrologue`); otherwise the line
642
- is terminated with `;\n` directly (`toGLSLInstruction.cpp:2081-2086`).
643
-
644
- ### Type rules
645
- - Both `compare`/`src` (when present) are cast via the same
646
- `ui32DataTypeFlag` (`TO_AUTO_BITCAST_TO_UINT` or `_INT`), i.e. bitcast from the
647
- underlying float-vec4 register storage to whichever integer type the target
648
- memory location actually holds.
649
- - `previousValue` destination type is `SVT_UINT` or `SVT_INT` matching `isUint`,
650
- never float directly (though the register itself is stored as float and
651
- bitcast at the destination-write site per this project's register model).
652
- - These do **not** produce DXBC comparison masks; `atomic_umin`/`umax` compare
653
- internally to select which value to store, but the DXBC/GLSL result is the
654
- stored/previous *value*, not a boolean or 0xFFFFFFFF/0 mask.
655
-
656
- ### Helpers needed
657
- None implementable for WebGL2 (see below). Reference-only helpers if ever
658
- targeting ES 3.10+/desktop: `atomicUavOrTgsmOp(func, dest, addr, src,
659
- [compare], [returnsPrevious])`.
660
-
661
- ### Edge cases
662
- - `atomic_umin`/`atomic_umax` are unsigned-only per DXBC (`imin`/`imax` variants
663
- exist separately for signed); do not conflate with `atomic_imin`/`imax`.
664
- - The 1-vs-2-swizzle-component destAddr distinction (structured vs. raw
665
- addressing within the same atomic path) must be preserved if this is ever
666
- ported.
667
-
668
- ### WebGL2 notes
669
- `atomicAdd`/`atomicMin`/`atomicMax`/`atomicExchange`/`atomicCompSwap` (buffer/
670
- shared-memory atomics) and `imageAtomicAdd` etc. (image atomics) are GLSL ES
671
- 3.10+ compute-shader-only built-ins; none exist in ES 3.00 vertex/fragment
672
- shaders, regardless of which D3D11 stage the source instruction came from.
673
- **Fully out of scope for the WebGL2 emitter.** Detect any `atomic_*`/
674
- `imm_atomic_*` opcode and refuse the stage.
675
-
676
- Do **not** rely on "these only occur in compute shaders" as the reason for
677
- skipping this check in the pixel-stage emitter: `dx11-instruction-coverage.json`
678
- (`initialCandidateOpcodeExamples`) records a concrete `atomic_iadd` instance in
679
- `graphics\effect.dx11\managed\space\specialfx\lensflares\lensflareoccludert.sm_depth`
680
- tagged `stageIndex: 1` / `stageName: "pixel"` — an actual D3D11 pixel shader
681
- (D3D11.1 permits UAV access from pixel shaders; a lens-flare occlusion query
682
- written into a UAV counter from the pixel stage is a plausible, ordinary
683
- technique, not a mislabeled compute pass). The other four sampled corpus
684
- instances of this opcode group (`atomic_iadd` again in `createhistograms.sm_depth`,
685
- `imm_atomic_iadd` in `clear.sm_depth`, `imm_atomic_exch`/`atomic_umax`/
686
- `atomic_umin` in `computelightlists.sm_depth`) are all tagged `stageName:
687
- "geometry"` by the same tool, but those files' names (histogram building,
688
- particle-buffer clear, light-list culling) are classic GPGPU compute-shader
689
- workloads, and the coverage tool has no `"compute"` stage label at all in its
690
- vocabulary (only `vertex`/`pixel`/`geometry`/`hull`) those four are much
691
- better explained as compute shaders whose slot the tool mislabels than as
692
- genuine geometry shaders (a real DX11 geometry shader cannot declare
693
- `dcl_thread_group`/`sync`, which the *sibling* `createhistograms.sm_depth`
694
- example for the `sync` opcode does, and DXBC does not permit that in a
695
- geometry stage). The `lensflareoccludert` pixel-stage instance is not
696
- explained away by that reasoning and must be treated as real: the emitter's
697
- **ps-stage translation path itself** needs the detect-and-refuse check, not
698
- just a pre-filter that assumes this opcode class never survives into a vs/ps
699
- compile.
700
-
701
- `TRANSPILING-GAPS.md:100-114` ("UAV and atomic path... blocked for current
702
- WebGL2 target... `atomic_iadd`: 6... Affects the `lensflareoccludert` path"
703
- note that count was measured on a narrower earlier corpus slice than this
704
- family's 450k-instruction sweep, which shows 27) already names
705
- `lensflareoccludert` as the blocked case; it does not itself claim the
706
- instruction is compute-only, and the per-instruction corpus scan confirms it
707
- is not.
708
-
709
- ### Confidence
710
- **High** for the DXBC/GLSL semantics (read directly from source) and for the
711
- WebGL2-out-of-scope conclusion (ES 3.00 has no atomics in any stage, so the
712
- `lensflareoccludert` pixel-shader counterexample does not change the outcome).
713
- **Medium** on the blanket "compute-only" framing carried over from the
714
- project's decision log confirmed false for at least the `lensflareoccludert`
715
- `atomic_iadd` instance, which is a pixel shader; the emitter must not assume
716
- this opcode family is filtered out before reaching ps-stage translation.
717
-
718
- ---
719
-
720
- ## `ld_uav_typed` (18 instances)
721
-
722
- ### Semantics
723
- Reads a texel/element from a typed UAV (`RWTexture*`/`RWBuffer`) at an integer
724
- address, per D3D11 `ld_uav_typed` the read counterpart of `store_uav_typed`.
725
-
726
- ### GLSL lowering
727
- Case `OPCODE_LD_UAV_TYPED` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4266-4336`).
728
- Operands: `psDest=asOperands[0]`, `psSrcAddr=asOperands[1]`,
729
- `psSrc=asOperands[2]` (UAV resource). Address component mask derived from
730
- `psInst->eResDim` the same way as `store_uav_typed` (1/2/3 components,
731
- `toGLSLInstruction.cpp:4281-4300`). Source data type resolved from the UAV's
732
- reflected return type (`RETURN_TYPE_FLOAT/SINT/UINT/SNORM/UNORM`,
733
- `toGLSLInstruction.cpp:4302-4325`, with `UNORM`/`SNORM` both mapping to
734
- `SVT_FLOAT`). Emitted form:
735
- ```glsl
736
- dest.mask = imageLoad(<uavName>, <addr-by-dimension>)<swizzle-with-mask>;
737
- ```
738
- using `AddAssignToDest`/`AddAssignPrologue` for the destination, and
739
- `TranslateOperandSwizzleWithMask` to apply the resource operand's own swizzle to
740
- the 4-component `imageLoad` result restricted to the destination write mask
741
- (`toGLSLInstruction.cpp:4327-4335`).
742
-
743
- ### Type rules
744
- Destination component type follows the UAV's reflected return type, not a fixed
745
- uint-array convention (unlike `ld_structured`/`ld_raw`) — `imageLoad` always
746
- returns a 4-component vector of the sampler/image's declared base type
747
- (`ivec4`/`uvec4`/`vec4`), then swizzled down to the requested mask.
748
-
749
- ### Helpers needed
750
- None for WebGL2 (see below). Reference-only: `imageLoadTyped(uav, addr,
751
- returnType)`.
752
-
753
- ### Edge cases
754
- Requires resource-binding reflection (return type, dimension) exactly like
755
- `store_uav_typed` doubly blocked when `RDEF` is stripped, independent of the
756
- image-type gap below.
757
-
758
- ### WebGL2 notes
759
- `imageLoad` and image sampler types (`image2D` etc.) are ES 3.10+-only.
760
- **Fully out of scope for the WebGL2 emitter.** Matches the draft transpiler's
761
- explicit blocker (`Dx11GlesDraftTranspiler.js:129`) and the
762
- `TRANSPILING-GAPS.md` UAV decision. With only 18 corpus instances (vs.
763
- `store_uav_typed`'s 642), this is very likely the read side of a small set of
764
- compute/UAV effects rather than any vs/ps-reachable code path but the
765
- concrete sampled instance (`dx11-instruction-coverage.json`, `allOpcodeExamples`)
766
- is `graphics\effect.dx11\managed\space\postprocess\measureexposure.sm_depth`
767
- (a tone-mapping average-luminance compute pass), **not** `lensflareoccludert`.
768
- `lensflareoccludert` is confirmed by `TRANSPILING-GAPS.md:100-114` to carry
769
- `dcl_unordered_access_view_typed`/`atomic_iadd` (and per this family's own
770
- corpus scan, `atomic_iadd` there is a **pixel**-stage instance — see that
771
- section); do not conflate the two effects or assume `ld_uav_typed`'s
772
- compute-only reasoning transfers to `atomic_iadd`.
773
-
774
- ### Confidence
775
- **High** same corroboration as `store_uav_typed`, corrected to cite the
776
- right sampled effect (`measureexposure.sm_depth`, not `lensflareoccludert`).
777
-
778
- ---
779
-
780
- ## `bufinfo` (0 instances — specified for completeness only)
781
-
782
- ### Semantics
783
- Returns the element count of a structured/raw/typed buffer resource, per D3D11
784
- `bufinfo` (used for bounds-checking dynamic buffer accesses).
785
-
786
- ### GLSL lowering
787
- Case `OPCODE_BUFINFO` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4753-4766`):
788
- ```glsl
789
- dest = <ctor>(<resourceName>_buf.length());
790
- ```
791
- via `AddAssignToDest(dest, SVT_INT, 1, ...)` then
792
- `<resourceName>_buf.length()` then `AddAssignPrologue`.
793
-
794
- ### Type rules
795
- Result is always `SVT_INT` (a signed count), regardless of the buffer's element
796
- type.
797
-
798
- ### Helpers needed
799
- None zero corpus instances; no helper is justified without evidence of use.
800
-
801
- ### Edge cases
802
- N/A not observed in this corpus.
803
-
804
- ### WebGL2 notes
805
- `.length()` on a GLSL array returns a compile-time constant for fixed-size
806
- arrays (legal in ES 3.00) but is a **run-time** query only for SSBO
807
- runtime-sized arrays (`buffer T { ... x[]; }`), which do not exist in ES 3.00.
808
- Since this opcode's only real use (bounds-checking a structured/raw buffer) is
809
- tied to the same SSBO-only resource kinds as `ld_structured`/`ld_raw`, it would
810
- be out of scope for the same reason if it appeared. Zero corpus instances means
811
- no immediate action item, but the emitter should still recognize and refuse the
812
- opcode defensively rather than silently mis-translate.
813
-
814
- ### Confidence
815
- **Low** — zero real-world evidence in this corpus; semantics and lowering are
816
- read directly from HLSLcc source but entirely unvalidated against any actual
817
- shader.
818
-
819
- ---
820
-
821
- ## Helpers summary
822
-
823
- Helpers the memory-structured family needs the emitter to provide (grouped by
824
- whether they produce runnable WebGL2 output or are reference/detection-only):
825
-
826
- **Shipping (WebGL2-runnable) helpers:**
827
- 1. `lowerBoneTransformsToCb3` package-time text-rewrite pass that removes the
828
- HLSLcc `t0` SSBO declaration, grows `cb3.data[]` to at least 200 `vec4`s,
829
- strips the native bone-ring-buffer offset add, and rewrites each 4-component
830
- `t0_buf[idx].value[...]` row load to `cb3.data[26 + idx*3 + row]` (optionally
831
- swizzled). Port of `lowerWebgl2SkinningAbi` +
832
- `lowerStructuredBoneLoad` in `scripts/packageTr2WebglEffect.js:826-902`.
833
- 2. `lowerBlendIndicesToFloatAttribute` — package-time rewrite of
834
- `uvec4`/`ivec4`/etc. `in_BLENDINDICES<n>` vertex inputs to `vec<N>`, part of
835
- the same pass (`packageTr2WebglEffect.js:840-843`).
836
-
837
- **Reference-only helpers** (mirror HLSLcc's non-WebGL2 SSBO/UAV/atomic/compute
838
- lowering, useful for documentation, debugging, and any future non-WebGL2
839
- backend, but must never be emitted as final WebGL2 output):
840
- 3. `structuredLoadComponent(bufName, structIndex, byteOffset, component, destType)`
841
- 4. `structuredStoreComponent(bufName, structIndex, byteOffset, component, value, srcType)`
842
- 5. `rawLoadComponent(bufName, byteOffset, component, destType)`
843
- 6. `rawStoreComponent(bufName, byteOffset, component, value, srcType)`
844
- 7. `imageLoadTyped(uav, addr, returnType)`
845
- 8. `imageStoreTyped(uav, addr, value, returnType)`
846
- 9. `atomicUavOrTgsmOp(func, dest, addr, src, compare?, returnsPrevious?)`
847
-
848
- **Detection/refusal helpers** (must run before emission; there is no GLSL ES
849
- 3.00 lowering to fall back to):
850
- 10. `refuseComputeOnlyOpcode(opcodeName)` for `sync`, `store_structured`
851
- (non-skinning), `store_raw`, `store_uav_typed`, `ld_uav_typed`,
852
- `atomic_iadd`, `imm_atomic_iadd`, `imm_atomic_exch`, `atomic_umax`,
853
- `atomic_umin`, and `bufinfo` should it ever appear.
854
- 11. `refuseNonSkinningStructuredLoad(resourceName)` for `ld_structured` /
855
- `ld_raw` uses that are not the vertex-stage `BoneTransforms` skinning
856
- pattern (e.g. `LightBuffer`/`LightIndexBuffer` pixel-stage reads).
857
-
858
- ---
859
-
860
- *Sources consulted: `vendor/HLSLcc/src/toGLSLInstruction.cpp`,
861
- `toGLSLOperand.cpp`, `toGLSLDeclaration.cpp`, `HLSLccToolkit.cpp`,
862
- `internal_includes/languages.h`; `vendor/HLSLcc/CARBONENGINEJS-FORK.md`;
863
- `../shaderdiscovery/TRANSPILING-GAPS.md`; `../shaderdiscovery/AGENT-FINDINGS/decisions/005-`,
864
- `016-`, `028-cewg-*`, `014-`/`015-`/`016-`/`017-joint-matrix-*`;
865
- `../shaderdiscovery/src/core/transpiler/gles/Dx11GlesDraftTranspiler.js` (hints
866
- only); `scripts/packageTr2WebglEffect.js`;
867
- `../shaderdiscovery/artifacts/dx11-instruction-coverage.json` (per-instruction
868
- stage ground truth, used to correct several "compute-only" stage-reality
869
- claims); `../shaderdiscovery/artifacts/ab-shader-set/work/skinned_fxdirectionalv5/*.es300.glsl`
870
- (actual generated fixture, used to correct the `ld_structured` cb3 worked
871
- example).*
1
+ # DXBC → GLSL ES 3.00 Lowering Spec: Memory-Structured Family
2
+
3
+ Status: Evolving
4
+ Scope: `@carbonenginejs/runtime-resource/formats/webgl` structured-memory lowering
5
+ Audience: Shader translator maintainers and reviewers
6
+ Summary: Defines bounded WebGL2 adaptations for DXBC structured-memory operations.
7
+
8
+ Family key: `memory-structured`
9
+ Target: GLSL ES 3.00 (WebGL2), vertex + pixel stages only (no compute, no SSBOs).
10
+ Register model: every DXBC register is stored by the emitter as a `float` `vec4`; all
11
+ integer/unsigned reads and writes go through `floatBitsToInt` / `floatBitsToUint` /
12
+ `intBitsToFloat` / `uintBitsToFloat` at the use site, mirroring HLSLcc's own
13
+ `GetBitcastOp` (`vendor/HLSLcc/src/toGLSLOperand.cpp:327-353`) and
14
+ `AddOpAssignToDestWithMask` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:28-153`)
15
+ machinery, which HLSLcc itself falls back to whenever static data-type analysis is
16
+ unavailable (exactly the reflection-stripped situation this fork runs in per
17
+ `vendor/HLSLcc/CARBONENGINEJS-FORK.md:34-52`).
18
+
19
+ Corpus counts (450k-instruction sweep, 1611 EVE Online DX11 effects):
20
+
21
+ | Opcode | Count | Stage reality |
22
+ |---|---:|---|
23
+ | `ld_structured` | 4014 | vs (BoneTransforms skinning) + ps (LightBuffer/LightIndexBuffer-style tbuffer reads) |
24
+ | `store_structured` | 930 | compute-only in D3D11 (requires a UAV write target); **not observed as reachable in vs/ps stages actually shipped to WebGL2** — see per-opcode note |
25
+ | `store_uav_typed` | 642 | compute-only in practice for this corpus (UAV write) |
26
+ | `sync` | 183 | compute-only (`sync` only has meaning with `dcl_thread_group`) |
27
+ | `ld_raw` | 54 | no confirmed vs/ps corpus example found (see per-opcode note); same SSBO problem as `ld_structured` if it does appear in vs/ps |
28
+ | `store_raw` | 54 | compute-only in practice (RWByteAddressBuffer write) |
29
+ | `atomic_iadd` | 27 | **confirmed present in a pixel shader** (`lensflareoccludert.sm_depth`, `stageName: "pixel"` in `dx11-instruction-coverage.json`'s `initialCandidateOpcodeExamples`) — not compute-only, see per-opcode note |
30
+ | `imm_atomic_iadd` | 24 | compute-only (UAV atomic with previous-value return) |
31
+ | `ld_uav_typed` | 18 | compute-only in this corpus — sampled instance is `measureexposure.sm_depth` (tone-mapping luminance compute pass), **not** `lensflareoccludert` (that file's confirmed opcode is `atomic_iadd`/`dcl_unordered_access_view_typed`, per `TRANSPILING-GAPS.md:100-114`); see per-opcode note |
32
+ | `imm_atomic_exch` | 9 | compute-only |
33
+ | `atomic_umax` | 6 | compute-only |
34
+ | `atomic_umin` | 3 | compute-only |
35
+ | `bufinfo` | 0 | not observed in this corpus; specified for completeness only |
36
+
37
+ **Central WebGL2 constraint** (governs every opcode below): GLSL ES 3.00 has **no
38
+ shader storage buffers** (`buffer` blocks require `#version 310 es` or GL 4.3+), **no
39
+ image load/store types** (`image2D`/`imageLoad`/`imageStore` require ES 3.10+), and
40
+ **no atomic-memory built-ins outside compute shaders** (`atomicAdd`/`imageAtomicAdd`
41
+ etc. and `barrier()`/`memoryBarrier()` are ES 3.10 compute-shader built-ins, not part
42
+ of the ES 3.00 vertex/fragment built-in set). Every HLSLcc GLSL template shown below
43
+ is therefore **reference material for what desktop/Vulkan/Metal HLSLcc emits**, not
44
+ directly compilable WebGL2 output. The one opcode with a proven, shipping WebGL2
45
+ lowering is `ld_structured` restricted to the `BoneTransforms` skinning case, via the
46
+ package-time `cb3` rewrite described in its section below.
47
+
48
+ ---
49
+
50
+ ## Shared machinery referenced by this family
51
+
52
+ - `HaveUnsignedTypes(eLang)` and `HaveBitEncodingOps(eLang)`
53
+ (`vendor/HLSLcc/src/internal_includes/languages.h:156-180`) both return `1` for
54
+ every target except `LANG_ES_100`/`LANG_120`. `LANG_ES_300` (this project's
55
+ target) has unsigned integer types and bit-encoding intrinsics
56
+ (`floatBitsToInt`/`floatBitsToUint`/`intBitsToFloat`/`uintBitsToFloat`) available,
57
+ so all the `TO_FLAG_UNSIGNED_INTEGER` / bitcast branches below are live for our
58
+ target.
59
+ - `AddAssignToDest` / `AddAssignPrologue`
60
+ (`vendor/HLSLcc/src/toGLSLInstruction.cpp:155-171`) write the destination operand,
61
+ the write mask, `= `, and the correct number of constructor/bitcast open-parens;
62
+ `AddAssignPrologue` closes them and appends `;\n`. This is the generic
63
+ "assign-with-implicit-bitcast" pattern the emitter must reproduce for `ld_structured`,
64
+ `ld_raw`, `ld_uav_typed`, and `bufinfo`.
65
+ - `_sat` (saturate) is applied **generically, after the main switch**, only to
66
+ operand 0 (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4821-4844`): it re-clamps
67
+ `dest = clamp(dest, 0.0, 1.0)` (with an Adreno `min(max(dest,0.0),1.0)` workaround
68
+ path gated behind `#ifdef UNITY_ADRENO_ES3`, since `eTargetLanguage == LANG_ES_300`
69
+ triggers the workaround branch). This only matters for opcodes that write a
70
+ register destination — i.e. `ld_structured`, `ld_raw`, `ld_uav_typed`, `bufinfo`,
71
+ `imm_atomic_*` (previous-value destination). Store/`sync`/non-`imm_` atomics have
72
+ no float destination and DXBC does not encode `_sat` for them in practice.
73
+ - Structured/raw buffer declaration (`DeclareBufferVariable`,
74
+ `vendor/HLSLcc/src/toGLSLDeclaration.cpp:1027-1092`) is the HLSLcc reference
75
+ declaration these instructions index into:
76
+ ```glsl
77
+ struct t0_type { uint[<stride/4>] value; };
78
+ layout(std430, binding = N) readonly buffer t0 { t0_type t0_buf[]; };
79
+ ```
80
+ (raw buffers use `uint t0_buf[]` / `int t0_buf[]` directly, no wrapper struct,
81
+ selected by `HaveUnsignedTypes`). This declaration is unusable in GLSL ES 3.00 —
82
+ documented here only because the per-instruction `t0_buf[...]` indexing expression
83
+ it feeds is the exact text pattern the package-time `cb3` rewrite (see
84
+ `ld_structured`) pattern-matches against.
85
+
86
+ ---
87
+
88
+ ## `ld_structured` (4014 instances) — highest priority in this family
89
+
90
+ ### Semantics
91
+ Loads a structured-buffer element: given a structure index (operand 1) and a
92
+ byte offset within the structure (operand 2), reads one or more 32-bit components
93
+ from resource operand 3 (a `t#`/`u#` structured buffer) into the destination
94
+ register, per D3D11 `ld_structured` semantics (index-then-byte-offset addressing
95
+ into an array of fixed-stride structures).
96
+
97
+ ### GLSL lowering — A. HLSLcc reference (desktop/Vulkan/Metal SSBO path)
98
+ `TranslateShaderStorageLoad`, case `OPCODE_LD_STRUCTURED`
99
+ (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1585-1683`, dispatched at
100
+ `toGLSLInstruction.cpp:4256-4264`). Operands: `psDest=asOperands[0]`,
101
+ `psSrcAddr=asOperands[1]` (struct index), `psSrcByteOff=asOperands[2]` (byte
102
+ offset), `psSrc=asOperands[3]` (resource).
103
+
104
+ For each destination component `c` present in the destination write mask:
105
+ ```glsl
106
+ <bitcast_open><resourceName>_buf[<structIndexExpr>].value[(<byteOffExpr> >> 2u) + <swz>u]<bitcast_close>
107
+ ```
108
+ where `<swz>` is `psSrc->aui32Swizzle[c]` if the resource operand carries an
109
+ explicit swizzle (`OPERAND_4_COMPONENT_SWIZZLE_MODE`), else `c` itself
110
+ (`toGLSLInstruction.cpp:1673`) — i.e. the *resource* operand's own swizzle can
111
+ remap which dword of the structure element component `c` reads from. All such
112
+ per-component expressions are joined by `AddAssignToDest`/constructor into:
113
+ ```glsl
114
+ dest.mask = <ctor>(comp0, comp1, ...);
115
+ ```
116
+ (`toGLSLInstruction.cpp:1623-1682`).
117
+
118
+ `<bitcast_open>`/`<bitcast_close>` depend on `destDataType = psDest->GetDataType()`
119
+ (`toGLSLInstruction.cpp:1642-1654`):
120
+ - `SVT_FLOAT` → `uintBitsToFloat(...)` (since `HaveBitEncodingOps` is true for ES
121
+ 3.00); the code falls back to `float(...)` only for pre-bit-encoding targets.
122
+ - `SVT_INT`/`SVT_INT16`/`SVT_INT12` → `int(...)`.
123
+ - `SVT_UINT` → no wrapper at all (`addedBitcast` stays `0`) because the backing
124
+ `t0_type.value` array element type is always `uint` — "always uint array atm"
125
+ (`toGLSLInstruction.cpp:1641`).
126
+
127
+ The struct-index operand is translated with **both** `TO_FLAG_UNSIGNED_INTEGER |
128
+ TO_FLAG_INTEGER` set simultaneously (`toGLSLInstruction.cpp:1664`) — reproduce
129
+ this by picking whichever the index operand's own declared type implies (uint by
130
+ default on ES 3.00). The byte-offset operand's flag (`srcOffFlag`) is
131
+ `TO_FLAG_UNSIGNED_INTEGER` unless the target lacks unsigned types or the operand's
132
+ own `SVT_INT`/`SVT_INT16`/`SVT_INT12` type forces `TO_FLAG_INTEGER`
133
+ (`toGLSLInstruction.cpp:1618-1621`); when unsigned, both the `>> 2` and the `+
134
+ <swz>` component addend get a trailing `u` suffix (`toGLSLInstruction.cpp:1669-1675`).
135
+
136
+ ### GLSL lowering — B. WebGL2 `cb3` joint-matrix rewrite contract (the shipping path)
137
+ This is the **only** `ld_structured` lowering this emitter must actually produce
138
+ runnable WebGL2 GLSL for, restricted to the `BoneTransforms` skinning case
139
+ (vertex stage). It is a two-stage pipeline:
140
+
141
+ 1. Emit HLSLcc's reference SSBO GLSL exactly as in section A (this project's
142
+ HLSLcc fork already tolerates missing `RDEF` bindings for
143
+ `dcl_resource_structured` by falling back to the DXBC declaration's encoded
144
+ stride — see `CARBONENGINEJS-FORK.md:41-44` and
145
+ `TRANSPILING-GAPS.md:51-54`), producing text of the exact shape:
146
+ ```glsl
147
+ struct t0_type { uint[1] value; };
148
+ layout(std430, binding = 0) readonly buffer t0 { t0_type t0_buf[]; };
149
+ ...
150
+ dest = vec4(uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 0]),
151
+ uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 1]),
152
+ uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 2]),
153
+ uintBitsToFloat(t0_buf[idx].value[(0 >> 2) + 3]));
154
+ ```
155
+ Verified against an actual generated fixture
156
+ (`../shaderdiscovery/artifacts/ab-shader-set/work/skinned_fxdirectionalv5/skinned_fxdirectionalv5.sm_hi.dxbc_29291f5662ed6781.vertex.es300.glsl:60-64`):
157
+ all four components of one row share the **same** byte offset (row 0 uses
158
+ `0`, row 1 uses `16`, row 2 uses `32` — i.e. the row's base byte offset, not
159
+ a per-component offset of `0/4/8/12`), differing only in the trailing
160
+ `+ 0/1/2/3` dword index, and **without** a `u` suffix on either the shift or
161
+ the addend. The missing `u` is not a formatting nit: in this corpus the
162
+ byte-offset operand is declared `SVT_INT` (not `SVT_UINT`), so
163
+ `srcOffFlag` resolves to `TO_FLAG_INTEGER`
164
+ (`toGLSLInstruction.cpp:1618-1621`), which suppresses the `u` suffix
165
+ entirely (see `printImmediate32`, `toGLSLOperand.cpp:371-387` vs. `388-395`).
166
+ This also matters functionally: `lowerStructuredBoneLoad`'s regex
167
+ (`packageTr2WebglEffect.js:875`) matches literal `(\d+)\s*>>\s*2\s*\)` with
168
+ no `u` tolerance, and its 4-component agreement check requires all four
169
+ loads to share one `byteOffset` — a per-component-varying offset of
170
+ `0/4/8/12` would both fail to match the regex *and* fail the "same
171
+ byteOffset" agreement check, silently no-opping the rewrite. The previous
172
+ worked example here was internally inconsistent with the very rewrite
173
+ contract it was illustrating.
174
+ 2. A package-time rewrite pass over the generated GLSL text, performing the
175
+ steps below **in this exact order**.
176
+
177
+ > **Superseded (2026-08-02).** This pass no longer exists. The emitter now
178
+ > declares vertex-stage structured buffers as `std140` UBOs when it emits the
179
+ > shader, with real bindings, rather than rewriting text afterwards — see
180
+ > `DxbcGlslEmitter.js`, the `dcl_resource_structured` vertex branch. The
181
+ > regex functions it describes were deleted from
182
+ > `scripts/packageTr2WebglEffect.js`, so the line citations below point at
183
+ > nothing. The section is kept because it records *why* each rewrite was
184
+ > needed, which the ccpwgl runtime ABI still constrains; read it as history,
185
+ > not as a description of the code.
186
+ 1. Strip the `#ifdef GL_ARB_shader_storage_buffer_object` /
187
+ `GL_ARB_shader_image_load_store` extension guard blocks (regexes at
188
+ `packageTr2WebglEffect.js:832-833`).
189
+ 2. Strip the `struct t0_type { uint[1] value; };` declaration (regex at
190
+ `packageTr2WebglEffect.js:834`, matches only the 1-word/4-byte stride
191
+ shape).
192
+ 3. Strip the `layout(std430, binding = 0) readonly buffer t0 { t0_type
193
+ t0_buf[]; };` declaration (regex at `packageTr2WebglEffect.js:835`).
194
+ 4. Grow the vertex stage's `ConstantBuffer3` (`cb3`) declaration to
195
+ `vec4 data[max(existingSize, 200)]` (`packageTr2WebglEffect.js:836-839`) —
196
+ this is where `JointMat` lives at `cb3.data[26..199]` per the ccpwgl runtime
197
+ ABI (`cb3[26..199]`, 58 joints × 12 floats = 696 floats,
198
+ `AGENT-FINDINGS/decisions/016-cewg-skinning-abi-lowering-for-ccpwgl-2026-06-30.md`
199
+ and `015-joint-matrix-jointmat-findings-ccpwgl-runtime-truth.md`).
200
+ 5. Convert `uvec4`/`ivec4` (or `uvec2/3`, `ivec2/3`) `in_BLENDINDICES<n>` vertex
201
+ inputs to plain `vec<N>` (regex at `packageTr2WebglEffect.js:840-843`)
202
+ ccpwgl binds GR2 mesh blend indices as float attributes via
203
+ `vertexAttribPointer`, not `vertexAttribIPointer`
204
+ (`AGENT-FINDINGS/decisions/028-cewg-skinned-blend-index-abi-lowering.md`).
205
+ 6. Strip the DX11 global bone-offset add HLSLcc emits when combining
206
+ `in_BLENDINDICES0` with a `cb3.data[26]` offset uniform (two regex forms at
207
+ `packageTr2WebglEffect.js:845-852`, covering both the scalar `int(...) +
208
+ floatBitsToInt(cb3.data[26].x)` shape and the vector `(i)uvec/ivec(...) +
209
+ floatBitsToInt(cb3.data[26].<swz>)` shape) — ccpwgl's `cb3.data[26]` slot is
210
+ reused for `JointMat`, not the native bone-ring-buffer offset, so this add
211
+ must be removed entirely rather than merely rewired.
212
+ 7. Rewrite each 4-component `t0_buf[...]` row-load expression
213
+ (`vec4(t0_buf[idx].value[(byteOff>>2)+0], ...)`, all 4 components required,
214
+ `lowerStructuredBoneLoad`) into:
215
+ ```glsl
216
+ cb3.data[26 + (<idx>) * 3 + <row>]
217
+ ```
218
+ where `<row> = floor(byteOff / 16)` and must be in `{0,1,2}` (a `Float4x3`
219
+ bone matrix is 3 `vec4` rows); if any of the 4 component sub-expressions
220
+ disagree on `idx`/`byteOff`, or `row` falls outside `0..2`, or the swizzle
221
+ is anything but the identity `xyzw`/`.xyzw` is stripped when default,
222
+ **the rewrite silently no-ops and leaves the un-lowered `t0_buf` text in
223
+ place** (`packageTr2WebglEffect.js:886,890,895,898` all `return match`)
224
+ this is a silent-failure edge case the implementing engineer must guard
225
+ against (add a diagnostic) rather than trust to fail loudly.
226
+ 8. If any rewrite happened, inject a `// Carbon WebGL: BoneTransforms lowered to cb3
227
+ JointMat rows.` marker comment after `#version 300 es`
228
+ (`packageTr2WebglEffect.js:859-861`).
229
+
230
+ ### GLSL lowering — C. `ld_structured` in pixel stage / non-skinning resources
231
+ The corpus also uses `ld_structured` on `t#` "packed tbuffer" resources unrelated
232
+ to skinninge.g. `LightBuffer`/`LightIndexBuffer` reads in pixel shaders such as
233
+ `decalcylindricv5.sm_depth` (`AGENT-FINDINGS/decisions/005-structured-resource-only-opcodes-2026-06-26.md`).
234
+ **No `cb3`-style *functional* ABI rewrite exists for these** — they hit the same
235
+ SSBO-unavailability wall as section A. The emitter's default path lowers them to
236
+ pixel `usampler2D` data textures (see `DxbcGlslEmitter.js` `dcl_resource_structured`
237
+ pixel branch), which compiles but consumes a texture unit each; on real drivers
238
+ the `_depth` quad variants overflow `MAX_TEXTURE_IMAGE_UNITS`(16).
239
+
240
+ **Superseded (2026-08-02) the lights fit, and are kept.** The two light
241
+ buffers now lower to a single packed `RGBA32UI` data texture rather than one
242
+ texture each, which frees two units, and the `Detail1/2/3Map` textures merge into
243
+ one array texture, which frees one or two more. Both `.sm_depth` quad variants
244
+ land at or under 16 with lighting intact: `unpackedskinned_quaddetailv5` at 15,
245
+ `unpackedskinned_quadheatdetailv5` at 16. See
246
+ `/docs/contracts/webgl2-texture-budget.md`. Dropping the lights is still
247
+ available as `--stub-light-resources` for isolating a lighting problem, but it is
248
+ no longer the answer to the budget. The paragraph below describes that opt-in
249
+ path and remains accurate.
250
+
251
+ **Earlier resolution (2026-07-08) stub, not rewrite.** Since Carbon WebGL does not
252
+ support this tiled lighting, the packager can DROP it instead of lowering it. Run
253
+ `packageTr2WebglEffect.js --stub-light-resources`: it resolves the light resource
254
+ names (`LightBuffer`, `LightIndexBuffer`, `LightProfileArray`) to `t#` registers
255
+ from the Carbon `.sm` reflection (RDEF is stripped, so names live only there —
256
+ and the registers vary per permutation, so this is name-driven, not fixed to
257
+ sb11/sb12/s13) and passes them to `emitGlsl` as `stubResourceRegisters`. The
258
+ emitter then drops their decl+binding and lowers reads to `uintBitsToFloat(0u)`
259
+ (structured) / `vec4(0.0)` (sampled) zeroing the per-tile light count makes the
260
+ light loop dead. The packager also strips those `resource` bindings from the
261
+ manifest JSON (`stripLightResourcesFromManifest`) so the Carbon WebGL runtime does not
262
+ synthesize a texture def (glType 0 "Invalid shader texture definition") for the
263
+ now-undeclared light buffers. Opt-in, default off; every other package is
264
+ unchanged. A functional light constant-buffer path remains possible but was not
265
+ built.
266
+
267
+ Tested by `test/glsl-emitter.test.js` (synthetic pixel shaders with a structured
268
+ buffer / sampler2DArray: declared by default, dropped + no binding when the
269
+ register is in `stubResourceRegisters`, and only listed registers dropped) and
270
+ `test/stub-light-resources.test.js` (the packager's `resolveStubLightRegisters`
271
+ name→register resolution and `stripLightResourcesFromManifest` manifest filter,
272
+ in `scripts/stubLightResources.js`).
273
+
274
+ ### Type rules
275
+ - Struct index operand: read as int/uint (both flags set in HLSLcc; pick uint by
276
+ default for ES 3.00).
277
+ - Byte-offset operand: uint unless the operand's own declared type is signed int.
278
+ - Result component type follows the *destination* register's inferred type
279
+ (float `uintBitsToFloat`, int `int(...)`, uint passthrough), **not** the
280
+ source resource's declared return type — this is purely dest-driven, matching
281
+ the "everything is `float vec4`, bitcast at use" register model this project
282
+ already commits to.
283
+ - This is a data-movement instruction, not a comparison it does not produce a
284
+ 0xFFFFFFFF/0 mask.
285
+
286
+ ### Helpers needed
287
+ - `structuredLoadComponent(bufName, structIndex, byteOffset, component, destType)`
288
+ reference-only (HLSLcc SSBO shape), needed if the emitter ever targets a
289
+ non-WebGL2 backend or documents the pre-rewrite intermediate form.
290
+ - `lowerBoneTransformsToCb3` (package-time text pass; port of
291
+ `lowerWebgl2SkinningAbi` + `lowerStructuredBoneLoad`).
292
+ - `lowerBlendIndicesToFloatAttribute` (package-time text pass, part of the same
293
+ rewrite; port of the `in_BLENDINDICES` regex).
294
+ - `refuseNonSkinningStructuredLoad` (detection helper for section C).
295
+
296
+ ### Edge cases
297
+ - NaN/inf: none introduced by the load itself; `uintBitsToFloat` is a pure
298
+ bit-reinterpret, so any NaN bit pattern already in the buffer round-trips as
299
+ NaN.
300
+ - The resource-operand swizzle indirection (`psSrc->aui32Swizzle[component]`)
301
+ means component `c` of the destination is not guaranteed to read structure
302
+ dword `c` — verify this against real corpus DXBC before assuming identity
303
+ swizzle always holds.
304
+ - The row/index-agreement check in `lowerStructuredBoneLoad` requires **all 4**
305
+ components to share the same `idx`/`byteOffset`; a destination write mask
306
+ narrower than `.xyzw` (e.g. `.xy`) will not match the 4-load regex and will
307
+ silently fail to rewrite this is plausible for shaders that only need part of
308
+ a bone row and needs explicit test coverage.
309
+ - `bSaturate` on `ld_structured` is legal per the generic post-switch handling
310
+ but is not expected to appear in real bone/light-buffer loads; still must be
311
+ implemented for correctness if the corpus is ever re-scanned with `_sat`
312
+ detection.
313
+
314
+ ### WebGL2 notes
315
+ - SSBOs (`buffer` blocks) do not exist in GLSL ES 3.00 at all; section A's
316
+ output is fundamentally uncompilable in WebGL2 and must never reach the
317
+ final package unless rewritten by section B.
318
+ - `layout(std430, binding=N)` is likewise unavailable in ES 3.00 (`std430` and UBO
319
+ binding indices exist, but SSBO binding does not).
320
+
321
+ ### Confidence
322
+ **High** for the `BoneTransforms`/`cb3` path (validated end-to-end:
323
+ `336/336` and `240/240` WebGL2 program links per
324
+ `TRANSPILING-GAPS.md:60-63` and `016-cewg-skinning-abi-lowering-for-ccpwgl-2026-06-30.md`).
325
+ **Low** for non-skinning `ld_structured` in pixel stages — no validated WebGL2
326
+ lowering exists; treat as blocked pending a decision.
327
+
328
+ ---
329
+
330
+ ## `store_structured` (930 instances)
331
+
332
+ ### Semantics
333
+ Writes one or more 32-bit components of a structured-buffer element addressed by
334
+ a structure index and byte offset, per D3D11 `store_structured` (the inverse of
335
+ `ld_structured`; only valid against a UAV, since D3D11 `structured buffer`
336
+ read-only resources cannot be written).
337
+
338
+ ### GLSL lowering
339
+ `TranslateShaderStorageStore`, case `OPCODE_STORE_STRUCTURED`
340
+ (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1500-1583`, dispatched at
341
+ `toGLSLInstruction.cpp:4348-4357`). Operands: `psDest=asOperands[0]` (the UAV
342
+ resource, carrying the write mask via `OPERAND_4_COMPONENT_MASK_MODE`),
343
+ `psDestAddr=asOperands[1]` (struct index), `psDestByteOff=asOperands[2]` (byte
344
+ offset), `psSrc=asOperands[3]` (value to store).
345
+
346
+ For each component present in `psDest->ui32CompMask`:
347
+ ```glsl
348
+ <name>_buf[<structIndexExpr>].value[(<byteOffExpr> >> 2u) + <comp>u] = <uint-or-int-cast>(src.<swz-or-x>);
349
+ ```
350
+ (`toGLSLInstruction.cpp:1534-1582`). `dstOffFlag` follows the same
351
+ unsigned-unless-signed-typed rule as `ld_structured`. The source cast (`srcFlag`)
352
+ is `TO_FLAG_UNSIGNED_INTEGER` by default, flipped to `TO_FLAG_INTEGER` only when
353
+ `DeclareRWStructuredBufferTemplateTypeAsInteger` reports the target buffer as a
354
+ single-`int`-typed `RWStructuredBuffer<int4>` (the "avoid calling the wrong
355
+ `AtomicMin` overload" special case, `toGLSLDeclaration.cpp:998-1025`) otherwise
356
+ the destination array element type is always `uint` (`toGLSLInstruction.cpp:1569-1572`).
357
+ Source components are consumed left-to-right via an incrementing `srcComponent`
358
+ counter if the source operand has more than one swizzle element, else always
359
+ `.x` (`toGLSLInstruction.cpp:1575-1578`).
360
+
361
+ ### Type rules
362
+ - Destination index/byte-offset: same int/uint rule as `ld_structured`.
363
+ - Source value: bitcast to uint (default) or int (special RWStructuredBuffer<int>
364
+ case) before storing never stored as float, consistent with "backing array is
365
+ always uint".
366
+
367
+ ### Helpers needed
368
+ - `structuredStoreComponent(bufName, structIndex, byteOffset, component, value,
369
+ srcType)` reference-only; no WebGL2 target exists for this opcode (see below).
370
+
371
+ ### Edge cases
372
+ - No destination register write, so `_sat` never applies (DXBC does not attach
373
+ `_sat` to store instructions).
374
+ - Per-component write masking must exactly follow `psDest->ui32CompMask`
375
+ (`OPERAND_4_COMPONENT_MASK_MODE`), not the source operand's own mask.
376
+
377
+ ### WebGL2 notes
378
+ `store_structured` requires a writable UAV, which in turn requires an SSBO
379
+ (`buffer`, not `readonly buffer`) completely unavailable in GLSL ES 3.00. No
380
+ package-time rewrite analogous to the `cb3` skinning path exists for writes
381
+ (there is no ccpwgl uniform target that plausibly receives a per-invocation
382
+ compute-style scatter write). **This opcode is out of scope for the WebGL2
383
+ emitter.** The 930 corpus instances should be treated as evidence this opcode
384
+ occurs in DX11 stages that are not shipped to the current WebGL2 vs/ps target
385
+ (the sampled corpus instance is `createhistograms.sm_depth`, tagged
386
+ `stageName: "geometry"` in `dx11-instruction-coverage.json` but much more
387
+ plausibly a mislabeled compute shader given the histogram-building workload
388
+ and its co-occurring `sync`/`dcl_thread_group`-shaped instruction in the same
389
+ file — see the `atomic_iadd` section for the one confirmed **non**-compute
390
+ counterexample in this family, `lensflareoccludert`, which is a pixel shader,
391
+ not compute); the emitter should detect and refuse rather than attempt
392
+ emission.
393
+
394
+ ### Confidence
395
+ **Medium** on the HLSLcc reference lowering itself (directly read from source);
396
+ **high** on the WebGL2-scope conclusion (no counter-evidence of a vs/ps
397
+ `store_structured` shipping shader was found in the decision corpus, and the
398
+ project's own draft transpiler already special-cases the sibling UAV write
399
+ opcode `store_uav_typed` as a target blocker see that section).
400
+
401
+ ---
402
+
403
+ ## `store_uav_typed` (642 instances)
404
+
405
+ ### Semantics
406
+ Writes a full-precision (or format-converted) texel/element to a typed UAV
407
+ (`RWTexture*`/`RWBuffer`) at an integer address, per D3D11 `store_uav_typed`.
408
+
409
+ ### GLSL lowering
410
+ Case `OPCODE_STORE_UAV_TYPED` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4359-4415`):
411
+ ```glsl
412
+ imageStore(<uavName>, <addr-expr-by-dimension>, <value-cast-by-return-type>);
413
+ ```
414
+ The address component mask and any `TO_AUTO_EXPAND_TO_VEC{2,3,4}` flag are chosen
415
+ from the UAV's reflected `REFLECT_RESOURCE_DIMENSION_*`
416
+ (`toGLSLInstruction.cpp:4382-4407`): 1D/Buffer `.x` only; 2D/1DArray/2DMS
417
+ `.xy` with `TO_AUTO_EXPAND_TO_VEC2`; 2DArray/3D/2DMSArray/Cube `.xyz` with
418
+ `TO_AUTO_EXPAND_TO_VEC3`; CubeArray `TO_AUTO_EXPAND_TO_VEC4`. The stored value
419
+ is translated with `ResourceReturnTypeToFlag(psRes->ui32ReturnType)` i.e. cast
420
+ to match the UAV's declared return type (float/int/uint).
421
+
422
+ ### Type rules
423
+ Value operand bitcast is driven entirely by the UAV's reflected return type
424
+ (`RETURN_TYPE_FLOAT`/`SINT`/`UINT`/`UNORM`/`SNORM`), not by any DXBC instruction
425
+ flag this requires resource-binding reflection, which per
426
+ `CARBONENGINEJS-FORK.md:34-39` is frequently stripped in this project's shipped
427
+ DXBC and falls back to register-stable naming only (no return-type recovery
428
+ implied by that fallback).
429
+
430
+ ### Helpers needed
431
+ None for the WebGL2 emitter proper — see WebGL2 notes. Reference-only helper:
432
+ `imageStoreTyped(uav, addr, value, returnType)`.
433
+
434
+ ### Edge cases
435
+ - `imageStore` swizzle/expansion must match the UAV's declared dimensionality
436
+ exactly, or GLSL will reject a texel with the wrong component count.
437
+ - Missing `RDEF` reflection (this project's normal stripped-DXBC case) leaves the
438
+ return type unrecoverable, which independently blocks this opcode even before
439
+ the SSBO/image-type gap is considered.
440
+
441
+ ### WebGL2 notes
442
+ `image2D`/`imageBuffer` UAV types and `imageStore` are GLSL ES 3.10+ built-ins,
443
+ not part of ES 3.00. **Fully out of scope for the WebGL2 emitter.** This matches
444
+ the project's own draft-transpiler decision, which already lists
445
+ `store_uav_typed` as a hard `TARGET_BLOCKER_OPCODES` entry
446
+ (`../shaderdiscovery/src/core/transpiler/gles/Dx11GlesDraftTranspiler.js:130`) and
447
+ the `TRANSPILING-GAPS.md:100-114` "UAV and atomic path... blocked for current
448
+ WebGL2 target" decision. The emitter must detect `dcl_unordered_access_view_*`
449
+ declarations plus this opcode and refuse the stage (or the whole effect) with an
450
+ explicit diagnostic, never attempt best-effort emission.
451
+
452
+ ### Confidence
453
+ **High** — corroborated independently by HLSLcc source, the draft transpiler's
454
+ explicit blocker list, and the shaderdiscovery decision log.
455
+
456
+ ---
457
+
458
+ ## `sync` (183 instances)
459
+
460
+ ### Semantics
461
+ A compute-shader thread-group synchronization barrier. DXBC encodes which memory
462
+ domains/threads to synchronize via `ui32SyncFlags`: `SYNC_THREAD_GROUP_SHARED_MEMORY`,
463
+ `SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP`/`_GLOBAL`, and `SYNC_THREADS_IN_GROUP`.
464
+ It only has defined meaning inside a compute shader with a `dcl_thread_group` size.
465
+
466
+ ### GLSL lowering
467
+ Case `OPCODE_SYNC` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:3958-3984`):
468
+ ```glsl
469
+ if (flags & SYNC_THREAD_GROUP_SHARED_MEMORY) memoryBarrierShared();
470
+ if (flags & (SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP|_GLOBAL)) memoryBarrier();
471
+ if (flags & SYNC_THREADS_IN_GROUP) barrier();
472
+ ```
473
+ Each condition independently emits its statement (not mutually exclusive; a
474
+ single `sync` instruction can emit all three lines).
475
+
476
+ ### Type rules
477
+ N/Ano operands, no data type.
478
+
479
+ ### Helpers needed
480
+ None — this opcode has no GLSL ES 3.00 equivalent to helper-wrap; see WebGL2
481
+ notes.
482
+
483
+ ### Edge cases
484
+ None beyond the flag decoding itself (a bitmask, not an enum — must check all
485
+ three bits independently, not `switch`/`else if`).
486
+
487
+ ### WebGL2 notes
488
+ `barrier()`, `memoryBarrier()`, and `memoryBarrierShared()` are **compute-shader-
489
+ only** built-ins in GLSL ES (introduced with ES 3.10 compute shaders); they do
490
+ not exist in the ES 3.00 vertex/fragment built-in set at all, and vertex/fragment
491
+ shaders have no thread-group concept regardless of GLSL version. **Fully out of
492
+ scope for the WebGL2 emitter.** Detect `sync` (and its precondition,
493
+ `dcl_thread_group`) and refuse the stage.
494
+
495
+ ### Confidence
496
+ **High** — the DXBC semantics and the compute-only nature of `barrier`/
497
+ `memoryBarrier` in GLSL ES are unambiguous.
498
+
499
+ ---
500
+
501
+ ## `ld_raw` (54 instances)
502
+
503
+ ### Semantics
504
+ Reads one or more 32-bit components from a raw (`ByteAddressBuffer`) resource at
505
+ a byte offset, per D3D11 `ld_raw` same addressing model as `ld_structured` but
506
+ without a structure index (flat byte-addressed array).
507
+
508
+ ### GLSL lowering
509
+ Same function as `ld_structured`, `TranslateShaderStorageLoad`, case
510
+ `OPCODE_LD_RAW` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1602-1606`, dispatched
511
+ at `toGLSLInstruction.cpp:4416-4425`). Operands: `psDest=asOperands[0]`,
512
+ `psSrcByteOff=asOperands[1]`, `psSrc=asOperands[2]` no `psSrcAddr`, so the
513
+ `TranslateShaderStorageLoad` body skips the `[<idx>].value` indirection
514
+ entirely (`toGLSLInstruction.cpp:1661-1666`, gated on `if (psSrcAddr)`), producing:
515
+ ```glsl
516
+ <bitcast_open><name>_buf[(<byteOffExpr> >> 2u) + <comp>u]<bitcast_close>
517
+ ```
518
+ against a flat `uint`/`int` array (`vendor/HLSLcc/src/toGLSLDeclaration.cpp:1078-1088`,
519
+ `isRaw` branch: `uint <name>_buf[];` or `int <name>_buf[];` chosen by
520
+ `HaveUnsignedTypes`), not a `_type` struct array.
521
+
522
+ ### Type rules
523
+ Identical bitcast-by-destination-type rule as `ld_structured` (float
524
+ `uintBitsToFloat`, int `int(...)`, uint → passthrough).
525
+
526
+ ### Helpers needed
527
+ - `rawLoadComponent(bufName, byteOffset, component, destType)` — reference-only;
528
+ see WebGL2 notes for scope.
529
+
530
+ ### Edge cases
531
+ Same swizzle-indirection caveat as `ld_structured` (component addressing follows
532
+ the resource operand's own swizzle if present).
533
+
534
+ ### WebGL2 notes
535
+ Same SSBO unavailability as `ld_structured` section A/C. No `cb3`-style rewrite
536
+ is known or defined for raw-buffer reads the `BoneTransforms` rewrite is
537
+ specific to the structured-buffer `t0_buf[idx].value[...]` shape, not the flat
538
+ `t0_buf[...]` raw shape. **Out of scope for the WebGL2 emitter** unless/until a
539
+ specific raw-buffer resource is proven to need a package-time ABI rewrite
540
+ analogous to skinning.
541
+
542
+ The corpus table's "vs/ps" stage claim was overreach: the only sampled
543
+ instance in `dx11-instruction-coverage.json`'s `allOpcodeExamples` is
544
+ `graphics\effect.dx11\managed\space\specialfx\particles\gpu\emit.sm_depth`
545
+ tagged `stageName: "geometry"`, paired with the sibling `store_raw` opcode in
546
+ the exact same file/technique (also tagged `"geometry"`)a GPU particle
547
+ emission pass, which is much more plausibly a compute-style workload than a
548
+ genuine vertex/pixel `ByteAddressBuffer` read. Do not assume `ld_raw` is
549
+ `vs/ps`-reachable without a concrete counter-example (unlike `atomic_iadd`,
550
+ which has one — see that section).
551
+
552
+ ### Confidence
553
+ **Medium** HLSLcc source lowering is directly read and clear, but no shipping
554
+ corpus evidence of `ld_raw` reaching a WebGL2-validated vs/ps program was found
555
+ (only 54 instances total, none flagged in the skinning/JointMat decision
556
+ trail); the sole sampled corpus example is paired with `store_raw` in a
557
+ likely-compute GPU-particle-emission shader, not a vs/ps stage.
558
+
559
+ ---
560
+
561
+ ## `store_raw` (54 instances)
562
+
563
+ ### Semantics
564
+ Writes one or more 32-bit components to a raw UAV (`RWByteAddressBuffer`) at a
565
+ byte offset, per D3D11 `store_raw` — inverse of `ld_raw`.
566
+
567
+ ### GLSL lowering
568
+ Same function as `store_structured`, `TranslateShaderStorageStore`, case
569
+ `OPCODE_STORE_RAW` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1519-1523`,
570
+ dispatched at `toGLSLInstruction.cpp:4338-4346`). Operands: `psDest=asOperands[0]`,
571
+ `psDestByteOff=asOperands[1]`, `psSrc=asOperands[2]` — no `psDestAddr`, so no
572
+ `[<idx>].value` indirection (`toGLSLInstruction.cpp:1546-1551`, gated on `if
573
+ (psDestAddr)`):
574
+ ```glsl
575
+ <name>_buf[(<byteOffExpr> >> 2u) + <comp>u] = <uint-or-int-cast>(src.<swz-or-x>);
576
+ ```
577
+
578
+ ### Type rules
579
+ Same as `store_structured`: uint by default, int only for the special
580
+ single-int `RWStructuredBuffer<int4>`-shaped buffer detection (which does not
581
+ actually apply to raw buffers in practice, since that check is structured-buffer
582
+ specific, but the code path is shared).
583
+
584
+ ### Helpers needed
585
+ - `rawStoreComponent(bufName, byteOffset, component, value, srcType)`
586
+ reference-only.
587
+
588
+ ### Edge cases
589
+ No destination register, so `_sat` never applies.
590
+
591
+ ### WebGL2 notes
592
+ Requires a writable UAV/SSBO unavailable in ES 3.00. **Out of scope for the
593
+ WebGL2 emitter**; treat identically to `store_structured` (detect and refuse).
594
+
595
+ ### Confidence
596
+ **Medium** same reasoning as `ld_raw`; low corpus volume (54) with no
597
+ known vs/ps shipping path.
598
+
599
+ ---
600
+
601
+ ## `atomic_iadd` (27) / `imm_atomic_iadd` (24) / `imm_atomic_exch` (9) / `atomic_umax` (6) / `atomic_umin` (3)
602
+
603
+ Grouped: all five are handled by the single `TranslateAtomicMemOp` function and
604
+ differ only in GLSL function name and whether a previous-value destination
605
+ exists.
606
+
607
+ ### Semantics
608
+ - `atomic_iadd` / `imm_atomic_iadd`: atomically add a value to a UAV or
609
+ groupshared (TGSM) memory location; the `imm_` form additionally returns the
610
+ pre-add value into a destination register, the non-`imm_` form discards it.
611
+ - `imm_atomic_exch`: atomically replace the memory location's value and return
612
+ the previous value (exchange has no non-`imm_` counterpart in DXBC).
613
+ - `atomic_umax` / `atomic_umin`: atomically store `max`/`min` of the current
614
+ value and the source value (unsigned comparison), discarding the previous
615
+ value (no `imm_` variants observed in this corpus, though DXBC defines
616
+ `imm_atomic_umax`/`umin` too).
617
+
618
+ ### GLSL lowering
619
+ `TranslateAtomicMemOp` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:1685-2087`,
620
+ dispatched at `toGLSLInstruction.cpp:4428-4450`). Per-opcode operand layout and
621
+ GLSL function name selected at the top of the function
622
+ (`toGLSLInstruction.cpp:1700-1935`):
623
+
624
+ | Opcode | `func` | operands (dest addr order) |
625
+ |---|---|---|
626
+ | `imm_atomic_iadd` | `"Add"` | `[0]=previousValue, [1]=dest, [2]=destAddr, [3]=src` |
627
+ | `atomic_iadd` | `"Add"` | `[0]=dest, [1]=destAddr, [2]=src` (no previousValue) |
628
+ | `imm_atomic_exch` | `"Exchange"` | `[0]=previousValue, [1]=dest, [2]=destAddr, [3]=src` |
629
+ | `atomic_umin` | `"Min"` | `[0]=dest, [1]=destAddr, [2]=src` |
630
+ | `atomic_umax` | `"Max"` | `[0]=dest, [1]=destAddr, [2]=src` |
631
+
632
+ Resource-kind detection (`toGLSLInstruction.cpp:1968-2011`): if `dest` is not
633
+ `OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY`, look up its UAV binding.
634
+ `RTYPE_UAV_RWTYPED` → `isUint = (returnType == RETURN_TYPE_UINT)` and derive
635
+ `texDim` (1/2/3) from the UAV's resource dimension; `RTYPE_UAV_RWSTRUCTURED` →
636
+ `isUint=false, ui32DstDataTypeFlag |= TO_FLAG_INTEGER` only if
637
+ `DeclareRWStructuredBufferTemplateTypeAsInteger` says so; TGSM defaults to
638
+ `isUint=true, texDim=0`. Then:
639
+ ```glsl
640
+ ui32DataTypeFlag = isUint ? (TO_FLAG_UNSIGNED_INTEGER|TO_AUTO_BITCAST_TO_UINT)
641
+ : (TO_FLAG_INTEGER|TO_AUTO_BITCAST_TO_INT);
642
+ ```
643
+ (`toGLSLInstruction.cpp:2013-2016`). If `previousValue` exists, it's assigned via
644
+ `AddAssignToDest(previousValue, isUint?SVT_UINT:SVT_INT, 1, ...)` **before** the
645
+ atomic call text is emitted (`toGLSLInstruction.cpp:2018-2019`). Final emitted
646
+ shape (`toGLSLInstruction.cpp:2021-2086`):
647
+ - Typed-UAV (image) form (`texDim>0`):
648
+ ```glsl
649
+ [prev =] imageAtomic<Func>(<uavName>, <addr>.<xy|xyz|x>, <src-cast>);
650
+ ```
651
+ - Buffer/TGSM form (`texDim==0`):
652
+ ```glsl
653
+ [prev =] atomic<Func>(<name>[_buf][<addr> >> 2u], <src-cast>);
654
+ ```
655
+ where `<name>_buf[<addr>]` gains an extra `.value[<addrY> >> 2u]` indirection
656
+ if the destAddr operand carries **two** swizzle components (X and Y) — "structured
657
+ buf if we have both x & y swizzles" (`toGLSLInstruction.cpp:2055-2062`) vs. a
658
+ raw buffer's single-component addressing.
659
+ - No trailing `;` is appended when `previousValue` is set (the assignment prologue
660
+ handles closing parens/semicolon via `AddAssignPrologue`); otherwise the line
661
+ is terminated with `;\n` directly (`toGLSLInstruction.cpp:2081-2086`).
662
+
663
+ ### Type rules
664
+ - Both `compare`/`src` (when present) are cast via the same
665
+ `ui32DataTypeFlag` (`TO_AUTO_BITCAST_TO_UINT` or `_INT`), i.e. bitcast from the
666
+ underlying float-vec4 register storage to whichever integer type the target
667
+ memory location actually holds.
668
+ - `previousValue` destination type is `SVT_UINT` or `SVT_INT` matching `isUint`,
669
+ never float directly (though the register itself is stored as float and
670
+ bitcast at the destination-write site per this project's register model).
671
+ - These do **not** produce DXBC comparison masks; `atomic_umin`/`umax` compare
672
+ internally to select which value to store, but the DXBC/GLSL result is the
673
+ stored/previous *value*, not a boolean or 0xFFFFFFFF/0 mask.
674
+
675
+ ### Helpers needed
676
+ None implementable for WebGL2 (see below). Reference-only helpers if ever
677
+ targeting ES 3.10+/desktop: `atomicUavOrTgsmOp(func, dest, addr, src,
678
+ [compare], [returnsPrevious])`.
679
+
680
+ ### Edge cases
681
+ - `atomic_umin`/`atomic_umax` are unsigned-only per DXBC (`imin`/`imax` variants
682
+ exist separately for signed); do not conflate with `atomic_imin`/`imax`.
683
+ - The 1-vs-2-swizzle-component destAddr distinction (structured vs. raw
684
+ addressing within the same atomic path) must be preserved if this is ever
685
+ ported.
686
+
687
+ ### WebGL2 notes
688
+ `atomicAdd`/`atomicMin`/`atomicMax`/`atomicExchange`/`atomicCompSwap` (buffer/
689
+ shared-memory atomics) and `imageAtomicAdd` etc. (image atomics) are GLSL ES
690
+ 3.10+ compute-shader-only built-ins; none exist in ES 3.00 vertex/fragment
691
+ shaders, regardless of which D3D11 stage the source instruction came from.
692
+ **Fully out of scope for the WebGL2 emitter.** Detect any `atomic_*`/
693
+ `imm_atomic_*` opcode and refuse the stage.
694
+
695
+ Do **not** rely on "these only occur in compute shaders" as the reason for
696
+ skipping this check in the pixel-stage emitter: `dx11-instruction-coverage.json`
697
+ (`initialCandidateOpcodeExamples`) records a concrete `atomic_iadd` instance in
698
+ `graphics\effect.dx11\managed\space\specialfx\lensflares\lensflareoccludert.sm_depth`
699
+ tagged `stageIndex: 1` / `stageName: "pixel"` — an actual D3D11 pixel shader
700
+ (D3D11.1 permits UAV access from pixel shaders; a lens-flare occlusion query
701
+ written into a UAV counter from the pixel stage is a plausible, ordinary
702
+ technique, not a mislabeled compute pass). The other four sampled corpus
703
+ instances of this opcode group (`atomic_iadd` again in `createhistograms.sm_depth`,
704
+ `imm_atomic_iadd` in `clear.sm_depth`, `imm_atomic_exch`/`atomic_umax`/
705
+ `atomic_umin` in `computelightlists.sm_depth`) are all tagged `stageName:
706
+ "geometry"` by the same tool, but those files' names (histogram building,
707
+ particle-buffer clear, light-list culling) are classic GPGPU compute-shader
708
+ workloads, and the coverage tool has no `"compute"` stage label at all in its
709
+ vocabulary (only `vertex`/`pixel`/`geometry`/`hull`) — those four are much
710
+ better explained as compute shaders whose slot the tool mislabels than as
711
+ genuine geometry shaders (a real DX11 geometry shader cannot declare
712
+ `dcl_thread_group`/`sync`, which the *sibling* `createhistograms.sm_depth`
713
+ example for the `sync` opcode does, and DXBC does not permit that in a
714
+ geometry stage). The `lensflareoccludert` pixel-stage instance is not
715
+ explained away by that reasoning and must be treated as real: the emitter's
716
+ **ps-stage translation path itself** needs the detect-and-refuse check, not
717
+ just a pre-filter that assumes this opcode class never survives into a vs/ps
718
+ compile.
719
+
720
+ `TRANSPILING-GAPS.md:100-114` ("UAV and atomic path... blocked for current
721
+ WebGL2 target... `atomic_iadd`: 6... Affects the `lensflareoccludert` path" —
722
+ note that count was measured on a narrower earlier corpus slice than this
723
+ family's 450k-instruction sweep, which shows 27) already names
724
+ `lensflareoccludert` as the blocked case; it does not itself claim the
725
+ instruction is compute-only, and the per-instruction corpus scan confirms it
726
+ is not.
727
+
728
+ ### Confidence
729
+ **High** for the DXBC/GLSL semantics (read directly from source) and for the
730
+ WebGL2-out-of-scope conclusion (ES 3.00 has no atomics in any stage, so the
731
+ `lensflareoccludert` pixel-shader counterexample does not change the outcome).
732
+ **Medium** on the blanket "compute-only" framing carried over from the
733
+ project's decision log confirmed false for at least the `lensflareoccludert`
734
+ `atomic_iadd` instance, which is a pixel shader; the emitter must not assume
735
+ this opcode family is filtered out before reaching ps-stage translation.
736
+
737
+ ---
738
+
739
+ ## `ld_uav_typed` (18 instances)
740
+
741
+ ### Semantics
742
+ Reads a texel/element from a typed UAV (`RWTexture*`/`RWBuffer`) at an integer
743
+ address, per D3D11 `ld_uav_typed` — the read counterpart of `store_uav_typed`.
744
+
745
+ ### GLSL lowering
746
+ Case `OPCODE_LD_UAV_TYPED` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4266-4336`).
747
+ Operands: `psDest=asOperands[0]`, `psSrcAddr=asOperands[1]`,
748
+ `psSrc=asOperands[2]` (UAV resource). Address component mask derived from
749
+ `psInst->eResDim` the same way as `store_uav_typed` (1/2/3 components,
750
+ `toGLSLInstruction.cpp:4281-4300`). Source data type resolved from the UAV's
751
+ reflected return type (`RETURN_TYPE_FLOAT/SINT/UINT/SNORM/UNORM`,
752
+ `toGLSLInstruction.cpp:4302-4325`, with `UNORM`/`SNORM` both mapping to
753
+ `SVT_FLOAT`). Emitted form:
754
+ ```glsl
755
+ dest.mask = imageLoad(<uavName>, <addr-by-dimension>)<swizzle-with-mask>;
756
+ ```
757
+ using `AddAssignToDest`/`AddAssignPrologue` for the destination, and
758
+ `TranslateOperandSwizzleWithMask` to apply the resource operand's own swizzle to
759
+ the 4-component `imageLoad` result restricted to the destination write mask
760
+ (`toGLSLInstruction.cpp:4327-4335`).
761
+
762
+ ### Type rules
763
+ Destination component type follows the UAV's reflected return type, not a fixed
764
+ uint-array convention (unlike `ld_structured`/`ld_raw`)`imageLoad` always
765
+ returns a 4-component vector of the sampler/image's declared base type
766
+ (`ivec4`/`uvec4`/`vec4`), then swizzled down to the requested mask.
767
+
768
+ ### Helpers needed
769
+ None for WebGL2 (see below). Reference-only: `imageLoadTyped(uav, addr,
770
+ returnType)`.
771
+
772
+ ### Edge cases
773
+ Requires resource-binding reflection (return type, dimension) exactly like
774
+ `store_uav_typed` — doubly blocked when `RDEF` is stripped, independent of the
775
+ image-type gap below.
776
+
777
+ ### WebGL2 notes
778
+ `imageLoad` and image sampler types (`image2D` etc.) are ES 3.10+-only.
779
+ **Fully out of scope for the WebGL2 emitter.** Matches the draft transpiler's
780
+ explicit blocker (`Dx11GlesDraftTranspiler.js:129`) and the
781
+ `TRANSPILING-GAPS.md` UAV decision. With only 18 corpus instances (vs.
782
+ `store_uav_typed`'s 642), this is very likely the read side of a small set of
783
+ compute/UAV effects rather than any vs/ps-reachable code path but the
784
+ concrete sampled instance (`dx11-instruction-coverage.json`, `allOpcodeExamples`)
785
+ is `graphics\effect.dx11\managed\space\postprocess\measureexposure.sm_depth`
786
+ (a tone-mapping average-luminance compute pass), **not** `lensflareoccludert`.
787
+ `lensflareoccludert` is confirmed by `TRANSPILING-GAPS.md:100-114` to carry
788
+ `dcl_unordered_access_view_typed`/`atomic_iadd` (and per this family's own
789
+ corpus scan, `atomic_iadd` there is a **pixel**-stage instance — see that
790
+ section); do not conflate the two effects or assume `ld_uav_typed`'s
791
+ compute-only reasoning transfers to `atomic_iadd`.
792
+
793
+ ### Confidence
794
+ **High** same corroboration as `store_uav_typed`, corrected to cite the
795
+ right sampled effect (`measureexposure.sm_depth`, not `lensflareoccludert`).
796
+
797
+ ---
798
+
799
+ ## `bufinfo` (0 instances specified for completeness only)
800
+
801
+ ### Semantics
802
+ Returns the element count of a structured/raw/typed buffer resource, per D3D11
803
+ `bufinfo` (used for bounds-checking dynamic buffer accesses).
804
+
805
+ ### GLSL lowering
806
+ Case `OPCODE_BUFINFO` (`vendor/HLSLcc/src/toGLSLInstruction.cpp:4753-4766`):
807
+ ```glsl
808
+ dest = <ctor>(<resourceName>_buf.length());
809
+ ```
810
+ via `AddAssignToDest(dest, SVT_INT, 1, ...)` then
811
+ `<resourceName>_buf.length()` then `AddAssignPrologue`.
812
+
813
+ ### Type rules
814
+ Result is always `SVT_INT` (a signed count), regardless of the buffer's element
815
+ type.
816
+
817
+ ### Helpers needed
818
+ None — zero corpus instances; no helper is justified without evidence of use.
819
+
820
+ ### Edge cases
821
+ N/A not observed in this corpus.
822
+
823
+ ### WebGL2 notes
824
+ `.length()` on a GLSL array returns a compile-time constant for fixed-size
825
+ arrays (legal in ES 3.00) but is a **run-time** query only for SSBO
826
+ runtime-sized arrays (`buffer T { ... x[]; }`), which do not exist in ES 3.00.
827
+ Since this opcode's only real use (bounds-checking a structured/raw buffer) is
828
+ tied to the same SSBO-only resource kinds as `ld_structured`/`ld_raw`, it would
829
+ be out of scope for the same reason if it appeared. Zero corpus instances means
830
+ no immediate action item, but the emitter should still recognize and refuse the
831
+ opcode defensively rather than silently mis-translate.
832
+
833
+ ### Confidence
834
+ **Low** zero real-world evidence in this corpus; semantics and lowering are
835
+ read directly from HLSLcc source but entirely unvalidated against any actual
836
+ shader.
837
+
838
+ ---
839
+
840
+ ## Helpers summary
841
+
842
+ Helpers the memory-structured family needs the emitter to provide (grouped by
843
+ whether they produce runnable WebGL2 output or are reference/detection-only):
844
+
845
+ **Shipping (WebGL2-runnable) helpers:**
846
+ 1. `lowerBoneTransformsToCb3` package-time text-rewrite pass that removes the
847
+ HLSLcc `t0` SSBO declaration, grows `cb3.data[]` to at least 200 `vec4`s,
848
+ strips the native bone-ring-buffer offset add, and rewrites each 4-component
849
+ `t0_buf[idx].value[...]` row load to `cb3.data[26 + idx*3 + row]` (optionally
850
+ swizzled). Port of `lowerWebgl2SkinningAbi` +
851
+ `lowerStructuredBoneLoad` in `scripts/packageTr2WebglEffect.js:826-902`.
852
+ 2. `lowerBlendIndicesToFloatAttribute` — package-time rewrite of
853
+ `uvec4`/`ivec4`/etc. `in_BLENDINDICES<n>` vertex inputs to `vec<N>`, part of
854
+ the same pass (`packageTr2WebglEffect.js:840-843`).
855
+
856
+ **Reference-only helpers** (mirror HLSLcc's non-WebGL2 SSBO/UAV/atomic/compute
857
+ lowering, useful for documentation, debugging, and any future non-WebGL2
858
+ backend, but must never be emitted as final WebGL2 output):
859
+ 3. `structuredLoadComponent(bufName, structIndex, byteOffset, component, destType)`
860
+ 4. `structuredStoreComponent(bufName, structIndex, byteOffset, component, value, srcType)`
861
+ 5. `rawLoadComponent(bufName, byteOffset, component, destType)`
862
+ 6. `rawStoreComponent(bufName, byteOffset, component, value, srcType)`
863
+ 7. `imageLoadTyped(uav, addr, returnType)`
864
+ 8. `imageStoreTyped(uav, addr, value, returnType)`
865
+ 9. `atomicUavOrTgsmOp(func, dest, addr, src, compare?, returnsPrevious?)`
866
+
867
+ **Detection/refusal helpers** (must run before emission; there is no GLSL ES
868
+ 3.00 lowering to fall back to):
869
+ 10. `refuseComputeOnlyOpcode(opcodeName)` — for `sync`, `store_structured`
870
+ (non-skinning), `store_raw`, `store_uav_typed`, `ld_uav_typed`,
871
+ `atomic_iadd`, `imm_atomic_iadd`, `imm_atomic_exch`, `atomic_umax`,
872
+ `atomic_umin`, and `bufinfo` should it ever appear.
873
+ 11. `refuseNonSkinningStructuredLoad(resourceName)` — for `ld_structured` /
874
+ `ld_raw` uses that are not the vertex-stage `BoneTransforms` skinning
875
+ pattern (e.g. `LightBuffer`/`LightIndexBuffer` pixel-stage reads).
876
+
877
+ ---
878
+
879
+ *Sources consulted: `vendor/HLSLcc/src/toGLSLInstruction.cpp`,
880
+ `toGLSLOperand.cpp`, `toGLSLDeclaration.cpp`, `HLSLccToolkit.cpp`,
881
+ `internal_includes/languages.h`; `vendor/HLSLcc/CARBONENGINEJS-FORK.md`;
882
+ `../shaderdiscovery/TRANSPILING-GAPS.md`; `../shaderdiscovery/AGENT-FINDINGS/decisions/005-`,
883
+ `016-`, `028-cewg-*`, `014-`/`015-`/`016-`/`017-joint-matrix-*`;
884
+ `../shaderdiscovery/src/core/transpiler/gles/Dx11GlesDraftTranspiler.js` (hints
885
+ only); `scripts/packageTr2WebglEffect.js`;
886
+ `../shaderdiscovery/artifacts/dx11-instruction-coverage.json` (per-instruction
887
+ stage ground truth, used to correct several "compute-only" stage-reality
888
+ claims); `../shaderdiscovery/artifacts/ab-shader-set/work/skinned_fxdirectionalv5/*.es300.glsl`
889
+ (actual generated fixture, used to correct the `ld_structured` cb3 worked
890
+ example).*