@plasius/gpu-renderer 0.2.42 → 0.2.44
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/CHANGELOG.md +60 -1
- package/README.md +51 -3
- package/dist/index.cjs +381 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +381 -42
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
- package/src/feedback-diagnostics.js +190 -0
- package/src/index.d.ts +99 -13
- package/src/index.js +6 -0
- package/src/wavefront-compute.js +31 -46
- package/src/wavefront-config.js +161 -23
- package/src/wavefront-gpu-resources.js +8 -1
- package/src/wavefront-runtime-support.js +73 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plasius/gpu-renderer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"description": "Framework-agnostic WebGPU renderer runtime for Plasius projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsup",
|
|
29
29
|
"demo": "python3 -m http.server --directory ..",
|
|
30
|
-
"typecheck": "node scripts/check-source-syntax.cjs",
|
|
30
|
+
"typecheck": "node scripts/check-source-syntax.cjs && tsc -p tsconfig.types.json && node scripts/verify-clean-type-consumer.cjs",
|
|
31
31
|
"audit:eslint": "eslint . --max-warnings=0",
|
|
32
32
|
"audit:deps": "npm ls --all --omit=optional --omit=peer > /dev/null 2>&1 || true",
|
|
33
33
|
"audit:npm": "npm audit --audit-level=high --omit=dev",
|
|
@@ -53,14 +53,15 @@
|
|
|
53
53
|
"license": "Apache-2.0",
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@plasius/gpu-camera": "^0.1.18",
|
|
56
|
-
"@plasius/gpu-shared": "^1.
|
|
57
|
-
"@plasius/gpu-xr": "^0.1.17"
|
|
56
|
+
"@plasius/gpu-shared": "^1.1.1",
|
|
57
|
+
"@plasius/gpu-xr": "^0.1.17",
|
|
58
|
+
"@types/webxr": "^0.5.24"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"@eslint/js": "^10.0.1",
|
|
61
62
|
"c8": "^11.0.0",
|
|
62
|
-
"eslint": "^10.
|
|
63
|
-
"globals": "^17.
|
|
63
|
+
"eslint": "^10.9.1",
|
|
64
|
+
"globals": "^17.11.0",
|
|
64
65
|
"tsup": "^8.5.1",
|
|
65
66
|
"typescript": "^7.0.2"
|
|
66
67
|
},
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FEEDBACK_GAME_DIAGNOSTICS_CONTRACT_VERSION,
|
|
3
|
+
feedbackGameDiagnosticSurfaceRegistrations,
|
|
4
|
+
parseFeedbackGameDiagnostics,
|
|
5
|
+
} from "@plasius/gpu-shared/feedback-diagnostics";
|
|
6
|
+
|
|
7
|
+
const inputKeys = Object.freeze([
|
|
8
|
+
"featureEnabled",
|
|
9
|
+
"capabilityGranted",
|
|
10
|
+
"consentConfirmed",
|
|
11
|
+
"surfaceId",
|
|
12
|
+
"renderer",
|
|
13
|
+
"backend",
|
|
14
|
+
"viewportWidth",
|
|
15
|
+
"viewportHeight",
|
|
16
|
+
"frameRate",
|
|
17
|
+
"frameTimeMs",
|
|
18
|
+
"featureIds",
|
|
19
|
+
"counters",
|
|
20
|
+
"errorCodes",
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
export function bucketFeedbackGameViewport(width, height) {
|
|
24
|
+
if (
|
|
25
|
+
typeof width !== "number" ||
|
|
26
|
+
typeof height !== "number" ||
|
|
27
|
+
!Number.isFinite(width) ||
|
|
28
|
+
!Number.isFinite(height) ||
|
|
29
|
+
width <= 0 ||
|
|
30
|
+
height <= 0
|
|
31
|
+
) {
|
|
32
|
+
return "unknown";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const shorterEdge = Math.min(width, height);
|
|
36
|
+
const longerEdge = Math.max(width, height);
|
|
37
|
+
const size =
|
|
38
|
+
shorterEdge < 600
|
|
39
|
+
? "small"
|
|
40
|
+
: shorterEdge < 900 || longerEdge < 1_440
|
|
41
|
+
? "medium"
|
|
42
|
+
: "large";
|
|
43
|
+
const orientation = width > height ? "landscape" : "portrait";
|
|
44
|
+
return `${size}-${orientation}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function bucketFeedbackGameFrameRate(frameRate) {
|
|
48
|
+
if (
|
|
49
|
+
typeof frameRate !== "number" ||
|
|
50
|
+
!Number.isFinite(frameRate) ||
|
|
51
|
+
frameRate < 0
|
|
52
|
+
) {
|
|
53
|
+
return "unknown";
|
|
54
|
+
}
|
|
55
|
+
if (frameRate < 15) {
|
|
56
|
+
return "under-15";
|
|
57
|
+
}
|
|
58
|
+
if (frameRate < 30) {
|
|
59
|
+
return "15-29";
|
|
60
|
+
}
|
|
61
|
+
if (frameRate < 60) {
|
|
62
|
+
return "30-59";
|
|
63
|
+
}
|
|
64
|
+
return "60-plus";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function bucketFeedbackGameFrameTime(frameTimeMs) {
|
|
68
|
+
if (
|
|
69
|
+
typeof frameTimeMs !== "number" ||
|
|
70
|
+
!Number.isFinite(frameTimeMs) ||
|
|
71
|
+
frameTimeMs < 0
|
|
72
|
+
) {
|
|
73
|
+
return "unknown";
|
|
74
|
+
}
|
|
75
|
+
if (frameTimeMs < 17) {
|
|
76
|
+
return "under-17ms";
|
|
77
|
+
}
|
|
78
|
+
if (frameTimeMs < 34) {
|
|
79
|
+
return "17-33ms";
|
|
80
|
+
}
|
|
81
|
+
if (frameTimeMs < 67) {
|
|
82
|
+
return "34-66ms";
|
|
83
|
+
}
|
|
84
|
+
return "over-66ms";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createFeedbackGameDiagnosticSnapshot(input) {
|
|
88
|
+
try {
|
|
89
|
+
return createFeedbackGameDiagnosticSnapshotInternal(input);
|
|
90
|
+
} catch {
|
|
91
|
+
throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function createFeedbackGameDiagnosticSnapshotInternal(input) {
|
|
96
|
+
const snapshot = snapshotInputIfEnabled(input);
|
|
97
|
+
if (snapshot === null) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const registration =
|
|
102
|
+
typeof snapshot.surfaceId === "string" &&
|
|
103
|
+
Object.hasOwn(
|
|
104
|
+
feedbackGameDiagnosticSurfaceRegistrations,
|
|
105
|
+
snapshot.surfaceId
|
|
106
|
+
)
|
|
107
|
+
? feedbackGameDiagnosticSurfaceRegistrations[snapshot.surfaceId]
|
|
108
|
+
: undefined;
|
|
109
|
+
|
|
110
|
+
return parseFeedbackGameDiagnostics({
|
|
111
|
+
type: "feedback-game-diagnostics",
|
|
112
|
+
version: FEEDBACK_GAME_DIAGNOSTICS_CONTRACT_VERSION,
|
|
113
|
+
surfaceId: snapshot.surfaceId,
|
|
114
|
+
consentConfirmed: true,
|
|
115
|
+
provenanceContractId: registration?.provenanceContractId,
|
|
116
|
+
renderer: snapshot.renderer,
|
|
117
|
+
backend: snapshot.backend,
|
|
118
|
+
viewportBucket: bucketFeedbackGameViewport(
|
|
119
|
+
snapshot.viewportWidth,
|
|
120
|
+
snapshot.viewportHeight
|
|
121
|
+
),
|
|
122
|
+
frameRateBucket: bucketFeedbackGameFrameRate(snapshot.frameRate),
|
|
123
|
+
frameTimeBucket: bucketFeedbackGameFrameTime(snapshot.frameTimeMs),
|
|
124
|
+
featureIds: snapshot.featureIds,
|
|
125
|
+
counters: snapshot.counters,
|
|
126
|
+
errorCodes: snapshot.errorCodes,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function snapshotInputIfEnabled(input) {
|
|
131
|
+
assertValid(
|
|
132
|
+
input !== null &&
|
|
133
|
+
typeof input === "object" &&
|
|
134
|
+
!Array.isArray(input) &&
|
|
135
|
+
(Object.getPrototypeOf(input) === Object.prototype ||
|
|
136
|
+
Object.getPrototypeOf(input) === null)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const gateKeys = [
|
|
140
|
+
"featureEnabled",
|
|
141
|
+
"capabilityGranted",
|
|
142
|
+
"consentConfirmed",
|
|
143
|
+
];
|
|
144
|
+
const snapshot = Object.create(null);
|
|
145
|
+
for (const key of gateKeys) {
|
|
146
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
147
|
+
assertValid(
|
|
148
|
+
descriptor !== undefined &&
|
|
149
|
+
descriptor.enumerable === true &&
|
|
150
|
+
Object.hasOwn(descriptor, "value") &&
|
|
151
|
+
typeof descriptor.value === "boolean"
|
|
152
|
+
);
|
|
153
|
+
snapshot[key] = descriptor.value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const { featureEnabled, capabilityGranted, consentConfirmed } = snapshot;
|
|
157
|
+
if (
|
|
158
|
+
!featureEnabled ||
|
|
159
|
+
!capabilityGranted ||
|
|
160
|
+
!consentConfirmed
|
|
161
|
+
) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const actualKeys = Reflect.ownKeys(input);
|
|
166
|
+
assertValid(
|
|
167
|
+
actualKeys.length === inputKeys.length &&
|
|
168
|
+
inputKeys.every((key) => actualKeys.includes(key)) &&
|
|
169
|
+
actualKeys.every(
|
|
170
|
+
(key) => typeof key === "string" && inputKeys.includes(key)
|
|
171
|
+
)
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
for (const key of inputKeys.filter((key) => !gateKeys.includes(key))) {
|
|
175
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
176
|
+
assertValid(
|
|
177
|
+
descriptor !== undefined &&
|
|
178
|
+
descriptor.enumerable === true &&
|
|
179
|
+
Object.hasOwn(descriptor, "value")
|
|
180
|
+
);
|
|
181
|
+
snapshot[key] = descriptor.value;
|
|
182
|
+
}
|
|
183
|
+
return Object.freeze(snapshot);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function assertValid(condition) {
|
|
187
|
+
if (!condition) {
|
|
188
|
+
throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
|
|
189
|
+
}
|
|
190
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
|
+
/// <reference types="webxr" />
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
FeedbackGameDiagnosticBackend,
|
|
5
|
+
FeedbackGameDiagnosticCounter,
|
|
6
|
+
FeedbackGameDiagnosticErrorCode,
|
|
7
|
+
FeedbackGameDiagnosticFeatureId,
|
|
8
|
+
FeedbackGameDiagnosticFrameRateBucket,
|
|
9
|
+
FeedbackGameDiagnosticFrameTimeBucket,
|
|
10
|
+
FeedbackGameDiagnostics,
|
|
11
|
+
FeedbackGameDiagnosticRenderer,
|
|
12
|
+
FeedbackGameDiagnosticSurfaceId,
|
|
13
|
+
FeedbackGameDiagnosticViewportBucket,
|
|
14
|
+
} from "@plasius/gpu-shared/feedback-diagnostics";
|
|
15
|
+
import type { XrStoreState } from "@plasius/gpu-xr";
|
|
16
|
+
|
|
17
|
+
export interface CreateFeedbackGameDiagnosticSnapshotInput {
|
|
18
|
+
readonly featureEnabled: boolean;
|
|
19
|
+
readonly capabilityGranted: boolean;
|
|
20
|
+
readonly consentConfirmed: boolean;
|
|
21
|
+
readonly surfaceId: FeedbackGameDiagnosticSurfaceId;
|
|
22
|
+
readonly renderer: FeedbackGameDiagnosticRenderer;
|
|
23
|
+
readonly backend: FeedbackGameDiagnosticBackend;
|
|
24
|
+
/** CSS-pixel viewport width; it is bucketed synchronously and never returned. */
|
|
25
|
+
readonly viewportWidth: number | null;
|
|
26
|
+
/** CSS-pixel viewport height; it is bucketed synchronously and never returned. */
|
|
27
|
+
readonly viewportHeight: number | null;
|
|
28
|
+
/** Recent coarse FPS observation; it is bucketed synchronously and never returned. */
|
|
29
|
+
readonly frameRate: number | null;
|
|
30
|
+
/** Recent coarse frame-time observation; it is bucketed synchronously and never returned. */
|
|
31
|
+
readonly frameTimeMs: number | null;
|
|
32
|
+
readonly featureIds: readonly FeedbackGameDiagnosticFeatureId[];
|
|
33
|
+
readonly counters: readonly FeedbackGameDiagnosticCounter[];
|
|
34
|
+
readonly errorCodes: readonly FeedbackGameDiagnosticErrorCode[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function bucketFeedbackGameViewport(
|
|
38
|
+
width: unknown,
|
|
39
|
+
height: unknown,
|
|
40
|
+
): FeedbackGameDiagnosticViewportBucket;
|
|
41
|
+
|
|
42
|
+
export function bucketFeedbackGameFrameRate(
|
|
43
|
+
frameRate: unknown,
|
|
44
|
+
): FeedbackGameDiagnosticFrameRateBucket;
|
|
45
|
+
|
|
46
|
+
export function bucketFeedbackGameFrameTime(
|
|
47
|
+
frameTimeMs: unknown,
|
|
48
|
+
): FeedbackGameDiagnosticFrameTimeBucket;
|
|
49
|
+
|
|
50
|
+
export function createFeedbackGameDiagnosticSnapshot<
|
|
51
|
+
SurfaceId extends FeedbackGameDiagnosticSurfaceId,
|
|
52
|
+
>(
|
|
53
|
+
input: CreateFeedbackGameDiagnosticSnapshotInput & {
|
|
54
|
+
readonly surfaceId: SurfaceId;
|
|
55
|
+
},
|
|
56
|
+
): Extract<FeedbackGameDiagnostics, { readonly surfaceId: SurfaceId }> | null;
|
|
57
|
+
|
|
1
58
|
export type RendererColor = string | [number, number, number, number?];
|
|
2
59
|
export type AnimatedSceneVector3 = readonly [number, number, number] | readonly number[];
|
|
3
60
|
export type AnimatedScenePropKind =
|
|
@@ -509,7 +566,6 @@ export interface WavefrontMeshInput {
|
|
|
509
566
|
readonly occlusionTexture?: WavefrontTextureSampleInput | null;
|
|
510
567
|
readonly emissiveTexture?: WavefrontTextureSampleInput | null;
|
|
511
568
|
readonly medium?: WavefrontMediumInput | null;
|
|
512
|
-
readonly extensions?: Record<string, Record<string, unknown>>;
|
|
513
569
|
}
|
|
514
570
|
|
|
515
571
|
export interface WavefrontTriangleRecord {
|
|
@@ -960,12 +1016,20 @@ export interface WavefrontPathTracingMemoryEstimate {
|
|
|
960
1016
|
readonly triangleBytes: number;
|
|
961
1017
|
readonly materialTableBytes: number;
|
|
962
1018
|
readonly bvhNodeBytes: number;
|
|
1019
|
+
readonly bvhCombinedBytes: number;
|
|
963
1020
|
readonly bvhLeafReferenceBytes: number;
|
|
964
1021
|
readonly emissiveTriangleMetadataBytes: number;
|
|
1022
|
+
readonly meshVertexBytes: number;
|
|
1023
|
+
readonly meshIndexBytes: number;
|
|
1024
|
+
readonly meshRangeBytes: number;
|
|
965
1025
|
readonly environmentPortalBytes: number;
|
|
966
1026
|
readonly configBytes: number;
|
|
1027
|
+
readonly configBufferStride: number;
|
|
1028
|
+
readonly frameConfigBytes: number;
|
|
1029
|
+
readonly bvhBuildConfigBytes: number;
|
|
967
1030
|
readonly counterBytes: number;
|
|
968
1031
|
readonly indirectDispatchBytes: number;
|
|
1032
|
+
readonly sceneStorageBufferBindingBytes: number;
|
|
969
1033
|
readonly totalHotBufferBytes: number;
|
|
970
1034
|
}
|
|
971
1035
|
|
|
@@ -987,6 +1051,7 @@ export interface WavefrontGpuParallelismDiagnostics {
|
|
|
987
1051
|
readonly maxComputeWorkgroupsPerDimension: number | null;
|
|
988
1052
|
readonly maxStorageBuffersPerShaderStage: number | null;
|
|
989
1053
|
readonly maxStorageBufferBindingSize: number | null;
|
|
1054
|
+
readonly maxBufferSize: number | null;
|
|
990
1055
|
}>;
|
|
991
1056
|
readonly configuredWorkgroupSize: number;
|
|
992
1057
|
readonly directDispatches: number;
|
|
@@ -1279,12 +1344,27 @@ export function createWavefrontGpuMaterialSource(
|
|
|
1279
1344
|
): WavefrontGpuMaterialSource;
|
|
1280
1345
|
export function createDefaultWavefrontSceneObjects(): readonly WavefrontSceneObject[];
|
|
1281
1346
|
export function estimateWavefrontPathTracingMemory(options?: {
|
|
1347
|
+
width?: number;
|
|
1348
|
+
height?: number;
|
|
1349
|
+
tileSize?: number;
|
|
1350
|
+
samplesPerPixel?: number;
|
|
1282
1351
|
tilePixelCapacity?: number;
|
|
1352
|
+
maxDepth?: number;
|
|
1283
1353
|
sceneObjectCapacity?: number;
|
|
1284
1354
|
triangleCapacity?: number;
|
|
1355
|
+
materialCapacity?: number;
|
|
1285
1356
|
bvhNodeCapacity?: number;
|
|
1286
1357
|
bvhLeafSortCapacity?: number;
|
|
1287
1358
|
emissiveTriangleCapacity?: number;
|
|
1359
|
+
environmentPortalCapacity?: number;
|
|
1360
|
+
meshVertexCount?: number;
|
|
1361
|
+
meshIndexCount?: number;
|
|
1362
|
+
meshRangeCount?: number;
|
|
1363
|
+
bvhSortStageCount?: number;
|
|
1364
|
+
bvhBuildLevelCount?: number;
|
|
1365
|
+
denoise?: boolean;
|
|
1366
|
+
deferredPathResolve?: boolean;
|
|
1367
|
+
minUniformBufferOffsetAlignment?: number;
|
|
1288
1368
|
}): WavefrontPathTracingMemoryEstimate;
|
|
1289
1369
|
export function normalizeWavefrontMesh(
|
|
1290
1370
|
input: WavefrontMeshInput,
|
|
@@ -1570,13 +1650,12 @@ export interface GpuRenderer {
|
|
|
1570
1650
|
setXrActive(active: boolean): void;
|
|
1571
1651
|
getSnapshot(): RendererSnapshot;
|
|
1572
1652
|
bindXrManager(
|
|
1573
|
-
xrManager:
|
|
1574
|
-
subscribe: (listener: (state: { activeSession: XRSession | null }) => void) => () => void;
|
|
1575
|
-
getState?: () => { activeSession: XRSession | null };
|
|
1576
|
-
store?: { getSnapshot: () => { activeSession: XRSession | null } };
|
|
1577
|
-
},
|
|
1653
|
+
xrManager: RendererXrManager,
|
|
1578
1654
|
bindOptions?: {
|
|
1579
|
-
onSessionStart?: (
|
|
1655
|
+
onSessionStart?: (
|
|
1656
|
+
session: NonNullable<XrStoreState["activeSession"]>,
|
|
1657
|
+
renderer: GpuRenderer
|
|
1658
|
+
) => void;
|
|
1580
1659
|
onSessionEnd?: (renderer: GpuRenderer) => void;
|
|
1581
1660
|
}
|
|
1582
1661
|
): () => void;
|
|
@@ -1612,15 +1691,22 @@ export function createRendererDebugHooks(
|
|
|
1612
1691
|
options: RendererDebugHooksOptions
|
|
1613
1692
|
): Pick<RendererHooks, "onFrameStart" | "onFrameComplete">;
|
|
1614
1693
|
|
|
1694
|
+
export type RendererXrState = Pick<XrStoreState, "activeSession">;
|
|
1695
|
+
|
|
1696
|
+
export interface RendererXrManager {
|
|
1697
|
+
subscribe(listener: (state: RendererXrState) => void): () => void;
|
|
1698
|
+
getState?(): RendererXrState;
|
|
1699
|
+
store?: { getSnapshot(): RendererXrState };
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1615
1702
|
export function bindRendererToXrManager(
|
|
1616
1703
|
renderer: Pick<GpuRenderer, "setXrActive">,
|
|
1617
|
-
xrManager:
|
|
1618
|
-
subscribe: (listener: (state: { activeSession: XRSession | null }) => void) => () => void;
|
|
1619
|
-
getState?: () => { activeSession: XRSession | null };
|
|
1620
|
-
store?: { getSnapshot: () => { activeSession: XRSession | null } };
|
|
1621
|
-
},
|
|
1704
|
+
xrManager: RendererXrManager,
|
|
1622
1705
|
options?: {
|
|
1623
|
-
onSessionStart?: (
|
|
1706
|
+
onSessionStart?: (
|
|
1707
|
+
session: NonNullable<XrStoreState["activeSession"]>,
|
|
1708
|
+
renderer: Pick<GpuRenderer, "setXrActive">
|
|
1709
|
+
) => void;
|
|
1624
1710
|
onSessionEnd?: (renderer: Pick<GpuRenderer, "setXrActive">) => void;
|
|
1625
1711
|
}
|
|
1626
1712
|
): () => void;
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,12 @@ export {
|
|
|
4
4
|
export {
|
|
5
5
|
createProfessionalAnimatedSceneRenderer,
|
|
6
6
|
} from "./professional-animated-scene-renderer.js";
|
|
7
|
+
export {
|
|
8
|
+
bucketFeedbackGameFrameRate,
|
|
9
|
+
bucketFeedbackGameFrameTime,
|
|
10
|
+
bucketFeedbackGameViewport,
|
|
11
|
+
createFeedbackGameDiagnosticSnapshot,
|
|
12
|
+
} from "./feedback-diagnostics.js";
|
|
7
13
|
export {
|
|
8
14
|
createDefaultWavefrontSceneObjects,
|
|
9
15
|
createWavefrontBvhBuildLevels,
|
package/src/wavefront-compute.js
CHANGED
|
@@ -15,12 +15,12 @@ import {
|
|
|
15
15
|
createWavefrontMeshAcceleration,
|
|
16
16
|
} from "./wavefront-scene-data.js";
|
|
17
17
|
import {
|
|
18
|
+
estimateWavefrontPathTracingMemoryForConfig,
|
|
18
19
|
createWavefrontPathTracingComputeConfig,
|
|
19
20
|
packEnvironmentPortals,
|
|
20
21
|
supportsWavefrontPathTracingCompute,
|
|
21
22
|
} from "./wavefront-config.js";
|
|
22
23
|
import {
|
|
23
|
-
alignTo,
|
|
24
24
|
clampTileSizeForDevice,
|
|
25
25
|
createAtlasTextureResource,
|
|
26
26
|
createBrdfLutResource,
|
|
@@ -76,11 +76,7 @@ import {
|
|
|
76
76
|
} from "./wavefront-runtime-support.js";
|
|
77
77
|
|
|
78
78
|
import {
|
|
79
|
-
ACCUMULATION_RECORD_BYTES,
|
|
80
|
-
BVH_LEAF_REF_RECORD_BYTES,
|
|
81
79
|
BVH_NODE_RECORD_BYTES,
|
|
82
|
-
CONFIG_BUFFER_BYTES,
|
|
83
|
-
COUNTER_BUFFER_BYTES,
|
|
84
80
|
DEFAULT_AMBIENT_COLOR,
|
|
85
81
|
DEFAULT_BRDF_LUT_SAMPLE_COUNT,
|
|
86
82
|
DEFAULT_BRDF_LUT_SIZE,
|
|
@@ -98,14 +94,11 @@ import {
|
|
|
98
94
|
DEFAULT_WIDTH,
|
|
99
95
|
EMISSIVE_TRIANGLE_INDEX_BYTES,
|
|
100
96
|
EMPTY_TERMINATION_METRICS,
|
|
101
|
-
ENVIRONMENT_PORTAL_RECORD_BYTES,
|
|
102
97
|
GPU_MATERIAL_RECORD_BYTES,
|
|
103
98
|
GPU_MAX_SUBMITTED_WORK_DEADLINE_MS,
|
|
104
99
|
GPU_MAX_SUBMITTED_WORK_TIMEOUT_MS,
|
|
105
|
-
HIT_RECORD_BYTES,
|
|
106
100
|
HIT_TYPE_EMISSIVE,
|
|
107
101
|
HIT_TYPE_SURFACE,
|
|
108
|
-
INDIRECT_DISPATCH_ARGS_BYTES,
|
|
109
102
|
MATERIAL_DIELECTRIC,
|
|
110
103
|
MATERIAL_DIFFUSE,
|
|
111
104
|
MATERIAL_EMISSIVE,
|
|
@@ -114,19 +107,13 @@ import {
|
|
|
114
107
|
MAX_PATH_TRACING_DEPTH,
|
|
115
108
|
MAX_SAMPLES_PER_PIXEL,
|
|
116
109
|
MEDIUM_TABLE_ROWS,
|
|
117
|
-
MESH_RANGE_RECORD_BYTES,
|
|
118
|
-
MESH_VERTEX_RECORD_BYTES,
|
|
119
110
|
OBJECT_KIND_BOX,
|
|
120
111
|
OBJECT_KIND_SPHERE,
|
|
121
|
-
PATH_VERTEX_RECORD_BYTES,
|
|
122
|
-
RAY_RECORD_BYTES,
|
|
123
|
-
SCENE_OBJECT_RECORD_BYTES,
|
|
124
112
|
TERMINAL_SOURCE_KIND_AMBIENT_MAX_DEPTH,
|
|
125
113
|
TERMINAL_SOURCE_KIND_AMBIENT_QUEUE_OVERFLOW,
|
|
126
114
|
TERMINAL_SOURCE_KIND_EMISSIVE,
|
|
127
115
|
TERMINAL_SOURCE_KIND_ENVIRONMENT,
|
|
128
116
|
TRACE_STORAGE_BUFFER_BINDINGS,
|
|
129
|
-
TRIANGLE_RECORD_BYTES,
|
|
130
117
|
add,
|
|
131
118
|
asColor,
|
|
132
119
|
asUnitVec3,
|
|
@@ -201,7 +188,9 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
201
188
|
throw new Error("Unable to acquire a WebGPU adapter for wavefront path tracing.");
|
|
202
189
|
}
|
|
203
190
|
|
|
204
|
-
const device = await adapter.requestDevice(
|
|
191
|
+
const device = await adapter.requestDevice(
|
|
192
|
+
createWavefrontDeviceDescriptor(adapter, options, initialConfig.memory)
|
|
193
|
+
);
|
|
205
194
|
const gpuAdapterParallelism = createGpuAdapterParallelismDiagnostics(adapter, device);
|
|
206
195
|
const context = canvas.getContext("webgpu");
|
|
207
196
|
if (!context || typeof context.configure !== "function") {
|
|
@@ -222,8 +211,16 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
222
211
|
width: config.width,
|
|
223
212
|
height: config.height,
|
|
224
213
|
tileSize: safeTileSize,
|
|
214
|
+
tilePixelCapacity: Math.min(
|
|
215
|
+
config.tilePixelCapacity,
|
|
216
|
+
safeTileSize * safeTileSize
|
|
217
|
+
),
|
|
225
218
|
});
|
|
226
219
|
}
|
|
220
|
+
config = Object.freeze({
|
|
221
|
+
...config,
|
|
222
|
+
memory: estimateWavefrontPathTracingMemoryForConfig(config, device.limits),
|
|
223
|
+
});
|
|
227
224
|
canvas.width = config.width;
|
|
228
225
|
canvas.height = config.height;
|
|
229
226
|
context.configure({
|
|
@@ -233,82 +230,72 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
233
230
|
});
|
|
234
231
|
|
|
235
232
|
const bufferUsage = constants.buffer.STORAGE | constants.buffer.COPY_DST;
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
const activeQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.activeQueue");
|
|
241
|
-
const nextQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.nextQueue");
|
|
242
|
-
const hitBuffer = createBuffer(device, bufferUsage, hitBytes, "plasius.wavefront.hitBuffer");
|
|
233
|
+
const memory = config.memory;
|
|
234
|
+
const activeQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.activeQueue");
|
|
235
|
+
const nextQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.nextQueue");
|
|
236
|
+
const hitBuffer = createBuffer(device, bufferUsage, memory.hitBytes, "plasius.wavefront.hitBuffer");
|
|
243
237
|
const accumulationBuffer = createBuffer(
|
|
244
238
|
device,
|
|
245
239
|
bufferUsage,
|
|
246
|
-
accumulationBytes,
|
|
240
|
+
memory.accumulationBytes,
|
|
247
241
|
"plasius.wavefront.accumulation"
|
|
248
242
|
);
|
|
249
243
|
const pathVertexBuffer = createBuffer(
|
|
250
244
|
device,
|
|
251
245
|
bufferUsage,
|
|
252
|
-
pathVertexBytes,
|
|
246
|
+
memory.pathVertexBytes,
|
|
253
247
|
"plasius.wavefront.pathVertices"
|
|
254
248
|
);
|
|
255
249
|
const sceneObjectBuffer = createBuffer(
|
|
256
250
|
device,
|
|
257
251
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
258
|
-
|
|
252
|
+
memory.sceneObjectBytes,
|
|
259
253
|
"plasius.wavefront.sceneObjects"
|
|
260
254
|
);
|
|
261
255
|
const triangleBuffer = createBuffer(
|
|
262
256
|
device,
|
|
263
257
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
264
|
-
|
|
258
|
+
memory.triangleBytes,
|
|
265
259
|
"plasius.wavefront.triangles"
|
|
266
260
|
);
|
|
267
261
|
const bvhNodeBuffer = createBuffer(
|
|
268
262
|
device,
|
|
269
263
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
270
|
-
|
|
271
|
-
BVH_NODE_RECORD_BYTES,
|
|
264
|
+
memory.bvhCombinedBytes,
|
|
272
265
|
"plasius.wavefront.bvhNodes"
|
|
273
266
|
);
|
|
274
267
|
const meshVertexBuffer = createBuffer(
|
|
275
268
|
device,
|
|
276
269
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
277
|
-
|
|
270
|
+
memory.meshVertexBytes,
|
|
278
271
|
"plasius.wavefront.meshVertices"
|
|
279
272
|
);
|
|
280
273
|
const meshIndexBuffer = createBuffer(
|
|
281
274
|
device,
|
|
282
275
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
283
|
-
|
|
276
|
+
memory.meshIndexBytes,
|
|
284
277
|
"plasius.wavefront.meshIndices"
|
|
285
278
|
);
|
|
286
279
|
const meshRangeBuffer = createBuffer(
|
|
287
280
|
device,
|
|
288
281
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
289
|
-
|
|
282
|
+
memory.meshRangeBytes,
|
|
290
283
|
"plasius.wavefront.meshRanges"
|
|
291
284
|
);
|
|
292
285
|
const environmentPortalBuffer = createBuffer(
|
|
293
286
|
device,
|
|
294
287
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
295
|
-
|
|
288
|
+
memory.environmentPortalBytes,
|
|
296
289
|
"plasius.wavefront.environmentPortals"
|
|
297
290
|
);
|
|
298
291
|
const bvhLeafRefBuffer = createBuffer(
|
|
299
292
|
device,
|
|
300
293
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
301
|
-
|
|
294
|
+
memory.bvhLeafReferenceBytes,
|
|
302
295
|
"plasius.wavefront.bvhLeafRefs"
|
|
303
296
|
);
|
|
304
297
|
const tiles = createTiles(config.width, config.height, config.tileSize);
|
|
305
|
-
const
|
|
306
|
-
const configBufferStride = alignTo(
|
|
307
|
-
CONFIG_BUFFER_BYTES,
|
|
308
|
-
Number.isFinite(uniformOffsetAlignment) && uniformOffsetAlignment > 0
|
|
309
|
-
? uniformOffsetAlignment
|
|
310
|
-
: CONFIG_BUFFER_BYTES
|
|
311
|
-
);
|
|
298
|
+
const configBufferStride = memory.configBufferStride;
|
|
312
299
|
const outputConfigSlotCount = config.deferredPathResolve ? 0 : tiles.length;
|
|
313
300
|
const frameConfigSlotCount = Math.max(
|
|
314
301
|
1,
|
|
@@ -317,27 +304,25 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
317
304
|
const configBuffer = createBuffer(
|
|
318
305
|
device,
|
|
319
306
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
320
|
-
|
|
307
|
+
memory.frameConfigBytes,
|
|
321
308
|
"plasius.wavefront.frameConfig"
|
|
322
309
|
);
|
|
323
|
-
const bvhBuildConfigSlots =
|
|
324
|
-
1 + config.bvhSortStages.length + config.bvhBuildLevels.length;
|
|
325
310
|
const bvhBuildConfigBuffer = createBuffer(
|
|
326
311
|
device,
|
|
327
312
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
328
|
-
|
|
313
|
+
memory.bvhBuildConfigBytes,
|
|
329
314
|
"plasius.wavefront.bvhBuildConfig"
|
|
330
315
|
);
|
|
331
316
|
const counterBuffer = createBuffer(
|
|
332
317
|
device,
|
|
333
318
|
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
334
|
-
|
|
319
|
+
memory.counterBytes,
|
|
335
320
|
"plasius.wavefront.counters"
|
|
336
321
|
);
|
|
337
322
|
const activeDispatchBuffer = createBuffer(
|
|
338
323
|
device,
|
|
339
324
|
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
340
|
-
|
|
325
|
+
memory.indirectDispatchBytes,
|
|
341
326
|
"plasius.wavefront.activeDispatchArgs"
|
|
342
327
|
);
|
|
343
328
|
|