aigpu 0.3.1

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 (491) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +85 -0
  3. package/bin/aigpu.js +15 -0
  4. package/client.d.ts +15 -0
  5. package/dist/agent-tools.d.ts +61 -0
  6. package/dist/agent-tools.d.ts.map +1 -0
  7. package/dist/agent-tools.js +107 -0
  8. package/dist/agent-tools.js.map +1 -0
  9. package/dist/agent.d.ts +56 -0
  10. package/dist/agent.d.ts.map +1 -0
  11. package/dist/agent.js +243 -0
  12. package/dist/agent.js.map +1 -0
  13. package/dist/api-types.d.ts +56 -0
  14. package/dist/api-types.d.ts.map +1 -0
  15. package/dist/api-types.js +2 -0
  16. package/dist/api-types.js.map +1 -0
  17. package/dist/bind-cache.d.ts +19 -0
  18. package/dist/bind-cache.d.ts.map +1 -0
  19. package/dist/bind-cache.js +43 -0
  20. package/dist/bind-cache.js.map +1 -0
  21. package/dist/bundle.d.ts +30 -0
  22. package/dist/bundle.d.ts.map +1 -0
  23. package/dist/bundle.js +127 -0
  24. package/dist/bundle.js.map +1 -0
  25. package/dist/claim-validation-encode.d.ts +14 -0
  26. package/dist/claim-validation-encode.d.ts.map +1 -0
  27. package/dist/claim-validation-encode.js +28 -0
  28. package/dist/claim-validation-encode.js.map +1 -0
  29. package/dist/claim-validation.d.ts +73 -0
  30. package/dist/claim-validation.d.ts.map +1 -0
  31. package/dist/claim-validation.js +135 -0
  32. package/dist/claim-validation.js.map +1 -0
  33. package/dist/cli/bin/aigpu.js +101 -0
  34. package/dist/cli/lib/check/run.js +153 -0
  35. package/dist/cli/lib/docs/commands/cat.js +12 -0
  36. package/dist/cli/lib/docs/commands/find.js +180 -0
  37. package/dist/cli/lib/docs/commands/grep.js +49 -0
  38. package/dist/cli/lib/docs/commands/ls.js +41 -0
  39. package/dist/cli/lib/docs/commands/path.js +12 -0
  40. package/dist/cli/lib/docs/commands/resolve.js +41 -0
  41. package/dist/cli/lib/docs/commands/shared.js +13 -0
  42. package/dist/cli/lib/docs/commands/symbols.js +25 -0
  43. package/dist/cli/lib/docs/errors.js +8 -0
  44. package/dist/cli/lib/docs/generate/check-drift.js +61 -0
  45. package/dist/cli/lib/docs/generate/cli.js +12 -0
  46. package/dist/cli/lib/docs/generate/generate.js +113 -0
  47. package/dist/cli/lib/docs/generate/manifest.js +218 -0
  48. package/dist/cli/lib/docs/generate/skill.js +150 -0
  49. package/dist/cli/lib/docs/help.js +21 -0
  50. package/dist/cli/lib/docs/index.js +62 -0
  51. package/dist/cli/lib/docs/model.js +7 -0
  52. package/dist/cli/lib/docs/run.js +24 -0
  53. package/dist/cli/lib/docs/service.js +119 -0
  54. package/dist/cli/lib/doctor/run.js +236 -0
  55. package/dist/cli/lib/examples/errors.js +13 -0
  56. package/dist/cli/lib/examples/hashing.js +9 -0
  57. package/dist/cli/lib/examples/help.js +13 -0
  58. package/dist/cli/lib/examples/local-source.js +142 -0
  59. package/dist/cli/lib/examples/paths.js +12 -0
  60. package/dist/cli/lib/examples/pull.js +58 -0
  61. package/dist/cli/lib/examples/run.js +71 -0
  62. package/dist/cli/lib/examples/search.js +6 -0
  63. package/dist/cli/lib/examples/service.js +118 -0
  64. package/dist/cli/lib/generated/docs-manifest.generated.js +4758 -0
  65. package/dist/cli/lib/install-dawn/run.js +24 -0
  66. package/dist/cli/lib/install-software-renderer/run.js +17 -0
  67. package/dist/cli/lib/mcp/http.js +93 -0
  68. package/dist/cli/lib/mcp/server.js +258 -0
  69. package/dist/cli/lib/mcp/stdio.js +34 -0
  70. package/dist/cli/lib/snapshot/png.js +62 -0
  71. package/dist/cli/lib/snapshot/render.js +22 -0
  72. package/dist/cli/lib/snapshot/run.js +79 -0
  73. package/dist/cli/lib/snapshot/shaders.js +11 -0
  74. package/dist/cli/package.json +4 -0
  75. package/dist/client.d.ts +12 -0
  76. package/dist/client.d.ts.map +1 -0
  77. package/dist/client.js +2 -0
  78. package/dist/client.js.map +1 -0
  79. package/dist/clock.d.ts +26 -0
  80. package/dist/clock.d.ts.map +1 -0
  81. package/dist/clock.js +50 -0
  82. package/dist/clock.js.map +1 -0
  83. package/dist/compute.d.ts +41 -0
  84. package/dist/compute.d.ts.map +1 -0
  85. package/dist/compute.js +132 -0
  86. package/dist/compute.js.map +1 -0
  87. package/dist/core/render-bundle.d.ts +30 -0
  88. package/dist/core/render-bundle.d.ts.map +1 -0
  89. package/dist/core/render-bundle.js +39 -0
  90. package/dist/core/render-bundle.js.map +1 -0
  91. package/dist/core/storage-buffer.d.ts +81 -0
  92. package/dist/core/storage-buffer.d.ts.map +1 -0
  93. package/dist/core/storage-buffer.js +91 -0
  94. package/dist/core/storage-buffer.js.map +1 -0
  95. package/dist/core/structured-uniform.d.ts +33 -0
  96. package/dist/core/structured-uniform.d.ts.map +1 -0
  97. package/dist/core/structured-uniform.js +110 -0
  98. package/dist/core/structured-uniform.js.map +1 -0
  99. package/dist/core/uniform-pool-internals.d.ts +12 -0
  100. package/dist/core/uniform-pool-internals.d.ts.map +1 -0
  101. package/dist/core/uniform-pool-internals.js +24 -0
  102. package/dist/core/uniform-pool-internals.js.map +1 -0
  103. package/dist/core/uniform-pool-types.d.ts +22 -0
  104. package/dist/core/uniform-pool-types.d.ts.map +1 -0
  105. package/dist/core/uniform-pool-types.js +2 -0
  106. package/dist/core/uniform-pool-types.js.map +1 -0
  107. package/dist/core/uniform-pool.d.ts +22 -0
  108. package/dist/core/uniform-pool.d.ts.map +1 -0
  109. package/dist/core/uniform-pool.js +128 -0
  110. package/dist/core/uniform-pool.js.map +1 -0
  111. package/dist/core/uniform.d.ts +55 -0
  112. package/dist/core/uniform.d.ts.map +1 -0
  113. package/dist/core/uniform.js +64 -0
  114. package/dist/core/uniform.js.map +1 -0
  115. package/dist/core/wgsl-alignment.d.ts +24 -0
  116. package/dist/core/wgsl-alignment.d.ts.map +1 -0
  117. package/dist/core/wgsl-alignment.js +81 -0
  118. package/dist/core/wgsl-alignment.js.map +1 -0
  119. package/dist/core.d.ts +13 -0
  120. package/dist/core.d.ts.map +1 -0
  121. package/dist/core.js +7 -0
  122. package/dist/core.js.map +1 -0
  123. package/dist/dom.d.ts +37 -0
  124. package/dist/dom.d.ts.map +1 -0
  125. package/dist/dom.js +81 -0
  126. package/dist/dom.js.map +1 -0
  127. package/dist/draw-protocols.d.ts +36 -0
  128. package/dist/draw-protocols.d.ts.map +1 -0
  129. package/dist/draw-protocols.js +10 -0
  130. package/dist/draw-protocols.js.map +1 -0
  131. package/dist/draw.d.ts +248 -0
  132. package/dist/draw.d.ts.map +1 -0
  133. package/dist/draw.js +890 -0
  134. package/dist/draw.js.map +1 -0
  135. package/dist/effect.d.ts +53 -0
  136. package/dist/effect.d.ts.map +1 -0
  137. package/dist/effect.js +75 -0
  138. package/dist/effect.js.map +1 -0
  139. package/dist/entry-metadata.d.ts +16 -0
  140. package/dist/entry-metadata.d.ts.map +1 -0
  141. package/dist/entry-metadata.js +27 -0
  142. package/dist/entry-metadata.js.map +1 -0
  143. package/dist/errors.d.ts +96 -0
  144. package/dist/errors.d.ts.map +1 -0
  145. package/dist/errors.js +616 -0
  146. package/dist/errors.js.map +1 -0
  147. package/dist/frame-protocols.d.ts +107 -0
  148. package/dist/frame-protocols.d.ts.map +1 -0
  149. package/dist/frame-protocols.js +20 -0
  150. package/dist/frame-protocols.js.map +1 -0
  151. package/dist/frame-state.d.ts +32 -0
  152. package/dist/frame-state.d.ts.map +1 -0
  153. package/dist/frame-state.js +62 -0
  154. package/dist/frame-state.js.map +1 -0
  155. package/dist/frame.d.ts +127 -0
  156. package/dist/frame.d.ts.map +1 -0
  157. package/dist/frame.js +645 -0
  158. package/dist/frame.js.map +1 -0
  159. package/dist/group-claim.d.ts +9 -0
  160. package/dist/group-claim.d.ts.map +1 -0
  161. package/dist/group-claim.js +7 -0
  162. package/dist/group-claim.js.map +1 -0
  163. package/dist/index.d.ts +41 -0
  164. package/dist/index.d.ts.map +1 -0
  165. package/dist/index.js +27 -0
  166. package/dist/index.js.map +1 -0
  167. package/dist/indirect.d.ts +39 -0
  168. package/dist/indirect.d.ts.map +1 -0
  169. package/dist/indirect.js +61 -0
  170. package/dist/indirect.js.map +1 -0
  171. package/dist/init-from-device.d.ts +11 -0
  172. package/dist/init-from-device.d.ts.map +1 -0
  173. package/dist/init-from-device.js +56 -0
  174. package/dist/init-from-device.js.map +1 -0
  175. package/dist/init.d.ts +12 -0
  176. package/dist/init.d.ts.map +1 -0
  177. package/dist/init.js +7 -0
  178. package/dist/init.js.map +1 -0
  179. package/dist/kernel.d.ts +104 -0
  180. package/dist/kernel.d.ts.map +1 -0
  181. package/dist/kernel.js +151 -0
  182. package/dist/kernel.js.map +1 -0
  183. package/dist/lifecycle.d.ts +10 -0
  184. package/dist/lifecycle.d.ts.map +1 -0
  185. package/dist/lifecycle.js +21 -0
  186. package/dist/lifecycle.js.map +1 -0
  187. package/dist/live-kernel.d.ts +48 -0
  188. package/dist/live-kernel.d.ts.map +1 -0
  189. package/dist/live-kernel.js +67 -0
  190. package/dist/live-kernel.js.map +1 -0
  191. package/dist/mock.d.ts +42 -0
  192. package/dist/mock.d.ts.map +1 -0
  193. package/dist/mock.js +29 -0
  194. package/dist/mock.js.map +1 -0
  195. package/dist/node.d.ts +48 -0
  196. package/dist/node.d.ts.map +1 -0
  197. package/dist/node.js +36 -0
  198. package/dist/node.js.map +1 -0
  199. package/dist/ping-pong.d.ts +19 -0
  200. package/dist/ping-pong.d.ts.map +1 -0
  201. package/dist/ping-pong.js +67 -0
  202. package/dist/ping-pong.js.map +1 -0
  203. package/dist/pipeline-store.d.ts +89 -0
  204. package/dist/pipeline-store.d.ts.map +1 -0
  205. package/dist/pipeline-store.js +366 -0
  206. package/dist/pipeline-store.js.map +1 -0
  207. package/dist/query-ring.d.ts +91 -0
  208. package/dist/query-ring.d.ts.map +1 -0
  209. package/dist/query-ring.js +178 -0
  210. package/dist/query-ring.js.map +1 -0
  211. package/dist/render-service.d.ts +23 -0
  212. package/dist/render-service.d.ts.map +1 -0
  213. package/dist/render-service.js +37 -0
  214. package/dist/render-service.js.map +1 -0
  215. package/dist/sampler.d.ts +19 -0
  216. package/dist/sampler.d.ts.map +1 -0
  217. package/dist/sampler.js +46 -0
  218. package/dist/sampler.js.map +1 -0
  219. package/dist/scene/camera.d.ts +91 -0
  220. package/dist/scene/camera.d.ts.map +1 -0
  221. package/dist/scene/camera.js +221 -0
  222. package/dist/scene/camera.js.map +1 -0
  223. package/dist/scene/geometries.d.ts +26 -0
  224. package/dist/scene/geometries.d.ts.map +1 -0
  225. package/dist/scene/geometries.js +26 -0
  226. package/dist/scene/geometries.js.map +1 -0
  227. package/dist/scene/geometry-descriptor.d.ts +120 -0
  228. package/dist/scene/geometry-descriptor.d.ts.map +1 -0
  229. package/dist/scene/geometry-descriptor.js +378 -0
  230. package/dist/scene/geometry-descriptor.js.map +1 -0
  231. package/dist/scene/geometry-recipe.d.ts +41 -0
  232. package/dist/scene/geometry-recipe.d.ts.map +1 -0
  233. package/dist/scene/geometry-recipe.js +40 -0
  234. package/dist/scene/geometry-recipe.js.map +1 -0
  235. package/dist/scene/geometry-src/camera-math.d.ts +6 -0
  236. package/dist/scene/geometry-src/camera-math.d.ts.map +1 -0
  237. package/dist/scene/geometry-src/camera-math.js +47 -0
  238. package/dist/scene/geometry-src/camera-math.js.map +1 -0
  239. package/dist/scene/geometry-src/camera.d.ts +10 -0
  240. package/dist/scene/geometry-src/camera.d.ts.map +1 -0
  241. package/dist/scene/geometry-src/camera.js +2 -0
  242. package/dist/scene/geometry-src/camera.js.map +1 -0
  243. package/dist/scene/geometry-src/capsule-data.d.ts +10 -0
  244. package/dist/scene/geometry-src/capsule-data.d.ts.map +1 -0
  245. package/dist/scene/geometry-src/capsule-data.js +61 -0
  246. package/dist/scene/geometry-src/capsule-data.js.map +1 -0
  247. package/dist/scene/geometry-src/cone-data.d.ts +13 -0
  248. package/dist/scene/geometry-src/cone-data.d.ts.map +1 -0
  249. package/dist/scene/geometry-src/cone-data.js +52 -0
  250. package/dist/scene/geometry-src/cone-data.js.map +1 -0
  251. package/dist/scene/geometry-src/cylinder-data.d.ts +14 -0
  252. package/dist/scene/geometry-src/cylinder-data.d.ts.map +1 -0
  253. package/dist/scene/geometry-src/cylinder-data.js +58 -0
  254. package/dist/scene/geometry-src/cylinder-data.js.map +1 -0
  255. package/dist/scene/geometry-src/deg-to-rad.d.ts +2 -0
  256. package/dist/scene/geometry-src/deg-to-rad.d.ts.map +1 -0
  257. package/dist/scene/geometry-src/deg-to-rad.js +4 -0
  258. package/dist/scene/geometry-src/deg-to-rad.js.map +1 -0
  259. package/dist/scene/geometry-src/disk-data.d.ts +12 -0
  260. package/dist/scene/geometry-src/disk-data.d.ts.map +1 -0
  261. package/dist/scene/geometry-src/disk-data.js +21 -0
  262. package/dist/scene/geometry-src/disk-data.js.map +1 -0
  263. package/dist/scene/geometry-src/errors.d.ts +3 -0
  264. package/dist/scene/geometry-src/errors.d.ts.map +1 -0
  265. package/dist/scene/geometry-src/errors.js +5 -0
  266. package/dist/scene/geometry-src/errors.js.map +1 -0
  267. package/dist/scene/geometry-src/icosphere-data.d.ts +8 -0
  268. package/dist/scene/geometry-src/icosphere-data.d.ts.map +1 -0
  269. package/dist/scene/geometry-src/icosphere-data.js +58 -0
  270. package/dist/scene/geometry-src/icosphere-data.js.map +1 -0
  271. package/dist/scene/geometry-src/index.d.ts +36 -0
  272. package/dist/scene/geometry-src/index.d.ts.map +1 -0
  273. package/dist/scene/geometry-src/index.js +21 -0
  274. package/dist/scene/geometry-src/index.js.map +1 -0
  275. package/dist/scene/geometry-src/mesh-box.d.ts +8 -0
  276. package/dist/scene/geometry-src/mesh-box.d.ts.map +1 -0
  277. package/dist/scene/geometry-src/mesh-box.js +57 -0
  278. package/dist/scene/geometry-src/mesh-box.js.map +1 -0
  279. package/dist/scene/geometry-src/mesh-cache.d.ts +4 -0
  280. package/dist/scene/geometry-src/mesh-cache.d.ts.map +1 -0
  281. package/dist/scene/geometry-src/mesh-cache.js +14 -0
  282. package/dist/scene/geometry-src/mesh-cache.js.map +1 -0
  283. package/dist/scene/geometry-src/mesh-capsule.d.ts +14 -0
  284. package/dist/scene/geometry-src/mesh-capsule.d.ts.map +1 -0
  285. package/dist/scene/geometry-src/mesh-capsule.js +52 -0
  286. package/dist/scene/geometry-src/mesh-capsule.js.map +1 -0
  287. package/dist/scene/geometry-src/mesh-cone.d.ts +16 -0
  288. package/dist/scene/geometry-src/mesh-cone.d.ts.map +1 -0
  289. package/dist/scene/geometry-src/mesh-cone.js +54 -0
  290. package/dist/scene/geometry-src/mesh-cone.js.map +1 -0
  291. package/dist/scene/geometry-src/mesh-cylinder.d.ts +18 -0
  292. package/dist/scene/geometry-src/mesh-cylinder.d.ts.map +1 -0
  293. package/dist/scene/geometry-src/mesh-cylinder.js +67 -0
  294. package/dist/scene/geometry-src/mesh-cylinder.js.map +1 -0
  295. package/dist/scene/geometry-src/mesh-disk.d.ts +11 -0
  296. package/dist/scene/geometry-src/mesh-disk.d.ts.map +1 -0
  297. package/dist/scene/geometry-src/mesh-disk.js +45 -0
  298. package/dist/scene/geometry-src/mesh-disk.js.map +1 -0
  299. package/dist/scene/geometry-src/mesh-dodecahedron.d.ts +4 -0
  300. package/dist/scene/geometry-src/mesh-dodecahedron.d.ts.map +1 -0
  301. package/dist/scene/geometry-src/mesh-dodecahedron.js +10 -0
  302. package/dist/scene/geometry-src/mesh-dodecahedron.js.map +1 -0
  303. package/dist/scene/geometry-src/mesh-fullscreen-quad.d.ts +7 -0
  304. package/dist/scene/geometry-src/mesh-fullscreen-quad.d.ts.map +1 -0
  305. package/dist/scene/geometry-src/mesh-fullscreen-quad.js +39 -0
  306. package/dist/scene/geometry-src/mesh-fullscreen-quad.js.map +1 -0
  307. package/dist/scene/geometry-src/mesh-icosahedron.d.ts +4 -0
  308. package/dist/scene/geometry-src/mesh-icosahedron.d.ts.map +1 -0
  309. package/dist/scene/geometry-src/mesh-icosahedron.js +10 -0
  310. package/dist/scene/geometry-src/mesh-icosahedron.js.map +1 -0
  311. package/dist/scene/geometry-src/mesh-icosphere.d.ts +11 -0
  312. package/dist/scene/geometry-src/mesh-icosphere.d.ts.map +1 -0
  313. package/dist/scene/geometry-src/mesh-icosphere.js +47 -0
  314. package/dist/scene/geometry-src/mesh-icosphere.js.map +1 -0
  315. package/dist/scene/geometry-src/mesh-octahedron.d.ts +4 -0
  316. package/dist/scene/geometry-src/mesh-octahedron.d.ts.map +1 -0
  317. package/dist/scene/geometry-src/mesh-octahedron.js +10 -0
  318. package/dist/scene/geometry-src/mesh-octahedron.js.map +1 -0
  319. package/dist/scene/geometry-src/mesh-plane.d.ts +13 -0
  320. package/dist/scene/geometry-src/mesh-plane.d.ts.map +1 -0
  321. package/dist/scene/geometry-src/mesh-plane.js +51 -0
  322. package/dist/scene/geometry-src/mesh-plane.js.map +1 -0
  323. package/dist/scene/geometry-src/mesh-ring.d.ts +12 -0
  324. package/dist/scene/geometry-src/mesh-ring.d.ts.map +1 -0
  325. package/dist/scene/geometry-src/mesh-ring.js +47 -0
  326. package/dist/scene/geometry-src/mesh-ring.js.map +1 -0
  327. package/dist/scene/geometry-src/mesh-sphere.d.ts +10 -0
  328. package/dist/scene/geometry-src/mesh-sphere.d.ts.map +1 -0
  329. package/dist/scene/geometry-src/mesh-sphere.js +51 -0
  330. package/dist/scene/geometry-src/mesh-sphere.js.map +1 -0
  331. package/dist/scene/geometry-src/mesh-tetrahedron.d.ts +5 -0
  332. package/dist/scene/geometry-src/mesh-tetrahedron.d.ts.map +1 -0
  333. package/dist/scene/geometry-src/mesh-tetrahedron.js +10 -0
  334. package/dist/scene/geometry-src/mesh-tetrahedron.js.map +1 -0
  335. package/dist/scene/geometry-src/mesh-torus.d.ts +17 -0
  336. package/dist/scene/geometry-src/mesh-torus.d.ts.map +1 -0
  337. package/dist/scene/geometry-src/mesh-torus.js +56 -0
  338. package/dist/scene/geometry-src/mesh-torus.js.map +1 -0
  339. package/dist/scene/geometry-src/mesh-types.d.ts +38 -0
  340. package/dist/scene/geometry-src/mesh-types.d.ts.map +1 -0
  341. package/dist/scene/geometry-src/mesh-types.js +2 -0
  342. package/dist/scene/geometry-src/mesh-types.js.map +1 -0
  343. package/dist/scene/geometry-src/mesh.d.ts +61 -0
  344. package/dist/scene/geometry-src/mesh.d.ts.map +1 -0
  345. package/dist/scene/geometry-src/mesh.js +49 -0
  346. package/dist/scene/geometry-src/mesh.js.map +1 -0
  347. package/dist/scene/geometry-src/orthographic-camera.d.ts +14 -0
  348. package/dist/scene/geometry-src/orthographic-camera.d.ts.map +1 -0
  349. package/dist/scene/geometry-src/orthographic-camera.js +9 -0
  350. package/dist/scene/geometry-src/orthographic-camera.js.map +1 -0
  351. package/dist/scene/geometry-src/perspective-camera.d.ts +12 -0
  352. package/dist/scene/geometry-src/perspective-camera.d.ts.map +1 -0
  353. package/dist/scene/geometry-src/perspective-camera.js +9 -0
  354. package/dist/scene/geometry-src/perspective-camera.js.map +1 -0
  355. package/dist/scene/geometry-src/plane-data.d.ts +12 -0
  356. package/dist/scene/geometry-src/plane-data.d.ts.map +1 -0
  357. package/dist/scene/geometry-src/plane-data.js +25 -0
  358. package/dist/scene/geometry-src/plane-data.js.map +1 -0
  359. package/dist/scene/geometry-src/polyhedron-data.d.ts +7 -0
  360. package/dist/scene/geometry-src/polyhedron-data.d.ts.map +1 -0
  361. package/dist/scene/geometry-src/polyhedron-data.js +42 -0
  362. package/dist/scene/geometry-src/polyhedron-data.js.map +1 -0
  363. package/dist/scene/geometry-src/polyhedron-mesh.d.ts +10 -0
  364. package/dist/scene/geometry-src/polyhedron-mesh.d.ts.map +1 -0
  365. package/dist/scene/geometry-src/polyhedron-mesh.js +37 -0
  366. package/dist/scene/geometry-src/polyhedron-mesh.js.map +1 -0
  367. package/dist/scene/geometry-src/polyhedron-seeds.d.ts +6 -0
  368. package/dist/scene/geometry-src/polyhedron-seeds.d.ts.map +1 -0
  369. package/dist/scene/geometry-src/polyhedron-seeds.js +51 -0
  370. package/dist/scene/geometry-src/polyhedron-seeds.js.map +1 -0
  371. package/dist/scene/geometry-src/primitive-data-utils.d.ts +9 -0
  372. package/dist/scene/geometry-src/primitive-data-utils.d.ts.map +1 -0
  373. package/dist/scene/geometry-src/primitive-data-utils.js +36 -0
  374. package/dist/scene/geometry-src/primitive-data-utils.js.map +1 -0
  375. package/dist/scene/geometry-src/ring-data.d.ts +13 -0
  376. package/dist/scene/geometry-src/ring-data.d.ts.map +1 -0
  377. package/dist/scene/geometry-src/ring-data.js +24 -0
  378. package/dist/scene/geometry-src/ring-data.js.map +1 -0
  379. package/dist/scene/geometry-src/sphere-data.d.ts +11 -0
  380. package/dist/scene/geometry-src/sphere-data.d.ts.map +1 -0
  381. package/dist/scene/geometry-src/sphere-data.js +31 -0
  382. package/dist/scene/geometry-src/sphere-data.js.map +1 -0
  383. package/dist/scene/geometry-src/srgb.d.ts +5 -0
  384. package/dist/scene/geometry-src/srgb.d.ts.map +1 -0
  385. package/dist/scene/geometry-src/srgb.js +23 -0
  386. package/dist/scene/geometry-src/srgb.js.map +1 -0
  387. package/dist/scene/geometry-src/torus-data.d.ts +11 -0
  388. package/dist/scene/geometry-src/torus-data.d.ts.map +1 -0
  389. package/dist/scene/geometry-src/torus-data.js +38 -0
  390. package/dist/scene/geometry-src/torus-data.js.map +1 -0
  391. package/dist/scene/geometry-src/vertex-layout.d.ts +2 -0
  392. package/dist/scene/geometry-src/vertex-layout.d.ts.map +1 -0
  393. package/dist/scene/geometry-src/vertex-layout.js +2 -0
  394. package/dist/scene/geometry-src/vertex-layout.js.map +1 -0
  395. package/dist/scene/geometry.d.ts +70 -0
  396. package/dist/scene/geometry.d.ts.map +1 -0
  397. package/dist/scene/geometry.js +71 -0
  398. package/dist/scene/geometry.js.map +1 -0
  399. package/dist/scene/orbit.d.ts +9 -0
  400. package/dist/scene/orbit.d.ts.map +1 -0
  401. package/dist/scene/orbit.js +15 -0
  402. package/dist/scene/orbit.js.map +1 -0
  403. package/dist/scene/tree/errors.d.ts +4 -0
  404. package/dist/scene/tree/errors.d.ts.map +1 -0
  405. package/dist/scene/tree/errors.js +19 -0
  406. package/dist/scene/tree/errors.js.map +1 -0
  407. package/dist/scene/tree/light.d.ts +42 -0
  408. package/dist/scene/tree/light.d.ts.map +1 -0
  409. package/dist/scene/tree/light.js +102 -0
  410. package/dist/scene/tree/light.js.map +1 -0
  411. package/dist/scene/tree/material.d.ts +79 -0
  412. package/dist/scene/tree/material.d.ts.map +1 -0
  413. package/dist/scene/tree/material.js +117 -0
  414. package/dist/scene/tree/material.js.map +1 -0
  415. package/dist/scene/tree/math.d.ts +26 -0
  416. package/dist/scene/tree/math.d.ts.map +1 -0
  417. package/dist/scene/tree/math.js +217 -0
  418. package/dist/scene/tree/math.js.map +1 -0
  419. package/dist/scene/tree/mesh-node.d.ts +17 -0
  420. package/dist/scene/tree/mesh-node.d.ts.map +1 -0
  421. package/dist/scene/tree/mesh-node.js +24 -0
  422. package/dist/scene/tree/mesh-node.js.map +1 -0
  423. package/dist/scene/tree/node.d.ts +70 -0
  424. package/dist/scene/tree/node.d.ts.map +1 -0
  425. package/dist/scene/tree/node.js +220 -0
  426. package/dist/scene/tree/node.js.map +1 -0
  427. package/dist/scene/tree/orbit-controls.d.ts +69 -0
  428. package/dist/scene/tree/orbit-controls.d.ts.map +1 -0
  429. package/dist/scene/tree/orbit-controls.js +226 -0
  430. package/dist/scene/tree/orbit-controls.js.map +1 -0
  431. package/dist/scene.d.ts +21 -0
  432. package/dist/scene.d.ts.map +1 -0
  433. package/dist/scene.js +11 -0
  434. package/dist/scene.js.map +1 -0
  435. package/dist/set-core.d.ts +50 -0
  436. package/dist/set-core.d.ts.map +1 -0
  437. package/dist/set-core.js +268 -0
  438. package/dist/set-core.js.map +1 -0
  439. package/dist/set-layouts.d.ts +20 -0
  440. package/dist/set-layouts.d.ts.map +1 -0
  441. package/dist/set-layouts.js +103 -0
  442. package/dist/set-layouts.js.map +1 -0
  443. package/dist/set-packing.d.ts +4 -0
  444. package/dist/set-packing.d.ts.map +1 -0
  445. package/dist/set-packing.js +82 -0
  446. package/dist/set-packing.js.map +1 -0
  447. package/dist/set-resources.d.ts +20 -0
  448. package/dist/set-resources.d.ts.map +1 -0
  449. package/dist/set-resources.js +140 -0
  450. package/dist/set-resources.js.map +1 -0
  451. package/dist/shader-source.d.ts +4 -0
  452. package/dist/shader-source.d.ts.map +1 -0
  453. package/dist/shader-source.js +21 -0
  454. package/dist/shader-source.js.map +1 -0
  455. package/dist/storage.d.ts +38 -0
  456. package/dist/storage.d.ts.map +1 -0
  457. package/dist/storage.js +76 -0
  458. package/dist/storage.js.map +1 -0
  459. package/dist/surface.d.ts +89 -0
  460. package/dist/surface.d.ts.map +1 -0
  461. package/dist/surface.js +243 -0
  462. package/dist/surface.js.map +1 -0
  463. package/dist/target-offscreen.d.ts +41 -0
  464. package/dist/target-offscreen.d.ts.map +1 -0
  465. package/dist/target-offscreen.js +115 -0
  466. package/dist/target-offscreen.js.map +1 -0
  467. package/dist/target-utils.d.ts +37 -0
  468. package/dist/target-utils.d.ts.map +1 -0
  469. package/dist/target-utils.js +103 -0
  470. package/dist/target-utils.js.map +1 -0
  471. package/dist/target.d.ts +65 -0
  472. package/dist/target.d.ts.map +1 -0
  473. package/dist/target.js +2 -0
  474. package/dist/target.js.map +1 -0
  475. package/dist/timer.d.ts +78 -0
  476. package/dist/timer.d.ts.map +1 -0
  477. package/dist/timer.js +261 -0
  478. package/dist/timer.js.map +1 -0
  479. package/dist/uniforms-layout.d.ts +8 -0
  480. package/dist/uniforms-layout.d.ts.map +1 -0
  481. package/dist/uniforms-layout.js +84 -0
  482. package/dist/uniforms-layout.js.map +1 -0
  483. package/dist/uniforms.d.ts +43 -0
  484. package/dist/uniforms.d.ts.map +1 -0
  485. package/dist/uniforms.js +176 -0
  486. package/dist/uniforms.js.map +1 -0
  487. package/dist/visibility.d.ts +118 -0
  488. package/dist/visibility.d.ts.map +1 -0
  489. package/dist/visibility.js +290 -0
  490. package/dist/visibility.js.map +1 -0
  491. package/package.json +131 -0
package/dist/draw.js ADDED
@@ -0,0 +1,890 @@
1
+ import { reflectSource } from "@aigpu/wgsl/reflect-source";
2
+ import { createBindGroupCache } from "./bind-cache.js";
3
+ import { entryMetadata } from "./entry-metadata.js";
4
+ import { claimedGroupValidationDone, discardClaimedGroupValidationResults, discardClaimedGroupValidationScopes, discardLastClaimedGroupValidationScope, popLastClaimedGroupValidationScope, preferClaimedGroupValidationResult, pushClaimedGroupValidationScope, submittedWorkDone } from "./claim-validation.js";
5
+ import { endRenderPassWithClaimValidation } from "./claim-validation-encode.js";
6
+ import { createSetCore } from "./set-core.js";
7
+ import { bindGroupLayoutEntriesForGroup, bindGroupLayoutsForReflection, cachedBindGroupLayout, visibilityForEntries } from "./set-layouts.js";
8
+ import { normalizeConstantsOptions, normalizeSignature, pipelineKeyOf, selectEntryPoint, signatureKeyOf, validateTargetSignature, createPipelineLayoutCache, createPipelineStore, createShaderModuleCache } from "./pipeline-store.js";
9
+ import { hasStencilAspect, isTarget } from "./target-utils.js";
10
+ import { blendConstantInvalidError, blendInvalidError, claimedGroupNativeValidationError, colorsInvalidError, cullInvalidError, depthInvalidError, entryInvalidError, frontFaceInvalidError, indirectInvalidError, meshRangeInvalidError, multisampleInvalidError, stencilInvalidError, storageStageLimitError, surfaceNotInFrameError, targetRequiredError, unclippedDepthInvalidError, AIGpuError, writeMaskInvalidError } from "./errors.js";
11
+ import { isFrameActive, isSurface } from "./surface.js";
12
+ import { assertDeviceUsable } from "./lifecycle.js";
13
+ import { geometryLayoutResolver } from "./draw-protocols.js";
14
+ import { resolveIndirect } from "./indirect.js";
15
+ import { FRAME_DRAWABLE } from "./frame-protocols.js";
16
+ import { liveKernel } from "./live-kernel.js";
17
+ import { renderService } from "./render-service.js";
18
+ import { toWgsl } from "./shader-source.js";
19
+ /**
20
+ * Renderable shader unit of this gpu: a WGSL shader plus its pipeline state, bindings and
21
+ * optional geometry. Encode it with `pass.draw(triangle)` or call `triangle.draw(target)`.
22
+ *
23
+ * Pipelines, bind groups, shader modules and layouts come from the gpu's single render service, so
24
+ * two draws with the same shader and target signature share one compiled pipeline — and an
25
+ * `effect()` shares that same cache set. Nothing here exists until the first render call: `init()`
26
+ * creates no cache.
27
+ */
28
+ export function draw(gpu, opts) {
29
+ const kernel = liveKernel(gpu, "draw");
30
+ const render = renderService(kernel);
31
+ const shader = toWgsl(opts.shader);
32
+ return new InternalDraw(kernel.device, shader, { ...opts, shader }, render.binds, undefined, render.pipelines, render.shaderModules, render.pipelineLayouts, (error) => kernel.reportError(error), (promise) => { void kernel.trackDelivery(promise); });
33
+ }
34
+ let nextDrawId = 1;
35
+ const drawStates = new WeakMap();
36
+ /** Renderable shader unit with explicit bind layouts, set() ownership, pipeline cache, and R4 group hooks. */
37
+ export class InternalDraw {
38
+ source;
39
+ label;
40
+ #dynamicBindGroupLayouts = new Map();
41
+ constructor(device, source, opts, cache = createBindGroupCache(), defaultTarget, pipelineStore = createPipelineStore(device), shaderModules = createShaderModuleCache(device), pipelineLayouts = createPipelineLayoutCache(device), errorSink, trackSettled) {
42
+ this.source = source;
43
+ assertDeviceUsable(device, "Draw.constructor");
44
+ this.label = opts.label ?? "draw";
45
+ const id = nextDrawId++;
46
+ const reflection = reflectSource(source, `${this.label}.wgsl`);
47
+ // Entry selection runs before everything derived from the selected entries — binding visibility,
48
+ // storage-stage limits, bind group layouts, and vertex input layouts all reflect the chosen variant.
49
+ const entryNames = normalizeEntryOptions(this.label, opts.entry);
50
+ const vertexEntry = selectEntryPoint(this.label, reflection.entryPoints, "vertex", entryNames.vertex, "draw");
51
+ const fragmentEntry = selectEntryPoint(this.label, reflection.entryPoints, "fragment", entryNames.fragment, "draw");
52
+ const entryKey = entryKeyFor(reflection, vertexEntry, fragmentEntry);
53
+ const selectedEntries = [vertexEntry, fragmentEntry].filter((entry) => !!entry);
54
+ const visibility = visibilityForEntries(reflection.bindings, selectedEntries);
55
+ validateStorageStageLimits(device, this.label, reflection.bindings, selectedEntries, visibility);
56
+ const geometry = opts.geometry;
57
+ const inputs = vertexEntry ? entryMetadata(vertexEntry, "inputs", this.label) : [];
58
+ const vertexBufferLayouts = geometry && geometryLayoutResolver in geometry ? geometry[geometryLayoutResolver](inputs, `${this.label}.geometry`) : geometry?.vertexBufferLayouts;
59
+ const bindGroupLayouts = new Map(bindGroupLayoutsForReflection(device, this.label, reflection, visibility));
60
+ const pipelineLayout = pipelineLayouts.get(bindGroupLayouts);
61
+ const shaderModule = shaderModules.get(source, `${this.label}.shader`);
62
+ const recordedIn = createBundleRegistry();
63
+ const fragmentState = normalizeFragmentState(this.label, opts);
64
+ const blendConstantOptions = normalizeBlendConstantOptions(this.label, opts, fragmentState);
65
+ const primitiveOptions = normalizePrimitiveOptions(device, this.label, opts);
66
+ const depthOptions = normalizeDepthOptions(device, this.label, opts);
67
+ const stencilOptions = normalizeStencilOptions(this.label, opts);
68
+ const multisampleOptions = normalizeMultisampleOptions(this.label, opts);
69
+ const constantsOptions = normalizeConstantsOptions(this.label, opts.constants, reflection.overrides, "draw");
70
+ const setCore = createSetCore({
71
+ device,
72
+ label: this.label,
73
+ drawId: id,
74
+ reflection,
75
+ bindGroupLayouts,
76
+ cache,
77
+ onIdentityChange: (change) => recordedIn.markStale({ kind: "binding-identity", drawLabel: this.label, ...change }),
78
+ });
79
+ drawStates.set(this, { id, device, opts, vertexBufferLayouts, cache, defaultTarget, reflection, visibility, vertexEntry: vertexEntry?.name ?? "vs_main", fragmentEntry: fragmentEntry?.name ?? "fs_main", entryKey, setCore, bindGroupLayouts, pipelineLayout, shaderModule, pipelineStore, pipelineLayouts, errorSink, trackSettled, resolvedPipelineKeys: new Set(), recordedIn, ...fragmentState, ...blendConstantOptions, ...primitiveOptions, ...depthOptions, ...stencilOptions, ...multisampleOptions, ...constantsOptions });
80
+ if (opts.set)
81
+ this.set(opts.set);
82
+ for (const target of opts.targets ?? [])
83
+ this.compileSync(target);
84
+ }
85
+ get gpu() {
86
+ const state = drawState(this);
87
+ for (const key of state.resolvedPipelineKeys) {
88
+ const pipeline = state.pipelineStore.getReady(key);
89
+ if (pipeline)
90
+ return pipeline;
91
+ }
92
+ return undefined;
93
+ }
94
+ get targets() { return drawState(this).opts.targets; }
95
+ /**
96
+ * Frame drawable protocol: a `Frame` encodes through this instead of importing draw.ts, so a
97
+ * program that never draws never pulls this module. The instance is its own protocol object —
98
+ * `encode`, `label` and the depth/stencil metadata below are exactly what a pass needs.
99
+ */
100
+ get [FRAME_DRAWABLE]() { return this; }
101
+ /** @internal Frame drawable protocol; see {@link drawWritesDepth}. */
102
+ writesDepth() { return drawWritesDepth(this); }
103
+ /** @internal Frame drawable protocol; see {@link drawStencilWritingOps}. */
104
+ stencilWritingOps() { return drawStencilWritingOps(this); }
105
+ set(values) {
106
+ const state = drawState(this);
107
+ assertDeviceUsable(state.device, `${this.label}.set`);
108
+ for (const change of state.setCore.set(values))
109
+ state.recordedIn.markStale({ kind: "binding-identity", drawLabel: this.label, ...change });
110
+ return this;
111
+ }
112
+ group(n, bindGroup) {
113
+ const state = drawState(this);
114
+ assertDeviceUsable(state.device, `${this.label}.group`);
115
+ const expectedLayout = this.#dynamicBindGroupLayouts.get(n) ?? this.layout(n);
116
+ const previousIdentity = state.setCore.claimGroup(n, bindGroup, expectedLayout);
117
+ state.recordedIn.markStale({ kind: "group-claim", drawLabel: this.label, group: n, previousIdentity, newIdentity: `claimed-group:${n}` });
118
+ return this;
119
+ }
120
+ layout(n, opts = {}) {
121
+ assertDeviceUsable(drawState(this).device, `${this.label}.layout`);
122
+ if (!opts.dynamicOffsets)
123
+ return drawState(this).setCore.layout(n);
124
+ return this.#dynamicLayout(n);
125
+ }
126
+ #dynamicLayout(group) {
127
+ const state = drawState(this);
128
+ state.setCore.layout(group);
129
+ const existing = this.#dynamicBindGroupLayouts.get(group);
130
+ if (existing)
131
+ return existing;
132
+ const entries = dynamicEntries(this, group);
133
+ const layout = cachedBindGroupLayout(state.device, `${this.label}.group${group}.dynamic.bgl`, entries);
134
+ this.#dynamicBindGroupLayouts.set(group, layout);
135
+ state.bindGroupLayouts.set(group, layout);
136
+ state.pipelineLayout = state.pipelineLayouts.get(state.bindGroupLayouts);
137
+ return layout;
138
+ }
139
+ /**
140
+ * Encodes and submits this draw as a one-shot render pass.
141
+ *
142
+ * Raw claimed-bind-group validation failures are delivered asynchronously via
143
+ * `gpu.onError` as `AIGPU-R4-GROUP-VALIDATION`.
144
+ */
145
+ draw(arg = {}) {
146
+ assertDeviceUsable(drawState(this).device, `${this.label}.draw`);
147
+ const opts = isTarget(arg) ? { target: arg } : arg;
148
+ const state = drawState(this);
149
+ const target = opts.target ?? state.defaultTarget;
150
+ if (!target)
151
+ throw targetRequiredError(`${this.label}.draw`);
152
+ assertSurfaceTargetInFrame(target, `${this.label}.draw`);
153
+ const encoder = state.device.gpu.createCommandEncoder();
154
+ const pass = encoder.beginRenderPass(target.renderPassDescriptor());
155
+ const validations = [];
156
+ try {
157
+ this.encode(pass, target, opts, (result) => validations.push(result));
158
+ }
159
+ catch (error) {
160
+ discardClaimedGroupValidationResults(validations);
161
+ discardClaimedGroupValidationScopes(state.device);
162
+ try {
163
+ pass.end();
164
+ }
165
+ catch { /* ignore cleanup failure after encode failure */ }
166
+ throw error;
167
+ }
168
+ endRenderPassWithClaimValidation(state.device, pass, validations, validations[0]?.context);
169
+ let commandBuffer;
170
+ const finishContext = validations[0]?.context;
171
+ if (finishContext)
172
+ pushClaimedGroupValidationScope(state.device, finishContext);
173
+ try {
174
+ commandBuffer = encoder.finish();
175
+ }
176
+ catch (error) {
177
+ const result = finishContext ? popLastClaimedGroupValidationScope(state.device) : undefined;
178
+ discardClaimedGroupValidationResults(validations);
179
+ if (result)
180
+ discardClaimedGroupValidationResults([result]);
181
+ const context = result?.context ?? finishContext;
182
+ if (context) {
183
+ void reportDrawValidationError(state, context.label, context.group, error);
184
+ return;
185
+ }
186
+ throw error;
187
+ }
188
+ if (finishContext) {
189
+ const result = popLastClaimedGroupValidationScope(state.device);
190
+ if (result)
191
+ validations[0] = validations[0] ? preferClaimedGroupValidationResult(result, validations[0]) : result;
192
+ }
193
+ const submitContext = validations[0]?.context;
194
+ if (submitContext)
195
+ pushClaimedGroupValidationScope(state.device, submitContext);
196
+ try {
197
+ state.device.gpu.queue.submit([commandBuffer]);
198
+ }
199
+ catch (error) {
200
+ const result = submitContext ? popLastClaimedGroupValidationScope(state.device) : undefined;
201
+ discardClaimedGroupValidationResults(validations);
202
+ if (result)
203
+ discardClaimedGroupValidationResults([result]);
204
+ const context = result?.context ?? submitContext;
205
+ if (context) {
206
+ void reportDrawValidationError(state, context.label, context.group, error);
207
+ return;
208
+ }
209
+ throw error;
210
+ }
211
+ if (submitContext) {
212
+ const result = popLastClaimedGroupValidationScope(state.device);
213
+ if (result)
214
+ validations[0] = validations[0] ? preferClaimedGroupValidationResult(result, validations[0]) : result;
215
+ }
216
+ if (validations.length) {
217
+ const done = claimedGroupValidationDone(state.device, validations, { errorSink: state.errorSink });
218
+ state.trackSettled?.(done);
219
+ }
220
+ }
221
+ encode(pass, target, opts = {}, claimValidation) {
222
+ assertDeviceUsable(drawState(this).device, `${this.label}.encode`);
223
+ const pipeline = this.pipelineFor(target, true);
224
+ if (!pipeline)
225
+ return;
226
+ pass.setPipeline(pipeline);
227
+ const state = drawState(this);
228
+ if (state.blendConstant)
229
+ pass.setBlendConstant(state.blendConstant);
230
+ // Explicit ref always emits — even 0, which restores the pass default after an earlier draw changed it.
231
+ if (state.stencilRef !== undefined)
232
+ pass.setStencilReference(state.stencilRef);
233
+ for (const binding of state.setCore.bindGroups())
234
+ this.#setBindGroup(pass, binding, opts, claimValidation);
235
+ this.#encodeGeometry(pass, opts);
236
+ }
237
+ #setBindGroup(pass, binding, opts, claimValidation) {
238
+ const offsets = offsetsForGroup(opts.offsets, binding.group, binding.offsets);
239
+ if (!binding.claimValidation || !claimValidation) {
240
+ pass.setBindGroup(binding.group, binding.bindGroup, offsets);
241
+ return;
242
+ }
243
+ pushClaimedGroupValidationScope(drawState(this).device, binding.claimValidation);
244
+ try {
245
+ pass.setBindGroup(binding.group, binding.bindGroup, offsets);
246
+ }
247
+ catch (error) {
248
+ discardLastClaimedGroupValidationScope(drawState(this).device);
249
+ throw claimedGroupNativeValidationError(binding.claimValidation.label, binding.claimValidation.group, error);
250
+ }
251
+ const result = popLastClaimedGroupValidationScope(drawState(this).device);
252
+ if (result)
253
+ claimValidation(result);
254
+ }
255
+ compile(target) {
256
+ assertDeviceUsable(drawState(this).device, `${this.label}.compile`);
257
+ const { key, signature, signatureKey } = this.#compileKey(target, `${this.label}.compile`);
258
+ const promise = drawState(this).pipelineStore.getAsync(key, () => this.#createPipelineAsync(signature), { where: `${this.label}.compile`, signature: signatureKey });
259
+ return promise.then(() => {
260
+ assertDeviceUsable(drawState(this).device, `${this.label}.compile`);
261
+ drawState(this).resolvedPipelineKeys.add(key);
262
+ return this;
263
+ });
264
+ }
265
+ compileSync(target) {
266
+ assertDeviceUsable(drawState(this).device, `${this.label}.compileSync`);
267
+ const { key, signature, signatureKey } = this.#compileKey(target, `${this.label}.compileSync`);
268
+ const pipeline = drawState(this).pipelineStore.getSync(key, () => this.#createPipeline(signature), { where: `${this.label}.compileSync`, signature: signatureKey });
269
+ if (pipeline)
270
+ drawState(this).resolvedPipelineKeys.add(key);
271
+ return this;
272
+ }
273
+ pipelineFor(target, allowSurface = false) {
274
+ assertDeviceUsable(drawState(this).device, `${this.label}.pipelineFor`);
275
+ const { key, signature, signatureKey } = this.#compileKey(target, `${this.label}.pipelineFor`, allowSurface);
276
+ const pipeline = drawState(this).pipelineStore.getSync(key, () => this.#createPipeline(signature), { where: `${this.label}.pipelineFor`, signature: signatureKey });
277
+ if (pipeline)
278
+ drawState(this).resolvedPipelineKeys.add(key);
279
+ return pipeline;
280
+ }
281
+ pipelineForAsync(target) {
282
+ assertDeviceUsable(drawState(this).device, `${this.label}.pipelineForAsync`);
283
+ const { key, signature, signatureKey } = this.#compileKey(target, `${this.label}.pipelineForAsync`);
284
+ const promise = drawState(this).pipelineStore.getAsync(key, () => this.#createPipelineAsync(signature), { where: `${this.label}.pipelineForAsync`, signature: signatureKey });
285
+ return promise.then((pipeline) => {
286
+ assertDeviceUsable(drawState(this).device, `${this.label}.pipelineForAsync`);
287
+ drawState(this).resolvedPipelineKeys.add(key);
288
+ return pipeline;
289
+ });
290
+ }
291
+ #compileKey(target, where, allowSurface = false) {
292
+ const signature = this.#signatureForKeyTarget(target, where, allowSurface);
293
+ const signatureKey = signatureKeyOf(signature);
294
+ return { signature, signatureKey, key: this.#pipelineKey(signature) };
295
+ }
296
+ #signatureForKeyTarget(target, where, allowSurface = false) {
297
+ const state = drawState(this);
298
+ const resolvedTarget = target ?? state.defaultTarget;
299
+ if (!resolvedTarget)
300
+ throw targetRequiredError(where);
301
+ if (!allowSurface)
302
+ assertSurfaceTargetInFrame(resolvedTarget, where);
303
+ const signature = normalizeSignature(resolvedTarget);
304
+ validateTargetSignature(signature, where);
305
+ if (state.colorStates && state.colorStates.length !== signature.colors.length) {
306
+ throw colorsInvalidError(this.label, `expected one entry per color attachment; colors has ${state.colorStates.length}, but the target signature has ${signature.colors.length}.`, where);
307
+ }
308
+ // WebGPU: "If descriptor.alphaToCoverageEnabled is true: descriptor.count > 1." The companion createRenderPipeline
309
+ // rules — targets[0].format must be blendable with an alpha channel, and the fragment stage must not output the
310
+ // sample_mask builtin — depend on format capabilities and shader outputs that WGSL reflection does not expose
311
+ // (EntryPointInfo has no output info), so native validation covers them.
312
+ if (state.multisampleState?.alphaToCoverageEnabled && (signature.sampleCount ?? 1) <= 1) {
313
+ throw multisampleInvalidError(this.label, `alphaToCoverage requires a multisampled target, but the target signature has sampleCount ${signature.sampleCount ?? 1}; create the target with msaa: true.`, where);
314
+ }
315
+ // WebGPU: "If descriptor.stencilFront or descriptor.stencilBack are not the default values: descriptor.format must
316
+ // have a stencil component." The reference is likewise dead without a stencil aspect, so it fails the same check.
317
+ if ((state.stencilState || state.stencilRef !== undefined) && !hasStencilAspect(signature.depth)) {
318
+ throw stencilInvalidError(this.label, `stencil requires a depth format with a stencil aspect, but the target signature has ${signature.depth ? `"${signature.depth}"` : "no depth"}; create the target with depth: "depth24plus-stencil8".`, where);
319
+ }
320
+ return signature;
321
+ }
322
+ #pipelineKey(signature) {
323
+ const state = drawState(this);
324
+ const geometry = state.opts.geometry;
325
+ // The key must use the same stripIndexFormat the descriptor derives (primitiveState), or strip geometries that only
326
+ // differ in indexFormat collide on one pipeline.
327
+ return pipelineKeyOf({ module: state.shaderModule, pipelineLayout: state.pipelineLayout, vertexBufferLayouts: state.vertexBufferLayouts, signature, fragmentKey: state.fragmentKey, topology: geometry?.topology, stripIndexFormat: stripIndexFormatFor(geometry), cullMode: state.cullMode, frontFace: state.frontFace, unclippedDepth: state.unclippedDepth, depthKey: state.depthKey, stencilKey: state.stencilKey, multisampleKey: state.multisampleKey, constantsKey: state.constantsKey, entryKey: state.entryKey });
328
+ }
329
+ #encodeGeometry(pass, callOpts = {}) {
330
+ const geometry = drawState(this).opts.geometry;
331
+ if (geometry?.vertexBuffers)
332
+ geometry.vertexBuffers.forEach((buffer, index) => pass.setVertexBuffer(index, buffer));
333
+ if (callOpts.indirect !== undefined)
334
+ return this.#encodeIndirect(pass, geometry, callOpts);
335
+ const counts = resolveDrawCounts(this.label, geometry, drawState(this).opts, callOpts);
336
+ if (!geometry?.indexBuffer)
337
+ return pass.draw(counts.vertexCount, counts.instanceCount, counts.firstVertex, counts.firstInstance);
338
+ pass.setIndexBuffer(geometry.indexBuffer, geometry.indexFormat ?? "uint32");
339
+ pass.drawIndexed(counts.indexCount, counts.instanceCount, counts.firstIndex, counts.baseVertex, counts.firstInstance);
340
+ }
341
+ /**
342
+ * The GPU reads the draw arguments from the buffer, so per-call counts alongside indirect are dead options and throw.
343
+ * A non-zero firstInstance in the buffered arguments cannot be validated on the CPU; per WebGPU, it "must be 0,
344
+ * unless the 'indirect-first-instance' feature is enabled", otherwise the indirect call "will be treated as a no-op".
345
+ */
346
+ #encodeIndirect(pass, geometry, callOpts) {
347
+ const where = `${this.label}.draw`;
348
+ const conflict = INDIRECT_CONFLICT_FIELDS.find((field) => callOpts[field] !== undefined);
349
+ if (conflict !== undefined)
350
+ throw indirectInvalidError(this.label, `indirect cannot be combined with ${conflict} in the same call; the GPU reads the draw arguments from the buffer, so the CPU-side value would be ignored.`, where);
351
+ const indexed = !!geometry?.indexBuffer;
352
+ const { buffer, offset } = resolveIndirect(this.label, where, callOpts.indirect, indexed ? "drawIndexedIndirect" : "drawIndirect");
353
+ if (!indexed)
354
+ return pass.drawIndirect(buffer, offset);
355
+ pass.setIndexBuffer(geometry.indexBuffer, geometry.indexFormat ?? "uint32");
356
+ pass.drawIndexedIndirect(buffer, offset);
357
+ }
358
+ #createPipeline(signature) {
359
+ const state = drawState(this);
360
+ // One constants record serves both stages: WebGPU keys constants module-level ("The pipeline-overridable
361
+ // constant is not required to be statically used by entryPoint"), so no per-stage filtering is needed.
362
+ return state.device.gpu.createRenderPipeline({
363
+ label: `${this.label}.pipeline`,
364
+ layout: state.pipelineLayout,
365
+ vertex: { module: state.shaderModule, entryPoint: state.vertexEntry, buffers: [...(state.vertexBufferLayouts ?? [])], ...(state.constants ? { constants: state.constants } : {}) },
366
+ fragment: { module: state.shaderModule, entryPoint: state.fragmentEntry, targets: fragmentTargets(signature, state), ...(state.constants ? { constants: state.constants } : {}) },
367
+ primitive: primitiveState(state.opts.geometry, state.cullMode, state.frontFace, state.unclippedDepth),
368
+ depthStencil: depthStencilState(signature, state),
369
+ multisample: multisampleStateFor(signature, state),
370
+ });
371
+ }
372
+ #createPipelineAsync(signature) {
373
+ const state = drawState(this);
374
+ return state.device.gpu.createRenderPipelineAsync({
375
+ label: `${this.label}.pipeline`,
376
+ layout: state.pipelineLayout,
377
+ vertex: { module: state.shaderModule, entryPoint: state.vertexEntry, buffers: [...(state.vertexBufferLayouts ?? [])], ...(state.constants ? { constants: state.constants } : {}) },
378
+ fragment: { module: state.shaderModule, entryPoint: state.fragmentEntry, targets: fragmentTargets(signature, state), ...(state.constants ? { constants: state.constants } : {}) },
379
+ primitive: primitiveState(state.opts.geometry, state.cullMode, state.frontFace, state.unclippedDepth),
380
+ depthStencil: depthStencilState(signature, state),
381
+ multisample: multisampleStateFor(signature, state),
382
+ });
383
+ }
384
+ }
385
+ function validateStorageStageLimits(device, label, bindings, entries, visibility) {
386
+ const limits = device.limits;
387
+ for (const [stage, flag, limitName] of [["vertex", 1, "maxStorageBuffersInVertexStage"], ["fragment", 2, "maxStorageBuffersInFragmentStage"]]) {
388
+ const entry = entries.find((item) => item.stage === stage);
389
+ if (!entry)
390
+ continue;
391
+ const used = bindings.filter((binding) => binding.bindingLayout?.kind === "buffer" && binding.bindingLayout.buffer.type !== "uniform" && (visibility(binding) & flag));
392
+ const limit = limits[limitName] ?? limits.maxStorageBuffersPerShaderStage;
393
+ if (limit !== undefined && used.length > limit)
394
+ throw storageStageLimitError(label, stage, entry.name, used.length, limit, used);
395
+ }
396
+ }
397
+ const INDIRECT_CONFLICT_FIELDS = ["vertices", "indices", "instances", "firstVertex", "firstIndex", "baseVertex", "firstInstance"];
398
+ function fragmentTargets(signature, state) {
399
+ return signature.colors.map((format, index) => {
400
+ const overrides = state.colorStates?.[index];
401
+ const blendState = overrides?.blendState ?? state.blendState;
402
+ const writeMask = overrides?.writeMask ?? state.writeMask;
403
+ const target = { format };
404
+ if (blendState)
405
+ target.blend = blendState;
406
+ if (writeMask !== undefined)
407
+ target.writeMask = writeMask;
408
+ return target;
409
+ });
410
+ }
411
+ function resolveDrawCounts(label, geometry, drawOpts, callOpts) {
412
+ validateOptionalDrawCount(label, "DrawOptions.instances", drawOpts.instances);
413
+ validateOptionalDrawCount(label, "DrawOptions.vertices", drawOpts.vertices);
414
+ validateOptionalDrawCount(label, "DrawOptions.firstInstance", drawOpts.firstInstance);
415
+ validateOptionalDrawCount(label, "DrawCallOptions.instances", callOpts.instances);
416
+ validateOptionalGeometryRange(label, "DrawCallOptions.vertices", callOpts.vertices);
417
+ validateOptionalGeometryRange(label, "DrawCallOptions.indices", callOpts.indices);
418
+ validateOptionalGeometryRange(label, "DrawCallOptions.firstVertex", callOpts.firstVertex);
419
+ validateOptionalGeometryRange(label, "DrawCallOptions.firstIndex", callOpts.firstIndex);
420
+ validateOptionalGeometryRange(label, "DrawCallOptions.baseVertex", callOpts.baseVertex);
421
+ validateOptionalDrawCount(label, "DrawCallOptions.firstInstance", callOpts.firstInstance);
422
+ validateOptionalDrawCount(label, "GeometryLike.vertexCount", geometry?.vertexCount);
423
+ validateOptionalDrawCount(label, "GeometryLike.indexCount", geometry?.indexCount);
424
+ validateOptionalDrawCount(label, "GeometryLike.instanceCount", geometry?.instanceCount);
425
+ validateOptionalGeometryRange(label, "GeometryLike.firstVertex", geometry?.firstVertex);
426
+ validateOptionalGeometryRange(label, "GeometryLike.firstIndex", geometry?.firstIndex);
427
+ validateOptionalGeometryRange(label, "GeometryLike.baseVertex", geometry?.baseVertex);
428
+ const indexed = !!geometry?.indexBuffer;
429
+ const sliceParent = geometry?.geometry;
430
+ const parent = sliceParent ?? (geometry && geometryLayoutResolver in geometry ? geometry : undefined);
431
+ const firstVertex = callOpts.firstVertex ?? geometry?.firstVertex ?? 0;
432
+ const vertexCount = callOpts.vertices ?? geometry?.vertexCount ?? drawOpts.vertices ?? 3;
433
+ const firstIndex = callOpts.firstIndex ?? geometry?.firstIndex ?? 0;
434
+ const indexCount = callOpts.indices ?? geometry?.indexCount ?? 0;
435
+ const baseVertex = callOpts.baseVertex ?? geometry?.baseVertex ?? 0;
436
+ if (indexed)
437
+ validateDrawInterval(label, "index", firstIndex, indexCount, parent?.indexCount);
438
+ else if (callOpts.indices !== undefined || callOpts.firstIndex !== undefined || callOpts.baseVertex !== undefined)
439
+ throw meshRangeInvalidError(`${label}.draw`, "Index range needs an indexed geometry.");
440
+ if (!indexed)
441
+ validateDrawInterval(label, "vertex", firstVertex, vertexCount, parent?.vertexCount);
442
+ return {
443
+ instanceCount: callOpts.instances ?? drawOpts.instances ?? geometry?.instanceCount ?? 1,
444
+ firstInstance: callOpts.firstInstance ?? drawOpts.firstInstance ?? 0,
445
+ vertexCount,
446
+ firstVertex,
447
+ indexCount,
448
+ firstIndex,
449
+ baseVertex,
450
+ };
451
+ }
452
+ /** Single source of truth for the descriptor's stripIndexFormat, shared with the pipeline cache key. */
453
+ function stripIndexFormatFor(geometry) {
454
+ const topology = geometry?.topology ?? "triangle-list";
455
+ return geometry?.stripIndexFormat ?? (topology.endsWith("strip") ? geometry?.indexFormat : undefined);
456
+ }
457
+ function primitiveState(geometry, cullMode, frontFace, unclippedDepth) {
458
+ const topology = geometry?.topology ?? "triangle-list";
459
+ const stripIndexFormat = stripIndexFormatFor(geometry);
460
+ const state = stripIndexFormat ? { topology, stripIndexFormat } : { topology };
461
+ if (cullMode !== undefined)
462
+ state.cullMode = cullMode;
463
+ if (frontFace !== undefined)
464
+ state.frontFace = frontFace;
465
+ if (unclippedDepth)
466
+ state.unclippedDepth = true;
467
+ return state;
468
+ }
469
+ function validateDrawInterval(label, kind, first, count, max) {
470
+ if (max === undefined || first + count <= max)
471
+ return;
472
+ throw meshRangeInvalidError(`${label}.draw`, `${kind} range [${first}, ${first + count}) exceeds parent geometry ${kind} count ${max}.`);
473
+ }
474
+ function validateOptionalGeometryRange(label, field, value) {
475
+ if (value === undefined || (Number.isInteger(value) && value >= 0))
476
+ return;
477
+ throw meshRangeInvalidError(`${label}.draw`, `${field} must be an integer >= 0; received ${String(value)}.`);
478
+ }
479
+ function validateOptionalDrawCount(label, field, value) {
480
+ if (value === undefined)
481
+ return;
482
+ if (Number.isInteger(value) && value >= 0)
483
+ return;
484
+ throw new AIGpuError({
485
+ code: "AIGPU-R1-DRAW-COUNT",
486
+ message: `${field} of '${label}' must be an integer >= 0; received ${String(value)}. Use 0 only when you want to issue a valid draw with no vertices/instances.`,
487
+ where: `${label}.draw`,
488
+ });
489
+ }
490
+ function normalizeFragmentState(label, opts) {
491
+ const blendState = opts.blend === undefined ? undefined : normalizeBlend(label, opts.blend);
492
+ const writeMask = opts.writeMask === undefined ? undefined : normalizeWriteMask(label, opts.writeMask);
493
+ const colorStates = opts.colors === undefined ? undefined : normalizeColorStates(label, opts.colors);
494
+ const fragmentKey = colorStates
495
+ ? `${fragmentKeyFor(blendState, writeMask)}@${colorStates.map(colorStateKeyFor).join("@")}`
496
+ : blendState || writeMask !== undefined ? fragmentKeyFor(blendState, writeMask) : undefined;
497
+ return { blendState, writeMask, colorStates, fragmentKey };
498
+ }
499
+ function normalizeColorStates(label, value) {
500
+ if (!Array.isArray(value))
501
+ throw colorsInvalidError(label, `colors must be an array; received ${preview(value)}.`);
502
+ return value.map((entry, index) => {
503
+ if (entry === null || entry === undefined)
504
+ return null;
505
+ if (typeof entry !== "object" || Array.isArray(entry))
506
+ throw colorsInvalidError(label, `colors[${index}] must be null or { blend?, writeMask? }; received ${preview(entry)}.`);
507
+ const blendState = entry.blend === undefined ? undefined : normalizeBlend(`${label}.colors[${index}]`, entry.blend);
508
+ const writeMask = entry.writeMask === undefined ? undefined : normalizeWriteMask(`${label}.colors[${index}]`, entry.writeMask);
509
+ if (!blendState && writeMask === undefined)
510
+ return null;
511
+ return { blendState, writeMask };
512
+ });
513
+ }
514
+ function normalizeBlend(label, value) {
515
+ if (value === "alpha")
516
+ return blendState({ src: "src-alpha", dst: "one-minus-src-alpha" }, { src: "one", dst: "one-minus-src-alpha" });
517
+ if (value === "premultiplied")
518
+ return blendState({ src: "one", dst: "one-minus-src-alpha" }, { src: "one", dst: "one-minus-src-alpha" });
519
+ if (value === "additive")
520
+ return blendState({ src: "one", dst: "one" }, { src: "one", dst: "one" });
521
+ if (typeof value !== "object" || value === null || !validBlendComponent(value.color))
522
+ throw blendInvalidError(label, value);
523
+ const color = value.color;
524
+ const alpha = value.alpha;
525
+ if (alpha !== undefined && !validBlendComponent(alpha))
526
+ throw blendInvalidError(label, value);
527
+ return blendState(color, alpha ?? color);
528
+ }
529
+ function validBlendComponent(value) {
530
+ return typeof value === "object" && value !== null
531
+ && typeof value.src === "string"
532
+ && typeof value.dst === "string";
533
+ }
534
+ function blendState(color, alpha) {
535
+ return { color: blendComponent(color), alpha: blendComponent(alpha) };
536
+ }
537
+ function blendComponent(component) {
538
+ return { srcFactor: component.src, dstFactor: component.dst, operation: component.op ?? "add" };
539
+ }
540
+ function normalizeBlendConstantOptions(label, opts, fragmentState) {
541
+ if (opts.blendConstant === undefined)
542
+ return {};
543
+ const value = opts.blendConstant;
544
+ if (!Array.isArray(value) || value.length !== 4 || value.some((component) => typeof component !== "number" || !Number.isFinite(component))) {
545
+ throw blendConstantInvalidError(label, `received ${preview(value)}; expected [r, g, b, a] finite numbers.`);
546
+ }
547
+ // Constant factors without blendConstant stay legal (the value the pass holds applies); the reverse is a dead option.
548
+ // The check runs against the EFFECTIVE blend state of every color target — the same resolution fragmentTargets() uses,
549
+ // so a constant factor reached only through colors[i].blend counts, and a top-level one overridden on every target does not.
550
+ if (!effectiveBlendStates(fragmentState).some((blend) => blend && usesConstantBlendFactor(blend))) {
551
+ throw blendConstantInvalidError(label, `no color target's effective blend uses a "constant"/"one-minus-constant" factor (colors[i].blend replaces the top-level blend for that target), so blendConstant would have no effect.`);
552
+ }
553
+ return { blendConstant: { r: value[0], g: value[1], b: value[2], a: value[3] } };
554
+ }
555
+ /** Blend state each color target ends up with: the per-target override when it carries one, else the top-level blend (mirrors fragmentTargets). */
556
+ function effectiveBlendStates(fragmentState) {
557
+ if (!fragmentState.colorStates)
558
+ return [fragmentState.blendState];
559
+ return fragmentState.colorStates.map((entry) => entry?.blendState ?? fragmentState.blendState);
560
+ }
561
+ function usesConstantBlendFactor(blend) {
562
+ return [blend.color.srcFactor, blend.color.dstFactor, blend.alpha.srcFactor, blend.alpha.dstFactor]
563
+ .some((factor) => factor === "constant" || factor === "one-minus-constant");
564
+ }
565
+ function normalizeEntryOptions(label, value) {
566
+ if (value === undefined)
567
+ return {};
568
+ if (typeof value !== "object" || value === null || Array.isArray(value))
569
+ throw entryInvalidError(label, `received ${preview(value)}; expected { vertex?, fragment? } entry point names.`);
570
+ return value;
571
+ }
572
+ // Explicitly naming the first-of-stage entries behaves exactly like an absent option; pipeline cache keys stay byte-identical so they share pipelines.
573
+ function entryKeyFor(reflection, vertexEntry, fragmentEntry) {
574
+ const firstVertex = reflection.entryPoints.find((entry) => entry.stage === "vertex");
575
+ const firstFragment = reflection.entryPoints.find((entry) => entry.stage === "fragment");
576
+ if (vertexEntry === firstVertex && fragmentEntry === firstFragment)
577
+ return undefined;
578
+ return `en~${vertexEntry?.name ?? ""}~${fragmentEntry?.name ?? ""}`;
579
+ }
580
+ function normalizePrimitiveOptions(device, label, opts) {
581
+ const cullMode = opts.cull === undefined ? undefined : normalizeCull(label, opts.cull);
582
+ const frontFace = opts.frontFace === undefined ? undefined : normalizeFrontFace(label, opts.frontFace);
583
+ const unclippedDepth = opts.unclippedDepth === undefined ? undefined : normalizeUnclippedDepth(device, label, opts.unclippedDepth);
584
+ return { cullMode, frontFace, unclippedDepth };
585
+ }
586
+ function normalizeUnclippedDepth(device, label, value) {
587
+ if (typeof value !== "boolean")
588
+ throw unclippedDepthInvalidError(label, `received ${preview(value)}; expected a boolean.`);
589
+ // An explicit false behaves exactly like an absent option; descriptors and pipeline cache keys stay byte-identical.
590
+ if (!value)
591
+ return undefined;
592
+ // WebGPU: "If descriptor.unclippedDepth is true: 'depth-clip-control' must be enabled for device."
593
+ if (!device.features.has("depth-clip-control")) {
594
+ throw unclippedDepthInvalidError(label, `the device lacks the "depth-clip-control" feature; request it at init: init({ requiredFeatures: ["depth-clip-control"] }) on an adapter that supports it.`);
595
+ }
596
+ return true;
597
+ }
598
+ function normalizeCull(label, value) {
599
+ if (value === "none" || value === "front" || value === "back")
600
+ return value;
601
+ throw cullInvalidError(label, value);
602
+ }
603
+ function normalizeFrontFace(label, value) {
604
+ if (value === "ccw" || value === "cw")
605
+ return value;
606
+ throw frontFaceInvalidError(label, value);
607
+ }
608
+ const DEFAULT_DEPTH_STATE = { depthWriteEnabled: true, depthCompare: "less-equal" };
609
+ const DEPTH_COMPARE_FUNCTIONS = ["never", "less", "equal", "less-equal", "greater", "not-equal", "greater-equal", "always"];
610
+ const I32_MIN = -2147483648;
611
+ const I32_MAX = 2147483647;
612
+ function depthStencilState(signature, state) {
613
+ // A Draw may compile against targets with and without depth; opts.depth only applies when the signature has a depth attachment.
614
+ if (!signature.depth)
615
+ return undefined;
616
+ // Stencil merges into the depth state (defaulted when the depth option is absent); unset stencil fields stay omitted
617
+ // so the descriptor is byte-identical to today's when the stencil option is absent.
618
+ return { format: signature.depth, ...(state.depthState ?? DEFAULT_DEPTH_STATE), ...(state.stencilState ?? {}) };
619
+ }
620
+ function normalizeDepthOptions(device, label, opts) {
621
+ if (opts.depth === undefined)
622
+ return {};
623
+ const depthState = normalizeDepth(device, label, opts.depth, opts.geometry?.topology ?? "triangle-list");
624
+ return { depthState, depthKey: depthKeyFor(depthState) };
625
+ }
626
+ function normalizeDepth(device, label, value, topology) {
627
+ if (value === false)
628
+ return { depthWriteEnabled: false, depthCompare: "always" };
629
+ if (typeof value !== "object" || value === null)
630
+ throw depthInvalidError(label, `received ${preview(value)}.`);
631
+ if (value.write !== undefined && typeof value.write !== "boolean")
632
+ throw depthInvalidError(label, `write must be a boolean; received ${preview(value.write)}.`);
633
+ if (value.compare !== undefined && !DEPTH_COMPARE_FUNCTIONS.includes(value.compare))
634
+ throw depthInvalidError(label, `compare must be a GPUCompareFunction; received ${preview(value.compare)}.`);
635
+ if (value.bias !== undefined && !Number.isInteger(value.bias))
636
+ throw depthInvalidError(label, `bias must be an integer (WebGPU depthBias is i32); received ${preview(value.bias)}.`);
637
+ // WebGPU depthBias is a GPUDepthBias (i32); out-of-range integers wrap or fail in the native layer instead of biasing.
638
+ if (value.bias !== undefined && (value.bias < I32_MIN || value.bias > I32_MAX))
639
+ throw depthInvalidError(label, `bias must fit in the i32 range [${I32_MIN}, ${I32_MAX}] (WebGPU depthBias is i32); received ${preview(value.bias)}.`);
640
+ if (value.biasSlopeScale !== undefined && !Number.isFinite(value.biasSlopeScale))
641
+ throw depthInvalidError(label, `biasSlopeScale must be a finite number; received ${preview(value.biasSlopeScale)}.`);
642
+ if (value.biasClamp !== undefined && !Number.isFinite(value.biasClamp))
643
+ throw depthInvalidError(label, `biasClamp must be a finite number; received ${preview(value.biasClamp)}.`);
644
+ const bias = value.bias ?? 0;
645
+ const biasSlopeScale = value.biasSlopeScale ?? 0;
646
+ const biasClamp = value.biasClamp ?? 0;
647
+ // WebGPU makes nonzero depth bias a validation error outside triangle topologies.
648
+ if ((bias !== 0 || biasSlopeScale !== 0 || biasClamp !== 0) && !topology.startsWith("triangle"))
649
+ throw depthInvalidError(label, `bias, biasSlopeScale, and biasClamp must be 0 for "${topology}" topology.`);
650
+ // WebGPU compatibility mode requires depthBiasClamp to be 0.
651
+ if (biasClamp !== 0 && device.isCompatibilityMode)
652
+ throw depthInvalidError(label, `biasClamp must be 0 on a compatibility-mode device; received ${preview(value.biasClamp)}.`);
653
+ return {
654
+ depthWriteEnabled: value.write ?? true,
655
+ depthCompare: value.compare ?? "less-equal",
656
+ ...(bias !== 0 ? { depthBias: bias } : {}),
657
+ ...(biasSlopeScale !== 0 ? { depthBiasSlopeScale: biasSlopeScale } : {}),
658
+ ...(biasClamp !== 0 ? { depthBiasClamp: biasClamp } : {}),
659
+ };
660
+ }
661
+ function depthKeyFor(state) {
662
+ return `${state.depthWriteEnabled ? 1 : 0}~${state.depthCompare}~${state.depthBias ?? 0}~${state.depthBiasSlopeScale ?? 0}~${state.depthBiasClamp ?? 0}`;
663
+ }
664
+ const STENCIL_OPERATIONS = ["keep", "zero", "replace", "invert", "increment-clamp", "decrement-clamp", "increment-wrap", "decrement-wrap"];
665
+ function normalizeStencilOptions(label, opts) {
666
+ if (opts.stencil === undefined)
667
+ return {};
668
+ const value = opts.stencil;
669
+ if (typeof value !== "object" || value === null || Array.isArray(value))
670
+ throw stencilInvalidError(label, `received ${preview(value)}; expected { front?, back?, readMask?, writeMask?, ref? }.`);
671
+ const front = value.front === undefined ? undefined : normalizeStencilFace(label, "front", value.front);
672
+ const back = value.back === undefined ? undefined : normalizeStencilFace(label, "back", value.back);
673
+ validateStencilValue(label, "readMask", value.readMask);
674
+ validateStencilValue(label, "writeMask", value.writeMask);
675
+ validateStencilValue(label, "ref", value.ref);
676
+ const stencilState = {
677
+ ...(front ? { stencilFront: front } : {}),
678
+ // Omitted back mirrors the normalized front so both faces behave the same; with neither given, both keep the WebGPU defaults.
679
+ ...(back ?? front ? { stencilBack: back ?? { ...front } } : {}),
680
+ ...(value.readMask !== undefined ? { stencilReadMask: value.readMask } : {}),
681
+ ...(value.writeMask !== undefined ? { stencilWriteMask: value.writeMask } : {}),
682
+ };
683
+ const hasPipelineState = stencilState.stencilFront !== undefined || stencilState.stencilBack !== undefined || stencilState.stencilReadMask !== undefined || stencilState.stencilWriteMask !== undefined;
684
+ // An all-defaults object behaves exactly like an absent option; keep the pipeline key byte-identical so they share.
685
+ if (!hasPipelineState && value.ref === undefined)
686
+ return {};
687
+ return {
688
+ ...(hasPipelineState ? { stencilState, stencilKey: stencilKeyFor(stencilState) } : {}),
689
+ // The reference is encoder state (setStencilReference), not pipeline state; it stays out of the pipeline key.
690
+ ...(value.ref !== undefined ? { stencilRef: value.ref } : {}),
691
+ };
692
+ }
693
+ function normalizeStencilFace(label, field, value) {
694
+ if (typeof value !== "object" || value === null || Array.isArray(value))
695
+ throw stencilInvalidError(label, `${field} must be a { compare?, fail?, depthFail?, pass? } object; received ${preview(value)}.`);
696
+ if (value.compare !== undefined && !DEPTH_COMPARE_FUNCTIONS.includes(value.compare))
697
+ throw stencilInvalidError(label, `${field}.compare must be a GPUCompareFunction; received ${preview(value.compare)}.`);
698
+ for (const [name, op] of [["fail", value.fail], ["depthFail", value.depthFail], ["pass", value.pass]]) {
699
+ if (op !== undefined && !STENCIL_OPERATIONS.includes(op))
700
+ throw stencilInvalidError(label, `${field}.${name} must be a GPUStencilOperation; received ${preview(op)}.`);
701
+ }
702
+ return { compare: value.compare ?? "always", failOp: value.fail ?? "keep", depthFailOp: value.depthFail ?? "keep", passOp: value.pass ?? "keep" };
703
+ }
704
+ // WebGPU GPUStencilValue is [EnforceRange] unsigned long; masks, the reference, and clear values share the u32 range.
705
+ function validateStencilValue(label, field, value) {
706
+ if (value === undefined)
707
+ return;
708
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0 || value > 0xFFFFFFFF) {
709
+ throw stencilInvalidError(label, `${field} must be an integer in [0, 0xFFFFFFFF] (WebGPU GPUStencilValue is u32); received ${preview(value)}.`);
710
+ }
711
+ }
712
+ function stencilKeyFor(state) {
713
+ return `st~${stencilFaceKeyFor(state.stencilFront)}~${stencilFaceKeyFor(state.stencilBack)}~${state.stencilReadMask ?? 0xFFFFFFFF}~${state.stencilWriteMask ?? 0xFFFFFFFF}`;
714
+ }
715
+ function stencilFaceKeyFor(face) {
716
+ if (!face)
717
+ return "default";
718
+ return `${face.compare},${face.failOp},${face.depthFailOp},${face.passOp}`;
719
+ }
720
+ function multisampleStateFor(signature, state) {
721
+ // Fields stay omitted when unset so the descriptor is byte-identical to the plain { count } emitted without the option.
722
+ return { count: signature.sampleCount ?? 1, ...(state.multisampleState ?? {}) };
723
+ }
724
+ function normalizeMultisampleOptions(label, opts) {
725
+ if (opts.multisample === undefined)
726
+ return {};
727
+ const value = opts.multisample;
728
+ if (typeof value !== "object" || value === null || Array.isArray(value))
729
+ throw multisampleInvalidError(label, `received ${preview(value)}; expected { alphaToCoverage?, mask? }.`);
730
+ if (value.alphaToCoverage !== undefined && typeof value.alphaToCoverage !== "boolean")
731
+ throw multisampleInvalidError(label, `alphaToCoverage must be a boolean; received ${preview(value.alphaToCoverage)}.`);
732
+ // WebGPU GPUSampleMask is [EnforceRange] unsigned long. Bits above the target's sampleCount are legal and ignored.
733
+ if (value.mask !== undefined && (typeof value.mask !== "number" || !Number.isInteger(value.mask) || value.mask < 0 || value.mask > 0xFFFFFFFF)) {
734
+ throw multisampleInvalidError(label, `mask must be an integer in [0, 0xFFFFFFFF] (WebGPU GPUSampleMask is u32); received ${preview(value.mask)}.`);
735
+ }
736
+ const multisampleState = {
737
+ ...(value.alphaToCoverage !== undefined ? { alphaToCoverageEnabled: value.alphaToCoverage } : {}),
738
+ ...(value.mask !== undefined ? { mask: value.mask } : {}),
739
+ };
740
+ // An all-defaults object behaves exactly like an absent option; keep the pipeline key byte-identical so they share.
741
+ if (multisampleState.alphaToCoverageEnabled === undefined && multisampleState.mask === undefined)
742
+ return {};
743
+ return { multisampleState, multisampleKey: multisampleKeyFor(multisampleState) };
744
+ }
745
+ function multisampleKeyFor(state) {
746
+ return `ms~${state.alphaToCoverageEnabled ? 1 : 0}~${state.mask ?? 0xFFFFFFFF}`;
747
+ }
748
+ function normalizeWriteMask(label, value) {
749
+ if (!Array.isArray(value))
750
+ throw writeMaskInvalidError(label, preview(value));
751
+ let mask = 0;
752
+ for (const channel of value) {
753
+ if (channel === "r")
754
+ mask |= 1;
755
+ else if (channel === "g")
756
+ mask |= 2;
757
+ else if (channel === "b")
758
+ mask |= 4;
759
+ else if (channel === "a")
760
+ mask |= 8;
761
+ else
762
+ throw writeMaskInvalidError(label, preview(channel));
763
+ }
764
+ return mask;
765
+ }
766
+ function fragmentKeyFor(blend, mask) {
767
+ return `${blendKeyFor(blend)};${mask ?? 15}`;
768
+ }
769
+ function blendKeyFor(blend) {
770
+ if (!blend)
771
+ return "none;none";
772
+ const c = blend.color;
773
+ const a = blend.alpha;
774
+ return `${c.srcFactor},${c.dstFactor},${c.operation};${a.srcFactor},${a.dstFactor},${a.operation}`;
775
+ }
776
+ // "inherit" markers keep per-entry keys distinct from explicit state so an entry inheriting the top-level fallback never collides with one that pins it.
777
+ function colorStateKeyFor(state) {
778
+ if (!state)
779
+ return "inherit";
780
+ return `${state.blendState ? blendKeyFor(state.blendState) : "inherit"};${state.writeMask ?? "inherit"}`;
781
+ }
782
+ function preview(value) {
783
+ if (typeof value === "string")
784
+ return `"${value}"`;
785
+ try {
786
+ return JSON.stringify(value) ?? String(value);
787
+ }
788
+ catch {
789
+ return String(value);
790
+ }
791
+ }
792
+ export function drawReflection(draw) { return drawState(draw).reflection; }
793
+ export function drawBindingState(draw, name) { return drawState(draw).setCore.bindingState(name); }
794
+ export function registerDrawBundle(draw, bundle) { drawState(draw).recordedIn.add(bundle); }
795
+ /** Render bundle encoders cannot set the pass blend constant; bundle uses this to reject such draws at recording. */
796
+ export function drawUsesBlendConstant(draw) { return drawState(draw).blendConstant !== undefined; }
797
+ /** Render bundle encoders cannot set the pass stencil reference; bundle uses this to reject such draws at recording. */
798
+ export function drawUsesStencilReference(draw) { return drawState(draw).stencilRef !== undefined; }
799
+ /**
800
+ * FramePass uses this to pre-validate draws against read-only depth passes. Mirrors the WebGPU
801
+ * [[writesDepth]] pipeline slot: "If depthStencil.depthWriteEnabled is provided: Set
802
+ * pipeline.[[writesDepth]] to depthStencil.depthWriteEnabled." — aigpu always provides it on depth
803
+ * targets, defaulting to true.
804
+ */
805
+ export function drawWritesDepth(draw) {
806
+ return (drawState(draw).depthState ?? DEFAULT_DEPTH_STATE).depthWriteEnabled;
807
+ }
808
+ /**
809
+ * Stencil ops that make this draw write stencil, e.g. `front.pass: "replace"`; empty when the draw
810
+ * cannot write stencil. FramePass uses this to pre-validate draws against read-only stencil passes.
811
+ * Mirrors the WebGPU [[writesStencil]] computation: only when "depthStencil.stencilWriteMask is not 0",
812
+ * a face op is "not \"keep\"", and the face is not culled ("If cullMode is not \"front\", and any of
813
+ * stencilFront.passOp, stencilFront.depthFailOp, or stencilFront.failOp is not \"keep\"" — and the
814
+ * mirrored rule for stencilBack with "back") does the pipeline write stencil.
815
+ */
816
+ export function drawStencilWritingOps(draw) {
817
+ const state = drawState(draw);
818
+ const stencil = state.stencilState;
819
+ if (!stencil || stencil.stencilWriteMask === 0)
820
+ return [];
821
+ const cullMode = state.cullMode ?? "none";
822
+ const ops = [];
823
+ const collect = (faceName, face) => {
824
+ if (!face)
825
+ return;
826
+ for (const [name, op] of [["fail", face.failOp], ["depthFail", face.depthFailOp], ["pass", face.passOp]]) {
827
+ if (op !== undefined && op !== "keep")
828
+ ops.push(`${faceName}.${name}: "${op}"`);
829
+ }
830
+ };
831
+ if (cullMode !== "front")
832
+ collect("front", stencil.stencilFront);
833
+ if (cullMode !== "back")
834
+ collect("back", stencil.stencilBack);
835
+ return ops;
836
+ }
837
+ export function encodeDraw(draw, pass, target, opts = {}, claimValidation) {
838
+ draw.encode(pass, target, opts, claimValidation);
839
+ }
840
+ function drawState(draw) {
841
+ const state = drawStates.get(draw);
842
+ if (!state)
843
+ throw new TypeError("Invalid Draw instance");
844
+ return state;
845
+ }
846
+ function reportDrawValidationError(state, label, group, cause) {
847
+ const delivery = (async () => {
848
+ await submittedWorkDone(state.device);
849
+ assertDeviceUsable(state.device, `${label}.validation`);
850
+ const error = claimedGroupNativeValidationError(label, group, cause);
851
+ if (state.errorSink)
852
+ await state.errorSink(error);
853
+ else
854
+ console.error(error);
855
+ })();
856
+ state.trackSettled?.(delivery);
857
+ return delivery;
858
+ }
859
+ export function createBundleRegistry() {
860
+ const set = new Set();
861
+ return {
862
+ add(bundle) { set.add(bundle); },
863
+ delete(bundle) { set.delete(bundle); },
864
+ list() { return [...set]; },
865
+ markStale(event) { for (const bundle of set)
866
+ bundle.markStale(event); },
867
+ };
868
+ }
869
+ function offsetsForGroup(offsets, group, fallback) {
870
+ if (!offsets)
871
+ return fallback;
872
+ if (Array.isArray(offsets))
873
+ return offsets;
874
+ const byGroup = offsets;
875
+ return byGroup[group] ?? fallback;
876
+ }
877
+ function dynamicEntries(draw, group) {
878
+ const state = drawState(draw);
879
+ return bindGroupLayoutEntriesForGroup(state.reflection.bindings, group, state.visibility).map(dynamicEntry);
880
+ }
881
+ function dynamicEntry(entry) {
882
+ if (!entry.buffer)
883
+ return entry;
884
+ return { ...entry, buffer: { ...entry.buffer, hasDynamicOffset: true } };
885
+ }
886
+ function assertSurfaceTargetInFrame(target, where) {
887
+ if (isSurface(target) && !isFrameActive())
888
+ throw surfaceNotInFrameError(where);
889
+ }
890
+ //# sourceMappingURL=draw.js.map