@motion-core/motion-gpu 0.4.1 → 0.4.2

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 (205) hide show
  1. package/dist/advanced.d.ts +1 -0
  2. package/dist/advanced.d.ts.map +1 -0
  3. package/dist/advanced.js +12 -6
  4. package/dist/core/advanced.d.ts +1 -0
  5. package/dist/core/advanced.d.ts.map +1 -0
  6. package/dist/core/advanced.js +12 -5
  7. package/dist/core/current-value.d.ts +1 -0
  8. package/dist/core/current-value.d.ts.map +1 -0
  9. package/dist/core/current-value.js +35 -34
  10. package/dist/core/current-value.js.map +1 -0
  11. package/dist/core/error-diagnostics.d.ts +1 -0
  12. package/dist/core/error-diagnostics.d.ts.map +1 -0
  13. package/dist/core/error-diagnostics.js +70 -137
  14. package/dist/core/error-diagnostics.js.map +1 -0
  15. package/dist/core/error-report.d.ts +1 -0
  16. package/dist/core/error-report.d.ts.map +1 -0
  17. package/dist/core/error-report.js +184 -233
  18. package/dist/core/error-report.js.map +1 -0
  19. package/dist/core/frame-registry.d.ts +1 -0
  20. package/dist/core/frame-registry.d.ts.map +1 -0
  21. package/dist/core/frame-registry.js +546 -662
  22. package/dist/core/frame-registry.js.map +1 -0
  23. package/dist/core/index.d.ts +1 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +11 -12
  26. package/dist/core/material-preprocess.d.ts +1 -0
  27. package/dist/core/material-preprocess.d.ts.map +1 -0
  28. package/dist/core/material-preprocess.js +128 -151
  29. package/dist/core/material-preprocess.js.map +1 -0
  30. package/dist/core/material.d.ts +1 -0
  31. package/dist/core/material.d.ts.map +1 -0
  32. package/dist/core/material.js +263 -317
  33. package/dist/core/material.js.map +1 -0
  34. package/dist/core/recompile-policy.d.ts +1 -0
  35. package/dist/core/recompile-policy.d.ts.map +1 -0
  36. package/dist/core/recompile-policy.js +18 -13
  37. package/dist/core/recompile-policy.js.map +1 -0
  38. package/dist/core/render-graph.d.ts +1 -0
  39. package/dist/core/render-graph.d.ts.map +1 -0
  40. package/dist/core/render-graph.js +61 -68
  41. package/dist/core/render-graph.js.map +1 -0
  42. package/dist/core/render-targets.d.ts +1 -0
  43. package/dist/core/render-targets.d.ts.map +1 -0
  44. package/dist/core/render-targets.js +52 -53
  45. package/dist/core/render-targets.js.map +1 -0
  46. package/dist/core/renderer.d.ts +1 -0
  47. package/dist/core/renderer.d.ts.map +1 -0
  48. package/dist/core/renderer.js +942 -1081
  49. package/dist/core/renderer.js.map +1 -0
  50. package/dist/core/runtime-loop.d.ts +1 -0
  51. package/dist/core/runtime-loop.d.ts.map +1 -0
  52. package/dist/core/runtime-loop.js +305 -362
  53. package/dist/core/runtime-loop.js.map +1 -0
  54. package/dist/core/scheduler-helpers.d.ts +1 -0
  55. package/dist/core/scheduler-helpers.d.ts.map +1 -0
  56. package/dist/core/scheduler-helpers.js +52 -51
  57. package/dist/core/scheduler-helpers.js.map +1 -0
  58. package/dist/core/shader.d.ts +1 -0
  59. package/dist/core/shader.d.ts.map +1 -0
  60. package/dist/core/shader.js +92 -117
  61. package/dist/core/shader.js.map +1 -0
  62. package/dist/core/texture-loader.d.ts +1 -0
  63. package/dist/core/texture-loader.d.ts.map +1 -0
  64. package/dist/core/texture-loader.js +205 -273
  65. package/dist/core/texture-loader.js.map +1 -0
  66. package/dist/core/textures.d.ts +1 -0
  67. package/dist/core/textures.d.ts.map +1 -0
  68. package/dist/core/textures.js +106 -116
  69. package/dist/core/textures.js.map +1 -0
  70. package/dist/core/types.d.ts +1 -0
  71. package/dist/core/types.d.ts.map +1 -0
  72. package/dist/core/types.js +0 -4
  73. package/dist/core/uniforms.d.ts +1 -0
  74. package/dist/core/uniforms.d.ts.map +1 -0
  75. package/dist/core/uniforms.js +170 -191
  76. package/dist/core/uniforms.js.map +1 -0
  77. package/dist/index.d.ts +1 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +11 -6
  80. package/dist/passes/BlitPass.d.ts +1 -0
  81. package/dist/passes/BlitPass.d.ts.map +1 -0
  82. package/dist/passes/BlitPass.js +23 -18
  83. package/dist/passes/BlitPass.js.map +1 -0
  84. package/dist/passes/CopyPass.d.ts +1 -0
  85. package/dist/passes/CopyPass.d.ts.map +1 -0
  86. package/dist/passes/CopyPass.js +58 -52
  87. package/dist/passes/CopyPass.js.map +1 -0
  88. package/dist/passes/FullscreenPass.d.ts +1 -0
  89. package/dist/passes/FullscreenPass.d.ts.map +1 -0
  90. package/dist/passes/FullscreenPass.js +127 -130
  91. package/dist/passes/FullscreenPass.js.map +1 -0
  92. package/dist/passes/ShaderPass.d.ts +1 -0
  93. package/dist/passes/ShaderPass.d.ts.map +1 -0
  94. package/dist/passes/ShaderPass.js +40 -37
  95. package/dist/passes/ShaderPass.js.map +1 -0
  96. package/dist/passes/index.d.ts +1 -0
  97. package/dist/passes/index.d.ts.map +1 -0
  98. package/dist/passes/index.js +4 -3
  99. package/dist/react/FragCanvas.d.ts +1 -0
  100. package/dist/react/FragCanvas.d.ts.map +1 -0
  101. package/dist/react/FragCanvas.js +234 -211
  102. package/dist/react/FragCanvas.js.map +1 -0
  103. package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
  104. package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
  105. package/dist/react/MotionGPUErrorOverlay.js +96 -13
  106. package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
  107. package/dist/react/Portal.d.ts +1 -0
  108. package/dist/react/Portal.d.ts.map +1 -0
  109. package/dist/react/Portal.js +18 -21
  110. package/dist/react/Portal.js.map +1 -0
  111. package/dist/react/advanced.d.ts +1 -0
  112. package/dist/react/advanced.d.ts.map +1 -0
  113. package/dist/react/advanced.js +12 -6
  114. package/dist/react/frame-context.d.ts +1 -0
  115. package/dist/react/frame-context.d.ts.map +1 -0
  116. package/dist/react/frame-context.js +88 -94
  117. package/dist/react/frame-context.js.map +1 -0
  118. package/dist/react/index.d.ts +1 -0
  119. package/dist/react/index.d.ts.map +1 -0
  120. package/dist/react/index.js +10 -9
  121. package/dist/react/motiongpu-context.d.ts +1 -0
  122. package/dist/react/motiongpu-context.d.ts.map +1 -0
  123. package/dist/react/motiongpu-context.js +18 -15
  124. package/dist/react/motiongpu-context.js.map +1 -0
  125. package/dist/react/use-motiongpu-user-context.d.ts +1 -0
  126. package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
  127. package/dist/react/use-motiongpu-user-context.js +83 -82
  128. package/dist/react/use-motiongpu-user-context.js.map +1 -0
  129. package/dist/react/use-texture.d.ts +1 -0
  130. package/dist/react/use-texture.d.ts.map +1 -0
  131. package/dist/react/use-texture.js +132 -152
  132. package/dist/react/use-texture.js.map +1 -0
  133. package/dist/svelte/FragCanvas.svelte.d.ts +1 -0
  134. package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
  135. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
  136. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
  137. package/dist/svelte/Portal.svelte.d.ts +1 -0
  138. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  139. package/dist/svelte/advanced.d.ts +1 -0
  140. package/dist/svelte/advanced.d.ts.map +1 -0
  141. package/dist/svelte/advanced.js +11 -6
  142. package/dist/svelte/frame-context.d.ts +1 -0
  143. package/dist/svelte/frame-context.d.ts.map +1 -0
  144. package/dist/svelte/frame-context.js +27 -27
  145. package/dist/svelte/frame-context.js.map +1 -0
  146. package/dist/svelte/index.d.ts +1 -0
  147. package/dist/svelte/index.d.ts.map +1 -0
  148. package/dist/svelte/index.js +10 -9
  149. package/dist/svelte/motiongpu-context.d.ts +1 -0
  150. package/dist/svelte/motiongpu-context.d.ts.map +1 -0
  151. package/dist/svelte/motiongpu-context.js +24 -21
  152. package/dist/svelte/motiongpu-context.js.map +1 -0
  153. package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
  154. package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
  155. package/dist/svelte/use-motiongpu-user-context.js +69 -70
  156. package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
  157. package/dist/svelte/use-texture.d.ts +1 -0
  158. package/dist/svelte/use-texture.d.ts.map +1 -0
  159. package/dist/svelte/use-texture.js +125 -147
  160. package/dist/svelte/use-texture.js.map +1 -0
  161. package/package.json +12 -7
  162. package/src/lib/advanced.ts +6 -0
  163. package/src/lib/core/advanced.ts +12 -0
  164. package/src/lib/core/current-value.ts +64 -0
  165. package/src/lib/core/error-diagnostics.ts +236 -0
  166. package/src/lib/core/error-report.ts +406 -0
  167. package/src/lib/core/frame-registry.ts +1189 -0
  168. package/src/lib/core/index.ts +77 -0
  169. package/src/lib/core/material-preprocess.ts +284 -0
  170. package/src/lib/core/material.ts +667 -0
  171. package/src/lib/core/recompile-policy.ts +31 -0
  172. package/src/lib/core/render-graph.ts +143 -0
  173. package/src/lib/core/render-targets.ts +107 -0
  174. package/src/lib/core/renderer.ts +1547 -0
  175. package/src/lib/core/runtime-loop.ts +458 -0
  176. package/src/lib/core/scheduler-helpers.ts +136 -0
  177. package/src/lib/core/shader.ts +258 -0
  178. package/src/lib/core/texture-loader.ts +476 -0
  179. package/src/lib/core/textures.ts +235 -0
  180. package/src/lib/core/types.ts +582 -0
  181. package/src/lib/core/uniforms.ts +282 -0
  182. package/src/lib/index.ts +6 -0
  183. package/src/lib/passes/BlitPass.ts +54 -0
  184. package/src/lib/passes/CopyPass.ts +80 -0
  185. package/src/lib/passes/FullscreenPass.ts +173 -0
  186. package/src/lib/passes/ShaderPass.ts +88 -0
  187. package/src/lib/passes/index.ts +3 -0
  188. package/src/lib/react/FragCanvas.tsx +345 -0
  189. package/src/lib/react/MotionGPUErrorOverlay.tsx +392 -0
  190. package/src/lib/react/Portal.tsx +34 -0
  191. package/src/lib/react/advanced.ts +36 -0
  192. package/src/lib/react/frame-context.ts +169 -0
  193. package/src/lib/react/index.ts +51 -0
  194. package/src/lib/react/motiongpu-context.ts +88 -0
  195. package/src/lib/react/use-motiongpu-user-context.ts +186 -0
  196. package/src/lib/react/use-texture.ts +233 -0
  197. package/src/lib/svelte/FragCanvas.svelte +249 -0
  198. package/src/lib/svelte/MotionGPUErrorOverlay.svelte +382 -0
  199. package/src/lib/svelte/Portal.svelte +31 -0
  200. package/src/lib/svelte/advanced.ts +32 -0
  201. package/src/lib/svelte/frame-context.ts +87 -0
  202. package/src/lib/svelte/index.ts +51 -0
  203. package/src/lib/svelte/motiongpu-context.ts +97 -0
  204. package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
  205. package/src/lib/svelte/use-texture.ts +232 -0
@@ -1,365 +1,308 @@
1
- import { resolveMaterial } from './material.js';
2
- import { toMotionGPUErrorReport } from './error-report.js';
3
- import { createRenderer } from './renderer.js';
4
- import { buildRendererPipelineSignature } from './recompile-policy.js';
5
- import { assertUniformValueForType } from './uniforms.js';
1
+ import { assertUniformValueForType } from "./uniforms.js";
2
+ import { resolveMaterial } from "./material.js";
3
+ import { toMotionGPUErrorReport } from "./error-report.js";
4
+ import { createRenderer } from "./renderer.js";
5
+ import { buildRendererPipelineSignature } from "./recompile-policy.js";
6
+ //#region src/lib/core/runtime-loop.ts
6
7
  function getRendererRetryDelayMs(attempt) {
7
- return Math.min(8000, 250 * 2 ** Math.max(0, attempt - 1));
8
+ return Math.min(8e3, 250 * 2 ** Math.max(0, attempt - 1));
8
9
  }
9
- export function createMotionGPURuntimeLoop(options) {
10
- const { canvas: canvasElement, registry, size } = options;
11
- let frameId = null;
12
- let renderer = null;
13
- let isDisposed = false;
14
- let previousTime = performance.now() / 1000;
15
- let activeRendererSignature = '';
16
- let failedRendererSignature = null;
17
- let failedRendererAttempts = 0;
18
- let nextRendererRetryAt = 0;
19
- let rendererRebuildPromise = null;
20
- const runtimeUniforms = {};
21
- const runtimeTextures = {};
22
- let activeUniforms = {};
23
- let activeTextures = {};
24
- let uniformKeys = [];
25
- let uniformKeySet = new Set();
26
- let uniformTypes = new Map();
27
- let textureKeys = [];
28
- let textureKeySet = new Set();
29
- let activeMaterialSignature = '';
30
- let currentCssWidth = -1;
31
- let currentCssHeight = -1;
32
- const renderUniforms = {};
33
- const renderTextures = {};
34
- const canvasSize = { width: 0, height: 0 };
35
- let shouldContinueAfterFrame = false;
36
- let activeErrorKey = null;
37
- let errorHistory = [];
38
- const getHistoryLimit = () => {
39
- const value = options.getErrorHistoryLimit?.() ?? 0;
40
- if (!Number.isFinite(value) || value <= 0) {
41
- return 0;
42
- }
43
- return Math.floor(value);
44
- };
45
- const publishErrorHistory = () => {
46
- options.reportErrorHistory?.(errorHistory);
47
- const onErrorHistory = options.getOnErrorHistory?.();
48
- if (!onErrorHistory) {
49
- return;
50
- }
51
- try {
52
- onErrorHistory(errorHistory);
53
- }
54
- catch {
55
- // User-provided error history handlers must not break runtime error recovery.
56
- }
57
- };
58
- const syncErrorHistory = () => {
59
- const limit = getHistoryLimit();
60
- if (limit <= 0) {
61
- if (errorHistory.length === 0) {
62
- return;
63
- }
64
- errorHistory = [];
65
- publishErrorHistory();
66
- return;
67
- }
68
- if (errorHistory.length <= limit) {
69
- return;
70
- }
71
- errorHistory = errorHistory.slice(errorHistory.length - limit);
72
- publishErrorHistory();
73
- };
74
- const setError = (error, phase) => {
75
- const report = toMotionGPUErrorReport(error, phase);
76
- const reportKey = JSON.stringify({
77
- phase: report.phase,
78
- title: report.title,
79
- message: report.message,
80
- rawMessage: report.rawMessage
81
- });
82
- if (activeErrorKey === reportKey) {
83
- return;
84
- }
85
- activeErrorKey = reportKey;
86
- const historyLimit = getHistoryLimit();
87
- if (historyLimit > 0) {
88
- errorHistory = [...errorHistory, report];
89
- if (errorHistory.length > historyLimit) {
90
- errorHistory = errorHistory.slice(errorHistory.length - historyLimit);
91
- }
92
- publishErrorHistory();
93
- }
94
- options.reportError(report);
95
- const onError = options.getOnError();
96
- if (!onError) {
97
- return;
98
- }
99
- try {
100
- onError(report);
101
- }
102
- catch {
103
- // User-provided error handlers must not break runtime error recovery.
104
- }
105
- };
106
- const clearError = () => {
107
- if (activeErrorKey === null) {
108
- return;
109
- }
110
- activeErrorKey = null;
111
- options.reportError(null);
112
- };
113
- const scheduleFrame = () => {
114
- if (isDisposed || frameId !== null) {
115
- return;
116
- }
117
- frameId = requestAnimationFrame(renderFrame);
118
- };
119
- const requestFrame = () => {
120
- scheduleFrame();
121
- };
122
- const invalidate = (token) => {
123
- registry.invalidate(token);
124
- requestFrame();
125
- };
126
- const advance = () => {
127
- registry.advance();
128
- requestFrame();
129
- };
130
- const resetRuntimeMaps = () => {
131
- for (const key of Object.keys(runtimeUniforms)) {
132
- if (!uniformKeySet.has(key)) {
133
- Reflect.deleteProperty(runtimeUniforms, key);
134
- }
135
- }
136
- for (const key of Object.keys(runtimeTextures)) {
137
- if (!textureKeySet.has(key)) {
138
- Reflect.deleteProperty(runtimeTextures, key);
139
- }
140
- }
141
- };
142
- const resetRenderPayloadMaps = () => {
143
- for (const key of Object.keys(renderUniforms)) {
144
- if (!uniformKeySet.has(key)) {
145
- Reflect.deleteProperty(renderUniforms, key);
146
- }
147
- }
148
- for (const key of Object.keys(renderTextures)) {
149
- if (!textureKeySet.has(key)) {
150
- Reflect.deleteProperty(renderTextures, key);
151
- }
152
- }
153
- };
154
- const syncMaterialRuntimeState = (materialState) => {
155
- const signatureChanged = activeMaterialSignature !== materialState.signature;
156
- const defaultsChanged = activeUniforms !== materialState.uniforms || activeTextures !== materialState.textures;
157
- if (!signatureChanged && !defaultsChanged) {
158
- return;
159
- }
160
- activeUniforms = materialState.uniforms;
161
- activeTextures = materialState.textures;
162
- if (!signatureChanged) {
163
- return;
164
- }
165
- uniformKeys = materialState.uniformLayout.entries.map((entry) => entry.name);
166
- uniformTypes = new Map(materialState.uniformLayout.entries.map((entry) => [entry.name, entry.type]));
167
- textureKeys = materialState.textureKeys;
168
- uniformKeySet = new Set(uniformKeys);
169
- textureKeySet = new Set(textureKeys);
170
- resetRuntimeMaps();
171
- resetRenderPayloadMaps();
172
- activeMaterialSignature = materialState.signature;
173
- };
174
- const resolveActiveMaterial = () => {
175
- return resolveMaterial(options.getMaterial());
176
- };
177
- const setUniform = (name, value) => {
178
- if (!uniformKeySet.has(name)) {
179
- throw new Error(`Unknown uniform "${name}". Declare it in material.uniforms first.`);
180
- }
181
- const expectedType = uniformTypes.get(name);
182
- if (!expectedType) {
183
- throw new Error(`Unknown uniform type for "${name}"`);
184
- }
185
- assertUniformValueForType(expectedType, value);
186
- runtimeUniforms[name] = value;
187
- };
188
- const setTexture = (name, value) => {
189
- if (!textureKeySet.has(name)) {
190
- throw new Error(`Unknown texture "${name}". Declare it in material.textures first.`);
191
- }
192
- runtimeTextures[name] = value;
193
- };
194
- const renderFrame = (timestamp) => {
195
- frameId = null;
196
- if (isDisposed) {
197
- return;
198
- }
199
- syncErrorHistory();
200
- let materialState;
201
- try {
202
- materialState = resolveActiveMaterial();
203
- }
204
- catch (error) {
205
- setError(error, 'initialization');
206
- scheduleFrame();
207
- return;
208
- }
209
- shouldContinueAfterFrame = false;
210
- const outputColorSpace = options.getOutputColorSpace();
211
- const rendererSignature = buildRendererPipelineSignature({
212
- materialSignature: materialState.signature,
213
- outputColorSpace
214
- });
215
- syncMaterialRuntimeState(materialState);
216
- if (failedRendererSignature && failedRendererSignature !== rendererSignature) {
217
- failedRendererSignature = null;
218
- failedRendererAttempts = 0;
219
- nextRendererRetryAt = 0;
220
- }
221
- if (!renderer || activeRendererSignature !== rendererSignature) {
222
- if (failedRendererSignature === rendererSignature &&
223
- performance.now() < nextRendererRetryAt) {
224
- scheduleFrame();
225
- return;
226
- }
227
- if (!rendererRebuildPromise) {
228
- rendererRebuildPromise = (async () => {
229
- try {
230
- const nextRenderer = await createRenderer({
231
- canvas: canvasElement,
232
- fragmentWgsl: materialState.fragmentWgsl,
233
- fragmentLineMap: materialState.fragmentLineMap,
234
- fragmentSource: materialState.fragmentSource,
235
- includeSources: materialState.includeSources,
236
- defineBlockSource: materialState.defineBlockSource,
237
- materialSource: materialState.source,
238
- materialSignature: materialState.signature,
239
- uniformLayout: materialState.uniformLayout,
240
- textureKeys: materialState.textureKeys,
241
- textureDefinitions: materialState.textures,
242
- getRenderTargets: options.getRenderTargets,
243
- getPasses: options.getPasses,
244
- outputColorSpace,
245
- getClearColor: options.getClearColor,
246
- getDpr: () => options.dpr.current,
247
- adapterOptions: options.getAdapterOptions(),
248
- deviceDescriptor: options.getDeviceDescriptor()
249
- });
250
- if (isDisposed) {
251
- nextRenderer.destroy();
252
- return;
253
- }
254
- renderer?.destroy();
255
- renderer = nextRenderer;
256
- activeRendererSignature = rendererSignature;
257
- failedRendererSignature = null;
258
- failedRendererAttempts = 0;
259
- nextRendererRetryAt = 0;
260
- clearError();
261
- }
262
- catch (error) {
263
- failedRendererSignature = rendererSignature;
264
- failedRendererAttempts += 1;
265
- const retryDelayMs = getRendererRetryDelayMs(failedRendererAttempts);
266
- nextRendererRetryAt = performance.now() + retryDelayMs;
267
- setError(error, 'initialization');
268
- }
269
- finally {
270
- rendererRebuildPromise = null;
271
- scheduleFrame();
272
- }
273
- })();
274
- }
275
- return;
276
- }
277
- const time = timestamp / 1000;
278
- const rawDelta = Math.max(0, time - previousTime);
279
- const delta = Math.min(rawDelta, options.maxDelta.current);
280
- previousTime = time;
281
- const rect = canvasElement.getBoundingClientRect();
282
- const width = Math.max(0, Math.floor(rect.width));
283
- const height = Math.max(0, Math.floor(rect.height));
284
- if (width !== currentCssWidth || height !== currentCssHeight) {
285
- currentCssWidth = width;
286
- currentCssHeight = height;
287
- size.set({ width, height });
288
- }
289
- try {
290
- registry.run({
291
- time,
292
- delta,
293
- setUniform,
294
- setTexture,
295
- invalidate,
296
- advance,
297
- renderMode: registry.getRenderMode(),
298
- autoRender: registry.getAutoRender(),
299
- canvas: canvasElement
300
- });
301
- const shouldRenderFrame = registry.shouldRender();
302
- shouldContinueAfterFrame =
303
- registry.getRenderMode() === 'always' ||
304
- (registry.getRenderMode() === 'on-demand' && shouldRenderFrame);
305
- if (shouldRenderFrame) {
306
- for (const key of uniformKeys) {
307
- const runtimeValue = runtimeUniforms[key];
308
- renderUniforms[key] =
309
- runtimeValue === undefined ? activeUniforms[key] : runtimeValue;
310
- }
311
- for (const key of textureKeys) {
312
- const runtimeValue = runtimeTextures[key];
313
- renderTextures[key] =
314
- runtimeValue === undefined ? (activeTextures[key]?.source ?? null) : runtimeValue;
315
- }
316
- canvasSize.width = width;
317
- canvasSize.height = height;
318
- renderer.render({
319
- time,
320
- delta,
321
- renderMode: registry.getRenderMode(),
322
- uniforms: renderUniforms,
323
- textures: renderTextures,
324
- canvasSize
325
- });
326
- }
327
- clearError();
328
- }
329
- catch (error) {
330
- setError(error, 'render');
331
- }
332
- finally {
333
- registry.endFrame();
334
- }
335
- if (shouldContinueAfterFrame) {
336
- scheduleFrame();
337
- }
338
- };
339
- (async () => {
340
- try {
341
- const initialMaterial = resolveActiveMaterial();
342
- syncMaterialRuntimeState(initialMaterial);
343
- activeRendererSignature = '';
344
- scheduleFrame();
345
- }
346
- catch (error) {
347
- setError(error, 'initialization');
348
- scheduleFrame();
349
- }
350
- })();
351
- return {
352
- requestFrame,
353
- invalidate,
354
- advance,
355
- destroy: () => {
356
- isDisposed = true;
357
- if (frameId !== null) {
358
- cancelAnimationFrame(frameId);
359
- frameId = null;
360
- }
361
- renderer?.destroy();
362
- registry.clear();
363
- }
364
- };
10
+ function createMotionGPURuntimeLoop(options) {
11
+ const { canvas: canvasElement, registry, size } = options;
12
+ let frameId = null;
13
+ let renderer = null;
14
+ let isDisposed = false;
15
+ let previousTime = performance.now() / 1e3;
16
+ let activeRendererSignature = "";
17
+ let failedRendererSignature = null;
18
+ let failedRendererAttempts = 0;
19
+ let nextRendererRetryAt = 0;
20
+ let rendererRebuildPromise = null;
21
+ const runtimeUniforms = {};
22
+ const runtimeTextures = {};
23
+ let activeUniforms = {};
24
+ let activeTextures = {};
25
+ let uniformKeys = [];
26
+ let uniformKeySet = /* @__PURE__ */ new Set();
27
+ let uniformTypes = /* @__PURE__ */ new Map();
28
+ let textureKeys = [];
29
+ let textureKeySet = /* @__PURE__ */ new Set();
30
+ let activeMaterialSignature = "";
31
+ let currentCssWidth = -1;
32
+ let currentCssHeight = -1;
33
+ const renderUniforms = {};
34
+ const renderTextures = {};
35
+ const canvasSize = {
36
+ width: 0,
37
+ height: 0
38
+ };
39
+ let shouldContinueAfterFrame = false;
40
+ let activeErrorKey = null;
41
+ let errorHistory = [];
42
+ const getHistoryLimit = () => {
43
+ const value = options.getErrorHistoryLimit?.() ?? 0;
44
+ if (!Number.isFinite(value) || value <= 0) return 0;
45
+ return Math.floor(value);
46
+ };
47
+ const publishErrorHistory = () => {
48
+ options.reportErrorHistory?.(errorHistory);
49
+ const onErrorHistory = options.getOnErrorHistory?.();
50
+ if (!onErrorHistory) return;
51
+ try {
52
+ onErrorHistory(errorHistory);
53
+ } catch {}
54
+ };
55
+ const syncErrorHistory = () => {
56
+ const limit = getHistoryLimit();
57
+ if (limit <= 0) {
58
+ if (errorHistory.length === 0) return;
59
+ errorHistory = [];
60
+ publishErrorHistory();
61
+ return;
62
+ }
63
+ if (errorHistory.length <= limit) return;
64
+ errorHistory = errorHistory.slice(errorHistory.length - limit);
65
+ publishErrorHistory();
66
+ };
67
+ const setError = (error, phase) => {
68
+ const report = toMotionGPUErrorReport(error, phase);
69
+ const reportKey = JSON.stringify({
70
+ phase: report.phase,
71
+ title: report.title,
72
+ message: report.message,
73
+ rawMessage: report.rawMessage
74
+ });
75
+ if (activeErrorKey === reportKey) return;
76
+ activeErrorKey = reportKey;
77
+ const historyLimit = getHistoryLimit();
78
+ if (historyLimit > 0) {
79
+ errorHistory = [...errorHistory, report];
80
+ if (errorHistory.length > historyLimit) errorHistory = errorHistory.slice(errorHistory.length - historyLimit);
81
+ publishErrorHistory();
82
+ }
83
+ options.reportError(report);
84
+ const onError = options.getOnError();
85
+ if (!onError) return;
86
+ try {
87
+ onError(report);
88
+ } catch {}
89
+ };
90
+ const clearError = () => {
91
+ if (activeErrorKey === null) return;
92
+ activeErrorKey = null;
93
+ options.reportError(null);
94
+ };
95
+ const scheduleFrame = () => {
96
+ if (isDisposed || frameId !== null) return;
97
+ frameId = requestAnimationFrame(renderFrame);
98
+ };
99
+ const requestFrame = () => {
100
+ scheduleFrame();
101
+ };
102
+ const invalidate = (token) => {
103
+ registry.invalidate(token);
104
+ requestFrame();
105
+ };
106
+ const advance = () => {
107
+ registry.advance();
108
+ requestFrame();
109
+ };
110
+ const resetRuntimeMaps = () => {
111
+ for (const key of Object.keys(runtimeUniforms)) if (!uniformKeySet.has(key)) Reflect.deleteProperty(runtimeUniforms, key);
112
+ for (const key of Object.keys(runtimeTextures)) if (!textureKeySet.has(key)) Reflect.deleteProperty(runtimeTextures, key);
113
+ };
114
+ const resetRenderPayloadMaps = () => {
115
+ for (const key of Object.keys(renderUniforms)) if (!uniformKeySet.has(key)) Reflect.deleteProperty(renderUniforms, key);
116
+ for (const key of Object.keys(renderTextures)) if (!textureKeySet.has(key)) Reflect.deleteProperty(renderTextures, key);
117
+ };
118
+ const syncMaterialRuntimeState = (materialState) => {
119
+ const signatureChanged = activeMaterialSignature !== materialState.signature;
120
+ const defaultsChanged = activeUniforms !== materialState.uniforms || activeTextures !== materialState.textures;
121
+ if (!signatureChanged && !defaultsChanged) return;
122
+ activeUniforms = materialState.uniforms;
123
+ activeTextures = materialState.textures;
124
+ if (!signatureChanged) return;
125
+ uniformKeys = materialState.uniformLayout.entries.map((entry) => entry.name);
126
+ uniformTypes = new Map(materialState.uniformLayout.entries.map((entry) => [entry.name, entry.type]));
127
+ textureKeys = materialState.textureKeys;
128
+ uniformKeySet = new Set(uniformKeys);
129
+ textureKeySet = new Set(textureKeys);
130
+ resetRuntimeMaps();
131
+ resetRenderPayloadMaps();
132
+ activeMaterialSignature = materialState.signature;
133
+ };
134
+ const resolveActiveMaterial = () => {
135
+ return resolveMaterial(options.getMaterial());
136
+ };
137
+ const setUniform = (name, value) => {
138
+ if (!uniformKeySet.has(name)) throw new Error(`Unknown uniform "${name}". Declare it in material.uniforms first.`);
139
+ const expectedType = uniformTypes.get(name);
140
+ if (!expectedType) throw new Error(`Unknown uniform type for "${name}"`);
141
+ assertUniformValueForType(expectedType, value);
142
+ runtimeUniforms[name] = value;
143
+ };
144
+ const setTexture = (name, value) => {
145
+ if (!textureKeySet.has(name)) throw new Error(`Unknown texture "${name}". Declare it in material.textures first.`);
146
+ runtimeTextures[name] = value;
147
+ };
148
+ const renderFrame = (timestamp) => {
149
+ frameId = null;
150
+ if (isDisposed) return;
151
+ syncErrorHistory();
152
+ let materialState;
153
+ try {
154
+ materialState = resolveActiveMaterial();
155
+ } catch (error) {
156
+ setError(error, "initialization");
157
+ scheduleFrame();
158
+ return;
159
+ }
160
+ shouldContinueAfterFrame = false;
161
+ const outputColorSpace = options.getOutputColorSpace();
162
+ const rendererSignature = buildRendererPipelineSignature({
163
+ materialSignature: materialState.signature,
164
+ outputColorSpace
165
+ });
166
+ syncMaterialRuntimeState(materialState);
167
+ if (failedRendererSignature && failedRendererSignature !== rendererSignature) {
168
+ failedRendererSignature = null;
169
+ failedRendererAttempts = 0;
170
+ nextRendererRetryAt = 0;
171
+ }
172
+ if (!renderer || activeRendererSignature !== rendererSignature) {
173
+ if (failedRendererSignature === rendererSignature && performance.now() < nextRendererRetryAt) {
174
+ scheduleFrame();
175
+ return;
176
+ }
177
+ if (!rendererRebuildPromise) rendererRebuildPromise = (async () => {
178
+ try {
179
+ const nextRenderer = await createRenderer({
180
+ canvas: canvasElement,
181
+ fragmentWgsl: materialState.fragmentWgsl,
182
+ fragmentLineMap: materialState.fragmentLineMap,
183
+ fragmentSource: materialState.fragmentSource,
184
+ includeSources: materialState.includeSources,
185
+ defineBlockSource: materialState.defineBlockSource,
186
+ materialSource: materialState.source,
187
+ materialSignature: materialState.signature,
188
+ uniformLayout: materialState.uniformLayout,
189
+ textureKeys: materialState.textureKeys,
190
+ textureDefinitions: materialState.textures,
191
+ getRenderTargets: options.getRenderTargets,
192
+ getPasses: options.getPasses,
193
+ outputColorSpace,
194
+ getClearColor: options.getClearColor,
195
+ getDpr: () => options.dpr.current,
196
+ adapterOptions: options.getAdapterOptions(),
197
+ deviceDescriptor: options.getDeviceDescriptor()
198
+ });
199
+ if (isDisposed) {
200
+ nextRenderer.destroy();
201
+ return;
202
+ }
203
+ renderer?.destroy();
204
+ renderer = nextRenderer;
205
+ activeRendererSignature = rendererSignature;
206
+ failedRendererSignature = null;
207
+ failedRendererAttempts = 0;
208
+ nextRendererRetryAt = 0;
209
+ clearError();
210
+ } catch (error) {
211
+ failedRendererSignature = rendererSignature;
212
+ failedRendererAttempts += 1;
213
+ const retryDelayMs = getRendererRetryDelayMs(failedRendererAttempts);
214
+ nextRendererRetryAt = performance.now() + retryDelayMs;
215
+ setError(error, "initialization");
216
+ } finally {
217
+ rendererRebuildPromise = null;
218
+ scheduleFrame();
219
+ }
220
+ })();
221
+ return;
222
+ }
223
+ const time = timestamp / 1e3;
224
+ const rawDelta = Math.max(0, time - previousTime);
225
+ const delta = Math.min(rawDelta, options.maxDelta.current);
226
+ previousTime = time;
227
+ const rect = canvasElement.getBoundingClientRect();
228
+ const width = Math.max(0, Math.floor(rect.width));
229
+ const height = Math.max(0, Math.floor(rect.height));
230
+ if (width !== currentCssWidth || height !== currentCssHeight) {
231
+ currentCssWidth = width;
232
+ currentCssHeight = height;
233
+ size.set({
234
+ width,
235
+ height
236
+ });
237
+ }
238
+ try {
239
+ registry.run({
240
+ time,
241
+ delta,
242
+ setUniform,
243
+ setTexture,
244
+ invalidate,
245
+ advance,
246
+ renderMode: registry.getRenderMode(),
247
+ autoRender: registry.getAutoRender(),
248
+ canvas: canvasElement
249
+ });
250
+ const shouldRenderFrame = registry.shouldRender();
251
+ shouldContinueAfterFrame = registry.getRenderMode() === "always" || registry.getRenderMode() === "on-demand" && shouldRenderFrame;
252
+ if (shouldRenderFrame) {
253
+ for (const key of uniformKeys) {
254
+ const runtimeValue = runtimeUniforms[key];
255
+ renderUniforms[key] = runtimeValue === void 0 ? activeUniforms[key] : runtimeValue;
256
+ }
257
+ for (const key of textureKeys) {
258
+ const runtimeValue = runtimeTextures[key];
259
+ renderTextures[key] = runtimeValue === void 0 ? activeTextures[key]?.source ?? null : runtimeValue;
260
+ }
261
+ canvasSize.width = width;
262
+ canvasSize.height = height;
263
+ renderer.render({
264
+ time,
265
+ delta,
266
+ renderMode: registry.getRenderMode(),
267
+ uniforms: renderUniforms,
268
+ textures: renderTextures,
269
+ canvasSize
270
+ });
271
+ }
272
+ clearError();
273
+ } catch (error) {
274
+ setError(error, "render");
275
+ } finally {
276
+ registry.endFrame();
277
+ }
278
+ if (shouldContinueAfterFrame) scheduleFrame();
279
+ };
280
+ (async () => {
281
+ try {
282
+ syncMaterialRuntimeState(resolveActiveMaterial());
283
+ activeRendererSignature = "";
284
+ scheduleFrame();
285
+ } catch (error) {
286
+ setError(error, "initialization");
287
+ scheduleFrame();
288
+ }
289
+ })();
290
+ return {
291
+ requestFrame,
292
+ invalidate,
293
+ advance,
294
+ destroy: () => {
295
+ isDisposed = true;
296
+ if (frameId !== null) {
297
+ cancelAnimationFrame(frameId);
298
+ frameId = null;
299
+ }
300
+ renderer?.destroy();
301
+ registry.clear();
302
+ }
303
+ };
365
304
  }
305
+ //#endregion
306
+ export { createMotionGPURuntimeLoop };
307
+
308
+ //# sourceMappingURL=runtime-loop.js.map