@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/dist/index.cjs
CHANGED
|
@@ -24,8 +24,12 @@ __export(index_exports, {
|
|
|
24
24
|
applyMediumTransmittance: () => applyMediumTransmittance,
|
|
25
25
|
beerLambertTransmittance: () => beerLambertTransmittance,
|
|
26
26
|
bindRendererToXrManager: () => bindRendererToXrManager,
|
|
27
|
+
bucketFeedbackGameFrameRate: () => bucketFeedbackGameFrameRate,
|
|
28
|
+
bucketFeedbackGameFrameTime: () => bucketFeedbackGameFrameTime,
|
|
29
|
+
bucketFeedbackGameViewport: () => bucketFeedbackGameViewport,
|
|
27
30
|
createAnimatedSceneRenderer: () => createAnimatedSceneRenderer,
|
|
28
31
|
createDefaultWavefrontSceneObjects: () => createDefaultWavefrontSceneObjects,
|
|
32
|
+
createFeedbackGameDiagnosticSnapshot: () => createFeedbackGameDiagnosticSnapshot,
|
|
29
33
|
createGpuRenderer: () => createGpuRenderer,
|
|
30
34
|
createMediumStack: () => createMediumStack,
|
|
31
35
|
createProfessionalAnimatedSceneRenderer: () => createProfessionalAnimatedSceneRenderer,
|
|
@@ -2294,6 +2298,140 @@ async function createProfessionalAnimatedSceneRenderer(options = {}) {
|
|
|
2294
2298
|
};
|
|
2295
2299
|
}
|
|
2296
2300
|
|
|
2301
|
+
// src/feedback-diagnostics.js
|
|
2302
|
+
var import_feedback_diagnostics = require("@plasius/gpu-shared/feedback-diagnostics");
|
|
2303
|
+
var inputKeys = Object.freeze([
|
|
2304
|
+
"featureEnabled",
|
|
2305
|
+
"capabilityGranted",
|
|
2306
|
+
"consentConfirmed",
|
|
2307
|
+
"surfaceId",
|
|
2308
|
+
"renderer",
|
|
2309
|
+
"backend",
|
|
2310
|
+
"viewportWidth",
|
|
2311
|
+
"viewportHeight",
|
|
2312
|
+
"frameRate",
|
|
2313
|
+
"frameTimeMs",
|
|
2314
|
+
"featureIds",
|
|
2315
|
+
"counters",
|
|
2316
|
+
"errorCodes"
|
|
2317
|
+
]);
|
|
2318
|
+
function bucketFeedbackGameViewport(width, height) {
|
|
2319
|
+
if (typeof width !== "number" || typeof height !== "number" || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
2320
|
+
return "unknown";
|
|
2321
|
+
}
|
|
2322
|
+
const shorterEdge = Math.min(width, height);
|
|
2323
|
+
const longerEdge = Math.max(width, height);
|
|
2324
|
+
const size = shorterEdge < 600 ? "small" : shorterEdge < 900 || longerEdge < 1440 ? "medium" : "large";
|
|
2325
|
+
const orientation = width > height ? "landscape" : "portrait";
|
|
2326
|
+
return `${size}-${orientation}`;
|
|
2327
|
+
}
|
|
2328
|
+
function bucketFeedbackGameFrameRate(frameRate) {
|
|
2329
|
+
if (typeof frameRate !== "number" || !Number.isFinite(frameRate) || frameRate < 0) {
|
|
2330
|
+
return "unknown";
|
|
2331
|
+
}
|
|
2332
|
+
if (frameRate < 15) {
|
|
2333
|
+
return "under-15";
|
|
2334
|
+
}
|
|
2335
|
+
if (frameRate < 30) {
|
|
2336
|
+
return "15-29";
|
|
2337
|
+
}
|
|
2338
|
+
if (frameRate < 60) {
|
|
2339
|
+
return "30-59";
|
|
2340
|
+
}
|
|
2341
|
+
return "60-plus";
|
|
2342
|
+
}
|
|
2343
|
+
function bucketFeedbackGameFrameTime(frameTimeMs) {
|
|
2344
|
+
if (typeof frameTimeMs !== "number" || !Number.isFinite(frameTimeMs) || frameTimeMs < 0) {
|
|
2345
|
+
return "unknown";
|
|
2346
|
+
}
|
|
2347
|
+
if (frameTimeMs < 17) {
|
|
2348
|
+
return "under-17ms";
|
|
2349
|
+
}
|
|
2350
|
+
if (frameTimeMs < 34) {
|
|
2351
|
+
return "17-33ms";
|
|
2352
|
+
}
|
|
2353
|
+
if (frameTimeMs < 67) {
|
|
2354
|
+
return "34-66ms";
|
|
2355
|
+
}
|
|
2356
|
+
return "over-66ms";
|
|
2357
|
+
}
|
|
2358
|
+
function createFeedbackGameDiagnosticSnapshot(input) {
|
|
2359
|
+
try {
|
|
2360
|
+
return createFeedbackGameDiagnosticSnapshotInternal(input);
|
|
2361
|
+
} catch {
|
|
2362
|
+
throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
function createFeedbackGameDiagnosticSnapshotInternal(input) {
|
|
2366
|
+
const snapshot = snapshotInputIfEnabled(input);
|
|
2367
|
+
if (snapshot === null) {
|
|
2368
|
+
return null;
|
|
2369
|
+
}
|
|
2370
|
+
const registration = typeof snapshot.surfaceId === "string" && Object.hasOwn(
|
|
2371
|
+
import_feedback_diagnostics.feedbackGameDiagnosticSurfaceRegistrations,
|
|
2372
|
+
snapshot.surfaceId
|
|
2373
|
+
) ? import_feedback_diagnostics.feedbackGameDiagnosticSurfaceRegistrations[snapshot.surfaceId] : void 0;
|
|
2374
|
+
return (0, import_feedback_diagnostics.parseFeedbackGameDiagnostics)({
|
|
2375
|
+
type: "feedback-game-diagnostics",
|
|
2376
|
+
version: import_feedback_diagnostics.FEEDBACK_GAME_DIAGNOSTICS_CONTRACT_VERSION,
|
|
2377
|
+
surfaceId: snapshot.surfaceId,
|
|
2378
|
+
consentConfirmed: true,
|
|
2379
|
+
provenanceContractId: registration?.provenanceContractId,
|
|
2380
|
+
renderer: snapshot.renderer,
|
|
2381
|
+
backend: snapshot.backend,
|
|
2382
|
+
viewportBucket: bucketFeedbackGameViewport(
|
|
2383
|
+
snapshot.viewportWidth,
|
|
2384
|
+
snapshot.viewportHeight
|
|
2385
|
+
),
|
|
2386
|
+
frameRateBucket: bucketFeedbackGameFrameRate(snapshot.frameRate),
|
|
2387
|
+
frameTimeBucket: bucketFeedbackGameFrameTime(snapshot.frameTimeMs),
|
|
2388
|
+
featureIds: snapshot.featureIds,
|
|
2389
|
+
counters: snapshot.counters,
|
|
2390
|
+
errorCodes: snapshot.errorCodes
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
function snapshotInputIfEnabled(input) {
|
|
2394
|
+
assertValid(
|
|
2395
|
+
input !== null && typeof input === "object" && !Array.isArray(input) && (Object.getPrototypeOf(input) === Object.prototype || Object.getPrototypeOf(input) === null)
|
|
2396
|
+
);
|
|
2397
|
+
const gateKeys = [
|
|
2398
|
+
"featureEnabled",
|
|
2399
|
+
"capabilityGranted",
|
|
2400
|
+
"consentConfirmed"
|
|
2401
|
+
];
|
|
2402
|
+
const snapshot = /* @__PURE__ */ Object.create(null);
|
|
2403
|
+
for (const key of gateKeys) {
|
|
2404
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
2405
|
+
assertValid(
|
|
2406
|
+
descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value") && typeof descriptor.value === "boolean"
|
|
2407
|
+
);
|
|
2408
|
+
snapshot[key] = descriptor.value;
|
|
2409
|
+
}
|
|
2410
|
+
const { featureEnabled, capabilityGranted, consentConfirmed } = snapshot;
|
|
2411
|
+
if (!featureEnabled || !capabilityGranted || !consentConfirmed) {
|
|
2412
|
+
return null;
|
|
2413
|
+
}
|
|
2414
|
+
const actualKeys = Reflect.ownKeys(input);
|
|
2415
|
+
assertValid(
|
|
2416
|
+
actualKeys.length === inputKeys.length && inputKeys.every((key) => actualKeys.includes(key)) && actualKeys.every(
|
|
2417
|
+
(key) => typeof key === "string" && inputKeys.includes(key)
|
|
2418
|
+
)
|
|
2419
|
+
);
|
|
2420
|
+
for (const key of inputKeys.filter((key2) => !gateKeys.includes(key2))) {
|
|
2421
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
2422
|
+
assertValid(
|
|
2423
|
+
descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value")
|
|
2424
|
+
);
|
|
2425
|
+
snapshot[key] = descriptor.value;
|
|
2426
|
+
}
|
|
2427
|
+
return Object.freeze(snapshot);
|
|
2428
|
+
}
|
|
2429
|
+
function assertValid(condition) {
|
|
2430
|
+
if (!condition) {
|
|
2431
|
+
throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2297
2435
|
// src/wavefront-frame-runtime.js
|
|
2298
2436
|
function createGpuParallelismCounters() {
|
|
2299
2437
|
return {
|
|
@@ -4527,6 +4665,13 @@ function dispatchWavefrontGpuAccelerationBuild({
|
|
|
4527
4665
|
}
|
|
4528
4666
|
|
|
4529
4667
|
// src/wavefront-config.js
|
|
4668
|
+
var WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 256;
|
|
4669
|
+
function allocatedRecordBytes(count, recordBytes) {
|
|
4670
|
+
return Math.max(1, count) * recordBytes;
|
|
4671
|
+
}
|
|
4672
|
+
function alignByteSize(value, alignment) {
|
|
4673
|
+
return Math.ceil(value / alignment) * alignment;
|
|
4674
|
+
}
|
|
4530
4675
|
function resolveEnvironmentLighting(input, environmentColor, ambientColor) {
|
|
4531
4676
|
const source = input ?? {};
|
|
4532
4677
|
return Object.freeze({
|
|
@@ -4703,6 +4848,18 @@ function resolveCamera(input, width, height) {
|
|
|
4703
4848
|
});
|
|
4704
4849
|
}
|
|
4705
4850
|
function estimateWavefrontPathTracingMemory(options = {}) {
|
|
4851
|
+
const width = readPositiveInteger2("width", options.width, DEFAULT_WIDTH);
|
|
4852
|
+
const height = readPositiveInteger2("height", options.height, DEFAULT_HEIGHT);
|
|
4853
|
+
const tileSize = readPositiveInteger2("tileSize", options.tileSize, DEFAULT_TILE_SIZE);
|
|
4854
|
+
const samplesPerPixel = clamp2(
|
|
4855
|
+
readPositiveInteger2(
|
|
4856
|
+
"samplesPerPixel",
|
|
4857
|
+
options.samplesPerPixel,
|
|
4858
|
+
DEFAULT_SAMPLES_PER_PIXEL
|
|
4859
|
+
),
|
|
4860
|
+
1,
|
|
4861
|
+
MAX_SAMPLES_PER_PIXEL
|
|
4862
|
+
);
|
|
4706
4863
|
const tilePixelCapacity = readPositiveInteger2(
|
|
4707
4864
|
"tilePixelCapacity",
|
|
4708
4865
|
options.tilePixelCapacity,
|
|
@@ -4735,18 +4892,89 @@ function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
4735
4892
|
options.environmentPortalCapacity,
|
|
4736
4893
|
0
|
|
4737
4894
|
);
|
|
4738
|
-
|
|
4895
|
+
readNonNegativeInteger2("materialCapacity", options.materialCapacity, 0);
|
|
4896
|
+
const meshVertexCount = readNonNegativeInteger2(
|
|
4897
|
+
"meshVertexCount",
|
|
4898
|
+
options.meshVertexCount,
|
|
4899
|
+
0
|
|
4900
|
+
);
|
|
4901
|
+
const meshIndexCount = readNonNegativeInteger2(
|
|
4902
|
+
"meshIndexCount",
|
|
4903
|
+
options.meshIndexCount,
|
|
4904
|
+
0
|
|
4905
|
+
);
|
|
4906
|
+
const meshRangeCount = readNonNegativeInteger2(
|
|
4907
|
+
"meshRangeCount",
|
|
4908
|
+
options.meshRangeCount,
|
|
4909
|
+
0
|
|
4910
|
+
);
|
|
4911
|
+
const bvhSortStageCount = readNonNegativeInteger2(
|
|
4912
|
+
"bvhSortStageCount",
|
|
4913
|
+
options.bvhSortStageCount,
|
|
4914
|
+
0
|
|
4915
|
+
);
|
|
4916
|
+
const bvhBuildLevelCount = readNonNegativeInteger2(
|
|
4917
|
+
"bvhBuildLevelCount",
|
|
4918
|
+
options.bvhBuildLevelCount,
|
|
4919
|
+
0
|
|
4920
|
+
);
|
|
4921
|
+
const minUniformBufferOffsetAlignment = readPositiveInteger2(
|
|
4922
|
+
"minUniformBufferOffsetAlignment",
|
|
4923
|
+
options.minUniformBufferOffsetAlignment,
|
|
4924
|
+
WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
4925
|
+
);
|
|
4926
|
+
const denoise = options.denoise !== false;
|
|
4927
|
+
const deferredPathResolve = options.deferredPathResolve !== false;
|
|
4739
4928
|
const queueBytes = tilePixelCapacity * RAY_RECORD_BYTES;
|
|
4740
4929
|
const hitBytes = tilePixelCapacity * HIT_RECORD_BYTES;
|
|
4741
4930
|
const accumulationBytes = tilePixelCapacity * ACCUMULATION_RECORD_BYTES;
|
|
4742
4931
|
const pathVertexBytes = tilePixelCapacity * (maxDepth + 1) * PATH_VERTEX_RECORD_BYTES;
|
|
4743
4932
|
const sceneObjectBytes = sceneObjectCapacity * SCENE_OBJECT_RECORD_BYTES;
|
|
4744
|
-
const triangleBytes = triangleCapacity
|
|
4745
|
-
const materialTableBytes =
|
|
4933
|
+
const triangleBytes = allocatedRecordBytes(triangleCapacity, TRIANGLE_RECORD_BYTES);
|
|
4934
|
+
const materialTableBytes = 0;
|
|
4746
4935
|
const bvhNodeBytes = bvhNodeCapacity * BVH_NODE_RECORD_BYTES;
|
|
4747
|
-
const bvhLeafReferenceBytes =
|
|
4936
|
+
const bvhLeafReferenceBytes = allocatedRecordBytes(
|
|
4937
|
+
bvhLeafSortCapacity,
|
|
4938
|
+
BVH_LEAF_REF_RECORD_BYTES
|
|
4939
|
+
);
|
|
4748
4940
|
const emissiveTriangleMetadataBytes = emissiveTriangleCapacity * BVH_NODE_RECORD_BYTES;
|
|
4749
|
-
const
|
|
4941
|
+
const bvhCombinedBytes = allocatedRecordBytes(
|
|
4942
|
+
bvhNodeCapacity + emissiveTriangleCapacity,
|
|
4943
|
+
BVH_NODE_RECORD_BYTES
|
|
4944
|
+
);
|
|
4945
|
+
const meshVertexBytes = allocatedRecordBytes(meshVertexCount, MESH_VERTEX_RECORD_BYTES);
|
|
4946
|
+
const meshIndexBytes = allocatedRecordBytes(meshIndexCount, 4);
|
|
4947
|
+
const meshRangeBytes = allocatedRecordBytes(meshRangeCount, MESH_RANGE_RECORD_BYTES);
|
|
4948
|
+
const environmentPortalBytes = allocatedRecordBytes(
|
|
4949
|
+
environmentPortalCapacity,
|
|
4950
|
+
ENVIRONMENT_PORTAL_RECORD_BYTES
|
|
4951
|
+
);
|
|
4952
|
+
const tileCount = Math.ceil(width / tileSize) * Math.ceil(height / tileSize);
|
|
4953
|
+
const outputConfigSlotCount = deferredPathResolve ? 0 : tileCount;
|
|
4954
|
+
const frameConfigSlotCount = Math.max(
|
|
4955
|
+
1,
|
|
4956
|
+
tileCount * samplesPerPixel + outputConfigSlotCount + (denoise ? 1 : 0)
|
|
4957
|
+
);
|
|
4958
|
+
const configBufferStride = alignByteSize(
|
|
4959
|
+
CONFIG_BUFFER_BYTES,
|
|
4960
|
+
minUniformBufferOffsetAlignment
|
|
4961
|
+
);
|
|
4962
|
+
const frameConfigBytes = frameConfigSlotCount * configBufferStride;
|
|
4963
|
+
const bvhBuildConfigBytes = Math.max(
|
|
4964
|
+
1,
|
|
4965
|
+
1 + bvhSortStageCount + bvhBuildLevelCount
|
|
4966
|
+
) * configBufferStride;
|
|
4967
|
+
const sceneStorageBufferBindingBytes = Math.max(
|
|
4968
|
+
sceneObjectBytes,
|
|
4969
|
+
triangleBytes,
|
|
4970
|
+
bvhCombinedBytes,
|
|
4971
|
+
meshVertexBytes,
|
|
4972
|
+
meshIndexBytes,
|
|
4973
|
+
meshRangeBytes,
|
|
4974
|
+
environmentPortalBytes,
|
|
4975
|
+
bvhLeafReferenceBytes
|
|
4976
|
+
);
|
|
4977
|
+
const totalHotBufferBytes = queueBytes * 2 + hitBytes + accumulationBytes + pathVertexBytes + sceneObjectBytes + triangleBytes + bvhCombinedBytes + meshVertexBytes + meshIndexBytes + meshRangeBytes + bvhLeafReferenceBytes + environmentPortalBytes + frameConfigBytes + bvhBuildConfigBytes + COUNTER_BUFFER_BYTES + INDIRECT_DISPATCH_ARGS_BYTES;
|
|
4750
4978
|
return Object.freeze({
|
|
4751
4979
|
queueBytes,
|
|
4752
4980
|
queuePairBytes: queueBytes * 2,
|
|
@@ -4757,13 +4985,45 @@ function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
4757
4985
|
triangleBytes,
|
|
4758
4986
|
materialTableBytes,
|
|
4759
4987
|
bvhNodeBytes,
|
|
4988
|
+
bvhCombinedBytes,
|
|
4760
4989
|
bvhLeafReferenceBytes,
|
|
4761
4990
|
emissiveTriangleMetadataBytes,
|
|
4991
|
+
meshVertexBytes,
|
|
4992
|
+
meshIndexBytes,
|
|
4993
|
+
meshRangeBytes,
|
|
4762
4994
|
environmentPortalBytes,
|
|
4763
4995
|
configBytes: CONFIG_BUFFER_BYTES,
|
|
4996
|
+
configBufferStride,
|
|
4997
|
+
frameConfigBytes,
|
|
4998
|
+
bvhBuildConfigBytes,
|
|
4764
4999
|
counterBytes: COUNTER_BUFFER_BYTES,
|
|
4765
5000
|
indirectDispatchBytes: INDIRECT_DISPATCH_ARGS_BYTES,
|
|
4766
|
-
|
|
5001
|
+
sceneStorageBufferBindingBytes,
|
|
5002
|
+
totalHotBufferBytes
|
|
5003
|
+
});
|
|
5004
|
+
}
|
|
5005
|
+
function estimateWavefrontPathTracingMemoryForConfig(config, limits = {}) {
|
|
5006
|
+
return estimateWavefrontPathTracingMemory({
|
|
5007
|
+
width: config.width,
|
|
5008
|
+
height: config.height,
|
|
5009
|
+
tileSize: config.tileSize,
|
|
5010
|
+
samplesPerPixel: config.samplesPerPixel,
|
|
5011
|
+
tilePixelCapacity: config.tilePixelCapacity,
|
|
5012
|
+
maxDepth: config.maxDepth,
|
|
5013
|
+
sceneObjectCapacity: config.sceneObjectCapacity,
|
|
5014
|
+
triangleCapacity: config.triangleCapacity,
|
|
5015
|
+
bvhNodeCapacity: config.bvhNodeCapacity,
|
|
5016
|
+
bvhLeafSortCapacity: config.bvhLeafSortCapacity,
|
|
5017
|
+
emissiveTriangleCapacity: config.emissiveTriangleCapacity,
|
|
5018
|
+
environmentPortalCapacity: config.environmentPortalCapacity,
|
|
5019
|
+
meshVertexCount: config.gpuMeshSource.vertices.count,
|
|
5020
|
+
meshIndexCount: config.gpuMeshSource.indices.count,
|
|
5021
|
+
meshRangeCount: config.gpuMeshSource.meshes.count,
|
|
5022
|
+
bvhSortStageCount: config.bvhSortStages.length,
|
|
5023
|
+
bvhBuildLevelCount: config.bvhBuildLevels.length,
|
|
5024
|
+
denoise: config.denoise,
|
|
5025
|
+
deferredPathResolve: config.deferredPathResolve,
|
|
5026
|
+
minUniformBufferOffsetAlignment: limits.minUniformBufferOffsetAlignment ?? WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
4767
5027
|
});
|
|
4768
5028
|
}
|
|
4769
5029
|
function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
@@ -4908,15 +5168,25 @@ function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
|
4908
5168
|
denoise: options.denoise !== false,
|
|
4909
5169
|
frameIndex: readNonNegativeInteger2("frameIndex", options.frameIndex, 0),
|
|
4910
5170
|
memory: estimateWavefrontPathTracingMemory({
|
|
5171
|
+
width,
|
|
5172
|
+
height,
|
|
5173
|
+
tileSize,
|
|
5174
|
+
samplesPerPixel,
|
|
4911
5175
|
tilePixelCapacity,
|
|
4912
5176
|
maxDepth,
|
|
4913
5177
|
sceneObjectCapacity,
|
|
4914
5178
|
triangleCapacity,
|
|
4915
|
-
materialCapacity: gpuMaterialSource.count,
|
|
4916
5179
|
bvhNodeCapacity,
|
|
4917
5180
|
bvhLeafSortCapacity,
|
|
4918
5181
|
emissiveTriangleCapacity: emissiveTriangleIndices.capacity,
|
|
4919
|
-
environmentPortalCapacity
|
|
5182
|
+
environmentPortalCapacity,
|
|
5183
|
+
meshVertexCount: gpuMeshSource.vertices.count,
|
|
5184
|
+
meshIndexCount: gpuMeshSource.indices.count,
|
|
5185
|
+
meshRangeCount: gpuMeshSource.meshes.count,
|
|
5186
|
+
bvhSortStageCount: bvhSortStages.length,
|
|
5187
|
+
bvhBuildLevelCount: bvhBuildLevels.length,
|
|
5188
|
+
denoise: options.denoise !== false,
|
|
5189
|
+
deferredPathResolve
|
|
4920
5190
|
})
|
|
4921
5191
|
});
|
|
4922
5192
|
}
|
|
@@ -5007,7 +5277,13 @@ function clampTileSizeForDevice(config, device) {
|
|
|
5007
5277
|
}
|
|
5008
5278
|
const maxPixelsByRay = Math.floor(limit / RAY_RECORD_BYTES);
|
|
5009
5279
|
const maxPixelsByHit = Math.floor(limit / HIT_RECORD_BYTES);
|
|
5010
|
-
const
|
|
5280
|
+
const maxPixelsByPathVertex = Math.floor(
|
|
5281
|
+
limit / ((config.maxDepth + 1) * PATH_VERTEX_RECORD_BYTES)
|
|
5282
|
+
);
|
|
5283
|
+
const maxPixels = Math.max(
|
|
5284
|
+
256,
|
|
5285
|
+
Math.min(maxPixelsByRay, maxPixelsByHit, maxPixelsByPathVertex)
|
|
5286
|
+
);
|
|
5011
5287
|
if (config.tilePixelCapacity <= maxPixels) {
|
|
5012
5288
|
return config.tileSize;
|
|
5013
5289
|
}
|
|
@@ -5761,6 +6037,32 @@ function createWavefrontPresentBindGroup({
|
|
|
5761
6037
|
}
|
|
5762
6038
|
|
|
5763
6039
|
// src/wavefront-runtime-support.js
|
|
6040
|
+
var WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE = 128 * 1024 * 1024;
|
|
6041
|
+
var WEBGPU_DEFAULT_MAX_BUFFER_SIZE = 256 * 1024 * 1024;
|
|
6042
|
+
function readRequestedDeviceLimit(source, name) {
|
|
6043
|
+
const rawValue = source?.[name];
|
|
6044
|
+
if (rawValue === void 0 || rawValue === null) {
|
|
6045
|
+
return 0;
|
|
6046
|
+
}
|
|
6047
|
+
const value = Number(rawValue);
|
|
6048
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
6049
|
+
throw new Error(`${name} must be a non-negative safe integer.`);
|
|
6050
|
+
}
|
|
6051
|
+
return value;
|
|
6052
|
+
}
|
|
6053
|
+
function assertAdapterSupportsRequiredLimit(adapter, name, requiredValue) {
|
|
6054
|
+
const availableValue = Number(adapter?.limits?.[name]);
|
|
6055
|
+
if (!Number.isFinite(availableValue)) {
|
|
6056
|
+
throw new Error(
|
|
6057
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, but this adapter does not expose that limit.`
|
|
6058
|
+
);
|
|
6059
|
+
}
|
|
6060
|
+
if (availableValue < requiredValue) {
|
|
6061
|
+
throw new Error(
|
|
6062
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, but this adapter exposes ${availableValue} bytes.`
|
|
6063
|
+
);
|
|
6064
|
+
}
|
|
6065
|
+
}
|
|
5764
6066
|
function getGpuUsageConstants() {
|
|
5765
6067
|
if (typeof GPUBufferUsage === "undefined" || typeof GPUTextureUsage === "undefined" || typeof GPUShaderStage === "undefined") {
|
|
5766
6068
|
throw new Error("WebGPU runtime unavailable. Required GPU constants are missing.");
|
|
@@ -5858,8 +6160,13 @@ async function createRenderPipeline(device, descriptor) {
|
|
|
5858
6160
|
}
|
|
5859
6161
|
return device.createRenderPipeline(descriptor);
|
|
5860
6162
|
}
|
|
5861
|
-
function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
5862
|
-
const
|
|
6163
|
+
function createWavefrontDeviceDescriptor(adapter, options = {}, memory = null) {
|
|
6164
|
+
const descriptor = { ...options.deviceDescriptor ?? {} };
|
|
6165
|
+
const descriptorRequiredLimits = { ...descriptor.requiredLimits ?? {} };
|
|
6166
|
+
const requiredLimits = {
|
|
6167
|
+
...descriptorRequiredLimits,
|
|
6168
|
+
...options.requiredLimits ?? {}
|
|
6169
|
+
};
|
|
5863
6170
|
const exposedStorageBufferLimit = Number(adapter?.limits?.maxStorageBuffersPerShaderStage);
|
|
5864
6171
|
if (Number.isFinite(exposedStorageBufferLimit)) {
|
|
5865
6172
|
if (exposedStorageBufferLimit < TRACE_STORAGE_BUFFER_BINDINGS) {
|
|
@@ -5884,7 +6191,32 @@ function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
|
5884
6191
|
TRACE_SAMPLED_TEXTURE_BINDINGS
|
|
5885
6192
|
);
|
|
5886
6193
|
}
|
|
5887
|
-
const
|
|
6194
|
+
const sceneStorageBufferBindingBytes = Number(
|
|
6195
|
+
memory?.sceneStorageBufferBindingBytes ?? 0
|
|
6196
|
+
);
|
|
6197
|
+
const requestedStorageBufferBindingSize = Math.max(
|
|
6198
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxStorageBufferBindingSize"),
|
|
6199
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxStorageBufferBindingSize"),
|
|
6200
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE ? sceneStorageBufferBindingBytes : 0
|
|
6201
|
+
);
|
|
6202
|
+
if (requestedStorageBufferBindingSize > 0) {
|
|
6203
|
+
assertAdapterSupportsRequiredLimit(
|
|
6204
|
+
adapter,
|
|
6205
|
+
"maxStorageBufferBindingSize",
|
|
6206
|
+
requestedStorageBufferBindingSize
|
|
6207
|
+
);
|
|
6208
|
+
requiredLimits.maxStorageBufferBindingSize = requestedStorageBufferBindingSize;
|
|
6209
|
+
}
|
|
6210
|
+
const requestedMaxBufferSize = Math.max(
|
|
6211
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxBufferSize"),
|
|
6212
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxBufferSize"),
|
|
6213
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_BUFFER_SIZE ? sceneStorageBufferBindingBytes : 0,
|
|
6214
|
+
requestedStorageBufferBindingSize > WEBGPU_DEFAULT_MAX_BUFFER_SIZE ? requestedStorageBufferBindingSize : 0
|
|
6215
|
+
);
|
|
6216
|
+
if (requestedMaxBufferSize > 0) {
|
|
6217
|
+
assertAdapterSupportsRequiredLimit(adapter, "maxBufferSize", requestedMaxBufferSize);
|
|
6218
|
+
requiredLimits.maxBufferSize = requestedMaxBufferSize;
|
|
6219
|
+
}
|
|
5888
6220
|
const requiredFeatures = Array.from(descriptor.requiredFeatures ?? []);
|
|
5889
6221
|
const adapterFeatures = adapter?.features;
|
|
5890
6222
|
const timestampQuerySupported = typeof adapterFeatures?.has === "function" ? adapterFeatures.has("timestamp-query") : adapterFeatures && typeof adapterFeatures[Symbol.iterator] === "function" ? Array.from(adapterFeatures).includes("timestamp-query") : false;
|
|
@@ -5935,7 +6267,8 @@ function createGpuAdapterParallelismDiagnostics(adapter, device) {
|
|
|
5935
6267
|
maxComputeWorkgroupSizeZ: readGpuLimit(adapter, device, "maxComputeWorkgroupSizeZ"),
|
|
5936
6268
|
maxComputeWorkgroupsPerDimension: readGpuLimit(adapter, device, "maxComputeWorkgroupsPerDimension"),
|
|
5937
6269
|
maxStorageBuffersPerShaderStage: readGpuLimit(adapter, device, "maxStorageBuffersPerShaderStage"),
|
|
5938
|
-
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize")
|
|
6270
|
+
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize"),
|
|
6271
|
+
maxBufferSize: readGpuLimit(adapter, device, "maxBufferSize")
|
|
5939
6272
|
}),
|
|
5940
6273
|
configuredWorkgroupSize: WORKGROUP_SIZE
|
|
5941
6274
|
});
|
|
@@ -11241,7 +11574,9 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11241
11574
|
if (!adapter) {
|
|
11242
11575
|
throw new Error("Unable to acquire a WebGPU adapter for wavefront path tracing.");
|
|
11243
11576
|
}
|
|
11244
|
-
const device = await adapter.requestDevice(
|
|
11577
|
+
const device = await adapter.requestDevice(
|
|
11578
|
+
createWavefrontDeviceDescriptor(adapter, options, initialConfig.memory)
|
|
11579
|
+
);
|
|
11245
11580
|
const gpuAdapterParallelism = createGpuAdapterParallelismDiagnostics(adapter, device);
|
|
11246
11581
|
const context = canvas.getContext("webgpu");
|
|
11247
11582
|
if (!context || typeof context.configure !== "function") {
|
|
@@ -11256,9 +11591,17 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11256
11591
|
canvas,
|
|
11257
11592
|
width: config.width,
|
|
11258
11593
|
height: config.height,
|
|
11259
|
-
tileSize: safeTileSize
|
|
11594
|
+
tileSize: safeTileSize,
|
|
11595
|
+
tilePixelCapacity: Math.min(
|
|
11596
|
+
config.tilePixelCapacity,
|
|
11597
|
+
safeTileSize * safeTileSize
|
|
11598
|
+
)
|
|
11260
11599
|
});
|
|
11261
11600
|
}
|
|
11601
|
+
config = Object.freeze({
|
|
11602
|
+
...config,
|
|
11603
|
+
memory: estimateWavefrontPathTracingMemoryForConfig(config, device.limits)
|
|
11604
|
+
});
|
|
11262
11605
|
canvas.width = config.width;
|
|
11263
11606
|
canvas.height = config.height;
|
|
11264
11607
|
context.configure({
|
|
@@ -11267,79 +11610,72 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11267
11610
|
alphaMode: options.alpha === true ? "premultiplied" : "opaque"
|
|
11268
11611
|
});
|
|
11269
11612
|
const bufferUsage = constants.buffer.STORAGE | constants.buffer.COPY_DST;
|
|
11270
|
-
const
|
|
11271
|
-
const
|
|
11272
|
-
const
|
|
11273
|
-
const
|
|
11274
|
-
const activeQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.activeQueue");
|
|
11275
|
-
const nextQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.nextQueue");
|
|
11276
|
-
const hitBuffer = createBuffer(device, bufferUsage, hitBytes, "plasius.wavefront.hitBuffer");
|
|
11613
|
+
const memory = config.memory;
|
|
11614
|
+
const activeQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.activeQueue");
|
|
11615
|
+
const nextQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.nextQueue");
|
|
11616
|
+
const hitBuffer = createBuffer(device, bufferUsage, memory.hitBytes, "plasius.wavefront.hitBuffer");
|
|
11277
11617
|
const accumulationBuffer = createBuffer(
|
|
11278
11618
|
device,
|
|
11279
11619
|
bufferUsage,
|
|
11280
|
-
accumulationBytes,
|
|
11620
|
+
memory.accumulationBytes,
|
|
11281
11621
|
"plasius.wavefront.accumulation"
|
|
11282
11622
|
);
|
|
11283
11623
|
const pathVertexBuffer = createBuffer(
|
|
11284
11624
|
device,
|
|
11285
11625
|
bufferUsage,
|
|
11286
|
-
pathVertexBytes,
|
|
11626
|
+
memory.pathVertexBytes,
|
|
11287
11627
|
"plasius.wavefront.pathVertices"
|
|
11288
11628
|
);
|
|
11289
11629
|
const sceneObjectBuffer = createBuffer(
|
|
11290
11630
|
device,
|
|
11291
11631
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11292
|
-
|
|
11632
|
+
memory.sceneObjectBytes,
|
|
11293
11633
|
"plasius.wavefront.sceneObjects"
|
|
11294
11634
|
);
|
|
11295
11635
|
const triangleBuffer = createBuffer(
|
|
11296
11636
|
device,
|
|
11297
11637
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11298
|
-
|
|
11638
|
+
memory.triangleBytes,
|
|
11299
11639
|
"plasius.wavefront.triangles"
|
|
11300
11640
|
);
|
|
11301
11641
|
const bvhNodeBuffer = createBuffer(
|
|
11302
11642
|
device,
|
|
11303
11643
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11304
|
-
|
|
11644
|
+
memory.bvhCombinedBytes,
|
|
11305
11645
|
"plasius.wavefront.bvhNodes"
|
|
11306
11646
|
);
|
|
11307
11647
|
const meshVertexBuffer = createBuffer(
|
|
11308
11648
|
device,
|
|
11309
11649
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11310
|
-
|
|
11650
|
+
memory.meshVertexBytes,
|
|
11311
11651
|
"plasius.wavefront.meshVertices"
|
|
11312
11652
|
);
|
|
11313
11653
|
const meshIndexBuffer = createBuffer(
|
|
11314
11654
|
device,
|
|
11315
11655
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11316
|
-
|
|
11656
|
+
memory.meshIndexBytes,
|
|
11317
11657
|
"plasius.wavefront.meshIndices"
|
|
11318
11658
|
);
|
|
11319
11659
|
const meshRangeBuffer = createBuffer(
|
|
11320
11660
|
device,
|
|
11321
11661
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11322
|
-
|
|
11662
|
+
memory.meshRangeBytes,
|
|
11323
11663
|
"plasius.wavefront.meshRanges"
|
|
11324
11664
|
);
|
|
11325
11665
|
const environmentPortalBuffer = createBuffer(
|
|
11326
11666
|
device,
|
|
11327
11667
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11328
|
-
|
|
11668
|
+
memory.environmentPortalBytes,
|
|
11329
11669
|
"plasius.wavefront.environmentPortals"
|
|
11330
11670
|
);
|
|
11331
11671
|
const bvhLeafRefBuffer = createBuffer(
|
|
11332
11672
|
device,
|
|
11333
11673
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11334
|
-
|
|
11674
|
+
memory.bvhLeafReferenceBytes,
|
|
11335
11675
|
"plasius.wavefront.bvhLeafRefs"
|
|
11336
11676
|
);
|
|
11337
11677
|
const tiles = createTiles(config.width, config.height, config.tileSize);
|
|
11338
|
-
const
|
|
11339
|
-
const configBufferStride = alignTo(
|
|
11340
|
-
CONFIG_BUFFER_BYTES,
|
|
11341
|
-
Number.isFinite(uniformOffsetAlignment) && uniformOffsetAlignment > 0 ? uniformOffsetAlignment : CONFIG_BUFFER_BYTES
|
|
11342
|
-
);
|
|
11678
|
+
const configBufferStride = memory.configBufferStride;
|
|
11343
11679
|
const outputConfigSlotCount = config.deferredPathResolve ? 0 : tiles.length;
|
|
11344
11680
|
const frameConfigSlotCount = Math.max(
|
|
11345
11681
|
1,
|
|
@@ -11348,26 +11684,25 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11348
11684
|
const configBuffer = createBuffer(
|
|
11349
11685
|
device,
|
|
11350
11686
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11351
|
-
|
|
11687
|
+
memory.frameConfigBytes,
|
|
11352
11688
|
"plasius.wavefront.frameConfig"
|
|
11353
11689
|
);
|
|
11354
|
-
const bvhBuildConfigSlots = 1 + config.bvhSortStages.length + config.bvhBuildLevels.length;
|
|
11355
11690
|
const bvhBuildConfigBuffer = createBuffer(
|
|
11356
11691
|
device,
|
|
11357
11692
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11358
|
-
|
|
11693
|
+
memory.bvhBuildConfigBytes,
|
|
11359
11694
|
"plasius.wavefront.bvhBuildConfig"
|
|
11360
11695
|
);
|
|
11361
11696
|
const counterBuffer = createBuffer(
|
|
11362
11697
|
device,
|
|
11363
11698
|
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
11364
|
-
|
|
11699
|
+
memory.counterBytes,
|
|
11365
11700
|
"plasius.wavefront.counters"
|
|
11366
11701
|
);
|
|
11367
11702
|
const activeDispatchBuffer = createBuffer(
|
|
11368
11703
|
device,
|
|
11369
11704
|
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
11370
|
-
|
|
11705
|
+
memory.indirectDispatchBytes,
|
|
11371
11706
|
"plasius.wavefront.activeDispatchArgs"
|
|
11372
11707
|
);
|
|
11373
11708
|
let packedScene = packWavefrontSceneObjects(config.sceneObjects, config.sceneObjectCapacity);
|
|
@@ -13078,8 +13413,12 @@ function createRayTracingRenderPlan(options = {}) {
|
|
|
13078
13413
|
applyMediumTransmittance,
|
|
13079
13414
|
beerLambertTransmittance,
|
|
13080
13415
|
bindRendererToXrManager,
|
|
13416
|
+
bucketFeedbackGameFrameRate,
|
|
13417
|
+
bucketFeedbackGameFrameTime,
|
|
13418
|
+
bucketFeedbackGameViewport,
|
|
13081
13419
|
createAnimatedSceneRenderer,
|
|
13082
13420
|
createDefaultWavefrontSceneObjects,
|
|
13421
|
+
createFeedbackGameDiagnosticSnapshot,
|
|
13083
13422
|
createGpuRenderer,
|
|
13084
13423
|
createMediumStack,
|
|
13085
13424
|
createProfessionalAnimatedSceneRenderer,
|