@volter/blender-engine 0.1.58 → 0.1.60
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.
- package/browser/runtime.ts +14 -3
- package/browser/worker.ts +2 -1
- package/package.json +1 -1
- package/wasm/BUNDLE.json +7 -7
- package/wasm/blender_browser.wasm.br +0 -0
package/browser/runtime.ts
CHANGED
|
@@ -116,6 +116,8 @@ export interface BlenderCallMetrics {
|
|
|
116
116
|
* otherwise the worst call this session has ever seen is invisible for
|
|
117
117
|
* exactly as long as it keeps running. */
|
|
118
118
|
readonly maxCallMs: number | null;
|
|
119
|
+
/** Operation and load boundary owning the longest request; no payload data. */
|
|
120
|
+
readonly maxCallLabel?: string | null;
|
|
119
121
|
/** Calls whose duration passed 5s, counting outstanding ones already past it. */
|
|
120
122
|
readonly callsOver5s: number;
|
|
121
123
|
/** The same at 30s — a call this side of it is slow, past it is a wedge. */
|
|
@@ -163,6 +165,9 @@ export class BlenderRuntime {
|
|
|
163
165
|
};
|
|
164
166
|
/** `performance.now()` at the `postMessage` of every outstanding call. */
|
|
165
167
|
readonly #callStarts = new Map<number, number>();
|
|
168
|
+
readonly #callLabels = new Map<number, string>();
|
|
169
|
+
#loadBoundary = "engine-start";
|
|
170
|
+
#maxCompletedLabel: string | null = null;
|
|
166
171
|
readonly #callWork = new Map<number, () => void>();
|
|
167
172
|
#lastCallMs: number | null = null;
|
|
168
173
|
#maxCompletedMs = 0;
|
|
@@ -265,6 +270,7 @@ export class BlenderRuntime {
|
|
|
265
270
|
async #load(request: Extract<Request, { op: 'start' }>): Promise<RuntimeStart> {
|
|
266
271
|
let result = await this.#request(request) as PullResult<RuntimeStart>;
|
|
267
272
|
while (result?.load === 'continue') {
|
|
273
|
+
this.#loadBoundary = result.phase;
|
|
268
274
|
result = await this.#request({ op: 'load-next', token: result.token }) as PullResult<RuntimeStart>;
|
|
269
275
|
}
|
|
270
276
|
return result?.load === 'done' ? result.value : result as unknown as RuntimeStart;
|
|
@@ -518,12 +524,13 @@ export class BlenderRuntime {
|
|
|
518
524
|
metrics(now: number = performance.now()): BlenderCallMetrics {
|
|
519
525
|
let oldest: number | null = null;
|
|
520
526
|
let max = this.#maxCompletedMs;
|
|
527
|
+
let maxLabel = this.#maxCompletedLabel;
|
|
521
528
|
let over5 = this.#completedOver5s;
|
|
522
529
|
let over30 = this.#completedOver30s;
|
|
523
|
-
for (const started of this.#callStarts
|
|
530
|
+
for (const [id, started] of this.#callStarts) {
|
|
524
531
|
const elapsed = now - started;
|
|
525
532
|
if (oldest === null || elapsed > oldest) oldest = elapsed;
|
|
526
|
-
if (elapsed > max) max = elapsed;
|
|
533
|
+
if (elapsed > max) { max = elapsed; maxLabel = this.#callLabels.get(id) ?? null; }
|
|
527
534
|
if (elapsed >= 5_000) over5 += 1;
|
|
528
535
|
if (elapsed >= 30_000) over30 += 1;
|
|
529
536
|
}
|
|
@@ -533,6 +540,7 @@ export class BlenderRuntime {
|
|
|
533
540
|
// Zero here would mean "no call has ever taken any time", which is a
|
|
534
541
|
// different claim from "no call has happened yet".
|
|
535
542
|
maxCallMs: this.#lastCallMs === null && oldest === null ? null : Math.round(max),
|
|
543
|
+
maxCallLabel: maxLabel,
|
|
536
544
|
callsOver5s: over5,
|
|
537
545
|
callsOver30s: over30,
|
|
538
546
|
lastCallWindow: this.#lastCallWindow,
|
|
@@ -547,9 +555,11 @@ export class BlenderRuntime {
|
|
|
547
555
|
const started = this.#callStarts.get(id);
|
|
548
556
|
if (started === undefined) return;
|
|
549
557
|
this.#callStarts.delete(id);
|
|
558
|
+
const label = this.#callLabels.get(id) ?? null;
|
|
559
|
+
this.#callLabels.delete(id);
|
|
550
560
|
const elapsed = performance.now() - started;
|
|
551
561
|
this.#lastCallMs = elapsed;
|
|
552
|
-
if (elapsed > this.#maxCompletedMs) this.#maxCompletedMs = elapsed;
|
|
562
|
+
if (elapsed > this.#maxCompletedMs) { this.#maxCompletedMs = elapsed; this.#maxCompletedLabel = label; }
|
|
553
563
|
if (elapsed >= 5_000) this.#completedOver5s += 1;
|
|
554
564
|
if (elapsed >= 30_000) this.#completedOver30s += 1;
|
|
555
565
|
if (this.#lastCallWindow !== null && this.#lastCallWindow.start === started)
|
|
@@ -564,6 +574,7 @@ export class BlenderRuntime {
|
|
|
564
574
|
this.#pending.set(id, { resolve, reject });
|
|
565
575
|
const started = performance.now();
|
|
566
576
|
this.#callStarts.set(id, started);
|
|
577
|
+
this.#callLabels.set(id, request.op === "load-next" ? `load-next after ${this.#loadBoundary}` : request.op);
|
|
567
578
|
this.#lastCallWindow = { start: started, end: null };
|
|
568
579
|
this.#callWork.set(id, this.#work(`waiting for worker ${request.op}`));
|
|
569
580
|
try {
|
package/browser/worker.ts
CHANGED
|
@@ -71,7 +71,8 @@ const pendingPresents = new Map<
|
|
|
71
71
|
|
|
72
72
|
async function streamToTab(value: unknown): Promise<PresentAnswer> {
|
|
73
73
|
return await sendFrameValue(value, async chunk => {
|
|
74
|
-
|
|
74
|
+
const kind = value as { op?: string; mesh?: unknown; image?: unknown };
|
|
75
|
+
await loadCheckpoint?.(`frame-transfer/${kind.op ?? "unknown"}/${kind.mesh !== undefined ? "mesh" : kind.image !== undefined ? "image" : "manifest"}/${chunk.kind}`);
|
|
75
76
|
const id = ++presentId;
|
|
76
77
|
return new Promise<PresentAnswer>((resolve, reject) => {
|
|
77
78
|
pendingPresents.set(id, { resolve, reject });
|
package/package.json
CHANGED
package/wasm/BUNDLE.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"blender": "5.2.0 LTS",
|
|
3
|
-
"source": "
|
|
3
|
+
"source": "9fdd05db03bf0e4aa1028607be3e113be7f98d01",
|
|
4
4
|
"upstream": "fbe6228777e7d9afefcd61a413844e790ae75db7",
|
|
5
5
|
"sourceRepository": "https://github.com/volter-ai/blender",
|
|
6
|
-
"sourceRecipe": "https://github.com/volter-ai/blender/blob/
|
|
6
|
+
"sourceRecipe": "https://github.com/volter-ai/blender/blob/9fdd05db03bf0e4aa1028607be3e113be7f98d01/build_files/emscripten/RELEASE.md",
|
|
7
7
|
"factoryEngine": "BLENDER_EEVEE",
|
|
8
8
|
"files": {
|
|
9
9
|
"blender_browser.js": "raw",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"sha256": "0c63c29e7d4b1ba1fce4e94057778b0757767b25ea4f6f01d329e99351568f30"
|
|
17
17
|
},
|
|
18
18
|
"blender_browser.wasm": {
|
|
19
|
-
"bytes":
|
|
20
|
-
"sha256": "
|
|
19
|
+
"bytes": 86337036,
|
|
20
|
+
"sha256": "9d8cb5bd0dbb34fa7f04858fb6bc831195d0b06e8b82bb26889f3c6d807a9588"
|
|
21
21
|
},
|
|
22
22
|
"blender_browser.data": {
|
|
23
23
|
"bytes": 52698568,
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"sha256": "0c63c29e7d4b1ba1fce4e94057778b0757767b25ea4f6f01d329e99351568f30"
|
|
31
31
|
},
|
|
32
32
|
"blender_browser.wasm.br": {
|
|
33
|
-
"bytes":
|
|
34
|
-
"sha256": "
|
|
33
|
+
"bytes": 18604996,
|
|
34
|
+
"sha256": "782c1f8519851e8b901d5309d239429ecd07c4ed374adaf117214f9ac22f84c9"
|
|
35
35
|
},
|
|
36
36
|
"blender_browser.data.br": {
|
|
37
37
|
"bytes": 8056563,
|
|
@@ -45,6 +45,6 @@
|
|
|
45
45
|
"note": "Stoneguard c7/c14/c15 engine. Emscripten 6.0.5, Release -O3 objects and -O2 link. Portable native arm64 matrix reciprocal plus fused generic OpenSubdiv stencil and patch accumulation; bodice four-stage comparison 28/28 arrays exact. Full-scene comparison and memory scope recorded in provenance/stoneguard-memory.json. Historical battery absent; no full-battery or hosted acceptance claim.",
|
|
46
46
|
"callTrampoline": "CPython 3.13.13 is compiled with PY_CALL_TRAMPOLINE for Blender CPython slot arity casts. This applies to CPython dispatch, not arbitrary indirect calls.",
|
|
47
47
|
"engineIds": "The existing session registers Python render engines under CYCLES, BLENDER_EEVEE and BLENDER_WORKBENCH; the headless build permits built-in IDs to be shadowed.",
|
|
48
|
-
"exportDoor": "The source-owned bpy_web_export.cc exports Principled physical inputs, normal images, eight named UV layers and evaluated corner normals, and takes graph_materials/graph_images/graph_generated (a graph-drawn shader mix reduced to the one Principled BSDF it reaches, graph images at the door revisions with every UDIM tile, orco for deformed meshes whose graph reads Generated coordinates). A frame can defer its changed meshes and pictures (defer) for the caller to pull one at a time (export_mesh, export_image), each call freeing the previous one's columns and a picture it decoded; an undo step keeps the revisions when Blender kept the depsgraph (session_undo); Blender's CPU subdivision descriptor is released once a mesh is read; the memory door reports malloc in-use and free. Datablock revisions are keyed by session_uid. writefile.cc writes one copy of the document per save in the browser build. CPU evaluators adopt stencil tables without cloning; browser subdivision descriptors are released immediately after CPU tessellation/deformation. Native evaluated corner triangles accompany corner normals. Consumed local conversion stencils are released before later UV channels are constructed.",
|
|
48
|
+
"exportDoor": "The source-owned bpy_web_export.cc exports Principled physical inputs, normal images, eight named UV layers and evaluated corner normals, and takes graph_materials/graph_images/graph_generated (a graph-drawn shader mix reduced to the one Principled BSDF it reaches, graph images at the door revisions with every UDIM tile, orco for deformed meshes whose graph reads Generated coordinates). A frame can defer its changed meshes and pictures (defer) for the caller to pull one at a time (export_mesh, export_image), each call freeing the previous one's columns and a picture it decoded; an undo step keeps the revisions when Blender kept the depsgraph (session_undo); Blender's CPU subdivision descriptor is released once a mesh is read; the memory door reports malloc in-use and free. Datablock revisions are keyed by session_uid. writefile.cc writes one copy of the document per save in the browser build. CPU evaluators adopt stencil tables without cloning; browser subdivision descriptors are released immediately after CPU tessellation/deformation. Native evaluated corner triangles accompany corner normals. Consumed local conversion stencils are released before later UV channels are constructed. Caller-thread file-read, evaluated-object and subdivision checkpoints provide backpressure for resumable startup. Shared geometry revisions advance once per frame. Existing synchronous export remains available.",
|
|
49
49
|
"preloadedPayload": "releasePreloadedFileData releases the JS preload buffer after session ready. The measured working payload exclusions are retained."
|
|
50
50
|
}
|
|
Binary file
|