@plasius/gpu-world-generator 0.0.10 → 0.0.11
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 +24 -0
- package/dist/index.cjs +603 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -1
- package/dist/index.d.ts +75 -1
- package/dist/index.js +594 -1
- package/dist/index.js.map +1 -1
- package/docs/adrs/adr-0004-worker-dag-manifests-for-chunk-and-voxel-generation.md +37 -0
- package/docs/adrs/index.md +1 -0
- package/docs/design/worker-manifest-integration.md +42 -0
- package/docs/tdrs/index.md +3 -0
- package/docs/tdrs/tdr-0001-world-generator-worker-manifest-contract.md +39 -0
- package/package.json +6 -3
- package/src/index.ts +1 -0
- package/src/worker.ts +710 -0
package/src/worker.ts
ADDED
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
export type WorldGeneratorWorkerQueueClass = "voxel";
|
|
2
|
+
export type WorldGeneratorWorkerProfileName = "streaming" | "bake";
|
|
3
|
+
export type WorldGeneratorWorkerDomain = "geometry" | "textures" | "custom";
|
|
4
|
+
export type WorldGeneratorWorkerAuthority =
|
|
5
|
+
| "visual"
|
|
6
|
+
| "non-authoritative-simulation"
|
|
7
|
+
| "authoritative";
|
|
8
|
+
export type WorldGeneratorWorkerImportance = "medium" | "high" | "critical";
|
|
9
|
+
|
|
10
|
+
export interface WorldGeneratorWorkerBudgetLevelConfig {
|
|
11
|
+
maxDispatchesPerFrame: number;
|
|
12
|
+
maxJobsPerDispatch: number;
|
|
13
|
+
cadenceDivisor: number;
|
|
14
|
+
workgroupScale: number;
|
|
15
|
+
maxQueueDepth: number;
|
|
16
|
+
metadata: Readonly<{
|
|
17
|
+
owner: typeof worldGeneratorDebugOwner;
|
|
18
|
+
queueClass: typeof worldGeneratorWorkerQueueClass;
|
|
19
|
+
jobType: string;
|
|
20
|
+
quality: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface WorldGeneratorWorkerBudgetLevel {
|
|
25
|
+
id: string;
|
|
26
|
+
estimatedCostMs: number;
|
|
27
|
+
config: WorldGeneratorWorkerBudgetLevelConfig;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface WorldGeneratorWorkerProfile {
|
|
31
|
+
readonly name: WorldGeneratorWorkerProfileName;
|
|
32
|
+
readonly description: string;
|
|
33
|
+
readonly jobs: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface WorldGeneratorWorkerManifestJob {
|
|
37
|
+
readonly key: string;
|
|
38
|
+
readonly label: string;
|
|
39
|
+
readonly worker: Readonly<{
|
|
40
|
+
jobType: string;
|
|
41
|
+
queueClass: typeof worldGeneratorWorkerQueueClass;
|
|
42
|
+
priority: number;
|
|
43
|
+
dependencies: readonly string[];
|
|
44
|
+
schedulerMode: "dag";
|
|
45
|
+
}>;
|
|
46
|
+
readonly performance: Readonly<{
|
|
47
|
+
id: string;
|
|
48
|
+
jobType: string;
|
|
49
|
+
queueClass: typeof worldGeneratorWorkerQueueClass;
|
|
50
|
+
domain: WorldGeneratorWorkerDomain;
|
|
51
|
+
authority: WorldGeneratorWorkerAuthority;
|
|
52
|
+
importance: WorldGeneratorWorkerImportance;
|
|
53
|
+
levels: readonly WorldGeneratorWorkerBudgetLevel[];
|
|
54
|
+
}>;
|
|
55
|
+
readonly debug: Readonly<{
|
|
56
|
+
owner: typeof worldGeneratorDebugOwner;
|
|
57
|
+
queueClass: typeof worldGeneratorWorkerQueueClass;
|
|
58
|
+
jobType: string;
|
|
59
|
+
tags: readonly string[];
|
|
60
|
+
suggestedAllocationIds: readonly string[];
|
|
61
|
+
}>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface WorldGeneratorWorkerManifest {
|
|
65
|
+
readonly schemaVersion: 1;
|
|
66
|
+
readonly owner: typeof worldGeneratorDebugOwner;
|
|
67
|
+
readonly profile: WorldGeneratorWorkerProfileName;
|
|
68
|
+
readonly description: string;
|
|
69
|
+
readonly queueClass: typeof worldGeneratorWorkerQueueClass;
|
|
70
|
+
readonly schedulerMode: "dag";
|
|
71
|
+
readonly suggestedAllocationIds: readonly string[];
|
|
72
|
+
readonly jobs: readonly WorldGeneratorWorkerManifestJob[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const worldGeneratorDebugOwner = "world-generator";
|
|
76
|
+
export const worldGeneratorWorkerQueueClass = "voxel";
|
|
77
|
+
export const defaultWorldGeneratorWorkerProfile = "streaming";
|
|
78
|
+
|
|
79
|
+
type WorkerLevelSpec = Omit<WorldGeneratorWorkerBudgetLevel, "config"> & {
|
|
80
|
+
config: Omit<WorldGeneratorWorkerBudgetLevelConfig, "metadata">;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type WorkerJobSpec = {
|
|
84
|
+
priority: number;
|
|
85
|
+
dependencies: readonly string[];
|
|
86
|
+
domain: WorldGeneratorWorkerDomain;
|
|
87
|
+
authority: WorldGeneratorWorkerAuthority;
|
|
88
|
+
importance: WorldGeneratorWorkerImportance;
|
|
89
|
+
levels: readonly WorkerLevelSpec[];
|
|
90
|
+
suggestedAllocationIds: readonly string[];
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type WorkerProfileSpec = {
|
|
94
|
+
description: string;
|
|
95
|
+
suggestedAllocationIds: readonly string[];
|
|
96
|
+
jobs: Readonly<Record<string, WorkerJobSpec>>;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function buildBudgetLevels(
|
|
100
|
+
jobType: string,
|
|
101
|
+
queueClass: WorldGeneratorWorkerQueueClass,
|
|
102
|
+
levels: readonly WorkerLevelSpec[]
|
|
103
|
+
) {
|
|
104
|
+
return Object.freeze(
|
|
105
|
+
levels.map((level) =>
|
|
106
|
+
Object.freeze({
|
|
107
|
+
id: level.id,
|
|
108
|
+
estimatedCostMs: level.estimatedCostMs,
|
|
109
|
+
config: Object.freeze({
|
|
110
|
+
maxDispatchesPerFrame: level.config.maxDispatchesPerFrame,
|
|
111
|
+
maxJobsPerDispatch: level.config.maxJobsPerDispatch,
|
|
112
|
+
cadenceDivisor: level.config.cadenceDivisor,
|
|
113
|
+
workgroupScale: level.config.workgroupScale,
|
|
114
|
+
maxQueueDepth: level.config.maxQueueDepth,
|
|
115
|
+
metadata: Object.freeze({
|
|
116
|
+
owner: worldGeneratorDebugOwner,
|
|
117
|
+
queueClass,
|
|
118
|
+
jobType,
|
|
119
|
+
quality: level.id,
|
|
120
|
+
}),
|
|
121
|
+
}),
|
|
122
|
+
})
|
|
123
|
+
)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const worldGeneratorWorkerProfileSpecs: Record<
|
|
128
|
+
WorldGeneratorWorkerProfileName,
|
|
129
|
+
WorkerProfileSpec
|
|
130
|
+
> = {
|
|
131
|
+
streaming: {
|
|
132
|
+
description:
|
|
133
|
+
"Runtime chunk generation DAG for fractal prepass, terrain synthesis, voxel materialization, mesh build, and tile bake.",
|
|
134
|
+
suggestedAllocationIds: [
|
|
135
|
+
"world.chunk.field.scratch",
|
|
136
|
+
"world.chunk.height.buffer",
|
|
137
|
+
"world.chunk.voxel.buffer",
|
|
138
|
+
"world.chunk.mesh.buffer",
|
|
139
|
+
],
|
|
140
|
+
jobs: {
|
|
141
|
+
fractalPrepass: {
|
|
142
|
+
priority: 4,
|
|
143
|
+
dependencies: [],
|
|
144
|
+
domain: "custom",
|
|
145
|
+
authority: "authoritative",
|
|
146
|
+
importance: "high",
|
|
147
|
+
levels: [
|
|
148
|
+
{
|
|
149
|
+
id: "fixed",
|
|
150
|
+
estimatedCostMs: 0.6,
|
|
151
|
+
config: {
|
|
152
|
+
maxDispatchesPerFrame: 1,
|
|
153
|
+
maxJobsPerDispatch: 1,
|
|
154
|
+
cadenceDivisor: 1,
|
|
155
|
+
workgroupScale: 1,
|
|
156
|
+
maxQueueDepth: 32,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
suggestedAllocationIds: ["world.chunk.field.scratch"],
|
|
161
|
+
},
|
|
162
|
+
fieldSynthesis: {
|
|
163
|
+
priority: 4,
|
|
164
|
+
dependencies: [],
|
|
165
|
+
domain: "custom",
|
|
166
|
+
authority: "authoritative",
|
|
167
|
+
importance: "critical",
|
|
168
|
+
levels: [
|
|
169
|
+
{
|
|
170
|
+
id: "fixed",
|
|
171
|
+
estimatedCostMs: 0.9,
|
|
172
|
+
config: {
|
|
173
|
+
maxDispatchesPerFrame: 1,
|
|
174
|
+
maxJobsPerDispatch: 2,
|
|
175
|
+
cadenceDivisor: 1,
|
|
176
|
+
workgroupScale: 1,
|
|
177
|
+
maxQueueDepth: 48,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
suggestedAllocationIds: ["world.chunk.field.scratch"],
|
|
182
|
+
},
|
|
183
|
+
terrainSynthesis: {
|
|
184
|
+
priority: 5,
|
|
185
|
+
dependencies: ["fractalPrepass", "fieldSynthesis"],
|
|
186
|
+
domain: "custom",
|
|
187
|
+
authority: "authoritative",
|
|
188
|
+
importance: "critical",
|
|
189
|
+
levels: [
|
|
190
|
+
{
|
|
191
|
+
id: "fixed",
|
|
192
|
+
estimatedCostMs: 1.4,
|
|
193
|
+
config: {
|
|
194
|
+
maxDispatchesPerFrame: 1,
|
|
195
|
+
maxJobsPerDispatch: 1,
|
|
196
|
+
cadenceDivisor: 1,
|
|
197
|
+
workgroupScale: 1,
|
|
198
|
+
maxQueueDepth: 32,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
suggestedAllocationIds: ["world.chunk.height.buffer"],
|
|
203
|
+
},
|
|
204
|
+
voxelMaterialize: {
|
|
205
|
+
priority: 3,
|
|
206
|
+
dependencies: ["terrainSynthesis"],
|
|
207
|
+
domain: "custom",
|
|
208
|
+
authority: "non-authoritative-simulation",
|
|
209
|
+
importance: "high",
|
|
210
|
+
levels: [
|
|
211
|
+
{
|
|
212
|
+
id: "low",
|
|
213
|
+
estimatedCostMs: 0.8,
|
|
214
|
+
config: {
|
|
215
|
+
maxDispatchesPerFrame: 1,
|
|
216
|
+
maxJobsPerDispatch: 1,
|
|
217
|
+
cadenceDivisor: 2,
|
|
218
|
+
workgroupScale: 0.6,
|
|
219
|
+
maxQueueDepth: 24,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
id: "medium",
|
|
224
|
+
estimatedCostMs: 1.2,
|
|
225
|
+
config: {
|
|
226
|
+
maxDispatchesPerFrame: 1,
|
|
227
|
+
maxJobsPerDispatch: 2,
|
|
228
|
+
cadenceDivisor: 1,
|
|
229
|
+
workgroupScale: 0.8,
|
|
230
|
+
maxQueueDepth: 32,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: "high",
|
|
235
|
+
estimatedCostMs: 1.8,
|
|
236
|
+
config: {
|
|
237
|
+
maxDispatchesPerFrame: 2,
|
|
238
|
+
maxJobsPerDispatch: 2,
|
|
239
|
+
cadenceDivisor: 1,
|
|
240
|
+
workgroupScale: 1,
|
|
241
|
+
maxQueueDepth: 40,
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
suggestedAllocationIds: ["world.chunk.voxel.buffer"],
|
|
246
|
+
},
|
|
247
|
+
meshBuild: {
|
|
248
|
+
priority: 2,
|
|
249
|
+
dependencies: ["terrainSynthesis", "voxelMaterialize"],
|
|
250
|
+
domain: "geometry",
|
|
251
|
+
authority: "visual",
|
|
252
|
+
importance: "high",
|
|
253
|
+
levels: [
|
|
254
|
+
{
|
|
255
|
+
id: "low",
|
|
256
|
+
estimatedCostMs: 0.7,
|
|
257
|
+
config: {
|
|
258
|
+
maxDispatchesPerFrame: 1,
|
|
259
|
+
maxJobsPerDispatch: 1,
|
|
260
|
+
cadenceDivisor: 2,
|
|
261
|
+
workgroupScale: 0.6,
|
|
262
|
+
maxQueueDepth: 16,
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: "medium",
|
|
267
|
+
estimatedCostMs: 1.1,
|
|
268
|
+
config: {
|
|
269
|
+
maxDispatchesPerFrame: 1,
|
|
270
|
+
maxJobsPerDispatch: 1,
|
|
271
|
+
cadenceDivisor: 1,
|
|
272
|
+
workgroupScale: 0.8,
|
|
273
|
+
maxQueueDepth: 24,
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
id: "high",
|
|
278
|
+
estimatedCostMs: 1.6,
|
|
279
|
+
config: {
|
|
280
|
+
maxDispatchesPerFrame: 2,
|
|
281
|
+
maxJobsPerDispatch: 2,
|
|
282
|
+
cadenceDivisor: 1,
|
|
283
|
+
workgroupScale: 1,
|
|
284
|
+
maxQueueDepth: 32,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
suggestedAllocationIds: ["world.chunk.mesh.buffer"],
|
|
289
|
+
},
|
|
290
|
+
tileBake: {
|
|
291
|
+
priority: 2,
|
|
292
|
+
dependencies: ["terrainSynthesis"],
|
|
293
|
+
domain: "textures",
|
|
294
|
+
authority: "non-authoritative-simulation",
|
|
295
|
+
importance: "medium",
|
|
296
|
+
levels: [
|
|
297
|
+
{
|
|
298
|
+
id: "low",
|
|
299
|
+
estimatedCostMs: 0.6,
|
|
300
|
+
config: {
|
|
301
|
+
maxDispatchesPerFrame: 1,
|
|
302
|
+
maxJobsPerDispatch: 1,
|
|
303
|
+
cadenceDivisor: 3,
|
|
304
|
+
workgroupScale: 0.5,
|
|
305
|
+
maxQueueDepth: 16,
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
id: "medium",
|
|
310
|
+
estimatedCostMs: 0.9,
|
|
311
|
+
config: {
|
|
312
|
+
maxDispatchesPerFrame: 1,
|
|
313
|
+
maxJobsPerDispatch: 1,
|
|
314
|
+
cadenceDivisor: 2,
|
|
315
|
+
workgroupScale: 0.75,
|
|
316
|
+
maxQueueDepth: 24,
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
id: "high",
|
|
321
|
+
estimatedCostMs: 1.3,
|
|
322
|
+
config: {
|
|
323
|
+
maxDispatchesPerFrame: 2,
|
|
324
|
+
maxJobsPerDispatch: 2,
|
|
325
|
+
cadenceDivisor: 1,
|
|
326
|
+
workgroupScale: 1,
|
|
327
|
+
maxQueueDepth: 32,
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
],
|
|
331
|
+
suggestedAllocationIds: ["world.chunk.height.buffer"],
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
bake: {
|
|
336
|
+
description:
|
|
337
|
+
"Offline tile bake DAG for terrain generation, voxel materialization, mesh build, and asset serialization.",
|
|
338
|
+
suggestedAllocationIds: [
|
|
339
|
+
"world.bake.field.scratch",
|
|
340
|
+
"world.bake.height.buffer",
|
|
341
|
+
"world.bake.mesh.buffer",
|
|
342
|
+
"world.bake.asset.binary",
|
|
343
|
+
],
|
|
344
|
+
jobs: {
|
|
345
|
+
fractalPrepass: {
|
|
346
|
+
priority: 4,
|
|
347
|
+
dependencies: [],
|
|
348
|
+
domain: "custom",
|
|
349
|
+
authority: "authoritative",
|
|
350
|
+
importance: "high",
|
|
351
|
+
levels: [
|
|
352
|
+
{
|
|
353
|
+
id: "fixed",
|
|
354
|
+
estimatedCostMs: 0.7,
|
|
355
|
+
config: {
|
|
356
|
+
maxDispatchesPerFrame: 1,
|
|
357
|
+
maxJobsPerDispatch: 1,
|
|
358
|
+
cadenceDivisor: 1,
|
|
359
|
+
workgroupScale: 1,
|
|
360
|
+
maxQueueDepth: 32,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
suggestedAllocationIds: ["world.bake.field.scratch"],
|
|
365
|
+
},
|
|
366
|
+
fieldSynthesis: {
|
|
367
|
+
priority: 4,
|
|
368
|
+
dependencies: [],
|
|
369
|
+
domain: "custom",
|
|
370
|
+
authority: "authoritative",
|
|
371
|
+
importance: "critical",
|
|
372
|
+
levels: [
|
|
373
|
+
{
|
|
374
|
+
id: "fixed",
|
|
375
|
+
estimatedCostMs: 1.0,
|
|
376
|
+
config: {
|
|
377
|
+
maxDispatchesPerFrame: 1,
|
|
378
|
+
maxJobsPerDispatch: 2,
|
|
379
|
+
cadenceDivisor: 1,
|
|
380
|
+
workgroupScale: 1,
|
|
381
|
+
maxQueueDepth: 48,
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
suggestedAllocationIds: ["world.bake.field.scratch"],
|
|
386
|
+
},
|
|
387
|
+
terrainSynthesis: {
|
|
388
|
+
priority: 5,
|
|
389
|
+
dependencies: ["fractalPrepass", "fieldSynthesis"],
|
|
390
|
+
domain: "custom",
|
|
391
|
+
authority: "authoritative",
|
|
392
|
+
importance: "critical",
|
|
393
|
+
levels: [
|
|
394
|
+
{
|
|
395
|
+
id: "fixed",
|
|
396
|
+
estimatedCostMs: 1.6,
|
|
397
|
+
config: {
|
|
398
|
+
maxDispatchesPerFrame: 1,
|
|
399
|
+
maxJobsPerDispatch: 1,
|
|
400
|
+
cadenceDivisor: 1,
|
|
401
|
+
workgroupScale: 1,
|
|
402
|
+
maxQueueDepth: 32,
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
suggestedAllocationIds: ["world.bake.height.buffer"],
|
|
407
|
+
},
|
|
408
|
+
voxelMaterialize: {
|
|
409
|
+
priority: 3,
|
|
410
|
+
dependencies: ["terrainSynthesis"],
|
|
411
|
+
domain: "custom",
|
|
412
|
+
authority: "non-authoritative-simulation",
|
|
413
|
+
importance: "high",
|
|
414
|
+
levels: [
|
|
415
|
+
{
|
|
416
|
+
id: "low",
|
|
417
|
+
estimatedCostMs: 0.9,
|
|
418
|
+
config: {
|
|
419
|
+
maxDispatchesPerFrame: 1,
|
|
420
|
+
maxJobsPerDispatch: 1,
|
|
421
|
+
cadenceDivisor: 2,
|
|
422
|
+
workgroupScale: 0.6,
|
|
423
|
+
maxQueueDepth: 24,
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: "medium",
|
|
428
|
+
estimatedCostMs: 1.4,
|
|
429
|
+
config: {
|
|
430
|
+
maxDispatchesPerFrame: 1,
|
|
431
|
+
maxJobsPerDispatch: 2,
|
|
432
|
+
cadenceDivisor: 1,
|
|
433
|
+
workgroupScale: 0.8,
|
|
434
|
+
maxQueueDepth: 32,
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: "high",
|
|
439
|
+
estimatedCostMs: 2.0,
|
|
440
|
+
config: {
|
|
441
|
+
maxDispatchesPerFrame: 2,
|
|
442
|
+
maxJobsPerDispatch: 2,
|
|
443
|
+
cadenceDivisor: 1,
|
|
444
|
+
workgroupScale: 1,
|
|
445
|
+
maxQueueDepth: 48,
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
],
|
|
449
|
+
suggestedAllocationIds: ["world.bake.height.buffer"],
|
|
450
|
+
},
|
|
451
|
+
meshBuild: {
|
|
452
|
+
priority: 2,
|
|
453
|
+
dependencies: ["terrainSynthesis", "voxelMaterialize"],
|
|
454
|
+
domain: "geometry",
|
|
455
|
+
authority: "visual",
|
|
456
|
+
importance: "high",
|
|
457
|
+
levels: [
|
|
458
|
+
{
|
|
459
|
+
id: "low",
|
|
460
|
+
estimatedCostMs: 0.9,
|
|
461
|
+
config: {
|
|
462
|
+
maxDispatchesPerFrame: 1,
|
|
463
|
+
maxJobsPerDispatch: 1,
|
|
464
|
+
cadenceDivisor: 2,
|
|
465
|
+
workgroupScale: 0.6,
|
|
466
|
+
maxQueueDepth: 16,
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
id: "medium",
|
|
471
|
+
estimatedCostMs: 1.3,
|
|
472
|
+
config: {
|
|
473
|
+
maxDispatchesPerFrame: 1,
|
|
474
|
+
maxJobsPerDispatch: 1,
|
|
475
|
+
cadenceDivisor: 1,
|
|
476
|
+
workgroupScale: 0.8,
|
|
477
|
+
maxQueueDepth: 24,
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
id: "high",
|
|
482
|
+
estimatedCostMs: 1.9,
|
|
483
|
+
config: {
|
|
484
|
+
maxDispatchesPerFrame: 2,
|
|
485
|
+
maxJobsPerDispatch: 2,
|
|
486
|
+
cadenceDivisor: 1,
|
|
487
|
+
workgroupScale: 1,
|
|
488
|
+
maxQueueDepth: 32,
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
],
|
|
492
|
+
suggestedAllocationIds: ["world.bake.mesh.buffer"],
|
|
493
|
+
},
|
|
494
|
+
tileBake: {
|
|
495
|
+
priority: 2,
|
|
496
|
+
dependencies: ["terrainSynthesis"],
|
|
497
|
+
domain: "textures",
|
|
498
|
+
authority: "non-authoritative-simulation",
|
|
499
|
+
importance: "medium",
|
|
500
|
+
levels: [
|
|
501
|
+
{
|
|
502
|
+
id: "low",
|
|
503
|
+
estimatedCostMs: 0.8,
|
|
504
|
+
config: {
|
|
505
|
+
maxDispatchesPerFrame: 1,
|
|
506
|
+
maxJobsPerDispatch: 1,
|
|
507
|
+
cadenceDivisor: 3,
|
|
508
|
+
workgroupScale: 0.5,
|
|
509
|
+
maxQueueDepth: 16,
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
id: "medium",
|
|
514
|
+
estimatedCostMs: 1.1,
|
|
515
|
+
config: {
|
|
516
|
+
maxDispatchesPerFrame: 1,
|
|
517
|
+
maxJobsPerDispatch: 1,
|
|
518
|
+
cadenceDivisor: 2,
|
|
519
|
+
workgroupScale: 0.75,
|
|
520
|
+
maxQueueDepth: 24,
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
id: "high",
|
|
525
|
+
estimatedCostMs: 1.5,
|
|
526
|
+
config: {
|
|
527
|
+
maxDispatchesPerFrame: 2,
|
|
528
|
+
maxJobsPerDispatch: 2,
|
|
529
|
+
cadenceDivisor: 1,
|
|
530
|
+
workgroupScale: 1,
|
|
531
|
+
maxQueueDepth: 32,
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
],
|
|
535
|
+
suggestedAllocationIds: ["world.bake.height.buffer"],
|
|
536
|
+
},
|
|
537
|
+
assetSerialize: {
|
|
538
|
+
priority: 1,
|
|
539
|
+
dependencies: ["meshBuild", "tileBake"],
|
|
540
|
+
domain: "custom",
|
|
541
|
+
authority: "non-authoritative-simulation",
|
|
542
|
+
importance: "medium",
|
|
543
|
+
levels: [
|
|
544
|
+
{
|
|
545
|
+
id: "low",
|
|
546
|
+
estimatedCostMs: 0.4,
|
|
547
|
+
config: {
|
|
548
|
+
maxDispatchesPerFrame: 1,
|
|
549
|
+
maxJobsPerDispatch: 1,
|
|
550
|
+
cadenceDivisor: 4,
|
|
551
|
+
workgroupScale: 0.5,
|
|
552
|
+
maxQueueDepth: 8,
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
id: "medium",
|
|
557
|
+
estimatedCostMs: 0.7,
|
|
558
|
+
config: {
|
|
559
|
+
maxDispatchesPerFrame: 1,
|
|
560
|
+
maxJobsPerDispatch: 1,
|
|
561
|
+
cadenceDivisor: 2,
|
|
562
|
+
workgroupScale: 0.75,
|
|
563
|
+
maxQueueDepth: 12,
|
|
564
|
+
},
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
id: "high",
|
|
568
|
+
estimatedCostMs: 1.0,
|
|
569
|
+
config: {
|
|
570
|
+
maxDispatchesPerFrame: 2,
|
|
571
|
+
maxJobsPerDispatch: 2,
|
|
572
|
+
cadenceDivisor: 1,
|
|
573
|
+
workgroupScale: 1,
|
|
574
|
+
maxQueueDepth: 16,
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
suggestedAllocationIds: ["world.bake.asset.binary"],
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
function buildWorldGeneratorWorkerProfile(
|
|
585
|
+
name: WorldGeneratorWorkerProfileName,
|
|
586
|
+
spec: WorkerProfileSpec
|
|
587
|
+
) {
|
|
588
|
+
return Object.freeze({
|
|
589
|
+
name,
|
|
590
|
+
description: spec.description,
|
|
591
|
+
jobs: Object.freeze(Object.keys(spec.jobs)),
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function buildWorldGeneratorWorkerManifestJob(
|
|
596
|
+
profileName: WorldGeneratorWorkerProfileName,
|
|
597
|
+
jobName: string,
|
|
598
|
+
spec: WorkerJobSpec
|
|
599
|
+
) {
|
|
600
|
+
const label = `world-generator.${profileName}.${jobName}`;
|
|
601
|
+
return Object.freeze({
|
|
602
|
+
key: jobName,
|
|
603
|
+
label,
|
|
604
|
+
worker: Object.freeze({
|
|
605
|
+
jobType: label,
|
|
606
|
+
queueClass: worldGeneratorWorkerQueueClass,
|
|
607
|
+
priority: spec.priority,
|
|
608
|
+
dependencies: Object.freeze(
|
|
609
|
+
spec.dependencies.map(
|
|
610
|
+
(dependency) => `world-generator.${profileName}.${dependency}`
|
|
611
|
+
)
|
|
612
|
+
),
|
|
613
|
+
schedulerMode: "dag",
|
|
614
|
+
}),
|
|
615
|
+
performance: Object.freeze({
|
|
616
|
+
id: label,
|
|
617
|
+
jobType: label,
|
|
618
|
+
queueClass: worldGeneratorWorkerQueueClass,
|
|
619
|
+
domain: spec.domain,
|
|
620
|
+
authority: spec.authority,
|
|
621
|
+
importance: spec.importance,
|
|
622
|
+
levels: buildBudgetLevels(
|
|
623
|
+
label,
|
|
624
|
+
worldGeneratorWorkerQueueClass,
|
|
625
|
+
spec.levels
|
|
626
|
+
),
|
|
627
|
+
}),
|
|
628
|
+
debug: Object.freeze({
|
|
629
|
+
owner: worldGeneratorDebugOwner,
|
|
630
|
+
queueClass: worldGeneratorWorkerQueueClass,
|
|
631
|
+
jobType: label,
|
|
632
|
+
tags: Object.freeze(["world-generator", profileName, jobName, spec.domain]),
|
|
633
|
+
suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds]),
|
|
634
|
+
}),
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function buildWorldGeneratorWorkerManifest(
|
|
639
|
+
name: WorldGeneratorWorkerProfileName,
|
|
640
|
+
spec: WorkerProfileSpec
|
|
641
|
+
) {
|
|
642
|
+
return Object.freeze({
|
|
643
|
+
schemaVersion: 1,
|
|
644
|
+
owner: worldGeneratorDebugOwner,
|
|
645
|
+
profile: name,
|
|
646
|
+
description: spec.description,
|
|
647
|
+
queueClass: worldGeneratorWorkerQueueClass,
|
|
648
|
+
schedulerMode: "dag",
|
|
649
|
+
suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds]),
|
|
650
|
+
jobs: Object.freeze(
|
|
651
|
+
Object.entries(spec.jobs).map(([jobName, jobSpec]) =>
|
|
652
|
+
buildWorldGeneratorWorkerManifestJob(name, jobName, jobSpec)
|
|
653
|
+
)
|
|
654
|
+
),
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
export const worldGeneratorWorkerProfiles = Object.freeze(
|
|
659
|
+
Object.fromEntries(
|
|
660
|
+
Object.entries(worldGeneratorWorkerProfileSpecs).map(([name, spec]) => [
|
|
661
|
+
name,
|
|
662
|
+
buildWorldGeneratorWorkerProfile(
|
|
663
|
+
name as WorldGeneratorWorkerProfileName,
|
|
664
|
+
spec
|
|
665
|
+
),
|
|
666
|
+
])
|
|
667
|
+
)
|
|
668
|
+
) as Readonly<Record<WorldGeneratorWorkerProfileName, WorldGeneratorWorkerProfile>>;
|
|
669
|
+
|
|
670
|
+
export const worldGeneratorWorkerProfileNames = Object.freeze(
|
|
671
|
+
Object.keys(worldGeneratorWorkerProfiles)
|
|
672
|
+
) as readonly WorldGeneratorWorkerProfileName[];
|
|
673
|
+
|
|
674
|
+
export const worldGeneratorWorkerManifests = Object.freeze(
|
|
675
|
+
Object.fromEntries(
|
|
676
|
+
Object.entries(worldGeneratorWorkerProfileSpecs).map(([name, spec]) => [
|
|
677
|
+
name,
|
|
678
|
+
buildWorldGeneratorWorkerManifest(
|
|
679
|
+
name as WorldGeneratorWorkerProfileName,
|
|
680
|
+
spec
|
|
681
|
+
),
|
|
682
|
+
])
|
|
683
|
+
)
|
|
684
|
+
) as Readonly<Record<WorldGeneratorWorkerProfileName, WorldGeneratorWorkerManifest>>;
|
|
685
|
+
|
|
686
|
+
export function getWorldGeneratorWorkerProfile(
|
|
687
|
+
name: WorldGeneratorWorkerProfileName = defaultWorldGeneratorWorkerProfile
|
|
688
|
+
) {
|
|
689
|
+
const profile = worldGeneratorWorkerProfiles[name];
|
|
690
|
+
if (!profile) {
|
|
691
|
+
const available = worldGeneratorWorkerProfileNames.join(", ");
|
|
692
|
+
throw new Error(
|
|
693
|
+
`Unknown world-generator worker profile "${name}". Available: ${available}.`
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
return profile;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export function getWorldGeneratorWorkerManifest(
|
|
700
|
+
name: WorldGeneratorWorkerProfileName = defaultWorldGeneratorWorkerProfile
|
|
701
|
+
) {
|
|
702
|
+
const manifest = worldGeneratorWorkerManifests[name];
|
|
703
|
+
if (!manifest) {
|
|
704
|
+
const available = worldGeneratorWorkerProfileNames.join(", ");
|
|
705
|
+
throw new Error(
|
|
706
|
+
`Unknown world-generator worker profile "${name}". Available: ${available}.`
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
return manifest;
|
|
710
|
+
}
|