@carbonenginejs/runtime-resource 0.12.2 → 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,955 +1,1147 @@
1
- import { CjsFormatWriteError } from '../CjsFormatError.js';
2
- import { compareUtf8 } from '../compareUtf8.js';
3
-
4
- // Source: trinity/shadercompiler/EffectData.h (Save methods)
5
- // Source: trinity/trinity/Shader/Tr2EffectDescription.cpp (Read)
6
-
7
-
8
- /**
9
- * The only description-blob version this module reads or writes.
10
- *
11
- * `DATA_VERSION` in `EffectData.h:10`. Carbon's reader accepts 2..15
12
- * (`Tr2EffectRes.cpp:209`) but annotates the v13/v14 field-order boundaries as
13
- * unverified — `// CHECK IS IT IN RIGHT FUNCTION?` at
14
- * `Tr2EffectDescription.cpp:177`, `// CHECK` at `:257` and `:578`. The v15
15
- * layout is the one with an authoritative writer to check against, it is the
16
- * only version the shipped corpus contains, and it is byte-identical to v14 in
17
- * the body — v15 differs from v14 only by the 36 outer header bytes.
18
- */
19
- const CARBON_EFFECT_DATA_VERSION = 15;
20
-
21
- /**
22
- * Annotation type codes (`EffectData.h:35-41`). Only `STRING` changes the wire
23
- * shape of the value that follows.
24
- */
25
- const CARBON_ANNOTATION_TYPE = Object.freeze({
26
- BOOL: 0,
27
- INT: 1,
28
- FLOAT: 2,
29
- STRING: 3
30
- });
31
-
32
- /**
33
- * Carbon's inclusive count limits, from the `SanityCheck` call sites in
34
- * `Tr2EffectDescription.cpp:28-36`. `SanityCheck` throws only when
35
- * `value > limit`, so each number is the largest accepted count.
36
- *
37
- * The absent entries are absent in Carbon too: `techniques`, `registers`,
38
- * `staticSamplers`, `constants`, `libraries`, `exports` and the per-annotation
39
- * counts are read with no limit at all, guarded only by the end-of-buffer
40
- * check. We do not invent caps Carbon does not have.
41
- */
42
- const CARBON_EFFECT_COUNT_CAPS = Object.freeze({
43
- pipelineInputs: 64,
44
- passes: 64,
45
- stages: 6,
46
- textures: 64,
47
- samplers: 64,
48
- uavs: 64,
49
- renderStates: 64,
50
- effectAnnotations: 256
51
- });
52
-
53
- /**
54
- * `SHADER_CONSTANTS_MAX` (`Tr2EffectDescription.h:160`) — Carbon clamps a
55
- * stage's default-constant-value copy to this without rejecting the file, while
56
- * still advancing the cursor by the untruncated size.
57
- */
58
- const CARBON_SHADER_CONSTANTS_MAX = 4096;
59
-
60
- /**
61
- * Compares two annotation names the way Carbon sorts annotation keys before
62
- * writing them (`strcmp`, `EffectData.h:613-616` and `:839-842`).
63
- *
64
- * `strcmp` orders by unsigned byte, which for names outside ASCII is not the
65
- * same as JavaScript's UTF-16 code-unit order — hence the explicit UTF-8
66
- * comparison.
67
- *
68
- * @param {string} a First name.
69
- * @param {string} b Second name.
70
- * @returns {number} Negative, zero, or positive ordering result.
71
- */
72
- function compareAnnotationNames(a, b) {
73
- return compareUtf8(a, b);
74
- }
75
-
76
- /**
77
- * Resolver that writes each arena reference back at the offset it was read
78
- * from, reusing the source arena verbatim.
79
- *
80
- * This is what proves field order independently of arena policy: a re-emit
81
- * through this resolver must reproduce the original description bytes exactly,
82
- * whatever the arena happens to contain.
83
- */
84
- const passthroughArena = Object.freeze({
85
- /**
86
- * Returns a parsed string reference's original offset.
87
- *
88
- * @param {{offset:number}} reference Parsed string reference.
89
- * @returns {number} Original arena offset.
90
- */
91
- string(reference) {
92
- return reference.offset;
93
- },
94
- /**
95
- * Returns a parsed blob reference's original offset.
96
- *
97
- * @param {{offset:number}} reference Parsed blob reference.
98
- * @returns {number} Original arena offset.
99
- */
100
- blob(reference) {
101
- return reference.offset;
102
- }
103
- });
104
-
105
- /**
106
- * Creates a resolver that re-interns every reference into a fresh string table,
107
- * so the emitted arena is rebuilt under Carbon's sorted-offset policy.
108
- *
109
- * @param {import("../CjsStringTable.js").CjsStringTable} table Target arena.
110
- * @returns {{string:Function, blob:Function}} Arena resolver.
111
- */
112
- function internArena(table) {
113
- return {
114
- /**
115
- * Interns a string reference's text and returns its offset.
116
- *
117
- * @param {{value:string}} reference Parsed string reference.
118
- * @returns {number} Arena offset.
119
- */
120
- string(reference) {
121
- return table.offsetOf(table.addString(reference.value));
122
- },
123
- /**
124
- * Interns a blob reference's bytes and returns its offset. A zero-size
125
- * blob keeps its original reference — Carbon leaves the offset word
126
- * unset in that case, and the reader never dereferences it.
127
- *
128
- * @param {{size:number, offset:number, bytes:Uint8Array}} reference Parsed blob reference.
129
- * @returns {number} Arena offset.
130
- */
131
- blob(reference) {
132
- if (reference.size === 0) return reference.offset;
133
- return table.offsetOf(table.addBytes(reference.bytes));
134
- }
135
- };
136
- }
137
-
138
- /**
139
- * Creates a resolver that only interns, emitting a placeholder offset.
140
- *
141
- * Carbon resolves an arena offset while packing a body
142
- * (`PackedStream::Save(StringReference)`, `EffectData.h:187-193`), by which
143
- * point every string must already be in the table — a late `AddString` marks
144
- * the table dirty and the next `GetOffset` re-sorts it, silently invalidating
145
- * every offset already baked into a packed body. Carbon dodges this by
146
- * interning all late strings up front (`ShaderCompiler.cpp:686-694`, before the
147
- * packing loop at `:697-714`).
148
- *
149
- * Running the write walk twice — once collecting, once emitting — reproduces
150
- * that discipline without depending on a caller remembering it, and because
151
- * both passes traverse the same code they cannot drift apart.
152
- *
153
- * @param {import("../CjsStringTable.js").CjsStringTable} table Target arena.
154
- * @returns {{string:Function, blob:Function}} Collect-only resolver.
155
- */
156
- function collectArena(table) {
157
- return {
158
- /**
159
- * Interns a string reference's text.
160
- *
161
- * @param {{value:string}} reference Parsed string reference.
162
- * @returns {number} Placeholder offset.
163
- */
164
- string(reference) {
165
- table.addString(reference.value);
166
- return 0;
167
- },
168
- /**
169
- * Interns a blob reference's bytes, skipping zero-size blobs.
170
- *
171
- * @param {{size:number, bytes:Uint8Array}} reference Parsed blob reference.
172
- * @returns {number} Placeholder offset.
173
- */
174
- blob(reference) {
175
- if (reference.size !== 0) table.addBytes(reference.bytes);
176
- return 0;
177
- }
178
- };
179
- }
180
-
181
- /**
182
- * Reads a bare `u32` arena offset and the NUL-terminated string behind it.
183
- *
184
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
185
- * @returns {{offset:number, value:string}} String reference.
186
- */
187
- function readStringRef(reader) {
188
- const offset = reader.readUint32();
189
- return {
190
- offset,
191
- value: reader.readStringAt(offset)
192
- };
193
- }
194
-
195
- /**
196
- * Reads a `{u32 size, u32 offset}` blob reference.
197
- *
198
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
199
- * @returns {{size:number, offset:number, bytes:Uint8Array}} Blob reference.
200
- */
201
- function readBlobRef(reader) {
202
- const size = reader.readUint32();
203
- const blob = reader.readTableBlobOptional(size);
204
- return {
205
- size,
206
- offset: blob.offset,
207
- bytes: blob.bytes
208
- };
209
- }
210
-
211
- /**
212
- * Writes a `{u32 size, u32 offset}` blob reference.
213
- *
214
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
215
- * @param {object} arena Arena resolver.
216
- * @param {{size:number}} reference Blob reference.
217
- */
218
- function writeBlobRef(writer, arena, reference) {
219
- writer.u32(reference.size);
220
- writer.u32(arena.blob(reference));
221
- }
222
-
223
- /**
224
- * An absent sized blob: zero length, Carbon's null offset. The offset word is
225
- * still written, and a reader must not dereference it.
226
- */
227
- const EMPTY_BLOB = Object.freeze({
228
- size: 0,
229
- offset: 0xffffffff,
230
- bytes: new Uint8Array(0)
231
- });
232
-
233
- /**
234
- * Error factory used by the write path's cap checks.
235
- *
236
- * @param {string} message Failure reason.
237
- * @param {object} details Structured details.
238
- * @returns {CjsFormatWriteError} Write error.
239
- */
240
- function writeError(message, details) {
241
- return new CjsFormatWriteError(message, details);
242
- }
243
-
244
- /**
245
- * Requires that a sized record parsed to exactly its declared end.
246
- *
247
- * This is the universal form of the rule the backend block discovered, and it
248
- * carries real weight: it is the successor to roughly 600 lines of cross-chunk
249
- * agreement checks that the container rewrite deletes. Those checks caught a
250
- * malformed *tree* our writer emitting something structurally wrong — not only a
251
- * malformed file. Under a record layout a writer bug either fails to parse, which
252
- * is self-announcing, or it parses and leaves the cursor somewhere other than the
253
- * declared end. Trailing bytes therefore mean one of two things, both fatal: the
254
- * writer knew fields this reader does not, or the writer miscounted.
255
- *
256
- * Applying it to some sized records and not others is a gap that stays invisible
257
- * until a writer bug hides in one of the others, so every sized record gets it.
258
- *
259
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Reader at the record end.
260
- * @param {string} what Record name for the error message.
261
- * @param {Function} makeError Error factory.
262
- */
263
- function requireExhaustive(reader, what, makeError) {
264
- if (reader.remaining !== 0) {
265
- throw makeError(`Carbon effect ${what} has ${reader.remaining} unparsed trailing byte(s)`, {
266
- trailingBytes: reader.remaining,
267
- offset: reader.offset,
268
- end: reader.end
269
- });
270
- }
271
- }
272
-
273
- /**
274
- * Rejects a count above Carbon's inclusive limit for that field.
275
- *
276
- * @param {number} value Count read or about to be written.
277
- * @param {string} field Cap key in `CARBON_EFFECT_COUNT_CAPS`.
278
- * @param {Function} makeError Error factory taking a message and details.
279
- * @returns {number} The count.
280
- */
281
- function sanityCheck(value, field, makeError) {
282
- const limit = CARBON_EFFECT_COUNT_CAPS[field];
283
- if (limit !== undefined && value > limit) {
284
- throw makeError(`Effect ${field} count ${value} exceeds Carbon's limit of ${limit}`, {
285
- field,
286
- value,
287
- limit
288
- });
289
- }
290
- return value;
291
- }
292
-
293
- /**
294
- * Reads one annotation map: `u8 count`, then name/type/value triples
295
- * (`ParameterAnnotation::Save` `EffectData.h:601-623`, `ReadAnnotations`
296
- * `Tr2EffectDescription.cpp:114-134`).
297
- *
298
- * A non-string value is kept as its raw four bytes. Carbon writes it through
299
- * the `float` member of a `{float,int32_t}` union and reads it back through a
300
- * different union, so the bytes are the only faithful representation; applying
301
- * an int/float conversion here would corrupt round-trips.
302
- *
303
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
304
- * @returns {object[]} Annotation records.
305
- */
306
- function readAnnotations(reader) {
307
- const count = reader.readUint8();
308
- const annotations = [];
309
- for (let index = 0; index < count; index += 1) {
310
- const name = readStringRef(reader);
311
- const type = reader.readUint8();
312
- if (type === CARBON_ANNOTATION_TYPE.STRING) {
313
- annotations.push({
314
- name,
315
- type,
316
- stringValue: readStringRef(reader),
317
- rawValue: null
318
- });
319
- } else {
320
- annotations.push({
321
- name,
322
- type,
323
- stringValue: null,
324
- rawValue: Uint8Array.from(reader.readRaw(4))
325
- });
326
- }
327
- }
328
- return annotations;
329
- }
330
-
331
- /**
332
- * Writes one annotation map.
333
- *
334
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
335
- * @param {object} arena Arena resolver.
336
- * @param {object[]} annotations Annotation records.
337
- */
338
- function writeAnnotations(writer, arena, annotations) {
339
- writer.u8(annotations.length);
340
- for (const annotation of annotations) {
341
- writer.u32(arena.string(annotation.name));
342
- writer.u8(annotation.type);
343
- if (annotation.type === CARBON_ANNOTATION_TYPE.STRING) {
344
- writer.u32(arena.string(annotation.stringValue));
345
- } else {
346
- writer.bytes(annotation.rawValue);
347
- }
348
- }
349
- }
350
-
351
- /**
352
- * Reads one `Constant` (`EffectData.h:283-294`, `ReadConstant`
353
- * `Tr2EffectDescription.cpp:136-170`).
354
- *
355
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
356
- * @returns {object} Constant record.
357
- */
358
- function readConstant(reader) {
359
- return {
360
- name: readStringRef(reader),
361
- offset: reader.readUint32(),
362
- size: reader.readUint32(),
363
- type: reader.readUint8(),
364
- dimension: reader.readUint8(),
365
- elements: reader.readUint32(),
366
- isSRGB: reader.readUint8(),
367
- isAutoregister: reader.readUint8()
368
- };
369
- }
370
-
371
- /**
372
- * Writes one `Constant`.
373
- *
374
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
375
- * @param {object} arena Arena resolver.
376
- * @param {object} constant Constant record.
377
- */
378
- function writeConstant(writer, arena, constant) {
379
- writer.u32(arena.string(constant.name));
380
- writer.u32(constant.offset);
381
- writer.u32(constant.size);
382
- writer.u8(constant.type);
383
- writer.u8(constant.dimension);
384
- writer.u32(constant.elements);
385
- writer.u8(constant.isSRGB);
386
- writer.u8(constant.isAutoregister);
387
- }
388
-
389
- /**
390
- * Reads one `Texture` (`EffectData.h:320-328`, `ReadResource`
391
- * `Tr2EffectDescription.cpp:172-190`). `count` is the reader's
392
- * `arrayElements`.
393
- *
394
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
395
- * @returns {object} Texture record.
396
- */
397
- function readTexture(reader) {
398
- return {
399
- name: readStringRef(reader),
400
- type: reader.readUint8(),
401
- count: reader.readUint32(),
402
- isSRGB: reader.readUint8(),
403
- isAutoregister: reader.readUint8()
404
- };
405
- }
406
-
407
- /**
408
- * Writes one `Texture`.
409
- *
410
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
411
- * @param {object} arena Arena resolver.
412
- * @param {object} texture Texture record.
413
- */
414
- function writeTexture(writer, arena, texture) {
415
- writer.u32(arena.string(texture.name));
416
- writer.u8(texture.type);
417
- writer.u32(texture.count);
418
- writer.u8(texture.isSRGB);
419
- writer.u8(texture.isAutoregister);
420
- }
421
-
422
- /**
423
- * Reads one `Uav` (`EffectData.h:345-352`, inline at
424
- * `Tr2EffectDescription.cpp:449-463`).
425
- *
426
- * A UAV record is one byte shorter than a texture record: it carries no
427
- * `isSRGB`. Carbon's reader hardcodes `isSRGB = false`
428
- * (`Tr2EffectDescription.cpp:450`) rather than reading it, and `Uav::Save`
429
- * omits it. Reusing a shared "resource" codec for both is the mistake this
430
- * comment exists to prevent.
431
- *
432
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
433
- * @returns {object} UAV record.
434
- */
435
- function readUav(reader) {
436
- return {
437
- name: readStringRef(reader),
438
- type: reader.readUint8(),
439
- count: reader.readUint32(),
440
- isAutoregister: reader.readUint8()
441
- };
442
- }
443
-
444
- /**
445
- * Writes one `Uav`.
446
- *
447
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
448
- * @param {object} arena Arena resolver.
449
- * @param {object} uav UAV record.
450
- */
451
- function writeUav(writer, arena, uav) {
452
- writer.u32(arena.string(uav.name));
453
- writer.u8(uav.type);
454
- writer.u32(uav.count);
455
- writer.u8(uav.isAutoregister);
456
- }
457
-
458
- /**
459
- * Reads one `Sampler` (`EffectData.h:368-390`, `ReadSampler`
460
- * `Tr2EffectDescription.cpp:192-232` plus the name at `:413` and `isDynamic`
461
- * at `:429`). Border colour here is four floats unlike a static sampler,
462
- * where it is a one-byte enum.
463
- *
464
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
465
- * @returns {object} Sampler record.
466
- */
467
- function readSampler(reader) {
468
- return {
469
- name: readStringRef(reader),
470
- comparison: reader.readUint8(),
471
- minFilter: reader.readUint8(),
472
- magFilter: reader.readUint8(),
473
- mipFilter: reader.readUint8(),
474
- addressU: reader.readUint8(),
475
- addressV: reader.readUint8(),
476
- addressW: reader.readUint8(),
477
- mipLODBias: reader.readFloat32(),
478
- maxAnisotropy: reader.readUint8(),
479
- comparisonFunc: reader.readUint8(),
480
- borderColor: [reader.readFloat32(), reader.readFloat32(), reader.readFloat32(), reader.readFloat32()],
481
- minLOD: reader.readFloat32(),
482
- maxLOD: reader.readFloat32(),
483
- isDynamic: reader.readUint8()
484
- };
485
- }
486
-
487
- /**
488
- * Writes one `Sampler`.
489
- *
490
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
491
- * @param {object} arena Arena resolver.
492
- * @param {object} sampler Sampler record.
493
- */
494
- function writeSampler(writer, arena, sampler) {
495
- writer.u32(arena.string(sampler.name));
496
- writer.u8(sampler.comparison);
497
- writer.u8(sampler.minFilter);
498
- writer.u8(sampler.magFilter);
499
- writer.u8(sampler.mipFilter);
500
- writer.u8(sampler.addressU);
501
- writer.u8(sampler.addressV);
502
- writer.u8(sampler.addressW);
503
- writer.f32(sampler.mipLODBias);
504
- writer.u8(sampler.maxAnisotropy);
505
- writer.u8(sampler.comparisonFunc);
506
- writer.f32(sampler.borderColor[0]);
507
- writer.f32(sampler.borderColor[1]);
508
- writer.f32(sampler.borderColor[2]);
509
- writer.f32(sampler.borderColor[3]);
510
- writer.f32(sampler.minLOD);
511
- writer.f32(sampler.maxLOD);
512
- writer.u8(sampler.isDynamic);
513
- }
514
-
515
- /**
516
- * Reads one `StaticSampler` (`EffectData.h:512-531`, read inside
517
- * `ReadRegisters` at `Tr2EffectDescription.cpp:324-365`). Border colour is a
518
- * one-byte enum here, and there is no name.
519
- *
520
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
521
- * @returns {object} Static sampler record.
522
- */
523
- function readStaticSampler(reader) {
524
- return {
525
- registerIndex: reader.readUint32(),
526
- registerSpace: reader.readUint8(),
527
- comparison: reader.readUint8(),
528
- minFilter: reader.readUint8(),
529
- magFilter: reader.readUint8(),
530
- mipFilter: reader.readUint8(),
531
- addressU: reader.readUint8(),
532
- addressV: reader.readUint8(),
533
- addressW: reader.readUint8(),
534
- mipLODBias: reader.readFloat32(),
535
- maxAnisotropy: reader.readUint8(),
536
- comparisonFunc: reader.readUint8(),
537
- borderColor: reader.readUint8(),
538
- minLOD: reader.readFloat32(),
539
- maxLOD: reader.readFloat32()
540
- };
541
- }
542
-
543
- /**
544
- * Writes one `StaticSampler`.
545
- *
546
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
547
- * @param {object} sampler Static sampler record.
548
- */
549
- function writeStaticSampler(writer, sampler) {
550
- writer.u32(sampler.registerIndex);
551
- writer.u8(sampler.registerSpace);
552
- writer.u8(sampler.comparison);
553
- writer.u8(sampler.minFilter);
554
- writer.u8(sampler.magFilter);
555
- writer.u8(sampler.mipFilter);
556
- writer.u8(sampler.addressU);
557
- writer.u8(sampler.addressV);
558
- writer.u8(sampler.addressW);
559
- writer.f32(sampler.mipLODBias);
560
- writer.u8(sampler.maxAnisotropy);
561
- writer.u8(sampler.comparisonFunc);
562
- writer.u8(sampler.borderColor);
563
- writer.f32(sampler.minLOD);
564
- writer.f32(sampler.maxLOD);
565
- }
566
-
567
- /**
568
- * Reads the `StageData` block: registers, static samplers, constants, default
569
- * constant values, textures, samplers, UAVs, annotations
570
- * (`StageData::Save` `EffectData.h:631-676`).
571
- *
572
- * Carbon's reader splits this single contiguous run across two functions —
573
- * `ReadRegisters` takes the first two sub-records
574
- * (`Tr2EffectDescription.cpp:258-367`) and `ReadInput` the remaining six
575
- * (`:369-472`). Keeping them adjacent here is what makes the split invisible.
576
- *
577
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
578
- * @param {Function} makeError Error factory.
579
- * @returns {object} Stage data record.
580
- */
581
- function readStageData(reader, makeError) {
582
- const registers = [];
583
- const registerCount = reader.readUint8();
584
- for (let index = 0; index < registerCount; index += 1) {
585
- registers.push({
586
- registerType: reader.readUint8(),
587
- registerIndex: reader.readUint32(),
588
- registerCount: reader.readUint32(),
589
- registerSpace: reader.readUint8()
590
- });
591
- }
592
- const staticSamplers = [];
593
- const staticSamplerCount = reader.readUint8();
594
- for (let index = 0; index < staticSamplerCount; index += 1) {
595
- staticSamplers.push(readStaticSampler(reader));
596
- }
597
- const constants = [];
598
- const constantCount = reader.readUint32();
599
- for (let index = 0; index < constantCount; index += 1) {
600
- constants.push(readConstant(reader));
601
- }
602
- const defaultValues = readBlobRef(reader);
603
- const textures = [];
604
- const textureCount = sanityCheck(reader.readUint8(), "textures", makeError);
605
- for (let index = 0; index < textureCount; index += 1) {
606
- const registerIndex = reader.readUint8();
607
- textures.push({
608
- registerIndex,
609
- ...readTexture(reader)
610
- });
611
- }
612
- const samplers = [];
613
- const samplerCount = sanityCheck(reader.readUint8(), "samplers", makeError);
614
- for (let index = 0; index < samplerCount; index += 1) {
615
- const registerIndex = reader.readUint8();
616
- samplers.push({
617
- registerIndex,
618
- ...readSampler(reader)
619
- });
620
- }
621
- const uavs = [];
622
- const uavCount = sanityCheck(reader.readUint8(), "uavs", makeError);
623
- for (let index = 0; index < uavCount; index += 1) {
624
- const registerIndex = reader.readUint8();
625
- uavs.push({
626
- registerIndex,
627
- ...readUav(reader)
628
- });
629
- }
630
- return {
631
- registers,
632
- staticSamplers,
633
- constants,
634
- defaultValues,
635
- textures,
636
- samplers,
637
- uavs,
638
- annotations: readAnnotations(reader)
639
- };
640
- }
641
-
642
- /**
643
- * Writes the `StageData` block.
644
- *
645
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
646
- * @param {object} arena Arena resolver.
647
- * @param {object} stageData Stage data record.
648
- */
649
- function writeStageData(writer, arena, stageData) {
650
- writer.u8(stageData.registers.length);
651
- for (const register of stageData.registers) {
652
- writer.u8(register.registerType);
653
- writer.u32(register.registerIndex);
654
- writer.u32(register.registerCount);
655
- writer.u8(register.registerSpace);
656
- }
657
- writer.u8(stageData.staticSamplers.length);
658
- for (const sampler of stageData.staticSamplers) {
659
- writeStaticSampler(writer, sampler);
660
- }
661
- writer.u32(stageData.constants.length);
662
- for (const constant of stageData.constants) {
663
- writeConstant(writer, arena, constant);
664
- }
665
- writeBlobRef(writer, arena, stageData.defaultValues);
666
-
667
- // Carbon's compiler enforces none of these caps while its runtime rejects
668
- // anything above them, so an over-large effect compiles and then fails to
669
- // load. Check on the way out instead.
670
- sanityCheck(stageData.textures.length, "textures", writeError);
671
- sanityCheck(stageData.samplers.length, "samplers", writeError);
672
- sanityCheck(stageData.uavs.length, "uavs", writeError);
673
- writer.u8(stageData.textures.length);
674
- for (const texture of stageData.textures) {
675
- writer.u8(texture.registerIndex);
676
- writeTexture(writer, arena, texture);
677
- }
678
- writer.u8(stageData.samplers.length);
679
- for (const sampler of stageData.samplers) {
680
- writer.u8(sampler.registerIndex);
681
- writeSampler(writer, arena, sampler);
682
- }
683
- writer.u8(stageData.uavs.length);
684
- for (const uav of stageData.uavs) {
685
- writer.u8(uav.registerIndex);
686
- writeUav(writer, arena, uav);
687
- }
688
- writeAnnotations(writer, arena, stageData.annotations);
689
- }
690
-
691
- /**
692
- * Reads one stage (`StageInput::Save` `EffectData.h:691-709`,
693
- * `Tr2EffectDescription.cpp:532-585`).
694
- *
695
- * At v15 the program payload comes first and the signature tables follow.
696
- * Before v14 it was the other way round; the reorder is the v14 change, and
697
- * Carbon marks its own v14 branch `// CHECK` (`:578`). Verified against the
698
- * writer: `type`, `shaderSize`, `shaderData`, `threadGroupSize[0..2]`,
699
- * `pipelineInputs`, then `StageData`.
700
- *
701
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
702
- * @param {Function} makeError Error factory.
703
- * @returns {object} Stage record.
704
- */
705
- function readStage(reader, makeError) {
706
- const type = reader.readUint8();
707
- const shaderData = readBlobRef(reader);
708
- const threadGroupSize = [reader.readUint32(), reader.readUint32(), reader.readUint32()];
709
- const pipelineInputs = [];
710
- const pipelineInputCount = sanityCheck(reader.readUint8(), "pipelineInputs", makeError);
711
- for (let index = 0; index < pipelineInputCount; index += 1) {
712
- pipelineInputs.push({
713
- usage: reader.readUint8(),
714
- registerIndex: reader.readUint8(),
715
- usageIndex: reader.readUint8(),
716
- usedMask: reader.readUint8(),
717
- type: reader.readUint8(),
718
- dimension: reader.readUint8()
719
- });
720
- }
721
- return {
722
- type,
723
- shaderData,
724
- threadGroupSize,
725
- pipelineInputs,
726
- ...readStageData(reader, makeError)
727
- };
728
- }
729
-
730
- /**
731
- * Writes one stage.
732
- *
733
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
734
- * @param {object} arena Arena resolver.
735
- * @param {object} stage Stage record.
736
- */
737
- function writeStage(writer, arena, stage) {
738
- sanityCheck(stage.pipelineInputs.length, "pipelineInputs", writeError);
739
- writer.u8(stage.type);
740
- writeBlobRef(writer, arena, stage.shaderData);
741
- writer.u32(stage.threadGroupSize[0]);
742
- writer.u32(stage.threadGroupSize[1]);
743
- writer.u32(stage.threadGroupSize[2]);
744
- writer.u8(stage.pipelineInputs.length);
745
- for (const input of stage.pipelineInputs) {
746
- writer.u8(input.usage);
747
- writer.u8(input.registerIndex);
748
- writer.u8(input.usageIndex);
749
- writer.u8(input.usedMask);
750
- writer.u8(input.type);
751
- writer.u8(input.dimension);
752
- }
753
- writeStageData(writer, arena, stage);
754
- }
755
-
756
- /**
757
- * Reads one pass (`Pass::Save` `EffectData.h:724-738`).
758
- *
759
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
760
- * @param {Function} makeError Error factory.
761
- * @param {boolean} backend Whether the optional trailing block is present.
762
- * @returns {object} Pass record.
763
- */
764
- function readPass(reader, makeError, backend) {
765
- const stages = [];
766
- const stageCount = sanityCheck(reader.readUint8(), "stages", makeError);
767
- for (let index = 0; index < stageCount; index += 1) {
768
- stages.push(readStage(reader, makeError));
769
- }
770
- const renderStates = [];
771
- const stateCount = sanityCheck(reader.readUint8(), "renderStates", makeError);
772
- for (let index = 0; index < stateCount; index += 1) {
773
- renderStates.push({
774
- state: reader.readUint32(),
775
- value: reader.readUint32()
776
- });
777
- }
778
-
779
- // The one optional trailing block, present only in our own containers. A
780
- // Carbon file ends the pass at the render-state table, so leaving this gate
781
- // closed reproduces Carbon's bytes exactly.
782
- const backendBlock = backend ? readBlobRef(reader) : null;
783
- return {
784
- stages,
785
- renderStates,
786
- ...(backendBlock ? {
787
- backendBlock
788
- } : {})
789
- };
790
- }
791
-
792
- /**
793
- * Writes one pass.
794
- *
795
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
796
- * @param {object} arena Arena resolver.
797
- * @param {object} pass Pass record.
798
- * @param {boolean} backend Whether to emit the optional trailing block.
799
- */
800
- function writePass(writer, arena, pass, backend) {
801
- writer.u8(pass.stages.length);
802
- for (const stage of pass.stages) {
803
- writeStage(writer, arena, stage);
804
- }
805
- writer.u8(pass.renderStates.length);
806
- for (const entry of pass.renderStates) {
807
- writer.u32(entry.state);
808
- writer.u32(entry.value);
809
- }
810
- if (backend) {
811
- writeBlobRef(writer, arena, pass.backendBlock ?? EMPTY_BLOB);
812
- }
813
- }
814
-
815
- /**
816
- * Reads one raytracing library (`Library::Save` `EffectData.h:760-775`,
817
- * `Tr2EffectDescription.cpp:675-721`). A library carries two `StageData`
818
- * blocks and no pipeline inputs, thread group size, or stage type.
819
- *
820
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
821
- * @param {Function} makeError Error factory.
822
- * @returns {object} Library record.
823
- */
824
- function readLibrary(reader, makeError) {
825
- const payloadSize = reader.readUint32();
826
- const shaderData = readBlobRef(reader);
827
- const exports = [];
828
- const exportCount = reader.readUint32();
829
- for (let index = 0; index < exportCount; index += 1) {
830
- exports.push({
831
- type: reader.readUint8(),
832
- name: readStringRef(reader)
833
- });
834
- }
835
- return {
836
- payloadSize,
837
- shaderData,
838
- exports,
839
- hitGroupName: readStringRef(reader),
840
- globalInputs: readStageData(reader, makeError),
841
- localInputs: readStageData(reader, makeError)
842
- };
843
- }
844
-
845
- /**
846
- * Writes one raytracing library.
847
- *
848
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
849
- * @param {object} arena Arena resolver.
850
- * @param {object} library Library record.
851
- */
852
- function writeLibrary(writer, arena, library) {
853
- writer.u32(library.payloadSize);
854
- writeBlobRef(writer, arena, library.shaderData);
855
- writer.u32(library.exports.length);
856
- for (const entry of library.exports) {
857
- writer.u8(entry.type);
858
- writer.u32(arena.string(entry.name));
859
- }
860
- writer.u32(arena.string(library.hitGroupName));
861
- writeStageData(writer, arena, library.globalInputs);
862
- writeStageData(writer, arena, library.localInputs);
863
- }
864
-
865
- /**
866
- * Reads a whole v15 description blob (`EffectData::Save`
867
- * `EffectData.h:821-849`, `Tr2EffectDescription::Read`
868
- * `Tr2EffectDescription.cpp:476-731`).
869
- *
870
- * @param {import("../CjsByteReader.js").CjsByteReader} reader Reader positioned at the blob.
871
- * @param {object} [options] Read options.
872
- * @param {Function} [options.makeError] Error factory taking a message and details.
873
- * @param {boolean} [options.backend] Expect our optional per-pass trailing block.
874
- * Leave false for a Carbon file, which ends each pass at the render states.
875
- * @returns {object} Description record tree.
876
- */
877
- function readEffectDescription(reader, options = {}) {
878
- const makeError = options.makeError ?? ((message, details) => reader._error(message, details));
879
- const backend = options.backend === true;
880
- const techniques = [];
881
- const techniqueCount = reader.readUint8();
882
- for (let techniqueIndex = 0; techniqueIndex < techniqueCount; techniqueIndex += 1) {
883
- const name = readStringRef(reader);
884
- const passes = [];
885
- const passCount = sanityCheck(reader.readUint8(), "passes", makeError);
886
- for (let passIndex = 0; passIndex < passCount; passIndex += 1) {
887
- passes.push(readPass(reader, makeError, backend));
888
- }
889
- const libraries = [];
890
- const libraryCount = reader.readUint8();
891
- for (let libraryIndex = 0; libraryIndex < libraryCount; libraryIndex += 1) {
892
- libraries.push(readLibrary(reader, makeError));
893
- }
894
- techniques.push({
895
- name,
896
- passes,
897
- libraries
898
- });
899
- }
900
- const annotations = [];
901
- const parameterCount = sanityCheck(reader.readUint16(), "effectAnnotations", makeError);
902
- for (let index = 0; index < parameterCount; index += 1) {
903
- annotations.push({
904
- name: readStringRef(reader),
905
- annotations: readAnnotations(reader)
906
- });
907
- }
908
- requireExhaustive(reader, "description blob", makeError);
909
- return {
910
- techniques,
911
- annotations
912
- };
913
- }
914
-
915
- /**
916
- * Writes a whole v15 description blob.
917
- *
918
- * The `arena` resolver decides what an arena reference becomes: `passthroughArena`
919
- * keeps the source offsets, `internArena(table)` re-interns into a new table.
920
- *
921
- * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
922
- * @param {object} description Description record tree.
923
- * @param {object} [options] Write options.
924
- * @param {object} [options.arena] Arena resolver; defaults to passthrough.
925
- * @param {boolean} [options.backend] Emit our optional per-pass trailing block.
926
- * Leave false to produce bytes a Carbon reader accepts unchanged.
927
- * @returns {import("../CjsByteWriter.js").CjsByteWriter} The writer.
928
- */
929
- function writeEffectDescription(writer, description, options = {}) {
930
- const arena = options.arena ?? passthroughArena;
931
- const backend = options.backend === true;
932
- writer.u8(description.techniques.length);
933
- for (const technique of description.techniques) {
934
- writer.u32(arena.string(technique.name));
935
- writer.u8(sanityCheck(technique.passes.length, "passes", writeError));
936
- for (const pass of technique.passes) {
937
- sanityCheck(pass.stages.length, "stages", writeError);
938
- sanityCheck(pass.renderStates.length, "renderStates", writeError);
939
- writePass(writer, arena, pass, backend);
940
- }
941
- writer.u8(technique.libraries.length);
942
- for (const library of technique.libraries) {
943
- writeLibrary(writer, arena, library);
944
- }
945
- }
946
- writer.u16(sanityCheck(description.annotations.length, "effectAnnotations", writeError));
947
- for (const parameter of description.annotations) {
948
- writer.u32(arena.string(parameter.name));
949
- writeAnnotations(writer, arena, parameter.annotations);
950
- }
951
- return writer;
952
- }
953
-
954
- export { CARBON_ANNOTATION_TYPE, CARBON_EFFECT_COUNT_CAPS, CARBON_EFFECT_DATA_VERSION, CARBON_SHADER_CONSTANTS_MAX, collectArena, compareAnnotationNames, internArena, passthroughArena, readEffectDescription, writeEffectDescription };
955
- //# sourceMappingURL=carbonEffectRecords.js.map
1
+ import { CjsFormatWriteError } from '../CjsFormatError.js';
2
+ import { compareUtf8 } from '../compareUtf8.js';
3
+
4
+ // Source: trinity/shadercompiler/EffectData.h (Save methods)
5
+ // Source: trinity/trinity/Shader/Tr2EffectDescription.cpp (Read)
6
+
7
+
8
+ /**
9
+ * The current description-blob version, and the only one this module writes.
10
+ *
11
+ * `DATA_VERSION` in `EffectData.h:10`. Carbon's reader accepts 2..15
12
+ * (`Tr2EffectRes.cpp:209`) but annotates the v13/v14 field-order boundaries as
13
+ * unverified — `// CHECK IS IT IN RIGHT FUNCTION?` at
14
+ * `Tr2EffectDescription.cpp:177`, `// CHECK` at `:257` and `:578`. The v15
15
+ * layout is the one with an authoritative writer to check against, it is the
16
+ * only version the shipped corpus contains, and it is byte-identical to v14 in
17
+ * the body — v15 differs from v14 only by the 36 outer header bytes.
18
+ */
19
+ const CARBON_EFFECT_DATA_VERSION = 15;
20
+
21
+ /**
22
+ * The oldest description-blob version this module reads.
23
+ *
24
+ * Carbon threads the version through parsing rather than gating on it twice,
25
+ * and its branches reach back to version 2. Maintainer decision, 2026-08-02:
26
+ * **8 is the lowest version worth reading** — the branches below 8 have no
27
+ * examined file, no writer, and no consumer, so restoring them would be code
28
+ * with no evidence. Reading a version is not supporting it: the reader's job
29
+ * ends at a correct record tree, normalized to the v15 record shape.
30
+ */
31
+ const CARBON_EFFECT_MIN_DATA_VERSION = 8;
32
+
33
+ /**
34
+ * Annotation type codes (`EffectData.h:35-41`). Only `STRING` changes the wire
35
+ * shape of the value that follows.
36
+ */
37
+ const CARBON_ANNOTATION_TYPE = Object.freeze({
38
+ BOOL: 0,
39
+ INT: 1,
40
+ FLOAT: 2,
41
+ STRING: 3
42
+ });
43
+
44
+ /**
45
+ * Carbon's inclusive count limits, from the `SanityCheck` call sites in
46
+ * `Tr2EffectDescription.cpp:28-36`. `SanityCheck` throws only when
47
+ * `value > limit`, so each number is the largest accepted count.
48
+ *
49
+ * The absent entries are absent in Carbon too: `techniques`, `registers`,
50
+ * `staticSamplers`, `constants`, `libraries`, `exports` and the per-annotation
51
+ * counts are read with no limit at all, guarded only by the end-of-buffer
52
+ * check. We do not invent caps Carbon does not have.
53
+ */
54
+ const CARBON_EFFECT_COUNT_CAPS = Object.freeze({
55
+ pipelineInputs: 64,
56
+ passes: 64,
57
+ stages: 6,
58
+ textures: 64,
59
+ samplers: 64,
60
+ uavs: 64,
61
+ renderStates: 64,
62
+ effectAnnotations: 256
63
+ });
64
+
65
+ /**
66
+ * `SHADER_CONSTANTS_MAX` (`Tr2EffectDescription.h:160`) — Carbon clamps a
67
+ * stage's default-constant-value copy to this without rejecting the file, while
68
+ * still advancing the cursor by the untruncated size.
69
+ */
70
+ const CARBON_SHADER_CONSTANTS_MAX = 4096;
71
+
72
+ /**
73
+ * Compares two annotation names the way Carbon sorts annotation keys before
74
+ * writing them (`strcmp`, `EffectData.h:613-616` and `:839-842`).
75
+ *
76
+ * `strcmp` orders by unsigned byte, which for names outside ASCII is not the
77
+ * same as JavaScript's UTF-16 code-unit order hence the explicit UTF-8
78
+ * comparison.
79
+ *
80
+ * @param {string} a First name.
81
+ * @param {string} b Second name.
82
+ * @returns {number} Negative, zero, or positive ordering result.
83
+ */
84
+ function compareAnnotationNames(a, b) {
85
+ return compareUtf8(a, b);
86
+ }
87
+
88
+ /**
89
+ * Resolver that writes each arena reference back at the offset it was read
90
+ * from, reusing the source arena verbatim.
91
+ *
92
+ * This is what proves field order independently of arena policy: a re-emit
93
+ * through this resolver must reproduce the original description bytes exactly,
94
+ * whatever the arena happens to contain.
95
+ */
96
+ const passthroughArena = Object.freeze({
97
+ /**
98
+ * Returns a parsed string reference's original offset.
99
+ *
100
+ * @param {{offset:number}} reference Parsed string reference.
101
+ * @returns {number} Original arena offset.
102
+ */
103
+ string(reference) {
104
+ return reference.offset;
105
+ },
106
+ /**
107
+ * Returns a parsed blob reference's original offset.
108
+ *
109
+ * @param {{offset:number}} reference Parsed blob reference.
110
+ * @returns {number} Original arena offset.
111
+ */
112
+ blob(reference) {
113
+ return reference.offset;
114
+ }
115
+ });
116
+
117
+ /**
118
+ * Creates a resolver that re-interns every reference into a fresh string table,
119
+ * so the emitted arena is rebuilt under Carbon's sorted-offset policy.
120
+ *
121
+ * @param {import("../CjsStringTable.js").CjsStringTable} table Target arena.
122
+ * @returns {{string:Function, blob:Function}} Arena resolver.
123
+ */
124
+ function internArena(table) {
125
+ return {
126
+ /**
127
+ * Interns a string reference's text and returns its offset.
128
+ *
129
+ * @param {{value:string}} reference Parsed string reference.
130
+ * @returns {number} Arena offset.
131
+ */
132
+ string(reference) {
133
+ return table.offsetOf(table.addString(reference.value));
134
+ },
135
+ /**
136
+ * Interns a blob reference's bytes and returns its offset. A zero-size
137
+ * blob keeps its original reference — Carbon leaves the offset word
138
+ * unset in that case, and the reader never dereferences it.
139
+ *
140
+ * @param {{size:number, offset:number, bytes:Uint8Array}} reference Parsed blob reference.
141
+ * @returns {number} Arena offset.
142
+ */
143
+ blob(reference) {
144
+ if (reference.size === 0) return reference.offset;
145
+ return table.offsetOf(table.addBytes(reference.bytes));
146
+ }
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Creates a resolver that only interns, emitting a placeholder offset.
152
+ *
153
+ * Carbon resolves an arena offset while packing a body
154
+ * (`PackedStream::Save(StringReference)`, `EffectData.h:187-193`), by which
155
+ * point every string must already be in the table — a late `AddString` marks
156
+ * the table dirty and the next `GetOffset` re-sorts it, silently invalidating
157
+ * every offset already baked into a packed body. Carbon dodges this by
158
+ * interning all late strings up front (`ShaderCompiler.cpp:686-694`, before the
159
+ * packing loop at `:697-714`).
160
+ *
161
+ * Running the write walk twice — once collecting, once emitting — reproduces
162
+ * that discipline without depending on a caller remembering it, and because
163
+ * both passes traverse the same code they cannot drift apart.
164
+ *
165
+ * @param {import("../CjsStringTable.js").CjsStringTable} table Target arena.
166
+ * @returns {{string:Function, blob:Function}} Collect-only resolver.
167
+ */
168
+ function collectArena(table) {
169
+ return {
170
+ /**
171
+ * Interns a string reference's text.
172
+ *
173
+ * @param {{value:string}} reference Parsed string reference.
174
+ * @returns {number} Placeholder offset.
175
+ */
176
+ string(reference) {
177
+ table.addString(reference.value);
178
+ return 0;
179
+ },
180
+ /**
181
+ * Interns a blob reference's bytes, skipping zero-size blobs.
182
+ *
183
+ * @param {{size:number, bytes:Uint8Array}} reference Parsed blob reference.
184
+ * @returns {number} Placeholder offset.
185
+ */
186
+ blob(reference) {
187
+ if (reference.size !== 0) table.addBytes(reference.bytes);
188
+ return 0;
189
+ }
190
+ };
191
+ }
192
+
193
+ /**
194
+ * Reads a bare `u32` arena offset and the NUL-terminated string behind it.
195
+ *
196
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
197
+ * @returns {{offset:number, value:string}} String reference.
198
+ */
199
+ function readStringRef(reader) {
200
+ const offset = reader.readUint32();
201
+ return {
202
+ offset,
203
+ value: reader.readStringAt(offset)
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Reads a `{u32 size, u32 offset}` blob reference.
209
+ *
210
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
211
+ * @returns {{size:number, offset:number, bytes:Uint8Array}} Blob reference.
212
+ */
213
+ function readBlobRef(reader) {
214
+ const size = reader.readUint32();
215
+ const blob = reader.readTableBlobOptional(size);
216
+ return {
217
+ size,
218
+ offset: blob.offset,
219
+ bytes: blob.bytes
220
+ };
221
+ }
222
+
223
+ /**
224
+ * Writes a `{u32 size, u32 offset}` blob reference.
225
+ *
226
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
227
+ * @param {object} arena Arena resolver.
228
+ * @param {{size:number}} reference Blob reference.
229
+ */
230
+ function writeBlobRef(writer, arena, reference) {
231
+ writer.u32(reference.size);
232
+ writer.u32(arena.blob(reference));
233
+ }
234
+
235
+ /**
236
+ * An absent sized blob: zero length, Carbon's null offset. The offset word is
237
+ * still written, and a reader must not dereference it.
238
+ */
239
+ const EMPTY_BLOB = Object.freeze({
240
+ size: 0,
241
+ offset: 0xffffffff,
242
+ bytes: new Uint8Array(0)
243
+ });
244
+
245
+ /**
246
+ * Error factory used by the write path's cap checks.
247
+ *
248
+ * @param {string} message Failure reason.
249
+ * @param {object} details Structured details.
250
+ * @returns {CjsFormatWriteError} Write error.
251
+ */
252
+ function writeError(message, details) {
253
+ return new CjsFormatWriteError(message, details);
254
+ }
255
+
256
+ /**
257
+ * Requires that a sized record parsed to exactly its declared end.
258
+ *
259
+ * This is the universal form of the rule the backend block discovered, and it
260
+ * carries real weight: it is the successor to roughly 600 lines of cross-chunk
261
+ * agreement checks that the container rewrite deletes. Those checks caught a
262
+ * malformed *tree* — our writer emitting something structurally wrong — not only a
263
+ * malformed file. Under a record layout a writer bug either fails to parse, which
264
+ * is self-announcing, or it parses and leaves the cursor somewhere other than the
265
+ * declared end. Trailing bytes therefore mean one of two things, both fatal: the
266
+ * writer knew fields this reader does not, or the writer miscounted.
267
+ *
268
+ * Applying it to some sized records and not others is a gap that stays invisible
269
+ * until a writer bug hides in one of the others, so every sized record gets it.
270
+ *
271
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Reader at the record end.
272
+ * @param {string} what Record name for the error message.
273
+ * @param {Function} makeError Error factory.
274
+ */
275
+ function requireExhaustive(reader, what, makeError) {
276
+ if (reader.remaining !== 0) {
277
+ throw makeError(`Carbon effect ${what} has ${reader.remaining} unparsed trailing byte(s)`, {
278
+ trailingBytes: reader.remaining,
279
+ offset: reader.offset,
280
+ end: reader.end
281
+ });
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Rejects a count above Carbon's inclusive limit for that field.
287
+ *
288
+ * @param {number} value Count read or about to be written.
289
+ * @param {string} field Cap key in `CARBON_EFFECT_COUNT_CAPS`.
290
+ * @param {Function} makeError Error factory taking a message and details.
291
+ * @returns {number} The count.
292
+ */
293
+ function sanityCheck(value, field, makeError) {
294
+ const limit = CARBON_EFFECT_COUNT_CAPS[field];
295
+ if (limit !== undefined && value > limit) {
296
+ throw makeError(`Effect ${field} count ${value} exceeds Carbon's limit of ${limit}`, {
297
+ field,
298
+ value,
299
+ limit
300
+ });
301
+ }
302
+ return value;
303
+ }
304
+
305
+ /**
306
+ * Reads one annotation map: `u8 count`, then name/type/value triples
307
+ * (`ParameterAnnotation::Save` `EffectData.h:601-623`, `ReadAnnotations`
308
+ * `Tr2EffectDescription.cpp:114-134`).
309
+ *
310
+ * A non-string value is kept as its raw four bytes. Carbon writes it through
311
+ * the `float` member of a `{float,int32_t}` union and reads it back through a
312
+ * different union, so the bytes are the only faithful representation; applying
313
+ * an int/float conversion here would corrupt round-trips.
314
+ *
315
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
316
+ * @returns {object[]} Annotation records.
317
+ */
318
+ function readAnnotations(reader) {
319
+ const count = reader.readUint8();
320
+ const annotations = [];
321
+ for (let index = 0; index < count; index += 1) {
322
+ const name = readStringRef(reader);
323
+ const type = reader.readUint8();
324
+ if (type === CARBON_ANNOTATION_TYPE.STRING) {
325
+ annotations.push({
326
+ name,
327
+ type,
328
+ stringValue: readStringRef(reader),
329
+ rawValue: null
330
+ });
331
+ } else {
332
+ annotations.push({
333
+ name,
334
+ type,
335
+ stringValue: null,
336
+ rawValue: Uint8Array.from(reader.readRaw(4))
337
+ });
338
+ }
339
+ }
340
+ return annotations;
341
+ }
342
+
343
+ /**
344
+ * Writes one annotation map.
345
+ *
346
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
347
+ * @param {object} arena Arena resolver.
348
+ * @param {object[]} annotations Annotation records.
349
+ */
350
+ function writeAnnotations(writer, arena, annotations) {
351
+ writer.u8(annotations.length);
352
+ for (const annotation of annotations) {
353
+ writer.u32(arena.string(annotation.name));
354
+ writer.u8(annotation.type);
355
+ if (annotation.type === CARBON_ANNOTATION_TYPE.STRING) {
356
+ writer.u32(arena.string(annotation.stringValue));
357
+ } else {
358
+ writer.bytes(annotation.rawValue);
359
+ }
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Maps a pre-v11 constant type byte onto the current enum
365
+ * (`Tr2EffectDescription.cpp:141-158`). The old wire knew FLOAT/INT/BOOL;
366
+ * the current numbering is FLOAT 0, INT 1, UINT 2, BOOL 3, OTHER 4.
367
+ *
368
+ * @param {number} value Pre-v11 type byte.
369
+ * @returns {number} Current constant type value.
370
+ */
371
+ function mapOldConstantType(value) {
372
+ if (value === 0) return 0;
373
+ if (value === 1) return 1;
374
+ if (value === 2) return 3;
375
+ return 4;
376
+ }
377
+
378
+ /**
379
+ * Reads one `Constant` (`EffectData.h:283-294`, `ReadConstant`
380
+ * `Tr2EffectDescription.cpp:136-170`). The byte layout is identical across
381
+ * versions 8..15; only the type byte's numbering changed at v11.
382
+ *
383
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
384
+ * @param {number} version Container data version.
385
+ * @returns {object} Constant record.
386
+ */
387
+ function readConstant(reader, version) {
388
+ const name = readStringRef(reader);
389
+ const offset = reader.readUint32();
390
+ const size = reader.readUint32();
391
+ const rawType = reader.readUint8();
392
+ return {
393
+ name,
394
+ offset,
395
+ size,
396
+ type: version < 11 ? mapOldConstantType(rawType) : rawType,
397
+ dimension: reader.readUint8(),
398
+ elements: reader.readUint32(),
399
+ isSRGB: reader.readUint8(),
400
+ isAutoregister: reader.readUint8()
401
+ };
402
+ }
403
+
404
+ /**
405
+ * Writes one `Constant`.
406
+ *
407
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
408
+ * @param {object} arena Arena resolver.
409
+ * @param {object} constant Constant record.
410
+ */
411
+ function writeConstant(writer, arena, constant) {
412
+ writer.u32(arena.string(constant.name));
413
+ writer.u32(constant.offset);
414
+ writer.u32(constant.size);
415
+ writer.u8(constant.type);
416
+ writer.u8(constant.dimension);
417
+ writer.u32(constant.elements);
418
+ writer.u8(constant.isSRGB);
419
+ writer.u8(constant.isAutoregister);
420
+ }
421
+
422
+ /**
423
+ * Reads one `Texture` (`EffectData.h:320-328`, `ReadResource`
424
+ * `Tr2EffectDescription.cpp:172-190`). `count` is the reader's
425
+ * `arrayElements`; before v13 the field is not on the wire and Carbon
426
+ * defaults it to one element.
427
+ *
428
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
429
+ * @param {number} version Container data version.
430
+ * @returns {object} Texture record.
431
+ */
432
+ function readTexture(reader, version) {
433
+ return {
434
+ name: readStringRef(reader),
435
+ type: reader.readUint8(),
436
+ count: version >= 13 ? reader.readUint32() : 1,
437
+ isSRGB: reader.readUint8(),
438
+ isAutoregister: reader.readUint8()
439
+ };
440
+ }
441
+
442
+ /**
443
+ * Writes one `Texture`.
444
+ *
445
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
446
+ * @param {object} arena Arena resolver.
447
+ * @param {object} texture Texture record.
448
+ */
449
+ function writeTexture(writer, arena, texture) {
450
+ writer.u32(arena.string(texture.name));
451
+ writer.u8(texture.type);
452
+ writer.u32(texture.count);
453
+ writer.u8(texture.isSRGB);
454
+ writer.u8(texture.isAutoregister);
455
+ }
456
+
457
+ /**
458
+ * Reads one `Uav` (`EffectData.h:345-352`, inline at
459
+ * `Tr2EffectDescription.cpp:449-463`).
460
+ *
461
+ * A UAV record is one byte shorter than a texture record: it carries no
462
+ * `isSRGB`. Carbon's reader hardcodes `isSRGB = false`
463
+ * (`Tr2EffectDescription.cpp:450`) rather than reading it, and `Uav::Save`
464
+ * omits it. Reusing a shared "resource" codec for both is the mistake this
465
+ * comment exists to prevent.
466
+ *
467
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
468
+ * @param {number} version Container data version.
469
+ * @returns {object} UAV record.
470
+ */
471
+ function readUav(reader, version) {
472
+ return {
473
+ name: readStringRef(reader),
474
+ type: reader.readUint8(),
475
+ count: version >= 13 ? reader.readUint32() : 1,
476
+ isAutoregister: reader.readUint8()
477
+ };
478
+ }
479
+
480
+ /**
481
+ * Writes one `Uav`.
482
+ *
483
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
484
+ * @param {object} arena Arena resolver.
485
+ * @param {object} uav UAV record.
486
+ */
487
+ function writeUav(writer, arena, uav) {
488
+ writer.u32(arena.string(uav.name));
489
+ writer.u8(uav.type);
490
+ writer.u32(uav.count);
491
+ writer.u8(uav.isAutoregister);
492
+ }
493
+
494
+ /**
495
+ * Reads one `Sampler` (`EffectData.h:368-390`, `ReadSampler`
496
+ * `Tr2EffectDescription.cpp:192-232` plus the name at `:413` and `isDynamic`
497
+ * at `:429`). Border colour here is four floats — unlike a static sampler,
498
+ * where it is a one-byte enum.
499
+ *
500
+ * `isDynamic` joined the wire at v13. For older versions the key is OMITTED
501
+ * from the record rather than synthesised: the concept did not exist, so any
502
+ * invented value would either lie or (via the v15 rule that a non-dynamic
503
+ * sampler's name is cleared) silently erase names a legacy file does carry.
504
+ *
505
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
506
+ * @param {number} version Container data version.
507
+ * @returns {object} Sampler record.
508
+ */
509
+ function readSampler(reader, version) {
510
+ const record = {
511
+ name: readStringRef(reader),
512
+ comparison: reader.readUint8(),
513
+ minFilter: reader.readUint8(),
514
+ magFilter: reader.readUint8(),
515
+ mipFilter: reader.readUint8(),
516
+ addressU: reader.readUint8(),
517
+ addressV: reader.readUint8(),
518
+ addressW: reader.readUint8(),
519
+ mipLODBias: reader.readFloat32(),
520
+ maxAnisotropy: reader.readUint8(),
521
+ comparisonFunc: reader.readUint8(),
522
+ borderColor: [reader.readFloat32(), reader.readFloat32(), reader.readFloat32(), reader.readFloat32()],
523
+ minLOD: reader.readFloat32(),
524
+ maxLOD: reader.readFloat32()
525
+ };
526
+ if (version > 12) {
527
+ record.isDynamic = reader.readUint8();
528
+ }
529
+ return record;
530
+ }
531
+
532
+ /**
533
+ * Writes one `Sampler`.
534
+ *
535
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
536
+ * @param {object} arena Arena resolver.
537
+ * @param {object} sampler Sampler record.
538
+ */
539
+ function writeSampler(writer, arena, sampler) {
540
+ writer.u32(arena.string(sampler.name));
541
+ writer.u8(sampler.comparison);
542
+ writer.u8(sampler.minFilter);
543
+ writer.u8(sampler.magFilter);
544
+ writer.u8(sampler.mipFilter);
545
+ writer.u8(sampler.addressU);
546
+ writer.u8(sampler.addressV);
547
+ writer.u8(sampler.addressW);
548
+ writer.f32(sampler.mipLODBias);
549
+ writer.u8(sampler.maxAnisotropy);
550
+ writer.u8(sampler.comparisonFunc);
551
+ writer.f32(sampler.borderColor[0]);
552
+ writer.f32(sampler.borderColor[1]);
553
+ writer.f32(sampler.borderColor[2]);
554
+ writer.f32(sampler.borderColor[3]);
555
+ writer.f32(sampler.minLOD);
556
+ writer.f32(sampler.maxLOD);
557
+ writer.u8(sampler.isDynamic);
558
+ }
559
+
560
+ /**
561
+ * Reads one `StaticSampler` (`EffectData.h:512-531`, read inside
562
+ * `ReadRegisters` at `Tr2EffectDescription.cpp:324-365`). Border colour is a
563
+ * one-byte enum here, and there is no name.
564
+ *
565
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
566
+ * @returns {object} Static sampler record.
567
+ */
568
+ function readStaticSampler(reader) {
569
+ return {
570
+ registerIndex: reader.readUint32(),
571
+ registerSpace: reader.readUint8(),
572
+ comparison: reader.readUint8(),
573
+ minFilter: reader.readUint8(),
574
+ magFilter: reader.readUint8(),
575
+ mipFilter: reader.readUint8(),
576
+ addressU: reader.readUint8(),
577
+ addressV: reader.readUint8(),
578
+ addressW: reader.readUint8(),
579
+ mipLODBias: reader.readFloat32(),
580
+ maxAnisotropy: reader.readUint8(),
581
+ comparisonFunc: reader.readUint8(),
582
+ borderColor: reader.readUint8(),
583
+ minLOD: reader.readFloat32(),
584
+ maxLOD: reader.readFloat32()
585
+ };
586
+ }
587
+
588
+ /**
589
+ * Writes one `StaticSampler`.
590
+ *
591
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
592
+ * @param {object} sampler Static sampler record.
593
+ */
594
+ function writeStaticSampler(writer, sampler) {
595
+ writer.u32(sampler.registerIndex);
596
+ writer.u8(sampler.registerSpace);
597
+ writer.u8(sampler.comparison);
598
+ writer.u8(sampler.minFilter);
599
+ writer.u8(sampler.magFilter);
600
+ writer.u8(sampler.mipFilter);
601
+ writer.u8(sampler.addressU);
602
+ writer.u8(sampler.addressV);
603
+ writer.u8(sampler.addressW);
604
+ writer.f32(sampler.mipLODBias);
605
+ writer.u8(sampler.maxAnisotropy);
606
+ writer.u8(sampler.comparisonFunc);
607
+ writer.u8(sampler.borderColor);
608
+ writer.f32(sampler.minLOD);
609
+ writer.f32(sampler.maxLOD);
610
+ }
611
+
612
+ /**
613
+ * Maps a pre-v10 register type byte onto the current register-type values
614
+ * (`Tr2EffectDescription.cpp:262-276`).
615
+ *
616
+ * @param {number} value Pre-v10 register type byte.
617
+ * @returns {number} Current register type value.
618
+ */
619
+ function mapOldRegisterType(value) {
620
+ if (value === 0) return 0;
621
+ if (value === 1) return 36;
622
+ if (value === 2) return 68;
623
+ if (value === 3) return 1;
624
+ return 36;
625
+ }
626
+
627
+ /**
628
+ * Reads the register signature and (v13+) static-sampler table
629
+ * (`ReadRegisters`, `Tr2EffectDescription.cpp:258-367`).
630
+ *
631
+ * Before v13 a register carries only its type and index; Carbon defaults the
632
+ * count to one and the space to the stage type (`:340-343`), and the record is
633
+ * normalized here so consumers see one shape.
634
+ *
635
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
636
+ * @param {number} version Container data version.
637
+ * @param {number} stageType Stage type owning the signature; only consulted
638
+ * for the pre-v13 register-space default.
639
+ * @returns {{registers:object[], staticSamplers:object[]}} Signature records.
640
+ */
641
+ function readSignature(reader, version, stageType) {
642
+ const registers = [];
643
+ const registerCount = reader.readUint8();
644
+ for (let index = 0; index < registerCount; index += 1) {
645
+ const rawType = reader.readUint8();
646
+ const registerType = version > 9 ? rawType : mapOldRegisterType(rawType);
647
+ const registerIndex = reader.readUint32();
648
+ if (version > 12) {
649
+ registers.push({
650
+ registerType,
651
+ registerIndex,
652
+ registerCount: reader.readUint32(),
653
+ registerSpace: reader.readUint8()
654
+ });
655
+ } else {
656
+ registers.push({
657
+ registerType,
658
+ registerIndex,
659
+ registerCount: 1,
660
+ registerSpace: stageType
661
+ });
662
+ }
663
+ }
664
+ const staticSamplers = [];
665
+ if (version > 12) {
666
+ const staticSamplerCount = reader.readUint8();
667
+ for (let index = 0; index < staticSamplerCount; index += 1) {
668
+ staticSamplers.push(readStaticSampler(reader));
669
+ }
670
+ }
671
+ return {
672
+ registers,
673
+ staticSamplers
674
+ };
675
+ }
676
+
677
+ /**
678
+ * Reads the resource half of a `StageData` block: constants, default constant
679
+ * values, textures, samplers, UAVs, annotations (`ReadInput`,
680
+ * `Tr2EffectDescription.cpp:369-472`).
681
+ *
682
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
683
+ * @param {number} version Container data version.
684
+ * @param {Function} makeError Error factory.
685
+ * @returns {object} Stage resource records.
686
+ */
687
+ function readStageResources(reader, version, makeError) {
688
+ const constants = [];
689
+ const constantCount = reader.readUint32();
690
+ for (let index = 0; index < constantCount; index += 1) {
691
+ constants.push(readConstant(reader, version));
692
+ }
693
+ const defaultValues = readBlobRef(reader);
694
+ const textures = [];
695
+ const textureCount = sanityCheck(reader.readUint8(), "textures", makeError);
696
+ for (let index = 0; index < textureCount; index += 1) {
697
+ const registerIndex = reader.readUint8();
698
+ textures.push({
699
+ registerIndex,
700
+ ...readTexture(reader, version)
701
+ });
702
+ }
703
+ const samplers = [];
704
+ const samplerCount = sanityCheck(reader.readUint8(), "samplers", makeError);
705
+ for (let index = 0; index < samplerCount; index += 1) {
706
+ const registerIndex = reader.readUint8();
707
+ samplers.push({
708
+ registerIndex,
709
+ ...readSampler(reader, version)
710
+ });
711
+ }
712
+ const uavs = [];
713
+ const uavCount = sanityCheck(reader.readUint8(), "uavs", makeError);
714
+ for (let index = 0; index < uavCount; index += 1) {
715
+ const registerIndex = reader.readUint8();
716
+ uavs.push({
717
+ registerIndex,
718
+ ...readUav(reader, version)
719
+ });
720
+ }
721
+ return {
722
+ constants,
723
+ defaultValues,
724
+ textures,
725
+ samplers,
726
+ uavs,
727
+ annotations: readAnnotations(reader)
728
+ };
729
+ }
730
+
731
+ /**
732
+ * Reads a whole `StageData` block: registers, static samplers, then the
733
+ * resource half (`StageData::Save` `EffectData.h:631-676`).
734
+ *
735
+ * Carbon's reader splits this single contiguous run across two functions —
736
+ * `ReadRegisters` takes the first two sub-records
737
+ * (`Tr2EffectDescription.cpp:258-367`) and `ReadInput` the remaining six
738
+ * (`:369-472`). The split exists here too, because before v14 the two halves
739
+ * are not adjacent on the wire — the signature precedes the program blob
740
+ * while the resources follow the thread-group size — and `readStage` places
741
+ * each half where its version put it.
742
+ *
743
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
744
+ * @param {number} version Container data version.
745
+ * @param {Function} makeError Error factory.
746
+ * @param {number} stageType Stage type owning the signature.
747
+ * @returns {object} Stage data record.
748
+ */
749
+ function readStageData(reader, version, makeError, stageType) {
750
+ return {
751
+ ...readSignature(reader, version, stageType),
752
+ ...readStageResources(reader, version, makeError)
753
+ };
754
+ }
755
+
756
+ /**
757
+ * Writes the `StageData` block.
758
+ *
759
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
760
+ * @param {object} arena Arena resolver.
761
+ * @param {object} stageData Stage data record.
762
+ */
763
+ function writeStageData(writer, arena, stageData) {
764
+ writer.u8(stageData.registers.length);
765
+ for (const register of stageData.registers) {
766
+ writer.u8(register.registerType);
767
+ writer.u32(register.registerIndex);
768
+ writer.u32(register.registerCount);
769
+ writer.u8(register.registerSpace);
770
+ }
771
+ writer.u8(stageData.staticSamplers.length);
772
+ for (const sampler of stageData.staticSamplers) {
773
+ writeStaticSampler(writer, sampler);
774
+ }
775
+ writer.u32(stageData.constants.length);
776
+ for (const constant of stageData.constants) {
777
+ writeConstant(writer, arena, constant);
778
+ }
779
+ writeBlobRef(writer, arena, stageData.defaultValues);
780
+
781
+ // Carbon's compiler enforces none of these caps while its runtime rejects
782
+ // anything above them, so an over-large effect compiles and then fails to
783
+ // load. Check on the way out instead.
784
+ sanityCheck(stageData.textures.length, "textures", writeError);
785
+ sanityCheck(stageData.samplers.length, "samplers", writeError);
786
+ sanityCheck(stageData.uavs.length, "uavs", writeError);
787
+ writer.u8(stageData.textures.length);
788
+ for (const texture of stageData.textures) {
789
+ writer.u8(texture.registerIndex);
790
+ writeTexture(writer, arena, texture);
791
+ }
792
+ writer.u8(stageData.samplers.length);
793
+ for (const sampler of stageData.samplers) {
794
+ writer.u8(sampler.registerIndex);
795
+ writeSampler(writer, arena, sampler);
796
+ }
797
+ writer.u8(stageData.uavs.length);
798
+ for (const uav of stageData.uavs) {
799
+ writer.u8(uav.registerIndex);
800
+ writeUav(writer, arena, uav);
801
+ }
802
+ writeAnnotations(writer, arena, stageData.annotations);
803
+ }
804
+
805
+ /**
806
+ * Reads the pipeline-input list (`Tr2EffectDescription.cpp:234-256`).
807
+ *
808
+ * The `type`/`dimension` bytes joined the wire at v11; before that Carbon
809
+ * derives them — UINT for the blend-index usage, FLOAT otherwise, always four
810
+ * components (`:247-252`) — and the record is normalized here the same way.
811
+ *
812
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
813
+ * @param {number} version Container data version.
814
+ * @param {Function} makeError Error factory.
815
+ * @returns {object[]} Pipeline-input records.
816
+ */
817
+ function readPipelineInputs(reader, version, makeError) {
818
+ const pipelineInputs = [];
819
+ const pipelineInputCount = sanityCheck(reader.readUint8(), "pipelineInputs", makeError);
820
+ for (let index = 0; index < pipelineInputCount; index += 1) {
821
+ const usage = reader.readUint8();
822
+ const registerIndex = reader.readUint8();
823
+ const usageIndex = reader.readUint8();
824
+ const usedMask = reader.readUint8();
825
+ if (version > 10) {
826
+ pipelineInputs.push({
827
+ usage,
828
+ registerIndex,
829
+ usageIndex,
830
+ usedMask,
831
+ type: reader.readUint8(),
832
+ dimension: reader.readUint8()
833
+ });
834
+ } else {
835
+ pipelineInputs.push({
836
+ usage,
837
+ registerIndex,
838
+ usageIndex,
839
+ usedMask,
840
+ // Constant-type values: 2 is UINT, 0 is FLOAT; usage 6 is the
841
+ // blend-index semantic.
842
+ type: usage === 6 ? 2 : 0,
843
+ dimension: 4
844
+ });
845
+ }
846
+ }
847
+ return pipelineInputs;
848
+ }
849
+
850
+ /**
851
+ * Reads one stage (`StageInput::Save` `EffectData.h:691-709`,
852
+ * `Tr2EffectDescription.cpp:532-585`).
853
+ *
854
+ * At v15 the program payload comes first and the signature tables follow.
855
+ * Before v14 it was the other way round; the reorder is the v14 change, and
856
+ * Carbon marks its own v14 branch `// CHECK` (`:578`). Verified against the
857
+ * writer for v15: `type`, `shaderSize`, `shaderData`,
858
+ * `threadGroupSize[0..2]`, `pipelineInputs`, then `StageData`. Two further
859
+ * legacy wrinkles, both from Carbon's reader: a stage carries no register
860
+ * signature at all before v9 (`:544`), and two legacy dwords follow the
861
+ * program reference before v12, read and discarded (`:559-563`).
862
+ *
863
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
864
+ * @param {number} version Container data version.
865
+ * @param {Function} makeError Error factory.
866
+ * @returns {object} Stage record.
867
+ */
868
+ function readStage(reader, version, makeError) {
869
+ const type = reader.readUint8();
870
+ let pipelineInputs = [];
871
+ let signature = {
872
+ registers: [],
873
+ staticSamplers: []
874
+ };
875
+ if (version < 14) {
876
+ pipelineInputs = readPipelineInputs(reader, version, makeError);
877
+ if (version > 8) {
878
+ signature = readSignature(reader, version, type);
879
+ }
880
+ }
881
+ const shaderData = readBlobRef(reader);
882
+ if (version < 12) {
883
+ reader.readUint32();
884
+ reader.readUint32();
885
+ }
886
+ const threadGroupSize = [reader.readUint32(), reader.readUint32(), reader.readUint32()];
887
+ if (version >= 14) {
888
+ pipelineInputs = readPipelineInputs(reader, version, makeError);
889
+ signature = readSignature(reader, version, type);
890
+ }
891
+ return {
892
+ type,
893
+ shaderData,
894
+ threadGroupSize,
895
+ pipelineInputs,
896
+ ...signature,
897
+ ...readStageResources(reader, version, makeError)
898
+ };
899
+ }
900
+
901
+ /**
902
+ * Writes one stage.
903
+ *
904
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
905
+ * @param {object} arena Arena resolver.
906
+ * @param {object} stage Stage record.
907
+ */
908
+ function writeStage(writer, arena, stage) {
909
+ sanityCheck(stage.pipelineInputs.length, "pipelineInputs", writeError);
910
+ writer.u8(stage.type);
911
+ writeBlobRef(writer, arena, stage.shaderData);
912
+ writer.u32(stage.threadGroupSize[0]);
913
+ writer.u32(stage.threadGroupSize[1]);
914
+ writer.u32(stage.threadGroupSize[2]);
915
+ writer.u8(stage.pipelineInputs.length);
916
+ for (const input of stage.pipelineInputs) {
917
+ writer.u8(input.usage);
918
+ writer.u8(input.registerIndex);
919
+ writer.u8(input.usageIndex);
920
+ writer.u8(input.usedMask);
921
+ writer.u8(input.type);
922
+ writer.u8(input.dimension);
923
+ }
924
+ writeStageData(writer, arena, stage);
925
+ }
926
+
927
+ /**
928
+ * Reads one pass (`Pass::Save` `EffectData.h:724-738`).
929
+ *
930
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
931
+ * @param {number} version Container data version.
932
+ * @param {Function} makeError Error factory.
933
+ * @param {boolean} backend Whether the optional trailing block is present.
934
+ * @returns {object} Pass record.
935
+ */
936
+ function readPass(reader, version, makeError, backend) {
937
+ const stages = [];
938
+ const stageCount = sanityCheck(reader.readUint8(), "stages", makeError);
939
+ for (let index = 0; index < stageCount; index += 1) {
940
+ stages.push(readStage(reader, version, makeError));
941
+ }
942
+ const renderStates = [];
943
+ const stateCount = sanityCheck(reader.readUint8(), "renderStates", makeError);
944
+ for (let index = 0; index < stateCount; index += 1) {
945
+ renderStates.push({
946
+ state: reader.readUint32(),
947
+ value: reader.readUint32()
948
+ });
949
+ }
950
+
951
+ // The one optional trailing block, present only in our own containers. A
952
+ // Carbon file ends the pass at the render-state table, so leaving this gate
953
+ // closed reproduces Carbon's bytes exactly.
954
+ const backendBlock = backend ? readBlobRef(reader) : null;
955
+ return {
956
+ stages,
957
+ renderStates,
958
+ ...(backendBlock ? {
959
+ backendBlock
960
+ } : {})
961
+ };
962
+ }
963
+
964
+ /**
965
+ * Writes one pass.
966
+ *
967
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
968
+ * @param {object} arena Arena resolver.
969
+ * @param {object} pass Pass record.
970
+ * @param {boolean} backend Whether to emit the optional trailing block.
971
+ */
972
+ function writePass(writer, arena, pass, backend) {
973
+ writer.u8(pass.stages.length);
974
+ for (const stage of pass.stages) {
975
+ writeStage(writer, arena, stage);
976
+ }
977
+ writer.u8(pass.renderStates.length);
978
+ for (const entry of pass.renderStates) {
979
+ writer.u32(entry.state);
980
+ writer.u32(entry.value);
981
+ }
982
+ if (backend) {
983
+ writeBlobRef(writer, arena, pass.backendBlock ?? EMPTY_BLOB);
984
+ }
985
+ }
986
+
987
+ /**
988
+ * Reads one raytracing library (`Library::Save` `EffectData.h:760-775`,
989
+ * `Tr2EffectDescription.cpp:675-721`). A library carries two `StageData`
990
+ * blocks and no pipeline inputs, thread group size, or stage type.
991
+ *
992
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Source reader.
993
+ * @param {number} version Container data version.
994
+ * @param {Function} makeError Error factory.
995
+ * @returns {object} Library record.
996
+ */
997
+ function readLibrary(reader, version, makeError) {
998
+ const payloadSize = reader.readUint32();
999
+ const shaderData = readBlobRef(reader);
1000
+ const exports = [];
1001
+ const exportCount = reader.readUint32();
1002
+ for (let index = 0; index < exportCount; index += 1) {
1003
+ exports.push({
1004
+ type: reader.readUint8(),
1005
+ name: readStringRef(reader)
1006
+ });
1007
+ }
1008
+
1009
+ // Libraries exist only from v14, so the pre-v13 register-space default in
1010
+ // the signature reader is unreachable here; the stage type it would need
1011
+ // is passed as zero.
1012
+ return {
1013
+ payloadSize,
1014
+ shaderData,
1015
+ exports,
1016
+ hitGroupName: readStringRef(reader),
1017
+ globalInputs: readStageData(reader, version, makeError, 0),
1018
+ localInputs: readStageData(reader, version, makeError, 0)
1019
+ };
1020
+ }
1021
+
1022
+ /**
1023
+ * Writes one raytracing library.
1024
+ *
1025
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
1026
+ * @param {object} arena Arena resolver.
1027
+ * @param {object} library Library record.
1028
+ */
1029
+ function writeLibrary(writer, arena, library) {
1030
+ writer.u32(library.payloadSize);
1031
+ writeBlobRef(writer, arena, library.shaderData);
1032
+ writer.u32(library.exports.length);
1033
+ for (const entry of library.exports) {
1034
+ writer.u8(entry.type);
1035
+ writer.u32(arena.string(entry.name));
1036
+ }
1037
+ writer.u32(arena.string(library.hitGroupName));
1038
+ writeStageData(writer, arena, library.globalInputs);
1039
+ writeStageData(writer, arena, library.localInputs);
1040
+ }
1041
+
1042
+ /**
1043
+ * Reads a whole v15 description blob (`EffectData::Save`
1044
+ * `EffectData.h:821-849`, `Tr2EffectDescription::Read`
1045
+ * `Tr2EffectDescription.cpp:476-731`).
1046
+ *
1047
+ * @param {import("../CjsByteReader.js").CjsByteReader} reader Reader positioned at the blob.
1048
+ * @param {object} [options] Read options.
1049
+ * @param {Function} [options.makeError] Error factory taking a message and details.
1050
+ * @param {number} [options.version] Container data version; defaults to the
1051
+ * current version. Accepted range is `CARBON_EFFECT_MIN_DATA_VERSION` to
1052
+ * `CARBON_EFFECT_DATA_VERSION`; the record tree comes out normalized to
1053
+ * the v15 shape whatever the wire carried.
1054
+ * @param {boolean} [options.backend] Expect our optional per-pass trailing block.
1055
+ * Leave false for a Carbon file, which ends each pass at the render states.
1056
+ * @returns {object} Description record tree.
1057
+ */
1058
+ function readEffectDescription(reader, options = {}) {
1059
+ const makeError = options.makeError ?? ((message, details) => reader._error(message, details));
1060
+ const backend = options.backend === true;
1061
+ const version = Number.isInteger(options.version) ? options.version : CARBON_EFFECT_DATA_VERSION;
1062
+ if (version < CARBON_EFFECT_MIN_DATA_VERSION || version > CARBON_EFFECT_DATA_VERSION) {
1063
+ throw makeError(`Unsupported Carbon effect version ${version}; expected ${CARBON_EFFECT_MIN_DATA_VERSION}..${CARBON_EFFECT_DATA_VERSION}`, {
1064
+ version
1065
+ });
1066
+ }
1067
+ const techniques = [];
1068
+ const techniqueCount = reader.readUint8();
1069
+ for (let techniqueIndex = 0; techniqueIndex < techniqueCount; techniqueIndex += 1) {
1070
+ const name = readStringRef(reader);
1071
+ const passes = [];
1072
+ const passCount = sanityCheck(reader.readUint8(), "passes", makeError);
1073
+ for (let passIndex = 0; passIndex < passCount; passIndex += 1) {
1074
+ passes.push(readPass(reader, version, makeError, backend));
1075
+ }
1076
+
1077
+ // The library table joined the wire at v14; older files end the
1078
+ // technique at its passes.
1079
+ const libraries = [];
1080
+ if (version > 13) {
1081
+ const libraryCount = reader.readUint8();
1082
+ for (let libraryIndex = 0; libraryIndex < libraryCount; libraryIndex += 1) {
1083
+ libraries.push(readLibrary(reader, version, makeError));
1084
+ }
1085
+ }
1086
+ techniques.push({
1087
+ name,
1088
+ passes,
1089
+ libraries
1090
+ });
1091
+ }
1092
+ const annotations = [];
1093
+ const parameterCount = sanityCheck(reader.readUint16(), "effectAnnotations", makeError);
1094
+ for (let index = 0; index < parameterCount; index += 1) {
1095
+ annotations.push({
1096
+ name: readStringRef(reader),
1097
+ annotations: readAnnotations(reader)
1098
+ });
1099
+ }
1100
+ requireExhaustive(reader, "description blob", makeError);
1101
+ return {
1102
+ techniques,
1103
+ annotations
1104
+ };
1105
+ }
1106
+
1107
+ /**
1108
+ * Writes a whole v15 description blob.
1109
+ *
1110
+ * The `arena` resolver decides what an arena reference becomes: `passthroughArena`
1111
+ * keeps the source offsets, `internArena(table)` re-interns into a new table.
1112
+ *
1113
+ * @param {import("../CjsByteWriter.js").CjsByteWriter} writer Target writer.
1114
+ * @param {object} description Description record tree.
1115
+ * @param {object} [options] Write options.
1116
+ * @param {object} [options.arena] Arena resolver; defaults to passthrough.
1117
+ * @param {boolean} [options.backend] Emit our optional per-pass trailing block.
1118
+ * Leave false to produce bytes a Carbon reader accepts unchanged.
1119
+ * @returns {import("../CjsByteWriter.js").CjsByteWriter} The writer.
1120
+ */
1121
+ function writeEffectDescription(writer, description, options = {}) {
1122
+ const arena = options.arena ?? passthroughArena;
1123
+ const backend = options.backend === true;
1124
+ writer.u8(description.techniques.length);
1125
+ for (const technique of description.techniques) {
1126
+ writer.u32(arena.string(technique.name));
1127
+ writer.u8(sanityCheck(technique.passes.length, "passes", writeError));
1128
+ for (const pass of technique.passes) {
1129
+ sanityCheck(pass.stages.length, "stages", writeError);
1130
+ sanityCheck(pass.renderStates.length, "renderStates", writeError);
1131
+ writePass(writer, arena, pass, backend);
1132
+ }
1133
+ writer.u8(technique.libraries.length);
1134
+ for (const library of technique.libraries) {
1135
+ writeLibrary(writer, arena, library);
1136
+ }
1137
+ }
1138
+ writer.u16(sanityCheck(description.annotations.length, "effectAnnotations", writeError));
1139
+ for (const parameter of description.annotations) {
1140
+ writer.u32(arena.string(parameter.name));
1141
+ writeAnnotations(writer, arena, parameter.annotations);
1142
+ }
1143
+ return writer;
1144
+ }
1145
+
1146
+ export { CARBON_ANNOTATION_TYPE, CARBON_EFFECT_COUNT_CAPS, CARBON_EFFECT_DATA_VERSION, CARBON_EFFECT_MIN_DATA_VERSION, CARBON_SHADER_CONSTANTS_MAX, collectArena, compareAnnotationNames, internArena, passthroughArena, readEffectDescription, writeEffectDescription };
1147
+ //# sourceMappingURL=carbonEffectRecords.js.map