@aardworx/wombat.rendering 0.8.1 → 0.9.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 (141) hide show
  1. package/dist/core/command.d.ts +7 -9
  2. package/dist/core/command.d.ts.map +1 -1
  3. package/dist/core/renderTask.d.ts +64 -1
  4. package/dist/core/renderTask.d.ts.map +1 -1
  5. package/dist/core/renderTask.js +3 -1
  6. package/dist/core/renderTask.js.map +1 -1
  7. package/dist/resources/preparedRenderObject.js +3 -3
  8. package/dist/resources/preparedRenderObject.js.map +1 -1
  9. package/dist/resources/uniformBuffer.d.ts.map +1 -1
  10. package/dist/resources/uniformBuffer.js +17 -0
  11. package/dist/resources/uniformBuffer.js.map +1 -1
  12. package/dist/runtime/derivedUniforms/dispatch.d.ts +105 -0
  13. package/dist/runtime/derivedUniforms/dispatch.d.ts.map +1 -0
  14. package/dist/runtime/derivedUniforms/dispatch.js +355 -0
  15. package/dist/runtime/derivedUniforms/dispatch.js.map +1 -0
  16. package/dist/runtime/derivedUniforms/index.d.ts +6 -0
  17. package/dist/runtime/derivedUniforms/index.d.ts.map +1 -0
  18. package/dist/runtime/derivedUniforms/index.js +26 -0
  19. package/dist/runtime/derivedUniforms/index.js.map +1 -0
  20. package/dist/runtime/derivedUniforms/recipes.d.ts +42 -0
  21. package/dist/runtime/derivedUniforms/recipes.d.ts.map +1 -0
  22. package/dist/runtime/derivedUniforms/recipes.js +134 -0
  23. package/dist/runtime/derivedUniforms/recipes.js.map +1 -0
  24. package/dist/runtime/derivedUniforms/sceneIntegration.d.ts +56 -0
  25. package/dist/runtime/derivedUniforms/sceneIntegration.d.ts.map +1 -0
  26. package/dist/runtime/derivedUniforms/sceneIntegration.js +171 -0
  27. package/dist/runtime/derivedUniforms/sceneIntegration.js.map +1 -0
  28. package/dist/runtime/derivedUniforms/slotId.d.ts +15 -0
  29. package/dist/runtime/derivedUniforms/slotId.d.ts.map +1 -0
  30. package/dist/runtime/derivedUniforms/slotId.js +30 -0
  31. package/dist/runtime/derivedUniforms/slotId.js.map +1 -0
  32. package/dist/runtime/derivedUniforms/slots.d.ts +49 -0
  33. package/dist/runtime/derivedUniforms/slots.d.ts.map +1 -0
  34. package/dist/runtime/derivedUniforms/slots.js +123 -0
  35. package/dist/runtime/derivedUniforms/slots.js.map +1 -0
  36. package/dist/runtime/derivedUniforms/uberKernel.wgsl.d.ts +13 -0
  37. package/dist/runtime/derivedUniforms/uberKernel.wgsl.d.ts.map +1 -0
  38. package/dist/runtime/derivedUniforms/uberKernel.wgsl.js +218 -0
  39. package/dist/runtime/derivedUniforms/uberKernel.wgsl.js.map +1 -0
  40. package/dist/runtime/flattenTree.d.ts +5 -0
  41. package/dist/runtime/flattenTree.d.ts.map +1 -0
  42. package/dist/runtime/flattenTree.js +45 -0
  43. package/dist/runtime/flattenTree.js.map +1 -0
  44. package/dist/runtime/heapAdapter.d.ts +16 -0
  45. package/dist/runtime/heapAdapter.d.ts.map +1 -0
  46. package/dist/runtime/heapAdapter.js +263 -0
  47. package/dist/runtime/heapAdapter.js.map +1 -0
  48. package/dist/runtime/heapEffect.d.ts +235 -0
  49. package/dist/runtime/heapEffect.d.ts.map +1 -0
  50. package/dist/runtime/heapEffect.js +529 -0
  51. package/dist/runtime/heapEffect.js.map +1 -0
  52. package/dist/runtime/heapEffectIR.d.ts +34 -0
  53. package/dist/runtime/heapEffectIR.d.ts.map +1 -0
  54. package/dist/runtime/heapEffectIR.js +1161 -0
  55. package/dist/runtime/heapEffectIR.js.map +1 -0
  56. package/dist/runtime/heapEligibility.d.ts +9 -0
  57. package/dist/runtime/heapEligibility.d.ts.map +1 -0
  58. package/dist/runtime/heapEligibility.js +195 -0
  59. package/dist/runtime/heapEligibility.js.map +1 -0
  60. package/dist/runtime/heapScene.d.ts +240 -31
  61. package/dist/runtime/heapScene.d.ts.map +1 -1
  62. package/dist/runtime/heapScene.js +3334 -265
  63. package/dist/runtime/heapScene.js.map +1 -1
  64. package/dist/runtime/heapShaderFamily.d.ts +132 -0
  65. package/dist/runtime/heapShaderFamily.d.ts.map +1 -0
  66. package/dist/runtime/heapShaderFamily.js +866 -0
  67. package/dist/runtime/heapShaderFamily.js.map +1 -0
  68. package/dist/runtime/hybridScene.d.ts +133 -0
  69. package/dist/runtime/hybridScene.d.ts.map +1 -0
  70. package/dist/runtime/hybridScene.js +159 -0
  71. package/dist/runtime/hybridScene.js.map +1 -0
  72. package/dist/runtime/index.d.ts +8 -1
  73. package/dist/runtime/index.d.ts.map +1 -1
  74. package/dist/runtime/index.js +9 -1
  75. package/dist/runtime/index.js.map +1 -1
  76. package/dist/runtime/renderTask.d.ts +21 -4
  77. package/dist/runtime/renderTask.d.ts.map +1 -1
  78. package/dist/runtime/renderTask.js +127 -32
  79. package/dist/runtime/renderTask.js.map +1 -1
  80. package/dist/runtime/runtime.d.ts +33 -3
  81. package/dist/runtime/runtime.d.ts.map +1 -1
  82. package/dist/runtime/runtime.js +12 -3
  83. package/dist/runtime/runtime.js.map +1 -1
  84. package/dist/runtime/scenePass.d.ts +28 -3
  85. package/dist/runtime/scenePass.d.ts.map +1 -1
  86. package/dist/runtime/scenePass.js +37 -4
  87. package/dist/runtime/scenePass.js.map +1 -1
  88. package/dist/runtime/textureAtlas/atlasMipGutterKernel.d.ts +35 -0
  89. package/dist/runtime/textureAtlas/atlasMipGutterKernel.d.ts.map +1 -0
  90. package/dist/runtime/textureAtlas/atlasMipGutterKernel.js +247 -0
  91. package/dist/runtime/textureAtlas/atlasMipGutterKernel.js.map +1 -0
  92. package/dist/runtime/textureAtlas/atlasPool.d.ts +240 -0
  93. package/dist/runtime/textureAtlas/atlasPool.d.ts.map +1 -0
  94. package/dist/runtime/textureAtlas/atlasPool.js +798 -0
  95. package/dist/runtime/textureAtlas/atlasPool.js.map +1 -0
  96. package/dist/runtime/textureAtlas/bvhTree2d.d.ts +33 -0
  97. package/dist/runtime/textureAtlas/bvhTree2d.d.ts.map +1 -0
  98. package/dist/runtime/textureAtlas/bvhTree2d.js +501 -0
  99. package/dist/runtime/textureAtlas/bvhTree2d.js.map +1 -0
  100. package/dist/runtime/textureAtlas/packer.d.ts +50 -0
  101. package/dist/runtime/textureAtlas/packer.d.ts.map +1 -0
  102. package/dist/runtime/textureAtlas/packer.js +390 -0
  103. package/dist/runtime/textureAtlas/packer.js.map +1 -0
  104. package/dist/window/loop.d.ts +14 -0
  105. package/dist/window/loop.d.ts.map +1 -1
  106. package/dist/window/loop.js +18 -5
  107. package/dist/window/loop.js.map +1 -1
  108. package/package.json +6 -5
  109. package/src/core/command.ts +9 -9
  110. package/src/core/renderTask.ts +55 -2
  111. package/src/resources/preparedRenderObject.ts +3 -3
  112. package/src/resources/uniformBuffer.ts +15 -0
  113. package/src/runtime/derivedUniforms/dispatch.ts +407 -0
  114. package/src/runtime/derivedUniforms/index.ts +52 -0
  115. package/src/runtime/derivedUniforms/recipes.ts +159 -0
  116. package/src/runtime/derivedUniforms/sceneIntegration.ts +239 -0
  117. package/src/runtime/derivedUniforms/slotId.ts +35 -0
  118. package/src/runtime/derivedUniforms/slots.ts +155 -0
  119. package/src/runtime/derivedUniforms/uberKernel.wgsl.ts +220 -0
  120. package/src/runtime/flattenTree.ts +46 -0
  121. package/src/runtime/heapAdapter.ts +314 -0
  122. package/src/runtime/heapEffect.ts +728 -0
  123. package/src/runtime/heapEffectIR.ts +1211 -0
  124. package/src/runtime/heapEligibility.ts +189 -0
  125. package/src/runtime/heapScene.ts +3981 -349
  126. package/src/runtime/heapShaderFamily.ts +1102 -0
  127. package/src/runtime/hybridScene.ts +310 -0
  128. package/src/runtime/index.ts +45 -1
  129. package/src/runtime/renderTask.ts +167 -32
  130. package/src/runtime/runtime.ts +37 -4
  131. package/src/runtime/scenePass.ts +39 -4
  132. package/src/runtime/textureAtlas/atlasMipGutterKernel.ts +291 -0
  133. package/src/runtime/textureAtlas/atlasPool.ts +991 -0
  134. package/src/runtime/textureAtlas/bvhTree2d.ts +530 -0
  135. package/src/runtime/textureAtlas/packer.ts +429 -0
  136. package/src/window/loop.ts +32 -6
  137. package/dist/runtime/heapShader.d.ts +0 -12
  138. package/dist/runtime/heapShader.d.ts.map +0 -1
  139. package/dist/runtime/heapShader.js +0 -157
  140. package/dist/runtime/heapShader.js.map +0 -1
  141. package/src/runtime/heapShader.ts +0 -185
@@ -0,0 +1,189 @@
1
+ // heapEligibility — reactive predicate over a RenderObject deciding
2
+ // whether it can ride the heap-bucket fast path.
3
+ //
4
+ // Three classes of conditions:
5
+ // 1. STATIC HARD WEDGES — features the heap path doesn't ingest
6
+ // yet (instanceAttributes, storageBuffers, > 1 texture or
7
+ // sampler). Decided once at classifier time.
8
+ // 2. STATIC SOFT WEDGES — supported with limits (indexed-only,
9
+ // instanceCount=1, baseVertex/firstIndex/firstInstance=0).
10
+ // Read once from the drawCall snapshot.
11
+ // 3. REACTIVE — every `aval<IBuffer>` (vertex attribs + indices)
12
+ // must currently resolve to `kind: "host"`. Every `aval<ITexture>`
13
+ // must be heap-servable: `kind: "host"` (atlasable / Tier-L
14
+ // host upload), 2D dimension, single array layer, and within
15
+ // `LEGACY_MAX_DIM` on each side. Anything failing those rules
16
+ // escalates to the legacy ScenePass — the user is managing a
17
+ // backend resource (render-target, video, environment probe,
18
+ // streaming tile) or asking for a cubemap/array/volume that
19
+ // the heap shaders don't support, or a texture too large for
20
+ // heap-side handling to be a win. Every `aval<ISampler>` must
21
+ // resolve to `kind: "gpu"`. When any of these mark and flip,
22
+ // the result aval marks → hybrid task repartitions.
23
+ //
24
+ // Out-of-scope blockers (return false unconditionally if present):
25
+ // - `storageBuffers` — same.
26
+ // - >1 texture or sampler — multi-binding API not in v1.
27
+ //
28
+ // Per-RO instancing IS supported: `instanceAttributes` are accepted as
29
+ // long as every entry passes the same tight-stride / stride-0-broadcast
30
+ // rule used for `vertexAttributes`, and `dc.instanceCount` may be any
31
+ // positive value (with `firstInstance === 0`).
32
+ //
33
+ // These are conservative wedges, not permanent: as the heap path
34
+ // grows feature support each becomes a per-buffer eligibility
35
+ // question instead of a blanket "no".
36
+
37
+ import { AVal, type aval } from "@aardworx/wombat.adaptive";
38
+ import type { IBuffer } from "../core/buffer.js";
39
+ import type { BufferView } from "../core/bufferView.js";
40
+ import type { ITexture } from "../core/texture.js";
41
+ import type { ISampler } from "../core/sampler.js";
42
+ import type { RenderObject } from "../core/renderObject.js";
43
+
44
+ /**
45
+ * Maximum texture extent (per side) the heap path is willing to
46
+ * ingest. Anything wider/taller escalates to the legacy renderer
47
+ * which gives each RO its own dedicated GPUTexture — that's a
48
+ * better fit than wasting an atlas page on a single ~4K image
49
+ * (and it sidesteps device-limit risk near `maxTextureDimension2D`).
50
+ */
51
+ const LEGACY_MAX_DIM = 4096;
52
+
53
+ const isHostBuffer = (b: IBuffer): boolean => b.kind === "host";
54
+ // Samplers: accept both descriptor-form (`kind: "host"`) and resolved
55
+ // (`kind: "gpu"`). The heap atlas path uses ONE shared GPU sampler for
56
+ // all atlas reads — per-RO sampler state (filter modes, wrap modes)
57
+ // is packed into the drawHeader's formatBits and consumed by the
58
+ // shader, not bound as a per-RO GPUSampler. So the heap path doesn't
59
+ // care whether the user handed in a descriptor or a pre-resolved
60
+ // sampler; both are equivalent at this level.
61
+ const isHeapServableSampler = (_s: ISampler): boolean => true;
62
+
63
+ /**
64
+ * Heap-servability check for a single texture value. Returns `true`
65
+ * when the texture fits the heap path's ingest envelope:
66
+ * - `kind === "host"` (the user isn't managing a backend
67
+ * resource — those go to legacy untouched).
68
+ * - 2D, single array layer (heap shaders are 2D-only).
69
+ * - Both extents `<= LEGACY_MAX_DIM`.
70
+ *
71
+ * For `kind: "gpu"` we currently always reject (rule 1) — even a
72
+ * plain 2D rgba8unorm GPUTexture goes legacy, on the assumption
73
+ * that the user attached a `GPUTexture` for a reason (render target,
74
+ * external import, streamed tile) and shouldn't be silently
75
+ * rebadged. The dimension/layer/size checks are still implemented
76
+ * for `kind: "gpu"` for clarity / future use if we relax rule 1.
77
+ *
78
+ * For `kind: "host"`, by construction `RawTextureSource` and
79
+ * `ExternalTextureSource` are 2D single-layer — but we read
80
+ * `depthOrArrayLayers` from raw sources defensively (it's optional
81
+ * on the descriptor and could in principle be set).
82
+ */
83
+ function isHeapServableTexture(t: ITexture): boolean {
84
+ if (t.kind === "gpu") return false;
85
+ const src = t.source;
86
+ if (src.kind === "raw") {
87
+ if ((src.depthOrArrayLayers ?? 1) !== 1) return false;
88
+ if (src.width > LEGACY_MAX_DIM || src.height > LEGACY_MAX_DIM) return false;
89
+ return true;
90
+ }
91
+ // external — read width/height off the source. Most types have
92
+ // it; HTMLVideoElement uses videoWidth/videoHeight. Sources
93
+ // without measurable dimensions are deferred (eligible until
94
+ // they resolve — heapAdapter handles undimensioned gracefully).
95
+ const ext = src.source as unknown;
96
+ let w = 0, h = 0;
97
+ if (typeof HTMLVideoElement !== "undefined" && ext instanceof HTMLVideoElement) {
98
+ w = ext.videoWidth; h = ext.videoHeight;
99
+ } else if (typeof ImageData !== "undefined" && ext instanceof ImageData) {
100
+ w = ext.width; h = ext.height;
101
+ } else {
102
+ const any = ext as { width?: number; height?: number };
103
+ w = any.width ?? 0;
104
+ h = any.height ?? 0;
105
+ }
106
+ if (w > LEGACY_MAX_DIM || h > LEGACY_MAX_DIM) return false;
107
+ return true;
108
+ }
109
+
110
+ function bufferAvals(ro: RenderObject): aval<IBuffer>[] {
111
+ const out: aval<IBuffer>[] = [];
112
+ ro.vertexAttributes.iter((_k, v: BufferView) => { out.push(v.buffer); });
113
+ if (ro.instanceAttributes !== undefined) {
114
+ ro.instanceAttributes.iter((_k, v: BufferView) => { out.push(v.buffer); });
115
+ }
116
+ if (ro.indices !== undefined) out.push(ro.indices.buffer);
117
+ return out;
118
+ }
119
+
120
+ function textureAvals(ro: RenderObject): aval<ITexture>[] {
121
+ const out: aval<ITexture>[] = [];
122
+ ro.textures.iter((_k, av) => { out.push(av); });
123
+ return out;
124
+ }
125
+
126
+ function samplerAvals(ro: RenderObject): aval<ISampler>[] {
127
+ const out: aval<ISampler>[] = [];
128
+ ro.samplers.iter((_k, av) => { out.push(av); });
129
+ return out;
130
+ }
131
+
132
+ /**
133
+ * `true` when the RO is heap-bucketable, `false` when it must fall
134
+ * back to the legacy per-RO path. Reactive on every contributing
135
+ * `aval`: rewires the partition automatically when any input flips.
136
+ */
137
+ export function isHeapEligible(ro: RenderObject): aval<boolean> {
138
+ // 1. Static hard wedges.
139
+ if (ro.storageBuffers !== undefined && ro.storageBuffers.count > 0) {
140
+ return AVal.constant(false);
141
+ }
142
+ if (ro.textures.count > 1 || ro.samplers.count > 1) {
143
+ return AVal.constant(false);
144
+ }
145
+
146
+ // 2. BufferView stride wedge — only tight per-vertex/per-instance
147
+ // layouts (and broadcasts via `singleValue` / stride 0) are
148
+ // ingested. The shader-side cyclic addressing (`vid % length`,
149
+ // `iidx % length`) makes broadcasts a degenerate length-1 case,
150
+ // so we don't reject them here — but interleaved strides remain
151
+ // unsupported. Per-instance attributes follow the same rule.
152
+ let strideBlocked = false;
153
+ const checkStride = (v: BufferView): void => {
154
+ const stride = v.stride ?? v.elementType.byteSize;
155
+ const isBroadcast = v.singleValue !== undefined || stride === 0;
156
+ if (!isBroadcast && stride !== v.elementType.byteSize) strideBlocked = true;
157
+ };
158
+ ro.vertexAttributes.iter((_k, v: BufferView) => checkStride(v));
159
+ if (ro.instanceAttributes !== undefined) {
160
+ ro.instanceAttributes.iter((_k, v: BufferView) => checkStride(v));
161
+ }
162
+ if (strideBlocked) return AVal.constant(false);
163
+
164
+ // 3. Index-format wedge — heap stores indices as u32.
165
+ if (ro.indices !== undefined && ro.indices.elementType.indexFormat !== "uint32") {
166
+ return AVal.constant(false);
167
+ }
168
+
169
+ const buffers = bufferAvals(ro);
170
+ const textures = textureAvals(ro);
171
+ const samplers = samplerAvals(ro);
172
+
173
+ // Reactive AND-fold over all participating avals. We also subscribe
174
+ // to drawCall (instanceCount/baseVertex/firstIndex/firstInstance
175
+ // can flip; if they violate heap constraints the RO routes to the
176
+ // legacy path that frame).
177
+ return AVal.custom(token => {
178
+ for (const av of buffers) if (!isHostBuffer(av.getValue(token))) return false;
179
+ for (const av of textures) if (!isHeapServableTexture(av.getValue(token))) return false;
180
+ for (const av of samplers) if (!isHeapServableSampler(av.getValue(token))) return false;
181
+ const dc = ro.drawCall.getValue(token);
182
+ if (dc.kind !== "indexed") return false;
183
+ if (dc.instanceCount < 1) return false;
184
+ if (dc.baseVertex !== 0) return false;
185
+ if (dc.firstIndex !== 0) return false;
186
+ if (dc.firstInstance !== 0) return false;
187
+ return true;
188
+ });
189
+ }