@carbonenginejs/runtime-resource 0.8.0 → 0.9.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/LICENSE +21 -21
- package/NOTICE +29 -29
- package/README.md +67 -548
- package/dist/CjsMotherLode.js +1271 -1271
- package/dist/CjsResMan.js +3005 -3005
- package/dist/CjsResManQueue.js +214 -214
- package/dist/CjsResource.js +566 -566
- package/dist/CjsResourceSource.js +59 -59
- package/dist/_virtual/_rollupPluginBabelHelpers.js +153 -153
- package/dist/format/CjsBlueReader.js +269 -269
- package/dist/format/CjsFormat.js +192 -192
- package/dist/format/CjsReader.js +18 -18
- package/dist/format/CjsResourceProbe.js +277 -277
- package/dist/format/payloadContract.js +173 -173
- package/dist/formats/black/CjsBlackFormat.js +278 -278
- package/dist/formats/black/core/CjsBlackBinaryReader.js +153 -153
- package/dist/formats/black/core/CjsBlackPropertyReaders.js +382 -382
- package/dist/formats/black/core/CjsBlackReader.js +639 -639
- package/dist/formats/black/core/CjsBlackSchemaRegistry.js +433 -433
- package/dist/formats/black/core/black-schema-v1-2026-07-11.json.js +4 -4
- package/dist/formats/black/core/blackConstants.js +7 -7
- package/dist/formats/black/core/blackDefinitions.js +10 -10
- package/dist/formats/black/core/blackEnums.js +6 -6
- package/dist/formats/black/core/blackSchema.js +3 -3
- package/dist/formats/black/core/blackVersion.js +22 -22
- package/dist/formats/black/core/helpers.js +182 -182
- package/dist/formats/black/core/schema.js +4 -4
- package/dist/formats/black/index.js +2 -2
- package/dist/formats/bnk/CjsBnkFormat.js +125 -125
- package/dist/formats/bnk/core/graph.js +140 -140
- package/dist/formats/bnk/core/helpers.js +409 -409
- package/dist/formats/bnk/core/musicNodes.js +489 -489
- package/dist/formats/bnk/core/soundbanksInfo.js +246 -246
- package/dist/formats/bnk/index.js +2 -2
- package/dist/formats/cmf/CjsCmfFormat.js +497 -497
- package/dist/formats/cmf/core/binary.js +118 -118
- package/dist/formats/cmf/core/buffers.js +233 -233
- package/dist/formats/cmf/core/constants.js +47 -47
- package/dist/formats/cmf/core/gr2Anim.js +453 -453
- package/dist/formats/cmf/core/helpers.js +287 -287
- package/dist/formats/cmf/core/pack.js +276 -276
- package/dist/formats/cmf/core/schema.js +364 -364
- package/dist/formats/cmf/core/shared.js +268 -268
- package/dist/formats/cmf/core/writer.js +517 -517
- package/dist/formats/cmf/index.js +2 -2
- package/dist/formats/dds/CjsDdsFormat.js +193 -193
- package/dist/formats/dds/core/bc6h.js +288 -288
- package/dist/formats/dds/core/bc7.js +251 -251
- package/dist/formats/dds/core/helpers.js +815 -815
- package/dist/formats/dds/index.js +2 -2
- package/dist/formats/fbx/CjsFbxFormat.js +266 -266
- package/dist/formats/fbx/core/helpers.js +3901 -3901
- package/dist/formats/fbx/index.js +2 -2
- package/dist/formats/flac/CjsFlacFormat.js +87 -87
- package/dist/formats/flac/core/helpers.js +295 -295
- package/dist/formats/flac/index.js +2 -2
- package/dist/formats/gif/CjsGifFormat.js +87 -87
- package/dist/formats/gif/core/helpers.js +360 -360
- package/dist/formats/gif/index.js +2 -2
- package/dist/formats/gltf/CjsGltfFormat.js +290 -290
- package/dist/formats/gltf/core/helpers.js +292 -292
- package/dist/formats/gltf/core/json.js +79 -79
- package/dist/formats/gltf/core/parser.js +666 -666
- package/dist/formats/gltf/core/targets.js +163 -163
- package/dist/formats/gltf/index.js +2 -2
- package/dist/formats/gr2/CjsGr2Format.js +46 -0
- package/dist/formats/gr2/CjsGr2Format.js.map +1 -0
- package/dist/formats/gr2/core/CjsFormatGr2.js +273 -0
- package/dist/formats/gr2/core/CjsFormatGr2.js.map +1 -0
- package/dist/formats/gr2/core/bitknit2.js +280 -0
- package/dist/formats/gr2/core/bitknit2.js.map +1 -0
- package/dist/formats/gr2/core/curves.js +1047 -0
- package/dist/formats/gr2/core/curves.js.map +1 -0
- package/dist/formats/gr2/core/gsf.js +72 -0
- package/dist/formats/gr2/core/gsf.js.map +1 -0
- package/dist/formats/gr2/core/helpers.js +332 -0
- package/dist/formats/gr2/core/helpers.js.map +1 -0
- package/dist/formats/gr2/core/json.js +622 -0
- package/dist/formats/gr2/core/json.js.map +1 -0
- package/dist/formats/gr2/core/oodle1.js +388 -0
- package/dist/formats/gr2/core/oodle1.js.map +1 -0
- package/dist/formats/gr2/core/reader.js +617 -0
- package/dist/formats/gr2/core/reader.js.map +1 -0
- package/dist/formats/gr2/core/tangents.js +48 -0
- package/dist/formats/gr2/core/tangents.js.map +1 -0
- package/dist/formats/gr2/core/targets.js +351 -0
- package/dist/formats/gr2/core/targets.js.map +1 -0
- package/dist/formats/gr2/index.js +3 -0
- package/dist/formats/gr2/index.js.map +1 -0
- package/dist/formats/index.js +30 -23
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/jpeg/CjsJpegFormat.js +206 -206
- package/dist/formats/jpeg/core/helpers.js +350 -350
- package/dist/formats/jpeg/core/jpeg.js +377 -377
- package/dist/formats/jpeg/index.js +2 -2
- package/dist/formats/mp3/CjsMp3Format.js +192 -192
- package/dist/formats/mp3/core/helpers.js +338 -338
- package/dist/formats/mp3/index.js +2 -2
- package/dist/formats/mp4/CjsMp4Format.js +191 -191
- package/dist/formats/mp4/core/helpers.js +449 -449
- package/dist/formats/mp4/index.js +2 -2
- package/dist/formats/obj/CjsObjFormat.js +253 -253
- package/dist/formats/obj/core/helpers.js +573 -573
- package/dist/formats/obj/core/json.js +64 -64
- package/dist/formats/obj/core/parser.js +321 -321
- package/dist/formats/obj/index.js +2 -2
- package/dist/formats/ogg/CjsOggFormat.js +88 -88
- package/dist/formats/ogg/core/helpers.js +387 -387
- package/dist/formats/ogg/core/imdct.js +178 -178
- package/dist/formats/ogg/core/vorbis.js +999 -999
- package/dist/formats/ogg/index.js +2 -2
- package/dist/formats/png/CjsPngFormat.js +195 -195
- package/dist/formats/png/core/helpers.js +583 -583
- package/dist/formats/png/index.js +2 -2
- package/dist/formats/red/CjsRedFormat.js +261 -261
- package/dist/formats/red/core/CjsRedReader.js +194 -194
- package/dist/formats/red/core/blackDefinitions.js +3 -3
- package/dist/formats/red/core/helpers.js +139 -139
- package/dist/formats/red/core/redGraph.js +68 -68
- package/dist/formats/red/core/schema.js +4 -4
- package/dist/formats/red/index.js +2 -2
- package/dist/formats/stl/CjsStlFormat.js +365 -365
- package/dist/formats/stl/core/helpers.js +261 -261
- package/dist/formats/stl/core/json.js +51 -51
- package/dist/formats/stl/core/stl.js +629 -629
- package/dist/formats/stl/core/targets.js +163 -163
- package/dist/formats/stl/index.js +2 -2
- package/dist/formats/tga/CjsTgaFormat.js +192 -192
- package/dist/formats/tga/core/helpers.js +446 -446
- package/dist/formats/tga/index.js +2 -2
- package/dist/formats/wav/CjsWavFormat.js +192 -192
- package/dist/formats/wav/core/helpers.js +328 -328
- package/dist/formats/wav/index.js +2 -2
- package/dist/formats/webm/CjsWebmFormat.js +191 -191
- package/dist/formats/webm/core/helpers.js +537 -537
- package/dist/formats/webm/index.js +2 -2
- package/dist/formats/webp/CjsWebpFormat.js +86 -86
- package/dist/formats/webp/core/helpers.js +214 -214
- package/dist/formats/webp/index.js +2 -2
- package/dist/formats/wem/CjsWemFormat.js +241 -241
- package/dist/formats/wem/core/bitStream.js +259 -259
- package/dist/formats/wem/core/codebookLibrary.js +164 -164
- package/dist/formats/wem/core/helpers.js +417 -417
- package/dist/formats/wem/core/packedCodebooksAotuv603.js +30 -30
- package/dist/formats/wem/core/ptadpcm.js +77 -77
- package/dist/formats/wem/core/resolve.js +121 -121
- package/dist/formats/wem/core/wemToOgg.js +485 -485
- package/dist/formats/wem/index.js +2 -2
- package/dist/formats/yaml/CjsYamlFormat.js +83 -83
- package/dist/formats/yaml/core/CjsYamlReader.js +305 -305
- package/dist/formats/yaml/core/helpers.js +160 -160
- package/dist/formats/yaml/index.js +2 -2
- package/dist/index.js +49 -48
- package/dist/index.js.map +1 -1
- package/dist/resourcePath.js +18 -18
- package/dist/resourceStates.js +9 -9
- package/dist/resources/AudioGeometryResData.js +47 -47
- package/dist/resources/GStateBindingCallbackData.js +31 -31
- package/dist/resources/MeshDecalData.js +37 -37
- package/dist/resources/MeshDecalLodData.js +34 -34
- package/dist/resources/Tr2EffectRes.js +71 -71
- package/dist/resources/Tr2GrannyIntersectionResult.js +60 -60
- package/dist/resources/Tr2GrannyStateRes.js +44 -44
- package/dist/resources/Tr2ImageRes.js +114 -114
- package/dist/resources/Tr2LightProfileRes.js +40 -40
- package/dist/resources/Tr2MaterialArea.js +34 -34
- package/dist/resources/Tr2MaterialMesh.js +31 -31
- package/dist/resources/Tr2MaterialRes.js +34 -34
- package/dist/resources/Tr2ShaderPermutation.js +43 -43
- package/dist/resources/Tr2TextureLodManager.js +80 -80
- package/dist/resources/Tr2TextureLodUpdateRequest.js +37 -37
- package/dist/resources/Tr2TexturePackChannel.js +37 -37
- package/dist/resources/Tr2TexturePipeline.js +52 -52
- package/dist/resources/Tr2TexturePipelineParams.js +34 -34
- package/dist/resources/Tr2TexturePipelineStepCompress.js +40 -40
- package/dist/resources/Tr2TexturePipelineStepGenerateMips.js +22 -0
- package/dist/resources/Tr2TexturePipelineStepGenerateMips.js.map +1 -0
- package/dist/resources/Tr2TexturePipelineStepLimitSize.js +34 -34
- package/dist/resources/Tr2TexturePipelineStepLoad.js +31 -31
- package/dist/resources/Tr2TexturePipelineStepPack.js +43 -43
- package/dist/resources/TriGeometryRes.js +239 -239
- package/dist/resources/TriGeometryResAreaData.js +59 -59
- package/dist/resources/TriGeometryResJointData.js +38 -38
- package/dist/resources/TriGeometryResLodData.js +88 -88
- package/dist/resources/TriGeometryResMeshData.js +63 -63
- package/dist/resources/TriGeometryResSkeletonData.js +34 -34
- package/dist/resources/TriGrannyRes.js +43 -43
- package/dist/resources/TriJointBinding.js +38 -38
- package/dist/resources/TriMorphTargetGeometryConstants.js +46 -46
- package/dist/resources/TriRtGeometryConstants.js +88 -88
- package/dist/resources/TriTextureRes.js +304 -304
- package/dist/resources/enums.js +18 -18
- package/dist/resources/resourceBoundary.js +47 -47
- package/dist/resources/texturePipelineBehavior.js +308 -308
- package/dist/texture/CjsTextureArrayRes.js +406 -406
- package/dist/texture/CjsTextureParameterProxy.js +133 -133
- package/docs/README.md +69 -0
- package/docs/architecture.md +86 -0
- package/docs/concepts/resource-lifecycle.md +217 -0
- package/docs/formats/README.md +104 -0
- package/{FORMAT-PROVENANCE.md → docs/formats/provenance.md} +173 -155
- package/docs/formats/stl.md +37 -0
- package/docs/formats/wwise.md +44 -0
- package/docs/reference/events.md +92 -0
- package/docs/reference/motherlode-cache.md +244 -0
- package/docs/reference/queues.md +102 -0
- package/docs/reference/reload.md +107 -0
- package/docs/reference/texture-arrays.md +113 -0
- package/docs/reference/texture-pipeline.md +53 -0
- package/docs/roadmap.md +104 -0
- package/format-notices/black/LICENSE +21 -21
- package/format-notices/black/NOTICE +47 -47
- package/format-notices/bnk/LICENSE +21 -21
- package/format-notices/bnk/NOTICE +20 -20
- package/format-notices/cmf/LICENSE +21 -21
- package/format-notices/cmf/NOTICE +36 -36
- package/format-notices/dds/LICENSE +21 -21
- package/format-notices/dds/NOTICE +14 -14
- package/format-notices/fbx/LICENSE +21 -21
- package/format-notices/fbx/NOTICE +14 -14
- package/format-notices/flac/LICENSE +21 -21
- package/format-notices/flac/NOTICE +14 -14
- package/format-notices/gif/LICENSE +21 -21
- package/format-notices/gif/NOTICE +14 -14
- package/format-notices/gltf/LICENSE +21 -21
- package/format-notices/gltf/NOTICE +27 -27
- package/format-notices/gr2/LICENSE +21 -0
- package/format-notices/gr2/NOTICE +60 -0
- package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -0
- package/format-notices/jpeg/LICENSE +21 -21
- package/format-notices/jpeg/NOTICE +14 -14
- package/format-notices/mp3/LICENSE +21 -21
- package/format-notices/mp3/NOTICE +14 -14
- package/format-notices/mp4/LICENSE +21 -21
- package/format-notices/mp4/NOTICE +14 -14
- package/format-notices/obj/LICENSE +21 -21
- package/format-notices/obj/NOTICE +26 -26
- package/format-notices/ogg/LICENSE +21 -21
- package/format-notices/ogg/NOTICE +28 -28
- package/format-notices/png/LICENSE +21 -21
- package/format-notices/png/NOTICE +14 -14
- package/format-notices/red/LICENSE +21 -21
- package/format-notices/red/NOTICE +31 -31
- package/format-notices/stl/LICENSE +21 -21
- package/format-notices/stl/NOTICE +21 -21
- package/format-notices/tga/LICENSE +21 -21
- package/format-notices/tga/NOTICE +14 -14
- package/format-notices/wav/LICENSE +21 -21
- package/format-notices/wav/NOTICE +14 -14
- package/format-notices/webm/LICENSE +21 -21
- package/format-notices/webm/NOTICE +14 -14
- package/format-notices/webp/LICENSE +21 -21
- package/format-notices/webp/NOTICE +14 -14
- package/format-notices/wem/LICENSE +57 -57
- package/format-notices/wem/NOTICE +33 -33
- package/format-notices/yaml/LICENSE +21 -21
- package/format-notices/yaml/NOTICE +44 -44
- package/package.json +52 -51
- package/resource-lifecycle.md +0 -679
package/resource-lifecycle.md
DELETED
|
@@ -1,679 +0,0 @@
|
|
|
1
|
-
# Runtime Resource Lifecycle
|
|
2
|
-
|
|
3
|
-
This note records how Carbon/ccpwgl resource loading maps to
|
|
4
|
-
`runtime-resource`.
|
|
5
|
-
|
|
6
|
-
## Carbon and ccpwgl
|
|
7
|
-
|
|
8
|
-
Carbon's resource model separates load from prepare. The source schemas expose
|
|
9
|
-
resource classes through `BlueAsyncRes`, and Carbon notes distinguish background
|
|
10
|
-
load work from main-thread/device prepare work.
|
|
11
|
-
|
|
12
|
-
ccpwgl makes that split visible in `Tw2Resource`:
|
|
13
|
-
|
|
14
|
-
```text
|
|
15
|
-
NO_INIT -> REQUESTED -> LOADED -> PREPARED
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Additional terminal or cleanup states include `ERROR`, `UNLOADED`, and `PURGED`.
|
|
19
|
-
|
|
20
|
-
The important behavior is:
|
|
21
|
-
|
|
22
|
-
- `Tw2ResMan.LoadResource()` requests a resource.
|
|
23
|
-
- The raw fetch resolves.
|
|
24
|
-
- `Tw2Resource.OnLoaded()` marks bytes or source data as loaded.
|
|
25
|
-
- The resource is queued for prepare.
|
|
26
|
-
- The manager tick later calls `res.Prepare(data)`.
|
|
27
|
-
- The concrete resource calls `OnPrepared()` after prepare work succeeds.
|
|
28
|
-
|
|
29
|
-
Some ccpwgl concrete `Prepare()` implementations also create WebGL objects.
|
|
30
|
-
That is a historical engine/runtime coupling, not the boundary we want in
|
|
31
|
-
CarbonEngineJS.
|
|
32
|
-
|
|
33
|
-
## CarbonEngineJS
|
|
34
|
-
|
|
35
|
-
`runtime-resource` owns the GPU-free half:
|
|
36
|
-
|
|
37
|
-
```text
|
|
38
|
-
EMPTY -> REQUESTED/LOADING -> LOADED
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Engine adapters own device realization:
|
|
42
|
-
|
|
43
|
-
```text
|
|
44
|
-
LOADED -> PREPARING -> PREPARED
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Current state meanings:
|
|
48
|
-
|
|
49
|
-
- `EMPTY`: resource identity exists, but no payload has been read.
|
|
50
|
-
- `REQUESTED`: the resource is waiting on a queued or shared source load.
|
|
51
|
-
- `LOADING`: source bytes are available and CPU reader/format work is active.
|
|
52
|
-
- `LOADED`: CPU payload or hydrated object graph exists.
|
|
53
|
-
- `PREPARING`: an engine adapter is realizing backend-owned resources.
|
|
54
|
-
- `PREPARED`: preparation completed successfully and the resource is usable.
|
|
55
|
-
- `FAILED`: CPU loading, conversion, validation, or publication failed before a valid payload was published.
|
|
56
|
-
- `UNLOADED`: resource payload was released.
|
|
57
|
-
- `PURGED`: an inactivity or recorded-byte cache policy evicted the resource
|
|
58
|
-
from active ownership. Ordinary replacement, `Delete()`, `Clear()`,
|
|
59
|
-
`ClearCached()`, and shutdown clean owned payloads/adapters but preserve the
|
|
60
|
-
detached handle's last valid state.
|
|
61
|
-
|
|
62
|
-
`CjsResMan.LoadObject()` now queues one deduplicated background source operation
|
|
63
|
-
per source/path and limits active source operations with `maxConcurrentLoads`.
|
|
64
|
-
After bytes arrive, object construction is split into separate main-queue
|
|
65
|
-
items:
|
|
66
|
-
|
|
67
|
-
```text
|
|
68
|
-
reader/format conversion -> publish
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
`maxPrepareTime` limits seconds spent starting synchronous main-queue work in
|
|
72
|
-
one pump, and `maxPrepareItemsPerTick` can add a count limit. Promise-returning
|
|
73
|
-
format work remains in flight without blocking the JavaScript event loop.
|
|
74
|
-
Publication moves the resource to `LOADED`, then stops. ResMan never performs
|
|
75
|
-
backend realization or marks the resource `PREPARED`/`GOOD`.
|
|
76
|
-
|
|
77
|
-
Format classes own conversion to the promised CPU output. Backend realization
|
|
78
|
-
is a separate explicit engine operation after publication. A realization
|
|
79
|
-
failure destroys its candidate and returns a current resource to `LOADED`
|
|
80
|
-
without discarding the valid CPU payload; an existing usable adapter may remain
|
|
81
|
-
`PREPARED`.
|
|
82
|
-
|
|
83
|
-
Every requested handle uses a normalized source path plus one promised output
|
|
84
|
-
tag. `variant` is explicit; `emit`, `requirement`, and `payload` are fallbacks.
|
|
85
|
-
The selected constructor, reader, and format defaults/options are setup-time
|
|
86
|
-
execution details, not MotherLode identity. A changed
|
|
87
|
-
registration does not create a hidden second resource; reset the affected
|
|
88
|
-
identity or create a new manager. A changed output contract uses a new tag.
|
|
89
|
-
|
|
90
|
-
Output matching is case-insensitive, then the canonical declaration spelling
|
|
91
|
-
is passed to the format reader. Direct object loaders expose only their
|
|
92
|
-
unforced default; multiple named outputs belong on a format class. Unsupported
|
|
93
|
-
output is rejected before a MotherLode cache hit can return.
|
|
94
|
-
|
|
95
|
-
Releasing an unlocked CPU payload keeps the lightweight handle and a small
|
|
96
|
-
reconstruction request containing its path/output and source provenance. Its
|
|
97
|
-
promised-output fields and retained source provenance remain pinned during
|
|
98
|
-
`Ready()`/`GetObject()` so another output/source cannot silently replace the
|
|
99
|
-
old identity. `Ready()` may re-read and rebuild it through current
|
|
100
|
-
registrations. Queries, lease renewal, sweeps, and adapter cleanup never
|
|
101
|
-
trigger that read. Engine adapters own their backend allocations and may
|
|
102
|
-
release those independently.
|
|
103
|
-
|
|
104
|
-
The Blue method names remain the public queue vocabulary: `AddToQueue`,
|
|
105
|
-
`CancelFromQueue`, `GetNextIdForQueue`, `PumpMainThreadQueue`, `PauseQueue`,
|
|
106
|
-
`ResumeQueue`, `GetPendingLoads`, and `GetPendingPrepares`. `Update()`/`Tick()`
|
|
107
|
-
pump queues. `Wait()` snapshots queued resource-operation roots and already
|
|
108
|
-
submitted low-level queue tasks before its first await. Captured roots remain
|
|
109
|
-
open through publication enqueued after an asynchronous read, failure, and
|
|
110
|
-
lock release; later unrelated roots/tasks are excluded. Failure and queued
|
|
111
|
-
cancellation cross the fence without making `Wait()` reject.
|
|
112
|
-
|
|
113
|
-
The default wait pumps only the two queues, never automatic retention sweeps,
|
|
114
|
-
and honors existing pause state and budgets. `{ pump: false }` requires an
|
|
115
|
-
external driver. A standalone canonical `PrepareResourceObjectQueued()` call
|
|
116
|
-
opens a queued root. Direct `LoadResourceObject()`, direct
|
|
117
|
-
`PrepareResourceObject()`, and standalone source/format reads bypass both
|
|
118
|
-
queues and are outside the fence. They are still tracked as active mutations
|
|
119
|
-
so synchronous MotherLode replacement cannot detach them. `WaitUrgent()`
|
|
120
|
-
remains open until real per-item priority and urgent membership exist.
|
|
121
|
-
|
|
122
|
-
## CjsLibrary resource-path workflow
|
|
123
|
-
|
|
124
|
-
The normal direct resource-path flow is:
|
|
125
|
-
|
|
126
|
-
```text
|
|
127
|
-
Application / runtime object
|
|
128
|
-
|
|
|
129
|
-
| requests "res:/model/ship.gr2"
|
|
130
|
-
| with optional per-request overrides
|
|
131
|
-
v
|
|
132
|
-
+-----------------------------------------------+
|
|
133
|
-
| CjsLibrary |
|
|
134
|
-
| |
|
|
135
|
-
| - starts from registered default behavior |
|
|
136
|
-
| - considers registered capability reports |
|
|
137
|
-
| - chooses requirement / emit / format |
|
|
138
|
-
| - applies explicit request overrides |
|
|
139
|
-
+-----------------------------------------------+
|
|
140
|
-
|
|
|
141
|
-
| path + resolved request options
|
|
142
|
-
v
|
|
143
|
-
+-----------------------------------------------+
|
|
144
|
-
| CjsResMan.GetResource(path, options) |
|
|
145
|
-
| |
|
|
146
|
-
| - normalize source path and extension |
|
|
147
|
-
| - resolve the promised output tag |
|
|
148
|
-
+-----------------------------------------------+
|
|
149
|
-
|
|
|
150
|
-
v
|
|
151
|
-
+-----------------------------------------------+
|
|
152
|
-
| CjsMotherLode.Lookup(resolved key) |
|
|
153
|
-
+-----------------------------------------------+
|
|
154
|
-
|
|
|
155
|
-
+--- cache hit ------------------------------+
|
|
156
|
-
| |
|
|
157
|
-
| reuse the CjsResource and any active |
|
|
158
|
-
| load/build operation |
|
|
159
|
-
| |
|
|
160
|
-
`--- cache miss -----------------------------+
|
|
161
|
-
| |
|
|
162
|
-
| resolve class from requirement |
|
|
163
|
-
| construct + Initialize() |
|
|
164
|
-
| insert into CjsMotherLode |
|
|
165
|
-
v |
|
|
166
|
-
new CjsResource -------------------------------+
|
|
167
|
-
|
|
|
168
|
-
| Ready() / GetObject()
|
|
169
|
-
v
|
|
170
|
-
+===============================================+
|
|
171
|
-
| BACKGROUND LOAD QUEUE |
|
|
172
|
-
| |
|
|
173
|
-
| - mark resource REQUESTED |
|
|
174
|
-
| - share one source operation per source/path |
|
|
175
|
-
| - obey maxConcurrentLoads |
|
|
176
|
-
| - source.Read(path) |
|
|
177
|
-
+===============================================+
|
|
178
|
-
|
|
|
179
|
-
| source bytes
|
|
180
|
-
v
|
|
181
|
-
+===============================================+
|
|
182
|
-
| MAIN PREPARE QUEUE |
|
|
183
|
-
| |
|
|
184
|
-
| every box below is a separately budgeted item |
|
|
185
|
-
+===============================================+
|
|
186
|
-
|
|
|
187
|
-
v
|
|
188
|
-
+-----------------------------------------------+
|
|
189
|
-
| Read stage |
|
|
190
|
-
| |
|
|
191
|
-
| current object loader for extension? |
|
|
192
|
-
| yes -> call it |
|
|
193
|
-
| no -> resolve registered formats by |
|
|
194
|
-
| bytes + request options |
|
|
195
|
-
+-----------------------------------------------+
|
|
196
|
-
|
|
|
197
|
-
| plain payload / hydrated object
|
|
198
|
-
v
|
|
199
|
-
+-----------------------------------------------+
|
|
200
|
-
| Publish stage |
|
|
201
|
-
| |
|
|
202
|
-
| semantic resource -> SetPayload(payload) |
|
|
203
|
-
| generic resource -> SetPayload(value) |
|
|
204
|
-
| object aliases payload |
|
|
205
|
-
+-----------------------------------------------+
|
|
206
|
-
|
|
|
207
|
-
+--- validation failure --------------------+
|
|
208
|
-
| |
|
|
209
|
-
| resource -> FAILED |
|
|
210
|
-
| Ready() rejects |
|
|
211
|
-
| |
|
|
212
|
-
`--- publication succeeds -----------------+
|
|
213
|
-
|
|
|
214
|
-
| resource -> LOADED
|
|
215
|
-
v
|
|
216
|
-
CjsLibrary returns
|
|
217
|
-
the built CjsResource/object
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Device realization is a separate continuation selected outside ResMan. It can
|
|
221
|
-
run again after adapter eviction or device loss while the CPU payload remains
|
|
222
|
-
resident:
|
|
223
|
-
|
|
224
|
-
```text
|
|
225
|
-
CjsResource LOADED
|
|
226
|
-
|
|
|
227
|
-
| selected engine adapter
|
|
228
|
-
v
|
|
229
|
-
PREPARING
|
|
230
|
-
|
|
|
231
|
-
| create candidate -> verify current target -> synchronous attach
|
|
232
|
-
v
|
|
233
|
-
PREPARED
|
|
234
|
-
|
|
235
|
-
failure: destroy candidate -> LOADED (CPU payload retained)
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Texture Array Generations
|
|
239
|
-
|
|
240
|
-
`CjsTextureArrayRes` is a derived multi-source resource with an explicit
|
|
241
|
-
requested/prepared revision boundary:
|
|
242
|
-
|
|
243
|
-
```text
|
|
244
|
-
proxy/source change
|
|
245
|
-
-> requested revision + dirty layer
|
|
246
|
-
-> one scheduled next-frame snapshot
|
|
247
|
-
-> consumed/in-flight request
|
|
248
|
-
-> adapter candidate preparation
|
|
249
|
-
-> guarded adapter + prepared-revision publication
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
`ConsumeUpdateRequest()` produces an immutable snapshot and marks that revision
|
|
253
|
-
in flight. A current consumed revision may be completed through
|
|
254
|
-
`CommitPreparedAdapterRevision()`, failed through `FailUpdateRequest()`, or
|
|
255
|
-
returned to the queue through `RetryUpdateRequest()`. Commit-before-consume and
|
|
256
|
-
stale commits are rejected; rejected candidate allocations are destroyed by
|
|
257
|
-
default.
|
|
258
|
-
|
|
259
|
-
Publication installs the adapter allocation and prepared revision before
|
|
260
|
-
completion events run. The result returns the displaced allocation to the
|
|
261
|
-
adapter owner for post-publication destruction. A reentrant source change may
|
|
262
|
-
therefore request a newer revision without allowing stale completion to replace
|
|
263
|
-
it. The previous prepared allocation and `IsGood()` remain usable while a
|
|
264
|
-
replacement is pending or if replacement preparation fails.
|
|
265
|
-
|
|
266
|
-
`Ready()` is specialized for this derived resource: it resolves when the
|
|
267
|
-
generation requested at call time has been published, rather than delegating
|
|
268
|
-
to a single-source object loader. Initial preparation failure rejects it.
|
|
269
|
-
|
|
270
|
-
Logical paths and resolved sources are independent. Attaching a redirected or
|
|
271
|
-
LOD-specific source does not rewrite persistence. `TouchLayer()` represents an
|
|
272
|
-
in-place source revision, and `HandleAdapterLoss()` invalidates the complete
|
|
273
|
-
topology after destroying an unusable adapter allocation. Topology snapshots
|
|
274
|
-
report an explicit `topologyChanged` flag and contain only valid current dirty
|
|
275
|
-
layer indices.
|
|
276
|
-
|
|
277
|
-
## Optional Runtime Manager Follow-up
|
|
278
|
-
|
|
279
|
-
The runtime-resource 0.6.0 ResMan/MotherLode contract is complete. Future
|
|
280
|
-
work should be driven by measured application needs rather than another
|
|
281
|
-
resource preparation abstraction:
|
|
282
|
-
|
|
283
|
-
- main-queue priority and starvation policy
|
|
284
|
-
- cancellation/abort propagation for work that has already started
|
|
285
|
-
- `WaitUrgent()` after real priority and bounded fairness
|
|
286
|
-
- queue-time and reader/format-time telemetry
|
|
287
|
-
- application-level default retention policy selection
|
|
288
|
-
- automatic resource/payload byte estimation and separate CPU/adapter budgets
|
|
289
|
-
- browser-aware source behavior such as fetch response type selection
|
|
290
|
-
|
|
291
|
-
Explicit `Ready()`/`GetObject()` reconstructs released CPU payloads. Backend
|
|
292
|
-
device-loss recovery belongs to the engine's realization operation.
|
|
293
|
-
|
|
294
|
-
## Memory Retention and Purging
|
|
295
|
-
|
|
296
|
-
ccpwgl keeps every resource in `Tw2MotherLode` until it is explicitly cleared or
|
|
297
|
-
auto-purged. Each resource has:
|
|
298
|
-
|
|
299
|
-
- `activeFrame`: last frame the resource was considered in use.
|
|
300
|
-
- `doNotPurge`: a lock counter/flag for resources that must stay resident.
|
|
301
|
-
- `KeepAlive()`: updates `activeFrame` and reloads an unloaded/purged resource
|
|
302
|
-
if it is touched again.
|
|
303
|
-
|
|
304
|
-
The manager advances an `activeFrame` counter on a cadence, and
|
|
305
|
-
`Tw2MotherLode.PurgeInactive()` unloads resources whose `activeFrame` is old
|
|
306
|
-
enough. It then marks them purged and removes them from the cache. In ccpwgl,
|
|
307
|
-
`IsGood()` also calls `KeepAlive()`, so many read/check paths implicitly keep
|
|
308
|
-
resources resident.
|
|
309
|
-
|
|
310
|
-
That model works for ccpwgl, but CarbonEngineJS is deliberately more explicit:
|
|
311
|
-
|
|
312
|
-
- `IsGood()`, `IsPrepared()`, and `HasLoaded()` remain pure state checks.
|
|
313
|
-
- `KeepAlive()` and `KeepPayloadAlive()` are the explicit liveness operations.
|
|
314
|
-
- `Lock()` / `Unlock()` maintain a non-underflowing count and prevent identity
|
|
315
|
-
and payload eviction during a sweep.
|
|
316
|
-
- MotherLode tracks separate identity and CPU-payload frame/time observations.
|
|
317
|
-
- `CjsMotherLode.PurgeInactive()` itself scans only when explicitly requested
|
|
318
|
-
and never infers JavaScript reachability. `CjsResMan.Update()` may request it
|
|
319
|
-
only under an explicitly configured automatic policy.
|
|
320
|
-
- `Unload()` should release engine adapter resources and optionally CPU payloads.
|
|
321
|
-
- A resource-level `Purge()`/`Reload()` vocabulary remains future policy work.
|
|
322
|
-
|
|
323
|
-
### Recorded-Byte Cache Contract
|
|
324
|
-
|
|
325
|
-
Carbon can infer when only its cache retains a resource through weak-reference
|
|
326
|
-
and refcount transitions. JavaScript cannot reproduce that ownership test
|
|
327
|
-
reliably, so `CjsMotherLode` budgets only entries that a caller explicitly
|
|
328
|
-
classifies with `{ cached: true, bytes }`. The byte value is an exact
|
|
329
|
-
caller-supplied safe-integer eviction weight; runtime-resource does not walk
|
|
330
|
-
arbitrary cyclic/shared object graphs or invoke payload getters to guess size.
|
|
331
|
-
|
|
332
|
-
Explicit cached entries receive a monotonic admission sequence.
|
|
333
|
-
With its default cleanup, `TrimCache(options)` destroys adapters, releases
|
|
334
|
-
payloads, detaches lifecycle callbacks, marks compatible handles `PURGED`, and
|
|
335
|
-
removes positive-byte entries oldest-first until `cacheBytes <= cacheSize`.
|
|
336
|
-
Live, locked, non-cacheable, and zero-byte entries do not create byte pressure.
|
|
337
|
-
`KeepAlive()` and `Lock()` promote a cached record to live; `Unlock()` does not
|
|
338
|
-
silently re-admit it.
|
|
339
|
-
|
|
340
|
-
`SetCacheSize(bytes, options)` installs and immediately enforces the new budget.
|
|
341
|
-
`CjsResMan.Update()` / `Tick()` also run cache housekeeping after queue pumping;
|
|
342
|
-
`{ cache: false }` skips one update without changing policy. Cleanup is
|
|
343
|
-
transactional per identity: a failed candidate remains canonical, later
|
|
344
|
-
candidates are still attempted, and the aggregate
|
|
345
|
-
`CJS_MOTHERLODE_CACHE_TRIM_FAILED` error carries successful evictions and any
|
|
346
|
-
remaining over-budget state. Trimming never reads, prepares, or reloads data.
|
|
347
|
-
|
|
348
|
-
The JS/browser split adds one more axis that ccpwgl blurs: CPU payload memory and
|
|
349
|
-
GPU/device memory are different budgets. A large decoded image, geometry buffer,
|
|
350
|
-
or shader graph can be expensive even before an engine adapter prepares it.
|
|
351
|
-
Runtime-resource should therefore support separate retention policy for:
|
|
352
|
-
|
|
353
|
-
- resource identity: path, extension, state, error summary, lightweight metadata.
|
|
354
|
-
- CPU payload: plain reader/converter objects, hydrated object graphs, decoded
|
|
355
|
-
typed arrays.
|
|
356
|
-
- adapter payload: WebGL/WebGPU textures, buffers, shader modules, pipelines.
|
|
357
|
-
|
|
358
|
-
A sane default would keep resource identity and lightweight metadata while
|
|
359
|
-
allowing CPU payloads and adapter payloads to be released independently. Engine
|
|
360
|
-
adapters should own adapter-resource destruction, but `runtime-resource` can
|
|
361
|
-
provide lifecycle hooks and opaque adapter slots so the adapter has a consistent
|
|
362
|
-
place to clean up.
|
|
363
|
-
|
|
364
|
-
### Payload Retention Contract
|
|
365
|
-
|
|
366
|
-
Reader and converter outputs are plain transient payload objects, not resource
|
|
367
|
-
classes or DTO models. A payload may contain more decoded data than a particular
|
|
368
|
-
resource or engine adapter needs. Each concrete resource validates the fields
|
|
369
|
-
it requires before publishing the payload and retains the scalars and references
|
|
370
|
-
it needs. An adapter may retain additional references in adapter-owned state.
|
|
371
|
-
Referencing payload-owned typed arrays is valid and preferable to copying them
|
|
372
|
-
merely to change ownership.
|
|
373
|
-
|
|
374
|
-
The lifecycle treats resource residency and payload residency independently:
|
|
375
|
-
|
|
376
|
-
```text
|
|
377
|
-
resource.KeepAlive()
|
|
378
|
-
-> renew resource/cache residency
|
|
379
|
-
|
|
380
|
-
resource.KeepPayloadAlive()
|
|
381
|
-
-> renew the attached payload lease
|
|
382
|
-
|
|
383
|
-
resource.ReleasePayload()
|
|
384
|
-
-> explicitly release the full payload reference
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
`CjsResMan` binds resource-facing `KeepAlive()`, `KeepPayloadAlive()`, `Lock()`,
|
|
388
|
-
and `Unlock()` to the resource's canonical MotherLode key. `SetPayload()` renews
|
|
389
|
-
both identity and payload activity when it publishes a non-null payload.
|
|
390
|
-
`GetPayload()` and `HasPayload()` are pure queries; reading the payload does not
|
|
391
|
-
implicitly renew its lease. Detached and purged handles retain deterministic
|
|
392
|
-
no-op liveness methods rather than silently starting work.
|
|
393
|
-
|
|
394
|
-
Both semantic and generic/base resource results use that payload slot. A base
|
|
395
|
-
resource also mirrors its payload on the compatibility `object` property;
|
|
396
|
-
`ReleasePayload()` clears the alias only when it still references that exact
|
|
397
|
-
payload. Semantic resources continue to expose `object === resource` while
|
|
398
|
-
holding their validated plain payload privately.
|
|
399
|
-
|
|
400
|
-
Object-operation promises are retained only while in flight. Concurrent
|
|
401
|
-
`GetObject()`/`Ready()` calls share one operation; a resident result is returned
|
|
402
|
-
without source work and renews the explicit payload lease. Settlement removes
|
|
403
|
-
the operation record so its result graph can be reclaimed and a failure can be
|
|
404
|
-
retried. After payload release, only a new explicit object/readiness call
|
|
405
|
-
reconstructs it; queries, lease calls, and purge sweeps do not.
|
|
406
|
-
|
|
407
|
-
Read-cache provenance is explicit and separate from path/output resource identity.
|
|
408
|
-
For a selected source object and normalized path, `sourceRevision` is an opaque
|
|
409
|
-
caller/source-supplied string or finite-number content token. Source and format
|
|
410
|
-
records do not share across revisions. Format records are additionally isolated
|
|
411
|
-
by source object, frozen registration descriptor, and effective format options,
|
|
412
|
-
so another source or a re-registered default cannot reuse a stale parse.
|
|
413
|
-
Registered defaults are deeply snapshotted for supported plain-object/array
|
|
414
|
-
configuration. Requests containing option values that cannot be represented
|
|
415
|
-
safely bypass parsed-format sharing instead of accepting an ambiguous key.
|
|
416
|
-
|
|
417
|
-
`cacheSource` and `cacheFormat` use the same per-call tri-state contract:
|
|
418
|
-
omitted shares existing in-flight/retained work but drops a newly completed
|
|
419
|
-
record; `true` retains success and upgrades joined work; `false` bypasses both
|
|
420
|
-
sharing and retention. Failures are never retained. Resource loaders capture
|
|
421
|
-
the effective selected source (including the creation-time manager default)
|
|
422
|
-
and revision for later reconstruction, but do not capture cache flags or
|
|
423
|
-
one-shot reload.
|
|
424
|
-
|
|
425
|
-
`reload: true` detaches all queued/source/format records for the selected
|
|
426
|
-
source/path when fresh candidate work begins. `InvalidateReadCache()` exposes
|
|
427
|
-
explicit path invalidation, optionally restricted to one revision. Detachment
|
|
428
|
-
never aborts or rejects existing consumers and never touches MotherLode or the
|
|
429
|
-
already-published canonical payload. `Delete()` remains resource-identity-only;
|
|
430
|
-
`Clear()` resets all read ledgers. A failed reload preserves the former payload
|
|
431
|
-
but does not restore reusable read-cache entries detached by its explicit
|
|
432
|
-
freshness request.
|
|
433
|
-
|
|
434
|
-
### Candidate-First Atomic Reload
|
|
435
|
-
|
|
436
|
-
When an owner already exists, `GetResource(path, { reload: true })` constructs
|
|
437
|
-
and initializes a distinct off-registry candidate. Ordinary `Lookup()` remains
|
|
438
|
-
on the former resource. Calling `Ready()` on the candidate, using
|
|
439
|
-
`GetObject()` / `FetchResource()` with `reload: true`, or calling the explicit
|
|
440
|
-
`ReloadObject()` / `ReloadResource()` helpers starts one shared candidate
|
|
441
|
-
operation.
|
|
442
|
-
|
|
443
|
-
The manager captures the exact MotherLode, key, former handle, former ownership
|
|
444
|
-
generation, and a newest-request token. It purge-locks the former owner and
|
|
445
|
-
tracks the candidate as a normal `Wait()` root. Reader, prepare, and publication
|
|
446
|
-
stages mutate only the detached candidate and validate candidate authority
|
|
447
|
-
before and after asynchronous boundaries. A fully loaded CPU candidate commits
|
|
448
|
-
through `CjsMotherLode.ReplaceExpected()` only if the exact former owner and
|
|
449
|
-
newest token still match. The final authority callback and exact-record check
|
|
450
|
-
run immediately before the synchronous map switch, with no user cleanup or
|
|
451
|
-
`await` between the comparison and publication.
|
|
452
|
-
|
|
453
|
-
After the switch, the displaced ownership generation is invalidated, the
|
|
454
|
-
candidate receives ordinary lifecycle/reconstruction callbacks, and the former
|
|
455
|
-
handle is cleaned exactly once. Existing JavaScript references are not
|
|
456
|
-
retargeted; fresh lookup returns the new handle. Source, format, or publication
|
|
457
|
-
failure leaves the exact former state, payload, and adapters canonical, retains
|
|
458
|
-
its original error, and cleans payload/adapters attached to the never-canonical
|
|
459
|
-
candidate. An otherwise-successful candidate that was superseded, deleted,
|
|
460
|
-
cleared, or replaced rejects with `CJS_RESMAN_STALE_RELOAD_CANDIDATE` and cannot
|
|
461
|
-
resurrect the key. Constructors that return the former singleton are rejected
|
|
462
|
-
before `Initialize()` can mutate it because staging requires a distinct handle.
|
|
463
|
-
|
|
464
|
-
Cleanup errors have explicit sides. Candidate cleanup failure aggregates with
|
|
465
|
-
the original preparation/stale error as
|
|
466
|
-
`CJS_RESMAN_RELOAD_CANDIDATE_CLEANUP_FAILED` while the former owner remains
|
|
467
|
-
canonical. A displaced-owner cleanup failure occurs after publication and
|
|
468
|
-
rejects as `CJS_MOTHERLODE_REPLACE_CLEANUP_FAILED` with a result where
|
|
469
|
-
`committed === true`; the already-good candidate remains canonical.
|
|
470
|
-
Started source/format work abort remains separate work.
|
|
471
|
-
|
|
472
|
-
This availability contract intentionally differs from Carbon.
|
|
473
|
-
`BlueAsyncRes::Reload` cancels/joins work, releases dependent cached data, and
|
|
474
|
-
reloads the same canonical object in place; failure can therefore leave that
|
|
475
|
-
stable handle bad. Carbon MotherLode replacement also switches immediately and
|
|
476
|
-
has no prepare-success gate or rollback. Runtime-resource instead preserves the
|
|
477
|
-
last published good handle until a distinct candidate has succeeded.
|
|
478
|
-
|
|
479
|
-
Every canonical queued/direct/standalone preparation captures an immutable
|
|
480
|
-
publication authority: exact MotherLode, canonical key, resource handle, and a
|
|
481
|
-
manager-local ownership generation. The manager validates that authority
|
|
482
|
-
before and after state changes, asynchronous reader/format work, and publication.
|
|
483
|
-
Delete, Clear, successful reload commit, or exact-handle reinsertion therefore makes
|
|
484
|
-
older work reject with `CJS_RESMAN_STALE_RESOURCE_OPERATION` before it can
|
|
485
|
-
publish. If stale work independently rejects, its original source/format error
|
|
486
|
-
is preserved and `SetError()` is suppressed on the detached handle.
|
|
487
|
-
|
|
488
|
-
`Register({ motherLode })` rejects with
|
|
489
|
-
`CJS_RESMAN_ACTIVE_RESOURCE_OPERATIONS` while queued or direct mutations are
|
|
490
|
-
active, including a reload candidate. Normal `Wait()` drains queued roots and
|
|
491
|
-
candidate lineages; a direct caller must await its own load/prepare promise
|
|
492
|
-
before retrying replacement. Canonical and candidate authority prevent late
|
|
493
|
-
publication, but started-work abort remains separate. Backend candidate
|
|
494
|
-
cleanup belongs to the explicit engine realization operation.
|
|
495
|
-
|
|
496
|
-
An explicit `PurgeInactive()` sweep accepts separate frame/time limits for
|
|
497
|
-
identity and payload residency. Identity expiry destroys adapter resources,
|
|
498
|
-
releases the payload, detaches lifecycle callbacks, marks compatible handles
|
|
499
|
-
`PURGED`, and removes the canonical key. Payload expiry calls
|
|
500
|
-
`ReleasePayload()` while retaining identity and adapter allocations. Locks skip
|
|
501
|
-
both operations, and candidate failures are aggregated after the sweep has
|
|
502
|
-
continued over other entries.
|
|
503
|
-
|
|
504
|
-
`CjsResMan` also exposes opt-in automatic scheduling through
|
|
505
|
-
`SetAutoPurgePolicy()` or the `autoPurgePolicy` registration option. It is
|
|
506
|
-
disabled by default. Automatic policy is time-only because MotherLode's current
|
|
507
|
-
activity frame counts observations rather than renderer frames. A policy must
|
|
508
|
-
set at least one of `maxIdleMilliseconds` or
|
|
509
|
-
`payloadMaxIdleMilliseconds`; `intervalMilliseconds` defaults to 1000. The
|
|
510
|
-
first `PumpAutoPurge()`/`Update()` after configuration sweeps immediately, then
|
|
511
|
-
the interval sets the minimum cadence. `Update({ purge: false })` suppresses a
|
|
512
|
-
sweep for one update without changing cadence. A regressing clock rebases and
|
|
513
|
-
skips one pump; custom deterministic clocks should be shared with MotherLode.
|
|
514
|
-
Recorded-byte cache trimming is separate from this opt-in inactivity policy and
|
|
515
|
-
runs on ordinary updates unless `{ cache: false }` is supplied.
|
|
516
|
-
|
|
517
|
-
Both queued `QueueResourceObject()` work and direct `LoadResourceObject()` work
|
|
518
|
-
hold one manager-owned lock from request/loading publication through success or
|
|
519
|
-
failure. The lock is balanced independently of caller locks, so automatic or
|
|
520
|
-
manual sweeps cannot detach a handle while its read/prepare operation is still
|
|
521
|
-
active. Lock release is conditional on the same captured ownership generation,
|
|
522
|
-
so stale work cannot decrement a newly rebound handle's lock. Scheduling and
|
|
523
|
-
active-work protection do not fetch or reload data.
|
|
524
|
-
|
|
525
|
-
The processor preparing a resource decides when the full payload can be
|
|
526
|
-
released:
|
|
527
|
-
|
|
528
|
-
```text
|
|
529
|
-
format reader -> plain payload -> resource validation + adapter prepare
|
|
530
|
-
|
|
|
531
|
-
+-> resource retains required values/references
|
|
532
|
-
+-> adapter retains adapter-specific state/references
|
|
533
|
-
+-> release payload after successful preparation
|
|
534
|
-
`-> or renew its lease for deferred/further work
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
A time- or frame-based lease is a fallback against abandoned payloads. An owner
|
|
538
|
-
performing deferred work can renew the lease. If an expired payload is required
|
|
539
|
-
again, the caller must explicitly request reconstruction; lease renewal and
|
|
540
|
-
purging never fetch or reload source data. Dynamic or non-reloadable resources
|
|
541
|
-
must remain locked, retain the required payload, or be able to recreate it.
|
|
542
|
-
|
|
543
|
-
Payload references are shared read-only by default. Preparing WebGL and WebGPU
|
|
544
|
-
adapters side by side should normally pass the same payload to both consumers
|
|
545
|
-
and retain it until both have finished. Copying is an explicit consumer
|
|
546
|
-
operation, justified when a consumer must mutate data, transfer and detach an
|
|
547
|
-
`ArrayBuffer`, or retain an independently writable snapshot. The consumer
|
|
548
|
-
should copy only the fields it requires; runtime-resource should not
|
|
549
|
-
automatically deep-clone entire payload or typed-array bundles. Any full-copy
|
|
550
|
-
operation should be format-aware rather than a generic resource-side clone.
|
|
551
|
-
|
|
552
|
-
Open design questions:
|
|
553
|
-
|
|
554
|
-
- Should `Unload()` drop only adapter payloads by default, or CPU payloads too?
|
|
555
|
-
- Should there be explicit `UnloadAdapterResources()`, `UnloadPayload()`, and
|
|
556
|
-
`Purge()` phases?
|
|
557
|
-
- Which format/resource-specific estimators should supply separate identity,
|
|
558
|
-
CPU-payload, and adapter byte weights without double-counting shared buffers?
|
|
559
|
-
- Should manually attached/dynamic resources default to locked, like ccpwgl's
|
|
560
|
-
manual shader resources use `doNotPurge`?
|
|
561
|
-
- What explicit `Reload()`/reconstruction API should restore purged resources
|
|
562
|
-
without introducing surprising browser or network work?
|
|
563
|
-
|
|
564
|
-
ccpwgl's raw event emitter shape is useful. The part we should not copy is the
|
|
565
|
-
separate resource notification/callback compatibility layer that sits beside
|
|
566
|
-
events. CarbonEngineJS exposes one small event-emitter API and avoids short
|
|
567
|
-
generic names such as `On`, `Once`, `Off`, and `Emit` on Carbon-shaped classes.
|
|
568
|
-
`CjsEventEmitter` is a separate base class so non-model runtime services can
|
|
569
|
-
extend it without extending `CjsModel`; `CjsResMan` already uses that path.
|
|
570
|
-
|
|
571
|
-
The API stays deliberately direct:
|
|
572
|
-
|
|
573
|
-
- `AddEvents(events)`
|
|
574
|
-
- `OnEvent(eventName, listener, source?)`
|
|
575
|
-
- `OnceEvent(eventName, listener, source?)`
|
|
576
|
-
- `OffEvent(eventName = "*", listener?, source?)`
|
|
577
|
-
- `EmitEvent(eventName, ...args)`
|
|
578
|
-
- `HasEvent(eventName = "*", listener?, source?)`
|
|
579
|
-
- `ClearEvent(eventName = "*")`
|
|
580
|
-
- `GetEventNames()` and `GetEventListenerCount(eventName = "*")`
|
|
581
|
-
|
|
582
|
-
The optional `source` is the callback's `this` value and an explicit matching
|
|
583
|
-
identity for removal. Mutating event methods return the emitter for chaining.
|
|
584
|
-
There are no listener scopes, subscription handles, owner-side `ListenTo()`
|
|
585
|
-
helpers, or parallel resource notification callbacks.
|
|
586
|
-
|
|
587
|
-
Event names are normalized to lowercase and dispatched by exact match. Resource
|
|
588
|
-
classes may emit their own state or domain events, but the emitter does not
|
|
589
|
-
invent a resource lifecycle contract.
|
|
590
|
-
|
|
591
|
-
Event memory rules matter as much as event names. Event storage is the optional
|
|
592
|
-
`events` member of the emitter's non-enumerable `__state` object. It is created
|
|
593
|
-
only when the first listener is registered and deleted when the last record is
|
|
594
|
-
removed. That does not make listeners weak. As long as an emitter is reachable,
|
|
595
|
-
its event map strongly references listener functions and sources, and those
|
|
596
|
-
listeners can keep whole scene/resource graphs alive.
|
|
597
|
-
|
|
598
|
-
CarbonEngineJS event emitters should therefore follow these rules:
|
|
599
|
-
|
|
600
|
-
- `OnceEvent()` should remove the listener before or immediately after the first
|
|
601
|
-
callback, even if the callback throws.
|
|
602
|
-
- `OffEvent(eventName, listener, source)` must remove the exact listener/source
|
|
603
|
-
entry.
|
|
604
|
-
- an external party that no longer observes a target must call `OffEvent()`;
|
|
605
|
-
`target.OffEvent("*", null, source)` removes all of that source's records.
|
|
606
|
-
- `Unload()` and `Purge()` are resource state/cache operations, not an implied
|
|
607
|
-
listener-destruction lifecycle.
|
|
608
|
-
- `OnEvent()` returns the emitter, ccpwgl-style. It does not return unsubscribe
|
|
609
|
-
closures because those closures create another reference path.
|
|
610
|
-
- event payload history is not stored.
|
|
611
|
-
- we should prefer deterministic cleanup over `WeakRef`/`FinalizationRegistry`;
|
|
612
|
-
those can help diagnostics, but they are not a lifecycle contract.
|
|
613
|
-
|
|
614
|
-
The target is "easy to debug, hard to leak": clear ownership of who subscribed,
|
|
615
|
-
who unsubscribes, and which cleanup phase clears all remaining listeners.
|
|
616
|
-
|
|
617
|
-
The event data model is deliberately small:
|
|
618
|
-
|
|
619
|
-
```text
|
|
620
|
-
emitter.__state (non-enumerable, allocated only when some subsystem needs it)
|
|
621
|
-
events -> eventName -> Set<listenerRecord>
|
|
622
|
-
|
|
623
|
-
listenerRecord
|
|
624
|
-
emitter
|
|
625
|
-
eventName
|
|
626
|
-
listener
|
|
627
|
-
source
|
|
628
|
-
once
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
The event map is allocated only when the first listener is registered. If the
|
|
632
|
-
emitter becomes unreachable, its state and event records can be collected with
|
|
633
|
-
it. While the emitter remains reachable, listener functions and sources are
|
|
634
|
-
strongly retained until `OffEvent()`, `ClearEvent()`, once dispatch, or emitter
|
|
635
|
-
collection. Multiple listeners on the same event are allowed because each event
|
|
636
|
-
bucket is a set of records. A raw `CjsEventEmitter` does not gain model-owned
|
|
637
|
-
`dirty` or `rebuild` state.
|
|
638
|
-
|
|
639
|
-
This is as far as the event system should go for now:
|
|
640
|
-
|
|
641
|
-
- lowercase exact event names only.
|
|
642
|
-
- no wildcard listener dispatch.
|
|
643
|
-
- wildcard names are accepted only by lookup and cleanup methods.
|
|
644
|
-
- no listener scope or subscription-object layer.
|
|
645
|
-
- no separate resource notification/callback compatibility layer.
|
|
646
|
-
- no `family.event` or ancestor routing.
|
|
647
|
-
- no event history by default.
|
|
648
|
-
- no global master event manager.
|
|
649
|
-
- debugging introspection should stay limited to counts and names unless a real
|
|
650
|
-
use case appears.
|
|
651
|
-
|
|
652
|
-
`CjsModel` has dirty-state helpers (`MarkDirty`, `ClearDirty`, `ConsumeDirty`,
|
|
653
|
-
`GetDirtyNotifications`) for model invalidation. `SetValues()` compares incoming
|
|
654
|
-
values with the current field values and only marks dirty when a value actually
|
|
655
|
-
changes. A plain `MarkDirty()` means broad dirty invalidation; it does not request
|
|
656
|
-
a rebuild. Deferred rebuild reasons belong to the independent
|
|
657
|
-
`model.__state.rebuild` set. This is not a resource lifecycle event system.
|
|
658
|
-
Resource lifecycle events should therefore remain a resource/resman concern.
|
|
659
|
-
|
|
660
|
-
## Why We Diverge
|
|
661
|
-
|
|
662
|
-
The Carbon and ccpwgl resource classes live inside an engine that can prepare
|
|
663
|
-
GPU objects directly. CarbonEngineJS keeps the format/resource layer reusable by
|
|
664
|
-
stopping before GPU work:
|
|
665
|
-
|
|
666
|
-
- `runtime-resource` selects and runs registered non-shader readers, then can
|
|
667
|
-
directly hydrate the requested runtime class or return another requested
|
|
668
|
-
outcome.
|
|
669
|
-
- `runtime-resource` stores lifecycle state, cache entries, and loaded object
|
|
670
|
-
payloads. Plain reader results are normally transient prepare inputs; the
|
|
671
|
-
resource or adapter retains only what it requires, by reference or by
|
|
672
|
-
explicit copy.
|
|
673
|
-
- Frozen standalone non-shader `format-*` packages remain compatibility
|
|
674
|
-
distributions. GR2 and all shader formats remain separate packages for now.
|
|
675
|
-
- engine packages create WebGL/WebGPU textures, buffers, shader modules,
|
|
676
|
-
pipelines, and bind groups from loaded resources.
|
|
677
|
-
|
|
678
|
-
This gives us the Carbon lifecycle shape without forcing WebGL/WebGPU imports or
|
|
679
|
-
device decisions into `runtime-resource`.
|