@motion-core/motion-gpu 0.4.1 → 0.5.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 (228) hide show
  1. package/README.md +99 -0
  2. package/dist/advanced.d.ts +1 -0
  3. package/dist/advanced.d.ts.map +1 -0
  4. package/dist/advanced.js +14 -6
  5. package/dist/core/advanced.d.ts +1 -0
  6. package/dist/core/advanced.d.ts.map +1 -0
  7. package/dist/core/advanced.js +14 -5
  8. package/dist/core/compute-shader.d.ts +87 -0
  9. package/dist/core/compute-shader.d.ts.map +1 -0
  10. package/dist/core/compute-shader.js +205 -0
  11. package/dist/core/compute-shader.js.map +1 -0
  12. package/dist/core/current-value.d.ts +1 -0
  13. package/dist/core/current-value.d.ts.map +1 -0
  14. package/dist/core/current-value.js +35 -34
  15. package/dist/core/current-value.js.map +1 -0
  16. package/dist/core/error-diagnostics.d.ts +1 -0
  17. package/dist/core/error-diagnostics.d.ts.map +1 -0
  18. package/dist/core/error-diagnostics.js +70 -137
  19. package/dist/core/error-diagnostics.js.map +1 -0
  20. package/dist/core/error-report.d.ts +2 -1
  21. package/dist/core/error-report.d.ts.map +1 -0
  22. package/dist/core/error-report.js +247 -233
  23. package/dist/core/error-report.js.map +1 -0
  24. package/dist/core/frame-registry.d.ts +1 -0
  25. package/dist/core/frame-registry.d.ts.map +1 -0
  26. package/dist/core/frame-registry.js +546 -662
  27. package/dist/core/frame-registry.js.map +1 -0
  28. package/dist/core/index.d.ts +6 -2
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +13 -12
  31. package/dist/core/material-preprocess.d.ts +1 -0
  32. package/dist/core/material-preprocess.d.ts.map +1 -0
  33. package/dist/core/material-preprocess.js +131 -152
  34. package/dist/core/material-preprocess.js.map +1 -0
  35. package/dist/core/material.d.ts +23 -6
  36. package/dist/core/material.d.ts.map +1 -0
  37. package/dist/core/material.js +290 -317
  38. package/dist/core/material.js.map +1 -0
  39. package/dist/core/recompile-policy.d.ts +1 -0
  40. package/dist/core/recompile-policy.d.ts.map +1 -0
  41. package/dist/core/recompile-policy.js +18 -13
  42. package/dist/core/recompile-policy.js.map +1 -0
  43. package/dist/core/render-graph.d.ts +8 -3
  44. package/dist/core/render-graph.d.ts.map +1 -0
  45. package/dist/core/render-graph.js +77 -68
  46. package/dist/core/render-graph.js.map +1 -0
  47. package/dist/core/render-targets.d.ts +1 -0
  48. package/dist/core/render-targets.d.ts.map +1 -0
  49. package/dist/core/render-targets.js +52 -53
  50. package/dist/core/render-targets.js.map +1 -0
  51. package/dist/core/renderer.d.ts +1 -0
  52. package/dist/core/renderer.d.ts.map +1 -0
  53. package/dist/core/renderer.js +1337 -1081
  54. package/dist/core/renderer.js.map +1 -0
  55. package/dist/core/runtime-loop.d.ts +3 -2
  56. package/dist/core/runtime-loop.d.ts.map +1 -0
  57. package/dist/core/runtime-loop.js +353 -362
  58. package/dist/core/runtime-loop.js.map +1 -0
  59. package/dist/core/scheduler-helpers.d.ts +1 -0
  60. package/dist/core/scheduler-helpers.d.ts.map +1 -0
  61. package/dist/core/scheduler-helpers.js +52 -51
  62. package/dist/core/scheduler-helpers.js.map +1 -0
  63. package/dist/core/shader.d.ts +10 -1
  64. package/dist/core/shader.d.ts.map +1 -0
  65. package/dist/core/shader.js +109 -115
  66. package/dist/core/shader.js.map +1 -0
  67. package/dist/core/storage-buffers.d.ts +37 -0
  68. package/dist/core/storage-buffers.d.ts.map +1 -0
  69. package/dist/core/storage-buffers.js +95 -0
  70. package/dist/core/storage-buffers.js.map +1 -0
  71. package/dist/core/texture-loader.d.ts +1 -0
  72. package/dist/core/texture-loader.d.ts.map +1 -0
  73. package/dist/core/texture-loader.js +209 -273
  74. package/dist/core/texture-loader.js.map +1 -0
  75. package/dist/core/textures.d.ts +13 -0
  76. package/dist/core/textures.d.ts.map +1 -0
  77. package/dist/core/textures.js +111 -116
  78. package/dist/core/textures.js.map +1 -0
  79. package/dist/core/types.d.ts +147 -4
  80. package/dist/core/types.d.ts.map +1 -0
  81. package/dist/core/types.js +0 -4
  82. package/dist/core/uniforms.d.ts +1 -0
  83. package/dist/core/uniforms.d.ts.map +1 -0
  84. package/dist/core/uniforms.js +170 -191
  85. package/dist/core/uniforms.js.map +1 -0
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +13 -6
  89. package/dist/passes/BlitPass.d.ts +1 -0
  90. package/dist/passes/BlitPass.d.ts.map +1 -0
  91. package/dist/passes/BlitPass.js +23 -18
  92. package/dist/passes/BlitPass.js.map +1 -0
  93. package/dist/passes/ComputePass.d.ts +83 -0
  94. package/dist/passes/ComputePass.d.ts.map +1 -0
  95. package/dist/passes/ComputePass.js +92 -0
  96. package/dist/passes/ComputePass.js.map +1 -0
  97. package/dist/passes/CopyPass.d.ts +1 -0
  98. package/dist/passes/CopyPass.d.ts.map +1 -0
  99. package/dist/passes/CopyPass.js +58 -52
  100. package/dist/passes/CopyPass.js.map +1 -0
  101. package/dist/passes/FullscreenPass.d.ts +1 -0
  102. package/dist/passes/FullscreenPass.d.ts.map +1 -0
  103. package/dist/passes/FullscreenPass.js +127 -130
  104. package/dist/passes/FullscreenPass.js.map +1 -0
  105. package/dist/passes/PingPongComputePass.d.ts +104 -0
  106. package/dist/passes/PingPongComputePass.d.ts.map +1 -0
  107. package/dist/passes/PingPongComputePass.js +132 -0
  108. package/dist/passes/PingPongComputePass.js.map +1 -0
  109. package/dist/passes/ShaderPass.d.ts +1 -0
  110. package/dist/passes/ShaderPass.d.ts.map +1 -0
  111. package/dist/passes/ShaderPass.js +41 -37
  112. package/dist/passes/ShaderPass.js.map +1 -0
  113. package/dist/passes/index.d.ts +3 -0
  114. package/dist/passes/index.d.ts.map +1 -0
  115. package/dist/passes/index.js +6 -3
  116. package/dist/react/FragCanvas.d.ts +3 -2
  117. package/dist/react/FragCanvas.d.ts.map +1 -0
  118. package/dist/react/FragCanvas.js +234 -211
  119. package/dist/react/FragCanvas.js.map +1 -0
  120. package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
  121. package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
  122. package/dist/react/MotionGPUErrorOverlay.js +200 -14
  123. package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
  124. package/dist/react/Portal.d.ts +1 -0
  125. package/dist/react/Portal.d.ts.map +1 -0
  126. package/dist/react/Portal.js +18 -21
  127. package/dist/react/Portal.js.map +1 -0
  128. package/dist/react/advanced.d.ts +1 -0
  129. package/dist/react/advanced.d.ts.map +1 -0
  130. package/dist/react/advanced.js +14 -6
  131. package/dist/react/frame-context.d.ts +1 -0
  132. package/dist/react/frame-context.d.ts.map +1 -0
  133. package/dist/react/frame-context.js +88 -94
  134. package/dist/react/frame-context.js.map +1 -0
  135. package/dist/react/index.d.ts +6 -2
  136. package/dist/react/index.d.ts.map +1 -0
  137. package/dist/react/index.js +12 -9
  138. package/dist/react/motiongpu-context.d.ts +1 -0
  139. package/dist/react/motiongpu-context.d.ts.map +1 -0
  140. package/dist/react/motiongpu-context.js +18 -15
  141. package/dist/react/motiongpu-context.js.map +1 -0
  142. package/dist/react/use-motiongpu-user-context.d.ts +1 -0
  143. package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
  144. package/dist/react/use-motiongpu-user-context.js +83 -82
  145. package/dist/react/use-motiongpu-user-context.js.map +1 -0
  146. package/dist/react/use-texture.d.ts +1 -0
  147. package/dist/react/use-texture.d.ts.map +1 -0
  148. package/dist/react/use-texture.js +132 -152
  149. package/dist/react/use-texture.js.map +1 -0
  150. package/dist/svelte/FragCanvas.svelte +2 -2
  151. package/dist/svelte/FragCanvas.svelte.d.ts +3 -2
  152. package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
  153. package/dist/svelte/MotionGPUErrorOverlay.svelte +137 -7
  154. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
  155. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
  156. package/dist/svelte/Portal.svelte.d.ts +1 -0
  157. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  158. package/dist/svelte/advanced.d.ts +1 -0
  159. package/dist/svelte/advanced.d.ts.map +1 -0
  160. package/dist/svelte/advanced.js +13 -6
  161. package/dist/svelte/frame-context.d.ts +1 -0
  162. package/dist/svelte/frame-context.d.ts.map +1 -0
  163. package/dist/svelte/frame-context.js +27 -27
  164. package/dist/svelte/frame-context.js.map +1 -0
  165. package/dist/svelte/index.d.ts +6 -2
  166. package/dist/svelte/index.d.ts.map +1 -0
  167. package/dist/svelte/index.js +12 -9
  168. package/dist/svelte/motiongpu-context.d.ts +1 -0
  169. package/dist/svelte/motiongpu-context.d.ts.map +1 -0
  170. package/dist/svelte/motiongpu-context.js +24 -21
  171. package/dist/svelte/motiongpu-context.js.map +1 -0
  172. package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
  173. package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
  174. package/dist/svelte/use-motiongpu-user-context.js +69 -70
  175. package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
  176. package/dist/svelte/use-texture.d.ts +1 -0
  177. package/dist/svelte/use-texture.d.ts.map +1 -0
  178. package/dist/svelte/use-texture.js +125 -147
  179. package/dist/svelte/use-texture.js.map +1 -0
  180. package/package.json +12 -7
  181. package/src/lib/advanced.ts +6 -0
  182. package/src/lib/core/advanced.ts +12 -0
  183. package/src/lib/core/compute-shader.ts +326 -0
  184. package/src/lib/core/current-value.ts +64 -0
  185. package/src/lib/core/error-diagnostics.ts +236 -0
  186. package/src/lib/core/error-report.ts +535 -0
  187. package/src/lib/core/frame-registry.ts +1190 -0
  188. package/src/lib/core/index.ts +94 -0
  189. package/src/lib/core/material-preprocess.ts +295 -0
  190. package/src/lib/core/material.ts +748 -0
  191. package/src/lib/core/recompile-policy.ts +31 -0
  192. package/src/lib/core/render-graph.ts +173 -0
  193. package/src/lib/core/render-targets.ts +107 -0
  194. package/src/lib/core/renderer.ts +2161 -0
  195. package/src/lib/core/runtime-loop.ts +537 -0
  196. package/src/lib/core/scheduler-helpers.ts +136 -0
  197. package/src/lib/core/shader.ts +301 -0
  198. package/src/lib/core/storage-buffers.ts +142 -0
  199. package/src/lib/core/texture-loader.ts +482 -0
  200. package/src/lib/core/textures.ts +257 -0
  201. package/src/lib/core/types.ts +743 -0
  202. package/src/lib/core/uniforms.ts +282 -0
  203. package/src/lib/index.ts +6 -0
  204. package/src/lib/passes/BlitPass.ts +54 -0
  205. package/src/lib/passes/ComputePass.ts +136 -0
  206. package/src/lib/passes/CopyPass.ts +80 -0
  207. package/src/lib/passes/FullscreenPass.ts +173 -0
  208. package/src/lib/passes/PingPongComputePass.ts +180 -0
  209. package/src/lib/passes/ShaderPass.ts +89 -0
  210. package/src/lib/passes/index.ts +9 -0
  211. package/src/lib/react/FragCanvas.tsx +345 -0
  212. package/src/lib/react/MotionGPUErrorOverlay.tsx +524 -0
  213. package/src/lib/react/Portal.tsx +34 -0
  214. package/src/lib/react/advanced.ts +36 -0
  215. package/src/lib/react/frame-context.ts +169 -0
  216. package/src/lib/react/index.ts +68 -0
  217. package/src/lib/react/motiongpu-context.ts +88 -0
  218. package/src/lib/react/use-motiongpu-user-context.ts +186 -0
  219. package/src/lib/react/use-texture.ts +233 -0
  220. package/src/lib/svelte/FragCanvas.svelte +249 -0
  221. package/src/lib/svelte/MotionGPUErrorOverlay.svelte +512 -0
  222. package/src/lib/svelte/Portal.svelte +31 -0
  223. package/src/lib/svelte/advanced.ts +32 -0
  224. package/src/lib/svelte/frame-context.ts +87 -0
  225. package/src/lib/svelte/index.ts +68 -0
  226. package/src/lib/svelte/motiongpu-context.ts +97 -0
  227. package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
  228. package/src/lib/svelte/use-texture.ts +232 -0
@@ -0,0 +1,92 @@
1
+ import { assertComputeContract, extractWorkgroupSize } from "../core/compute-shader.js";
2
+ //#region src/lib/passes/ComputePass.ts
3
+ /**
4
+ * Compute pass class used within the render graph.
5
+ *
6
+ * Validates compute shader contract, parses workgroup size,
7
+ * and resolves dispatch dimensions. Does **not** manage GPU resources
8
+ * (that responsibility belongs to the renderer).
9
+ */
10
+ var ComputePass = class {
11
+ /**
12
+ * Enables/disables this pass without removing it from graph.
13
+ */
14
+ enabled;
15
+ /**
16
+ * Discriminant flag for render graph to identify compute passes.
17
+ */
18
+ isCompute = true;
19
+ compute;
20
+ workgroupSize;
21
+ dispatch;
22
+ constructor(options) {
23
+ assertComputeContract(options.compute);
24
+ const workgroupSize = extractWorkgroupSize(options.compute);
25
+ this.compute = options.compute;
26
+ this.workgroupSize = workgroupSize;
27
+ this.dispatch = options.dispatch ?? "auto";
28
+ this.enabled = options.enabled ?? true;
29
+ }
30
+ /**
31
+ * Replaces current compute shader and updates workgroup size.
32
+ *
33
+ * @param compute - New compute shader WGSL source.
34
+ * @throws {Error} When shader does not match the compute contract.
35
+ */
36
+ setCompute(compute) {
37
+ assertComputeContract(compute);
38
+ const workgroupSize = extractWorkgroupSize(compute);
39
+ this.compute = compute;
40
+ this.workgroupSize = workgroupSize;
41
+ }
42
+ /**
43
+ * Updates dispatch strategy.
44
+ */
45
+ setDispatch(dispatch) {
46
+ this.dispatch = dispatch ?? "auto";
47
+ }
48
+ /**
49
+ * Returns current compute shader source.
50
+ */
51
+ getCompute() {
52
+ return this.compute;
53
+ }
54
+ /**
55
+ * Returns parsed workgroup size from current compute shader.
56
+ */
57
+ getWorkgroupSize() {
58
+ return [...this.workgroupSize];
59
+ }
60
+ /**
61
+ * Resolves dispatch workgroup counts for current frame.
62
+ *
63
+ * @param ctx - Dispatch context with canvas dimensions and timing.
64
+ * @returns Tuple [x, y, z] workgroup counts.
65
+ */
66
+ resolveDispatch(ctx) {
67
+ if (this.dispatch === "auto") return [
68
+ Math.ceil(ctx.width / this.workgroupSize[0]),
69
+ Math.ceil(ctx.height / this.workgroupSize[1]),
70
+ Math.ceil(1 / this.workgroupSize[2])
71
+ ];
72
+ if (typeof this.dispatch === "function") return this.dispatch(ctx);
73
+ if (Array.isArray(this.dispatch)) return [
74
+ this.dispatch[0],
75
+ this.dispatch[1] ?? 1,
76
+ this.dispatch[2] ?? 1
77
+ ];
78
+ return [
79
+ 1,
80
+ 1,
81
+ 1
82
+ ];
83
+ }
84
+ /**
85
+ * Releases resources (no-op since GPU resource lifecycle is renderer-managed).
86
+ */
87
+ dispose() {}
88
+ };
89
+ //#endregion
90
+ export { ComputePass };
91
+
92
+ //# sourceMappingURL=ComputePass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComputePass.js","names":[],"sources":["../../src/lib/passes/ComputePass.ts"],"sourcesContent":["import { assertComputeContract, extractWorkgroupSize } from '../core/compute-shader.js';\n\n/**\n * Dispatch context provided to dynamic dispatch callbacks.\n */\nexport interface ComputeDispatchContext {\n\twidth: number;\n\theight: number;\n\ttime: number;\n\tdelta: number;\n\tworkgroupSize: [number, number, number];\n}\n\n/**\n * Options for constructing a `ComputePass`.\n */\nexport interface ComputePassOptions {\n\t/**\n\t * Compute shader WGSL source code.\n\t * Must declare `@compute @workgroup_size(...) fn compute(@builtin(global_invocation_id) ...)`.\n\t */\n\tcompute: string;\n\t/**\n\t * Dispatch workgroup counts.\n\t * - Static tuple: `[x]`, `[x, y]`, or `[x, y, z]`\n\t * - `'auto'`: derived from canvas size / workgroup size\n\t * - Function: dynamic dispatch based on frame context\n\t */\n\tdispatch?:\n\t\t| [number, number?, number?]\n\t\t| 'auto'\n\t\t| ((ctx: ComputeDispatchContext) => [number, number, number]);\n\t/**\n\t * Enables/disables this compute pass.\n\t */\n\tenabled?: boolean;\n}\n\n/**\n * Compute pass class used within the render graph.\n *\n * Validates compute shader contract, parses workgroup size,\n * and resolves dispatch dimensions. Does **not** manage GPU resources\n * (that responsibility belongs to the renderer).\n */\nexport class ComputePass {\n\t/**\n\t * Enables/disables this pass without removing it from graph.\n\t */\n\tenabled: boolean;\n\n\t/**\n\t * Discriminant flag for render graph to identify compute passes.\n\t */\n\treadonly isCompute = true as const;\n\n\tprivate compute: string;\n\tprivate workgroupSize: [number, number, number];\n\tprivate dispatch: ComputePassOptions['dispatch'];\n\n\tconstructor(options: ComputePassOptions) {\n\t\tassertComputeContract(options.compute);\n\t\tconst workgroupSize = extractWorkgroupSize(options.compute);\n\t\tthis.compute = options.compute;\n\t\tthis.workgroupSize = workgroupSize;\n\t\tthis.dispatch = options.dispatch ?? 'auto';\n\t\tthis.enabled = options.enabled ?? true;\n\t}\n\n\t/**\n\t * Replaces current compute shader and updates workgroup size.\n\t *\n\t * @param compute - New compute shader WGSL source.\n\t * @throws {Error} When shader does not match the compute contract.\n\t */\n\tsetCompute(compute: string): void {\n\t\tassertComputeContract(compute);\n\t\tconst workgroupSize = extractWorkgroupSize(compute);\n\t\tthis.compute = compute;\n\t\tthis.workgroupSize = workgroupSize;\n\t}\n\n\t/**\n\t * Updates dispatch strategy.\n\t */\n\tsetDispatch(dispatch: ComputePassOptions['dispatch']): void {\n\t\tthis.dispatch = dispatch ?? 'auto';\n\t}\n\n\t/**\n\t * Returns current compute shader source.\n\t */\n\tgetCompute(): string {\n\t\treturn this.compute;\n\t}\n\n\t/**\n\t * Returns parsed workgroup size from current compute shader.\n\t */\n\tgetWorkgroupSize(): [number, number, number] {\n\t\treturn [...this.workgroupSize];\n\t}\n\n\t/**\n\t * Resolves dispatch workgroup counts for current frame.\n\t *\n\t * @param ctx - Dispatch context with canvas dimensions and timing.\n\t * @returns Tuple [x, y, z] workgroup counts.\n\t */\n\tresolveDispatch(ctx: ComputeDispatchContext): [number, number, number] {\n\t\tif (this.dispatch === 'auto') {\n\t\t\treturn [\n\t\t\t\tMath.ceil(ctx.width / this.workgroupSize[0]),\n\t\t\t\tMath.ceil(ctx.height / this.workgroupSize[1]),\n\t\t\t\tMath.ceil(1 / this.workgroupSize[2])\n\t\t\t];\n\t\t}\n\n\t\tif (typeof this.dispatch === 'function') {\n\t\t\treturn this.dispatch(ctx);\n\t\t}\n\n\t\tif (Array.isArray(this.dispatch)) {\n\t\t\treturn [this.dispatch[0], this.dispatch[1] ?? 1, this.dispatch[2] ?? 1];\n\t\t}\n\n\t\treturn [1, 1, 1];\n\t}\n\n\t/**\n\t * Releases resources (no-op since GPU resource lifecycle is renderer-managed).\n\t */\n\tdispose(): void {\n\t\t// No-op — GPU resources are managed by the renderer.\n\t}\n}\n"],"mappings":";;;;;;;;;AA6CA,IAAa,cAAb,MAAyB;;;;CAIxB;;;;CAKA,YAAqB;CAErB;CACA;CACA;CAEA,YAAY,SAA6B;AACxC,wBAAsB,QAAQ,QAAQ;EACtC,MAAM,gBAAgB,qBAAqB,QAAQ,QAAQ;AAC3D,OAAK,UAAU,QAAQ;AACvB,OAAK,gBAAgB;AACrB,OAAK,WAAW,QAAQ,YAAY;AACpC,OAAK,UAAU,QAAQ,WAAW;;;;;;;;CASnC,WAAW,SAAuB;AACjC,wBAAsB,QAAQ;EAC9B,MAAM,gBAAgB,qBAAqB,QAAQ;AACnD,OAAK,UAAU;AACf,OAAK,gBAAgB;;;;;CAMtB,YAAY,UAAgD;AAC3D,OAAK,WAAW,YAAY;;;;;CAM7B,aAAqB;AACpB,SAAO,KAAK;;;;;CAMb,mBAA6C;AAC5C,SAAO,CAAC,GAAG,KAAK,cAAc;;;;;;;;CAS/B,gBAAgB,KAAuD;AACtE,MAAI,KAAK,aAAa,OACrB,QAAO;GACN,KAAK,KAAK,IAAI,QAAQ,KAAK,cAAc,GAAG;GAC5C,KAAK,KAAK,IAAI,SAAS,KAAK,cAAc,GAAG;GAC7C,KAAK,KAAK,IAAI,KAAK,cAAc,GAAG;GACpC;AAGF,MAAI,OAAO,KAAK,aAAa,WAC5B,QAAO,KAAK,SAAS,IAAI;AAG1B,MAAI,MAAM,QAAQ,KAAK,SAAS,CAC/B,QAAO;GAAC,KAAK,SAAS;GAAI,KAAK,SAAS,MAAM;GAAG,KAAK,SAAS,MAAM;GAAE;AAGxE,SAAO;GAAC;GAAG;GAAG;GAAE;;;;;CAMjB,UAAgB"}
@@ -24,3 +24,4 @@ export declare class CopyPass implements RenderPass {
24
24
  render(context: RenderPassContext): void;
25
25
  dispose(): void;
26
26
  }
27
+ //# sourceMappingURL=CopyPass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopyPass.d.ts","sourceRoot":"","sources":["../../src/lib/passes/CopyPass.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EACX,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE,aAAa,CAAC;CACvB;AAED;;GAEG;AACH,qBAAa,QAAS,YAAW,UAAU;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAW;gBAE5B,OAAO,GAAE,eAAoB;IAiBzC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI5C,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAyBxC,OAAO,IAAI,IAAI;CAGf"}
@@ -1,53 +1,59 @@
1
- import { BlitPass } from './BlitPass.js';
1
+ import { BlitPass } from "./BlitPass.js";
2
+ //#region src/lib/passes/CopyPass.ts
2
3
  /**
3
- * Texture copy pass with fullscreen-blit fallback.
4
- */
5
- export class CopyPass {
6
- enabled;
7
- needsSwap;
8
- input;
9
- output;
10
- clear;
11
- clearColor;
12
- preserve;
13
- fallbackBlit;
14
- constructor(options = {}) {
15
- this.enabled = options.enabled ?? true;
16
- this.needsSwap = options.needsSwap ?? true;
17
- this.input = options.input ?? 'source';
18
- this.output = options.output ?? (this.needsSwap ? 'target' : 'source');
19
- this.clear = options.clear ?? false;
20
- this.clearColor = options.clearColor ?? [0, 0, 0, 1];
21
- this.preserve = options.preserve ?? true;
22
- this.fallbackBlit = new BlitPass({
23
- enabled: true,
24
- needsSwap: false,
25
- input: this.input,
26
- output: this.output,
27
- ...(options.filter !== undefined ? { filter: options.filter } : {})
28
- });
29
- }
30
- setSize(width, height) {
31
- this.fallbackBlit.setSize(width, height);
32
- }
33
- render(context) {
34
- const source = context.input;
35
- const target = context.output;
36
- const canDirectCopy = context.clear === false &&
37
- context.preserve === true &&
38
- source.texture !== target.texture &&
39
- source.texture !== context.canvas.texture &&
40
- target.texture !== context.canvas.texture &&
41
- source.width === target.width &&
42
- source.height === target.height &&
43
- source.format === target.format;
44
- if (canDirectCopy) {
45
- context.commandEncoder.copyTextureToTexture({ texture: source.texture }, { texture: target.texture }, { width: source.width, height: source.height, depthOrArrayLayers: 1 });
46
- return;
47
- }
48
- this.fallbackBlit.render(context);
49
- }
50
- dispose() {
51
- this.fallbackBlit.dispose();
52
- }
53
- }
4
+ * Texture copy pass with fullscreen-blit fallback.
5
+ */
6
+ var CopyPass = class {
7
+ enabled;
8
+ needsSwap;
9
+ input;
10
+ output;
11
+ clear;
12
+ clearColor;
13
+ preserve;
14
+ fallbackBlit;
15
+ constructor(options = {}) {
16
+ this.enabled = options.enabled ?? true;
17
+ this.needsSwap = options.needsSwap ?? true;
18
+ this.input = options.input ?? "source";
19
+ this.output = options.output ?? (this.needsSwap ? "target" : "source");
20
+ this.clear = options.clear ?? false;
21
+ this.clearColor = options.clearColor ?? [
22
+ 0,
23
+ 0,
24
+ 0,
25
+ 1
26
+ ];
27
+ this.preserve = options.preserve ?? true;
28
+ this.fallbackBlit = new BlitPass({
29
+ enabled: true,
30
+ needsSwap: false,
31
+ input: this.input,
32
+ output: this.output,
33
+ ...options.filter !== void 0 ? { filter: options.filter } : {}
34
+ });
35
+ }
36
+ setSize(width, height) {
37
+ this.fallbackBlit.setSize(width, height);
38
+ }
39
+ render(context) {
40
+ const source = context.input;
41
+ const target = context.output;
42
+ if (context.clear === false && context.preserve === true && source.texture !== target.texture && source.texture !== context.canvas.texture && target.texture !== context.canvas.texture && source.width === target.width && source.height === target.height && source.format === target.format) {
43
+ context.commandEncoder.copyTextureToTexture({ texture: source.texture }, { texture: target.texture }, {
44
+ width: source.width,
45
+ height: source.height,
46
+ depthOrArrayLayers: 1
47
+ });
48
+ return;
49
+ }
50
+ this.fallbackBlit.render(context);
51
+ }
52
+ dispose() {
53
+ this.fallbackBlit.dispose();
54
+ }
55
+ };
56
+ //#endregion
57
+ export { CopyPass };
58
+
59
+ //# sourceMappingURL=CopyPass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopyPass.js","names":[],"sources":["../../src/lib/passes/CopyPass.ts"],"sourcesContent":["import type {\n\tRenderPass,\n\tRenderPassContext,\n\tRenderPassFlags,\n\tRenderPassInputSlot,\n\tRenderPassOutputSlot\n} from '../core/types.js';\nimport { BlitPass } from './BlitPass.js';\n\nexport interface CopyPassOptions extends RenderPassFlags {\n\tenabled?: boolean;\n\tneedsSwap?: boolean;\n\tinput?: RenderPassInputSlot;\n\toutput?: RenderPassOutputSlot;\n\tfilter?: GPUFilterMode;\n}\n\n/**\n * Texture copy pass with fullscreen-blit fallback.\n */\nexport class CopyPass implements RenderPass {\n\tenabled: boolean;\n\tneedsSwap: boolean;\n\tinput: RenderPassInputSlot;\n\toutput: RenderPassOutputSlot;\n\tclear: boolean;\n\tclearColor: [number, number, number, number];\n\tpreserve: boolean;\n\tprivate readonly fallbackBlit: BlitPass;\n\n\tconstructor(options: CopyPassOptions = {}) {\n\t\tthis.enabled = options.enabled ?? true;\n\t\tthis.needsSwap = options.needsSwap ?? true;\n\t\tthis.input = options.input ?? 'source';\n\t\tthis.output = options.output ?? (this.needsSwap ? 'target' : 'source');\n\t\tthis.clear = options.clear ?? false;\n\t\tthis.clearColor = options.clearColor ?? [0, 0, 0, 1];\n\t\tthis.preserve = options.preserve ?? true;\n\t\tthis.fallbackBlit = new BlitPass({\n\t\t\tenabled: true,\n\t\t\tneedsSwap: false,\n\t\t\tinput: this.input,\n\t\t\toutput: this.output,\n\t\t\t...(options.filter !== undefined ? { filter: options.filter } : {})\n\t\t});\n\t}\n\n\tsetSize(width: number, height: number): void {\n\t\tthis.fallbackBlit.setSize(width, height);\n\t}\n\n\trender(context: RenderPassContext): void {\n\t\tconst source = context.input;\n\t\tconst target = context.output;\n\t\tconst canDirectCopy =\n\t\t\tcontext.clear === false &&\n\t\t\tcontext.preserve === true &&\n\t\t\tsource.texture !== target.texture &&\n\t\t\tsource.texture !== context.canvas.texture &&\n\t\t\ttarget.texture !== context.canvas.texture &&\n\t\t\tsource.width === target.width &&\n\t\t\tsource.height === target.height &&\n\t\t\tsource.format === target.format;\n\n\t\tif (canDirectCopy) {\n\t\t\tcontext.commandEncoder.copyTextureToTexture(\n\t\t\t\t{ texture: source.texture },\n\t\t\t\t{ texture: target.texture },\n\t\t\t\t{ width: source.width, height: source.height, depthOrArrayLayers: 1 }\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.fallbackBlit.render(context);\n\t}\n\n\tdispose(): void {\n\t\tthis.fallbackBlit.dispose();\n\t}\n}\n"],"mappings":";;;;;AAoBA,IAAa,WAAb,MAA4C;CAC3C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,UAA2B,EAAE,EAAE;AAC1C,OAAK,UAAU,QAAQ,WAAW;AAClC,OAAK,YAAY,QAAQ,aAAa;AACtC,OAAK,QAAQ,QAAQ,SAAS;AAC9B,OAAK,SAAS,QAAQ,WAAW,KAAK,YAAY,WAAW;AAC7D,OAAK,QAAQ,QAAQ,SAAS;AAC9B,OAAK,aAAa,QAAQ,cAAc;GAAC;GAAG;GAAG;GAAG;GAAE;AACpD,OAAK,WAAW,QAAQ,YAAY;AACpC,OAAK,eAAe,IAAI,SAAS;GAChC,SAAS;GACT,WAAW;GACX,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;GAClE,CAAC;;CAGH,QAAQ,OAAe,QAAsB;AAC5C,OAAK,aAAa,QAAQ,OAAO,OAAO;;CAGzC,OAAO,SAAkC;EACxC,MAAM,SAAS,QAAQ;EACvB,MAAM,SAAS,QAAQ;AAWvB,MATC,QAAQ,UAAU,SAClB,QAAQ,aAAa,QACrB,OAAO,YAAY,OAAO,WAC1B,OAAO,YAAY,QAAQ,OAAO,WAClC,OAAO,YAAY,QAAQ,OAAO,WAClC,OAAO,UAAU,OAAO,SACxB,OAAO,WAAW,OAAO,UACzB,OAAO,WAAW,OAAO,QAEP;AAClB,WAAQ,eAAe,qBACtB,EAAE,SAAS,OAAO,SAAS,EAC3B,EAAE,SAAS,OAAO,SAAS,EAC3B;IAAE,OAAO,OAAO;IAAO,QAAQ,OAAO;IAAQ,oBAAoB;IAAG,CACrE;AACD;;AAGD,OAAK,aAAa,OAAO,QAAQ;;CAGlC,UAAgB;AACf,OAAK,aAAa,SAAS"}
@@ -36,3 +36,4 @@ export declare abstract class FullscreenPass implements RenderPass {
36
36
  render(context: RenderPassContext): void;
37
37
  dispose(): void;
38
38
  }
39
+ //# sourceMappingURL=FullscreenPass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FullscreenPass.d.ts","sourceRoot":"","sources":["../../src/lib/passes/FullscreenPass.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EACX,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE,aAAa,CAAC;CACvB;AAED;;GAEG;AACH,8BAAsB,cAAe,YAAW,UAAU;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkD;IACnF,OAAO,CAAC,eAAe,CAA+C;IAEtE,SAAS,aAAa,OAAO,GAAE,qBAA0B;IAWzD,SAAS,CAAC,QAAQ,CAAC,UAAU,IAAI,MAAM;IACvC,SAAS,CAAC,QAAQ,CAAC,mBAAmB,IAAI,MAAM;IAChD,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAAI,MAAM;IAElD,SAAS,CAAC,yBAAyB,IAAI,IAAI;IAM3C,OAAO,CAAC,eAAe;IA6EvB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5C,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAwB5D,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAIxC,OAAO,IAAI,IAAI;CAMf"}
@@ -1,131 +1,128 @@
1
+ //#region src/lib/passes/FullscreenPass.ts
1
2
  /**
2
- * Shared base for fullscreen texture sampling passes.
3
- */
4
- export class FullscreenPass {
5
- enabled;
6
- needsSwap;
7
- input;
8
- output;
9
- clear;
10
- clearColor;
11
- preserve;
12
- filter;
13
- device = null;
14
- sampler = null;
15
- bindGroupLayout = null;
16
- shaderModule = null;
17
- pipelineByFormat = new Map();
18
- bindGroupByView = new WeakMap();
19
- constructor(options = {}) {
20
- this.enabled = options.enabled ?? true;
21
- this.needsSwap = options.needsSwap ?? true;
22
- this.input = options.input ?? 'source';
23
- this.output = options.output ?? (this.needsSwap ? 'target' : 'source');
24
- this.clear = options.clear ?? false;
25
- this.clearColor = options.clearColor ?? [0, 0, 0, 1];
26
- this.preserve = options.preserve ?? true;
27
- this.filter = options.filter ?? 'linear';
28
- }
29
- invalidateFullscreenCache() {
30
- this.shaderModule = null;
31
- this.pipelineByFormat.clear();
32
- this.bindGroupByView = new WeakMap();
33
- }
34
- ensureResources(device, format) {
35
- if (this.device !== device) {
36
- this.device = device;
37
- this.sampler = null;
38
- this.bindGroupLayout = null;
39
- this.invalidateFullscreenCache();
40
- }
41
- if (!this.sampler) {
42
- this.sampler = device.createSampler({
43
- magFilter: this.filter,
44
- minFilter: this.filter,
45
- addressModeU: 'clamp-to-edge',
46
- addressModeV: 'clamp-to-edge'
47
- });
48
- }
49
- if (!this.bindGroupLayout) {
50
- this.bindGroupLayout = device.createBindGroupLayout({
51
- entries: [
52
- {
53
- binding: 0,
54
- visibility: GPUShaderStage.FRAGMENT,
55
- sampler: { type: 'filtering' }
56
- },
57
- {
58
- binding: 1,
59
- visibility: GPUShaderStage.FRAGMENT,
60
- texture: {
61
- sampleType: 'float',
62
- viewDimension: '2d',
63
- multisampled: false
64
- }
65
- }
66
- ]
67
- });
68
- }
69
- if (!this.shaderModule) {
70
- this.shaderModule = device.createShaderModule({ code: this.getProgram() });
71
- }
72
- let pipeline = this.pipelineByFormat.get(format);
73
- if (!pipeline) {
74
- const pipelineLayout = device.createPipelineLayout({
75
- bindGroupLayouts: [this.bindGroupLayout]
76
- });
77
- pipeline = device.createRenderPipeline({
78
- layout: pipelineLayout,
79
- vertex: {
80
- module: this.shaderModule,
81
- entryPoint: this.getVertexEntryPoint()
82
- },
83
- fragment: {
84
- module: this.shaderModule,
85
- entryPoint: this.getFragmentEntryPoint(),
86
- targets: [{ format }]
87
- },
88
- primitive: { topology: 'triangle-list' }
89
- });
90
- this.pipelineByFormat.set(format, pipeline);
91
- }
92
- return {
93
- sampler: this.sampler,
94
- bindGroupLayout: this.bindGroupLayout,
95
- pipeline
96
- };
97
- }
98
- setSize(width, height) {
99
- void width;
100
- void height;
101
- }
102
- renderFullscreen(context) {
103
- const { sampler, bindGroupLayout, pipeline } = this.ensureResources(context.device, context.output.format);
104
- const inputView = context.input.view;
105
- let bindGroup = this.bindGroupByView.get(inputView);
106
- if (!bindGroup) {
107
- bindGroup = context.device.createBindGroup({
108
- layout: bindGroupLayout,
109
- entries: [
110
- { binding: 0, resource: sampler },
111
- { binding: 1, resource: inputView }
112
- ]
113
- });
114
- this.bindGroupByView.set(inputView, bindGroup);
115
- }
116
- const pass = context.beginRenderPass();
117
- pass.setPipeline(pipeline);
118
- pass.setBindGroup(0, bindGroup);
119
- pass.draw(3);
120
- pass.end();
121
- }
122
- render(context) {
123
- this.renderFullscreen(context);
124
- }
125
- dispose() {
126
- this.device = null;
127
- this.sampler = null;
128
- this.bindGroupLayout = null;
129
- this.invalidateFullscreenCache();
130
- }
131
- }
3
+ * Shared base for fullscreen texture sampling passes.
4
+ */
5
+ var FullscreenPass = class {
6
+ enabled;
7
+ needsSwap;
8
+ input;
9
+ output;
10
+ clear;
11
+ clearColor;
12
+ preserve;
13
+ filter;
14
+ device = null;
15
+ sampler = null;
16
+ bindGroupLayout = null;
17
+ shaderModule = null;
18
+ pipelineByFormat = /* @__PURE__ */ new Map();
19
+ bindGroupByView = /* @__PURE__ */ new WeakMap();
20
+ constructor(options = {}) {
21
+ this.enabled = options.enabled ?? true;
22
+ this.needsSwap = options.needsSwap ?? true;
23
+ this.input = options.input ?? "source";
24
+ this.output = options.output ?? (this.needsSwap ? "target" : "source");
25
+ this.clear = options.clear ?? false;
26
+ this.clearColor = options.clearColor ?? [
27
+ 0,
28
+ 0,
29
+ 0,
30
+ 1
31
+ ];
32
+ this.preserve = options.preserve ?? true;
33
+ this.filter = options.filter ?? "linear";
34
+ }
35
+ invalidateFullscreenCache() {
36
+ this.shaderModule = null;
37
+ this.pipelineByFormat.clear();
38
+ this.bindGroupByView = /* @__PURE__ */ new WeakMap();
39
+ }
40
+ ensureResources(device, format) {
41
+ if (this.device !== device) {
42
+ this.device = device;
43
+ this.sampler = null;
44
+ this.bindGroupLayout = null;
45
+ this.invalidateFullscreenCache();
46
+ }
47
+ if (!this.sampler) this.sampler = device.createSampler({
48
+ magFilter: this.filter,
49
+ minFilter: this.filter,
50
+ addressModeU: "clamp-to-edge",
51
+ addressModeV: "clamp-to-edge"
52
+ });
53
+ if (!this.bindGroupLayout) this.bindGroupLayout = device.createBindGroupLayout({ entries: [{
54
+ binding: 0,
55
+ visibility: GPUShaderStage.FRAGMENT,
56
+ sampler: { type: "filtering" }
57
+ }, {
58
+ binding: 1,
59
+ visibility: GPUShaderStage.FRAGMENT,
60
+ texture: {
61
+ sampleType: "float",
62
+ viewDimension: "2d",
63
+ multisampled: false
64
+ }
65
+ }] });
66
+ if (!this.shaderModule) this.shaderModule = device.createShaderModule({ code: this.getProgram() });
67
+ let pipeline = this.pipelineByFormat.get(format);
68
+ if (!pipeline) {
69
+ const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [this.bindGroupLayout] });
70
+ pipeline = device.createRenderPipeline({
71
+ layout: pipelineLayout,
72
+ vertex: {
73
+ module: this.shaderModule,
74
+ entryPoint: this.getVertexEntryPoint()
75
+ },
76
+ fragment: {
77
+ module: this.shaderModule,
78
+ entryPoint: this.getFragmentEntryPoint(),
79
+ targets: [{ format }]
80
+ },
81
+ primitive: { topology: "triangle-list" }
82
+ });
83
+ this.pipelineByFormat.set(format, pipeline);
84
+ }
85
+ return {
86
+ sampler: this.sampler,
87
+ bindGroupLayout: this.bindGroupLayout,
88
+ pipeline
89
+ };
90
+ }
91
+ setSize(width, height) {}
92
+ renderFullscreen(context) {
93
+ const { sampler, bindGroupLayout, pipeline } = this.ensureResources(context.device, context.output.format);
94
+ const inputView = context.input.view;
95
+ let bindGroup = this.bindGroupByView.get(inputView);
96
+ if (!bindGroup) {
97
+ bindGroup = context.device.createBindGroup({
98
+ layout: bindGroupLayout,
99
+ entries: [{
100
+ binding: 0,
101
+ resource: sampler
102
+ }, {
103
+ binding: 1,
104
+ resource: inputView
105
+ }]
106
+ });
107
+ this.bindGroupByView.set(inputView, bindGroup);
108
+ }
109
+ const pass = context.beginRenderPass();
110
+ pass.setPipeline(pipeline);
111
+ pass.setBindGroup(0, bindGroup);
112
+ pass.draw(3);
113
+ pass.end();
114
+ }
115
+ render(context) {
116
+ this.renderFullscreen(context);
117
+ }
118
+ dispose() {
119
+ this.device = null;
120
+ this.sampler = null;
121
+ this.bindGroupLayout = null;
122
+ this.invalidateFullscreenCache();
123
+ }
124
+ };
125
+ //#endregion
126
+ export { FullscreenPass };
127
+
128
+ //# sourceMappingURL=FullscreenPass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FullscreenPass.js","names":[],"sources":["../../src/lib/passes/FullscreenPass.ts"],"sourcesContent":["import type {\n\tRenderPass,\n\tRenderPassContext,\n\tRenderPassFlags,\n\tRenderPassInputSlot,\n\tRenderPassOutputSlot\n} from '../core/types.js';\n\nexport interface FullscreenPassOptions extends RenderPassFlags {\n\tenabled?: boolean;\n\tneedsSwap?: boolean;\n\tinput?: RenderPassInputSlot;\n\toutput?: RenderPassOutputSlot;\n\tfilter?: GPUFilterMode;\n}\n\n/**\n * Shared base for fullscreen texture sampling passes.\n */\nexport abstract class FullscreenPass implements RenderPass {\n\tenabled: boolean;\n\tneedsSwap: boolean;\n\tinput: RenderPassInputSlot;\n\toutput: RenderPassOutputSlot;\n\tclear: boolean;\n\tclearColor: [number, number, number, number];\n\tpreserve: boolean;\n\tprivate readonly filter: GPUFilterMode;\n\tprivate device: GPUDevice | null = null;\n\tprivate sampler: GPUSampler | null = null;\n\tprivate bindGroupLayout: GPUBindGroupLayout | null = null;\n\tprivate shaderModule: GPUShaderModule | null = null;\n\tprivate readonly pipelineByFormat = new Map<GPUTextureFormat, GPURenderPipeline>();\n\tprivate bindGroupByView = new WeakMap<GPUTextureView, GPUBindGroup>();\n\n\tprotected constructor(options: FullscreenPassOptions = {}) {\n\t\tthis.enabled = options.enabled ?? true;\n\t\tthis.needsSwap = options.needsSwap ?? true;\n\t\tthis.input = options.input ?? 'source';\n\t\tthis.output = options.output ?? (this.needsSwap ? 'target' : 'source');\n\t\tthis.clear = options.clear ?? false;\n\t\tthis.clearColor = options.clearColor ?? [0, 0, 0, 1];\n\t\tthis.preserve = options.preserve ?? true;\n\t\tthis.filter = options.filter ?? 'linear';\n\t}\n\n\tprotected abstract getProgram(): string;\n\tprotected abstract getVertexEntryPoint(): string;\n\tprotected abstract getFragmentEntryPoint(): string;\n\n\tprotected invalidateFullscreenCache(): void {\n\t\tthis.shaderModule = null;\n\t\tthis.pipelineByFormat.clear();\n\t\tthis.bindGroupByView = new WeakMap();\n\t}\n\n\tprivate ensureResources(\n\t\tdevice: GPUDevice,\n\t\tformat: GPUTextureFormat\n\t): {\n\t\tsampler: GPUSampler;\n\t\tbindGroupLayout: GPUBindGroupLayout;\n\t\tpipeline: GPURenderPipeline;\n\t} {\n\t\tif (this.device !== device) {\n\t\t\tthis.device = device;\n\t\t\tthis.sampler = null;\n\t\t\tthis.bindGroupLayout = null;\n\t\t\tthis.invalidateFullscreenCache();\n\t\t}\n\n\t\tif (!this.sampler) {\n\t\t\tthis.sampler = device.createSampler({\n\t\t\t\tmagFilter: this.filter,\n\t\t\t\tminFilter: this.filter,\n\t\t\t\taddressModeU: 'clamp-to-edge',\n\t\t\t\taddressModeV: 'clamp-to-edge'\n\t\t\t});\n\t\t}\n\n\t\tif (!this.bindGroupLayout) {\n\t\t\tthis.bindGroupLayout = device.createBindGroupLayout({\n\t\t\t\tentries: [\n\t\t\t\t\t{\n\t\t\t\t\t\tbinding: 0,\n\t\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\t\tsampler: { type: 'filtering' }\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tbinding: 1,\n\t\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\t\ttexture: {\n\t\t\t\t\t\t\tsampleType: 'float',\n\t\t\t\t\t\t\tviewDimension: '2d',\n\t\t\t\t\t\t\tmultisampled: false\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\t\t}\n\n\t\tif (!this.shaderModule) {\n\t\t\tthis.shaderModule = device.createShaderModule({ code: this.getProgram() });\n\t\t}\n\n\t\tlet pipeline = this.pipelineByFormat.get(format);\n\t\tif (!pipeline) {\n\t\t\tconst pipelineLayout = device.createPipelineLayout({\n\t\t\t\tbindGroupLayouts: [this.bindGroupLayout]\n\t\t\t});\n\t\t\tpipeline = device.createRenderPipeline({\n\t\t\t\tlayout: pipelineLayout,\n\t\t\t\tvertex: {\n\t\t\t\t\tmodule: this.shaderModule,\n\t\t\t\t\tentryPoint: this.getVertexEntryPoint()\n\t\t\t\t},\n\t\t\t\tfragment: {\n\t\t\t\t\tmodule: this.shaderModule,\n\t\t\t\t\tentryPoint: this.getFragmentEntryPoint(),\n\t\t\t\t\ttargets: [{ format }]\n\t\t\t\t},\n\t\t\t\tprimitive: { topology: 'triangle-list' }\n\t\t\t});\n\t\t\tthis.pipelineByFormat.set(format, pipeline);\n\t\t}\n\n\t\treturn {\n\t\t\tsampler: this.sampler,\n\t\t\tbindGroupLayout: this.bindGroupLayout,\n\t\t\tpipeline\n\t\t};\n\t}\n\n\tsetSize(width: number, height: number): void {\n\t\tvoid width;\n\t\tvoid height;\n\t}\n\n\tprotected renderFullscreen(context: RenderPassContext): void {\n\t\tconst { sampler, bindGroupLayout, pipeline } = this.ensureResources(\n\t\t\tcontext.device,\n\t\t\tcontext.output.format\n\t\t);\n\t\tconst inputView = context.input.view;\n\t\tlet bindGroup = this.bindGroupByView.get(inputView);\n\t\tif (!bindGroup) {\n\t\t\tbindGroup = context.device.createBindGroup({\n\t\t\t\tlayout: bindGroupLayout,\n\t\t\t\tentries: [\n\t\t\t\t\t{ binding: 0, resource: sampler },\n\t\t\t\t\t{ binding: 1, resource: inputView }\n\t\t\t\t]\n\t\t\t});\n\t\t\tthis.bindGroupByView.set(inputView, bindGroup);\n\t\t}\n\t\tconst pass = context.beginRenderPass();\n\t\tpass.setPipeline(pipeline);\n\t\tpass.setBindGroup(0, bindGroup);\n\t\tpass.draw(3);\n\t\tpass.end();\n\t}\n\n\trender(context: RenderPassContext): void {\n\t\tthis.renderFullscreen(context);\n\t}\n\n\tdispose(): void {\n\t\tthis.device = null;\n\t\tthis.sampler = null;\n\t\tthis.bindGroupLayout = null;\n\t\tthis.invalidateFullscreenCache();\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import type { ComputePassOptions, ComputeDispatchContext } from './ComputePass.js';
2
+ /**
3
+ * Options for constructing a `PingPongComputePass`.
4
+ */
5
+ export interface PingPongComputePassOptions {
6
+ /**
7
+ * Compute shader WGSL source code.
8
+ */
9
+ compute: string;
10
+ /**
11
+ * Target texture key from `material.textures`.
12
+ * The engine will auto-generate `{target}A` and `{target}B` bindings.
13
+ */
14
+ target: string;
15
+ /**
16
+ * Number of compute iterations per frame. Default: 1.
17
+ */
18
+ iterations?: number;
19
+ /**
20
+ * Dispatch workgroup counts (same as ComputePass).
21
+ */
22
+ dispatch?: ComputePassOptions['dispatch'];
23
+ /**
24
+ * Enables/disables this pass.
25
+ */
26
+ enabled?: boolean;
27
+ }
28
+ /**
29
+ * Ping-pong compute pass for iterative GPU simulations.
30
+ *
31
+ * Manages two texture buffers (A/B) and alternates between them each iteration,
32
+ * enabling read-from-previous-write patterns commonly used in fluid simulations,
33
+ * reaction-diffusion, and particle systems.
34
+ */
35
+ export declare class PingPongComputePass {
36
+ /**
37
+ * Enables/disables this pass without removing it from graph.
38
+ */
39
+ enabled: boolean;
40
+ /**
41
+ * Discriminant flag for render graph to identify compute passes.
42
+ */
43
+ readonly isCompute: true;
44
+ /**
45
+ * Discriminant flag to identify ping-pong compute passes.
46
+ */
47
+ readonly isPingPong: true;
48
+ private compute;
49
+ private target;
50
+ private iterations;
51
+ private dispatch;
52
+ private workgroupSize;
53
+ private frameCount;
54
+ constructor(options: PingPongComputePassOptions);
55
+ private static assertIterations;
56
+ /**
57
+ * Returns the texture key holding the latest result.
58
+ * Alternates between `{target}A` and `{target}B` based on total iteration parity.
59
+ */
60
+ getCurrentOutput(): string;
61
+ /**
62
+ * Advances the internal frame counter (called by renderer after each frame's iterations).
63
+ */
64
+ advanceFrame(): void;
65
+ /**
66
+ * Replaces compute shader and updates workgroup size.
67
+ */
68
+ setCompute(compute: string): void;
69
+ /**
70
+ * Updates iteration count.
71
+ *
72
+ * @param count - Must be >= 1.
73
+ */
74
+ setIterations(count: number): void;
75
+ /**
76
+ * Updates dispatch strategy.
77
+ */
78
+ setDispatch(dispatch: ComputePassOptions['dispatch']): void;
79
+ /**
80
+ * Returns the target texture key.
81
+ */
82
+ getTarget(): string;
83
+ /**
84
+ * Returns the current iteration count.
85
+ */
86
+ getIterations(): number;
87
+ /**
88
+ * Returns current compute shader source.
89
+ */
90
+ getCompute(): string;
91
+ /**
92
+ * Returns parsed workgroup size.
93
+ */
94
+ getWorkgroupSize(): [number, number, number];
95
+ /**
96
+ * Resolves dispatch workgroup counts for current frame.
97
+ */
98
+ resolveDispatch(ctx: ComputeDispatchContext): [number, number, number];
99
+ /**
100
+ * Releases resources (no-op, GPU lifecycle is renderer-managed).
101
+ */
102
+ dispose(): void;
103
+ }
104
+ //# sourceMappingURL=PingPongComputePass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PingPongComputePass.d.ts","sourceRoot":"","sources":["../../src/lib/passes/PingPongComputePass.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC1C;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC/B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAG,IAAI,CAAU;IAEnC;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAG,IAAI,CAAU;IAEpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,UAAU,CAAa;gBAEnB,OAAO,EAAE,0BAA0B;IAW/C,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAS/B;;;OAGG;IACH,gBAAgB,IAAI,MAAM;IAK1B;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOjC;;;;OAIG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;OAEG;IACH,gBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAI5C;;OAEG;IACH,eAAe,CAAC,GAAG,EAAE,sBAAsB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAoBtE;;OAEG;IACH,OAAO,IAAI,IAAI;CAGf"}