@aelionsdk/render-ir 1.2.0 → 2.0.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 +1 -1
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +48 -14
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ evaluation for AelionSDK.
|
|
|
9
9
|
npm install @aelionsdk/render-ir
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
`latest` currently resolves to `
|
|
12
|
+
`latest` currently resolves to `2.0.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,EAAE,KAAK,aAAa,EAAqC,MAAM,2BAA2B,CAAC;AAGlG,OAAO,KAAK,EAaV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAkgBpB,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;CAyOvB"}
|
package/dist/compiler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {} from '@aelionsdk/project-schema';
|
|
2
2
|
/**
|
|
3
3
|
* Objects `deepFreezePlain` has already frozen, along with everything beneath
|
|
4
4
|
* them.
|
|
@@ -24,6 +24,8 @@ const COMPILABLE_ITEM_TYPES = new Set([
|
|
|
24
24
|
'shape',
|
|
25
25
|
'material-content',
|
|
26
26
|
'adjustment',
|
|
27
|
+
// Compiles to no clip at all; see the Gap branch in the Track loop below.
|
|
28
|
+
'gap',
|
|
27
29
|
]);
|
|
28
30
|
function deepFreezePlain(value, seen = new WeakSet()) {
|
|
29
31
|
if (value === null || typeof value !== 'object')
|
|
@@ -32,12 +34,23 @@ function deepFreezePlain(value, seen = new WeakSet()) {
|
|
|
32
34
|
return value;
|
|
33
35
|
if (seen.has(value))
|
|
34
36
|
return value;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
seen.add(value);
|
|
39
|
+
for (const entry of value)
|
|
40
|
+
deepFreezePlain(entry, seen);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const prototype = Object.getPrototypeOf(value);
|
|
44
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
45
|
+
return value;
|
|
46
|
+
seen.add(value);
|
|
47
|
+
// `for...in` over a plain object walks V8's enumeration cache without
|
|
48
|
+
// materializing a key or value array for every node in the IR, which at a
|
|
49
|
+
// thousand clips is tens of thousands of throwaway arrays per compile.
|
|
50
|
+
for (const key in value) {
|
|
51
|
+
deepFreezePlain(value[key], seen);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
41
54
|
// Recorded only after the whole subtree is frozen, so membership never
|
|
42
55
|
// promises more than has actually been done.
|
|
43
56
|
deepFrozen.add(value);
|
|
@@ -216,22 +229,37 @@ function nestedSequenceSource(item) {
|
|
|
216
229
|
boundary: boundary,
|
|
217
230
|
};
|
|
218
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Serializes a value for fingerprint comparison.
|
|
234
|
+
*
|
|
235
|
+
* A fingerprint is only ever compared against the fingerprint the previous
|
|
236
|
+
* compile recorded for the same entity, so it needs one property: two entities
|
|
237
|
+
* that differ must serialize differently. Canonical ordering buys the stronger
|
|
238
|
+
* property that two *equal* entities always agree even if their keys were
|
|
239
|
+
* written in a different order -- which here would at worst cause a recompile
|
|
240
|
+
* that produces the same clip, and costs a hand-written walk over every value
|
|
241
|
+
* in the Sequence to avoid. `JSON.stringify` is exact for the plain JSON an
|
|
242
|
+
* admitted Project contains, and the engine runs it natively.
|
|
243
|
+
*/
|
|
244
|
+
function fingerprintOf(value) {
|
|
245
|
+
return JSON.stringify(value);
|
|
246
|
+
}
|
|
219
247
|
function clipFingerprint(item, materials, assets) {
|
|
220
248
|
const source = object(item.source ?? {}, `item ${item.id}.source`);
|
|
221
249
|
const sourceAssetId = typeof source.assetId === 'string' ? source.assetId : undefined;
|
|
222
250
|
const sourceAsset = sourceAssetId === undefined ? undefined : assets[sourceAssetId];
|
|
223
251
|
return [
|
|
224
|
-
|
|
252
|
+
fingerprintOf(item),
|
|
225
253
|
...(sourceAsset?.kind === 'image-sequence'
|
|
226
|
-
? [
|
|
254
|
+
? [fingerprintOf(sourceAsset.imageSequence ?? null)]
|
|
227
255
|
: []),
|
|
228
256
|
...item.materialInstanceIds.map(id => materialFingerprint(materials[id])),
|
|
229
257
|
].join('|');
|
|
230
258
|
}
|
|
231
259
|
function materialFingerprint(instance) {
|
|
232
260
|
if (instance === undefined)
|
|
233
|
-
return
|
|
234
|
-
return
|
|
261
|
+
return 'null';
|
|
262
|
+
return fingerprintOf({
|
|
235
263
|
id: instance.id,
|
|
236
264
|
definition: {
|
|
237
265
|
packageId: instance.definition.packageId,
|
|
@@ -450,7 +478,7 @@ export class IncrementalRenderCompiler {
|
|
|
450
478
|
/**
|
|
451
479
|
* Track fingerprints keyed by the source track object.
|
|
452
480
|
*
|
|
453
|
-
* A track fingerprint
|
|
481
|
+
* A track fingerprint serializes the whole Track, and a Track carries every
|
|
454
482
|
* item id on it, so recomputing it for a thousand-clip track dominated the cost
|
|
455
483
|
* of an incremental compile even when nothing on that track changed. Commits
|
|
456
484
|
* share structure: editing one item leaves every untouched track at the same
|
|
@@ -471,7 +499,7 @@ export class IncrementalRenderCompiler {
|
|
|
471
499
|
const cached = this.#trackFingerprints.get(track);
|
|
472
500
|
if (cached !== undefined)
|
|
473
501
|
return cached;
|
|
474
|
-
const fingerprint =
|
|
502
|
+
const fingerprint = fingerprintOf(track);
|
|
475
503
|
this.#trackFingerprints.set(track, fingerprint);
|
|
476
504
|
return fingerprint;
|
|
477
505
|
}
|
|
@@ -525,6 +553,12 @@ export class IncrementalRenderCompiler {
|
|
|
525
553
|
if (!COMPILABLE_ITEM_TYPES.has(item.type)) {
|
|
526
554
|
throw new TypeError(`Render IR cannot compile item type ${item.type}`);
|
|
527
555
|
}
|
|
556
|
+
// A Gap is time and nothing else. It still lengthens the Sequence,
|
|
557
|
+
// because `contentDuration` reads the Project rather than the clip
|
|
558
|
+
// list, but it produces no clip for the renderer or the mixer to
|
|
559
|
+
// consider.
|
|
560
|
+
if (item.type === 'gap')
|
|
561
|
+
continue;
|
|
528
562
|
const previous = previousClips.get(itemId);
|
|
529
563
|
if (canReuseByEntity &&
|
|
530
564
|
previous !== undefined &&
|
|
@@ -576,7 +610,7 @@ export class IncrementalRenderCompiler {
|
|
|
576
610
|
materialInstanceId: value.materialInstanceId,
|
|
577
611
|
dependencyEntityIds: [id, value.fromItemId, value.toItemId, value.materialInstanceId],
|
|
578
612
|
fingerprint: [
|
|
579
|
-
|
|
613
|
+
fingerprintOf(value),
|
|
580
614
|
materialFingerprint(materials[value.materialInstanceId]),
|
|
581
615
|
].join('|'),
|
|
582
616
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aelionsdk/render-ir",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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": "
|
|
38
|
-
"@aelionsdk/material-compiler": "
|
|
39
|
-
"@aelionsdk/project-schema": "
|
|
37
|
+
"@aelionsdk/core": "2.0.0",
|
|
38
|
+
"@aelionsdk/material-compiler": "2.0.0",
|
|
39
|
+
"@aelionsdk/project-schema": "2.0.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -b",
|