@aelionsdk/render-ir 1.2.0-rc.4 → 1.2.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.
- package/README.md +2 -2
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +64 -17
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@ evaluation for AelionSDK.
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
npm install @aelionsdk/render-ir
|
|
9
|
+
npm install @aelionsdk/render-ir
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
`
|
|
12
|
+
`latest` currently resolves to `1.2.0`. Product applications should use
|
|
13
13
|
`@aelionsdk/sdk`; direct use is for custom renderers, exporters and engine
|
|
14
14
|
instrumentation.
|
|
15
15
|
|
package/dist/compiler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAGnB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAaV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAsepB,qBAAa,yBAAyB;;IAcpC;;;;OAIG;IACI,IAAI,IAAI,yBAAyB;IAcxC,4EAA4E;IACrE,KAAK,IAAI,IAAI;IAOb,OAAO,CACZ,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,uBAAuB,GACnB,oBAAoB,GACpB,mBAAmB,CAAC,OAAO,CAAC,CAAC,gBAAgB,CAAM,GACtD,mBAAmB;CAoOvB"}
|
package/dist/compiler.js
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
import { canonicalStringify } from '@aelionsdk/project-schema';
|
|
1
|
+
import { canonicalStringify, } from '@aelionsdk/project-schema';
|
|
2
|
+
/**
|
|
3
|
+
* Objects `deepFreezePlain` has already frozen, along with everything beneath
|
|
4
|
+
* them.
|
|
5
|
+
*
|
|
6
|
+
* An incremental compile reuses most of the previous IR verbatim, and those
|
|
7
|
+
* objects were deep-frozen by the compile that produced them. Re-walking them
|
|
8
|
+
* dominated incremental compile time -- roughly three quarters of a no-op
|
|
9
|
+
* compile at a thousand clips. Membership means the whole subtree is already
|
|
10
|
+
* frozen, so the walk can stop at the first reused node.
|
|
11
|
+
*
|
|
12
|
+
* Entries are held weakly, so a released IR is still collectable.
|
|
13
|
+
*/
|
|
14
|
+
const deepFrozen = new WeakSet();
|
|
15
|
+
/** Item types the Render IR can compile, as a set so the check is one lookup. */
|
|
16
|
+
const COMPILABLE_ITEM_TYPES = new Set([
|
|
17
|
+
'video',
|
|
18
|
+
'image',
|
|
19
|
+
'audio',
|
|
20
|
+
'text',
|
|
21
|
+
'caption',
|
|
22
|
+
'nested-sequence',
|
|
23
|
+
'generator',
|
|
24
|
+
'shape',
|
|
25
|
+
'material-content',
|
|
26
|
+
'adjustment',
|
|
27
|
+
]);
|
|
2
28
|
function deepFreezePlain(value, seen = new WeakSet()) {
|
|
3
29
|
if (value === null || typeof value !== 'object')
|
|
4
30
|
return value;
|
|
31
|
+
if (deepFrozen.has(value))
|
|
32
|
+
return value;
|
|
5
33
|
if (seen.has(value))
|
|
6
34
|
return value;
|
|
7
35
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -10,6 +38,9 @@ function deepFreezePlain(value, seen = new WeakSet()) {
|
|
|
10
38
|
seen.add(value);
|
|
11
39
|
for (const entry of Object.values(value))
|
|
12
40
|
deepFreezePlain(entry, seen);
|
|
41
|
+
// Recorded only after the whole subtree is frozen, so membership never
|
|
42
|
+
// promises more than has actually been done.
|
|
43
|
+
deepFrozen.add(value);
|
|
13
44
|
return Object.freeze(value);
|
|
14
45
|
}
|
|
15
46
|
function object(value, context) {
|
|
@@ -416,6 +447,16 @@ function contentDuration(project, trackIds) {
|
|
|
416
447
|
export class IncrementalRenderCompiler {
|
|
417
448
|
#previous;
|
|
418
449
|
#compiling = false;
|
|
450
|
+
/**
|
|
451
|
+
* Track fingerprints keyed by the source track object.
|
|
452
|
+
*
|
|
453
|
+
* A track fingerprint is `canonicalStringify(track)`, and a track carries every
|
|
454
|
+
* item id on it, so recomputing it for a thousand-clip track dominated the cost
|
|
455
|
+
* of an incremental compile even when nothing on that track changed. Commits
|
|
456
|
+
* share structure: editing one item leaves every untouched track at the same
|
|
457
|
+
* object identity, so identity is a sound key and an edited track simply misses.
|
|
458
|
+
*/
|
|
459
|
+
#trackFingerprints = new WeakMap();
|
|
419
460
|
/**
|
|
420
461
|
* Creates an isolated compiler that reuses this compiler's immutable baseline.
|
|
421
462
|
* Compiling on the fork cannot advance or corrupt the parent baseline; a host
|
|
@@ -426,6 +467,14 @@ export class IncrementalRenderCompiler {
|
|
|
426
467
|
fork.#previous = this.#previous;
|
|
427
468
|
return fork;
|
|
428
469
|
}
|
|
470
|
+
#trackFingerprint(track) {
|
|
471
|
+
const cached = this.#trackFingerprints.get(track);
|
|
472
|
+
if (cached !== undefined)
|
|
473
|
+
return cached;
|
|
474
|
+
const fingerprint = canonicalStringify(track);
|
|
475
|
+
this.#trackFingerprints.set(track, fingerprint);
|
|
476
|
+
return fingerprint;
|
|
477
|
+
}
|
|
429
478
|
/** Releases the incremental baseline retained for clip/transition reuse. */
|
|
430
479
|
clear() {
|
|
431
480
|
if (this.#compiling) {
|
|
@@ -465,36 +514,34 @@ export class IncrementalRenderCompiler {
|
|
|
465
514
|
const track = project.tracks[trackId];
|
|
466
515
|
if (track === undefined)
|
|
467
516
|
throw new RangeError(`Track ${trackId} does not exist`);
|
|
468
|
-
|
|
517
|
+
// A plain loop rather than `flatMap`: the reuse path runs once per item on
|
|
518
|
+
// every commit, and wrapping each result in a throwaway single-element array
|
|
519
|
+
// was the largest remaining cost of an incremental compile.
|
|
520
|
+
const clips = [];
|
|
521
|
+
for (const itemId of track.itemIds) {
|
|
469
522
|
const item = project.items[itemId];
|
|
470
523
|
if (item === undefined)
|
|
471
524
|
throw new RangeError(`Item ${itemId} does not exist`);
|
|
472
|
-
if (item.type
|
|
473
|
-
item.type !== 'image' &&
|
|
474
|
-
item.type !== 'audio' &&
|
|
475
|
-
item.type !== 'text' &&
|
|
476
|
-
item.type !== 'caption' &&
|
|
477
|
-
item.type !== 'nested-sequence' &&
|
|
478
|
-
item.type !== 'generator' &&
|
|
479
|
-
item.type !== 'shape' &&
|
|
480
|
-
item.type !== 'material-content' &&
|
|
481
|
-
item.type !== 'adjustment')
|
|
525
|
+
if (!COMPILABLE_ITEM_TYPES.has(item.type)) {
|
|
482
526
|
throw new TypeError(`Render IR cannot compile item type ${item.type}`);
|
|
527
|
+
}
|
|
483
528
|
const previous = previousClips.get(itemId);
|
|
484
529
|
if (canReuseByEntity &&
|
|
485
530
|
previous !== undefined &&
|
|
486
531
|
!previous.dependencyEntityIds.some(id => affectedEntityIds.has(id))) {
|
|
487
532
|
reusedClips += 1;
|
|
488
|
-
|
|
533
|
+
clips.push(previous);
|
|
534
|
+
continue;
|
|
489
535
|
}
|
|
490
536
|
const candidate = compileClip(item, materials, project.assets);
|
|
491
537
|
if (previous?.fingerprint === candidate.fingerprint) {
|
|
492
538
|
reusedClips += 1;
|
|
493
|
-
|
|
539
|
+
clips.push(previous);
|
|
540
|
+
continue;
|
|
494
541
|
}
|
|
495
542
|
compiledClips += 1;
|
|
496
|
-
|
|
497
|
-
}
|
|
543
|
+
clips.push(candidate);
|
|
544
|
+
}
|
|
498
545
|
return {
|
|
499
546
|
id: track.id,
|
|
500
547
|
kind: track.kind,
|
|
@@ -506,7 +553,7 @@ export class IncrementalRenderCompiler {
|
|
|
506
553
|
: {}),
|
|
507
554
|
clips,
|
|
508
555
|
materialInstanceIds: [...track.materialInstanceIds],
|
|
509
|
-
fingerprint:
|
|
556
|
+
fingerprint: this.#trackFingerprint(track),
|
|
510
557
|
};
|
|
511
558
|
});
|
|
512
559
|
const transitions = sequence.transitionIds.map(id => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aelionsdk/render-ir",
|
|
3
|
-
"version": "1.2.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Incremental render intermediate representation compiler for AelionSDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"provenance": true
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@aelionsdk/core": "1.2.0
|
|
38
|
-
"@aelionsdk/material-compiler": "1.2.0
|
|
39
|
-
"@aelionsdk/project-schema": "1.2.0
|
|
37
|
+
"@aelionsdk/core": "1.2.0",
|
|
38
|
+
"@aelionsdk/material-compiler": "1.2.0",
|
|
39
|
+
"@aelionsdk/project-schema": "1.2.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -b",
|