@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.js
CHANGED
|
@@ -2205,6 +2205,144 @@ async function createProfessionalAnimatedSceneRenderer(options = {}) {
|
|
|
2205
2205
|
};
|
|
2206
2206
|
}
|
|
2207
2207
|
|
|
2208
|
+
// src/feedback-diagnostics.js
|
|
2209
|
+
import {
|
|
2210
|
+
FEEDBACK_GAME_DIAGNOSTICS_CONTRACT_VERSION,
|
|
2211
|
+
feedbackGameDiagnosticSurfaceRegistrations,
|
|
2212
|
+
parseFeedbackGameDiagnostics
|
|
2213
|
+
} from "@plasius/gpu-shared/feedback-diagnostics";
|
|
2214
|
+
var inputKeys = Object.freeze([
|
|
2215
|
+
"featureEnabled",
|
|
2216
|
+
"capabilityGranted",
|
|
2217
|
+
"consentConfirmed",
|
|
2218
|
+
"surfaceId",
|
|
2219
|
+
"renderer",
|
|
2220
|
+
"backend",
|
|
2221
|
+
"viewportWidth",
|
|
2222
|
+
"viewportHeight",
|
|
2223
|
+
"frameRate",
|
|
2224
|
+
"frameTimeMs",
|
|
2225
|
+
"featureIds",
|
|
2226
|
+
"counters",
|
|
2227
|
+
"errorCodes"
|
|
2228
|
+
]);
|
|
2229
|
+
function bucketFeedbackGameViewport(width, height) {
|
|
2230
|
+
if (typeof width !== "number" || typeof height !== "number" || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
2231
|
+
return "unknown";
|
|
2232
|
+
}
|
|
2233
|
+
const shorterEdge = Math.min(width, height);
|
|
2234
|
+
const longerEdge = Math.max(width, height);
|
|
2235
|
+
const size = shorterEdge < 600 ? "small" : shorterEdge < 900 || longerEdge < 1440 ? "medium" : "large";
|
|
2236
|
+
const orientation = width > height ? "landscape" : "portrait";
|
|
2237
|
+
return `${size}-${orientation}`;
|
|
2238
|
+
}
|
|
2239
|
+
function bucketFeedbackGameFrameRate(frameRate) {
|
|
2240
|
+
if (typeof frameRate !== "number" || !Number.isFinite(frameRate) || frameRate < 0) {
|
|
2241
|
+
return "unknown";
|
|
2242
|
+
}
|
|
2243
|
+
if (frameRate < 15) {
|
|
2244
|
+
return "under-15";
|
|
2245
|
+
}
|
|
2246
|
+
if (frameRate < 30) {
|
|
2247
|
+
return "15-29";
|
|
2248
|
+
}
|
|
2249
|
+
if (frameRate < 60) {
|
|
2250
|
+
return "30-59";
|
|
2251
|
+
}
|
|
2252
|
+
return "60-plus";
|
|
2253
|
+
}
|
|
2254
|
+
function bucketFeedbackGameFrameTime(frameTimeMs) {
|
|
2255
|
+
if (typeof frameTimeMs !== "number" || !Number.isFinite(frameTimeMs) || frameTimeMs < 0) {
|
|
2256
|
+
return "unknown";
|
|
2257
|
+
}
|
|
2258
|
+
if (frameTimeMs < 17) {
|
|
2259
|
+
return "under-17ms";
|
|
2260
|
+
}
|
|
2261
|
+
if (frameTimeMs < 34) {
|
|
2262
|
+
return "17-33ms";
|
|
2263
|
+
}
|
|
2264
|
+
if (frameTimeMs < 67) {
|
|
2265
|
+
return "34-66ms";
|
|
2266
|
+
}
|
|
2267
|
+
return "over-66ms";
|
|
2268
|
+
}
|
|
2269
|
+
function createFeedbackGameDiagnosticSnapshot(input) {
|
|
2270
|
+
try {
|
|
2271
|
+
return createFeedbackGameDiagnosticSnapshotInternal(input);
|
|
2272
|
+
} catch {
|
|
2273
|
+
throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
function createFeedbackGameDiagnosticSnapshotInternal(input) {
|
|
2277
|
+
const snapshot = snapshotInputIfEnabled(input);
|
|
2278
|
+
if (snapshot === null) {
|
|
2279
|
+
return null;
|
|
2280
|
+
}
|
|
2281
|
+
const registration = typeof snapshot.surfaceId === "string" && Object.hasOwn(
|
|
2282
|
+
feedbackGameDiagnosticSurfaceRegistrations,
|
|
2283
|
+
snapshot.surfaceId
|
|
2284
|
+
) ? feedbackGameDiagnosticSurfaceRegistrations[snapshot.surfaceId] : void 0;
|
|
2285
|
+
return parseFeedbackGameDiagnostics({
|
|
2286
|
+
type: "feedback-game-diagnostics",
|
|
2287
|
+
version: FEEDBACK_GAME_DIAGNOSTICS_CONTRACT_VERSION,
|
|
2288
|
+
surfaceId: snapshot.surfaceId,
|
|
2289
|
+
consentConfirmed: true,
|
|
2290
|
+
provenanceContractId: registration?.provenanceContractId,
|
|
2291
|
+
renderer: snapshot.renderer,
|
|
2292
|
+
backend: snapshot.backend,
|
|
2293
|
+
viewportBucket: bucketFeedbackGameViewport(
|
|
2294
|
+
snapshot.viewportWidth,
|
|
2295
|
+
snapshot.viewportHeight
|
|
2296
|
+
),
|
|
2297
|
+
frameRateBucket: bucketFeedbackGameFrameRate(snapshot.frameRate),
|
|
2298
|
+
frameTimeBucket: bucketFeedbackGameFrameTime(snapshot.frameTimeMs),
|
|
2299
|
+
featureIds: snapshot.featureIds,
|
|
2300
|
+
counters: snapshot.counters,
|
|
2301
|
+
errorCodes: snapshot.errorCodes
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
function snapshotInputIfEnabled(input) {
|
|
2305
|
+
assertValid(
|
|
2306
|
+
input !== null && typeof input === "object" && !Array.isArray(input) && (Object.getPrototypeOf(input) === Object.prototype || Object.getPrototypeOf(input) === null)
|
|
2307
|
+
);
|
|
2308
|
+
const gateKeys = [
|
|
2309
|
+
"featureEnabled",
|
|
2310
|
+
"capabilityGranted",
|
|
2311
|
+
"consentConfirmed"
|
|
2312
|
+
];
|
|
2313
|
+
const snapshot = /* @__PURE__ */ Object.create(null);
|
|
2314
|
+
for (const key of gateKeys) {
|
|
2315
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
2316
|
+
assertValid(
|
|
2317
|
+
descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value") && typeof descriptor.value === "boolean"
|
|
2318
|
+
);
|
|
2319
|
+
snapshot[key] = descriptor.value;
|
|
2320
|
+
}
|
|
2321
|
+
const { featureEnabled, capabilityGranted, consentConfirmed } = snapshot;
|
|
2322
|
+
if (!featureEnabled || !capabilityGranted || !consentConfirmed) {
|
|
2323
|
+
return null;
|
|
2324
|
+
}
|
|
2325
|
+
const actualKeys = Reflect.ownKeys(input);
|
|
2326
|
+
assertValid(
|
|
2327
|
+
actualKeys.length === inputKeys.length && inputKeys.every((key) => actualKeys.includes(key)) && actualKeys.every(
|
|
2328
|
+
(key) => typeof key === "string" && inputKeys.includes(key)
|
|
2329
|
+
)
|
|
2330
|
+
);
|
|
2331
|
+
for (const key of inputKeys.filter((key2) => !gateKeys.includes(key2))) {
|
|
2332
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
2333
|
+
assertValid(
|
|
2334
|
+
descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value")
|
|
2335
|
+
);
|
|
2336
|
+
snapshot[key] = descriptor.value;
|
|
2337
|
+
}
|
|
2338
|
+
return Object.freeze(snapshot);
|
|
2339
|
+
}
|
|
2340
|
+
function assertValid(condition) {
|
|
2341
|
+
if (!condition) {
|
|
2342
|
+
throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2208
2346
|
// src/wavefront-frame-runtime.js
|
|
2209
2347
|
function createGpuParallelismCounters() {
|
|
2210
2348
|
return {
|
|
@@ -4438,6 +4576,13 @@ function dispatchWavefrontGpuAccelerationBuild({
|
|
|
4438
4576
|
}
|
|
4439
4577
|
|
|
4440
4578
|
// src/wavefront-config.js
|
|
4579
|
+
var WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 256;
|
|
4580
|
+
function allocatedRecordBytes(count, recordBytes) {
|
|
4581
|
+
return Math.max(1, count) * recordBytes;
|
|
4582
|
+
}
|
|
4583
|
+
function alignByteSize(value, alignment) {
|
|
4584
|
+
return Math.ceil(value / alignment) * alignment;
|
|
4585
|
+
}
|
|
4441
4586
|
function resolveEnvironmentLighting(input, environmentColor, ambientColor) {
|
|
4442
4587
|
const source = input ?? {};
|
|
4443
4588
|
return Object.freeze({
|
|
@@ -4614,6 +4759,18 @@ function resolveCamera(input, width, height) {
|
|
|
4614
4759
|
});
|
|
4615
4760
|
}
|
|
4616
4761
|
function estimateWavefrontPathTracingMemory(options = {}) {
|
|
4762
|
+
const width = readPositiveInteger2("width", options.width, DEFAULT_WIDTH);
|
|
4763
|
+
const height = readPositiveInteger2("height", options.height, DEFAULT_HEIGHT);
|
|
4764
|
+
const tileSize = readPositiveInteger2("tileSize", options.tileSize, DEFAULT_TILE_SIZE);
|
|
4765
|
+
const samplesPerPixel = clamp2(
|
|
4766
|
+
readPositiveInteger2(
|
|
4767
|
+
"samplesPerPixel",
|
|
4768
|
+
options.samplesPerPixel,
|
|
4769
|
+
DEFAULT_SAMPLES_PER_PIXEL
|
|
4770
|
+
),
|
|
4771
|
+
1,
|
|
4772
|
+
MAX_SAMPLES_PER_PIXEL
|
|
4773
|
+
);
|
|
4617
4774
|
const tilePixelCapacity = readPositiveInteger2(
|
|
4618
4775
|
"tilePixelCapacity",
|
|
4619
4776
|
options.tilePixelCapacity,
|
|
@@ -4646,18 +4803,89 @@ function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
4646
4803
|
options.environmentPortalCapacity,
|
|
4647
4804
|
0
|
|
4648
4805
|
);
|
|
4649
|
-
|
|
4806
|
+
readNonNegativeInteger2("materialCapacity", options.materialCapacity, 0);
|
|
4807
|
+
const meshVertexCount = readNonNegativeInteger2(
|
|
4808
|
+
"meshVertexCount",
|
|
4809
|
+
options.meshVertexCount,
|
|
4810
|
+
0
|
|
4811
|
+
);
|
|
4812
|
+
const meshIndexCount = readNonNegativeInteger2(
|
|
4813
|
+
"meshIndexCount",
|
|
4814
|
+
options.meshIndexCount,
|
|
4815
|
+
0
|
|
4816
|
+
);
|
|
4817
|
+
const meshRangeCount = readNonNegativeInteger2(
|
|
4818
|
+
"meshRangeCount",
|
|
4819
|
+
options.meshRangeCount,
|
|
4820
|
+
0
|
|
4821
|
+
);
|
|
4822
|
+
const bvhSortStageCount = readNonNegativeInteger2(
|
|
4823
|
+
"bvhSortStageCount",
|
|
4824
|
+
options.bvhSortStageCount,
|
|
4825
|
+
0
|
|
4826
|
+
);
|
|
4827
|
+
const bvhBuildLevelCount = readNonNegativeInteger2(
|
|
4828
|
+
"bvhBuildLevelCount",
|
|
4829
|
+
options.bvhBuildLevelCount,
|
|
4830
|
+
0
|
|
4831
|
+
);
|
|
4832
|
+
const minUniformBufferOffsetAlignment = readPositiveInteger2(
|
|
4833
|
+
"minUniformBufferOffsetAlignment",
|
|
4834
|
+
options.minUniformBufferOffsetAlignment,
|
|
4835
|
+
WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
4836
|
+
);
|
|
4837
|
+
const denoise = options.denoise !== false;
|
|
4838
|
+
const deferredPathResolve = options.deferredPathResolve !== false;
|
|
4650
4839
|
const queueBytes = tilePixelCapacity * RAY_RECORD_BYTES;
|
|
4651
4840
|
const hitBytes = tilePixelCapacity * HIT_RECORD_BYTES;
|
|
4652
4841
|
const accumulationBytes = tilePixelCapacity * ACCUMULATION_RECORD_BYTES;
|
|
4653
4842
|
const pathVertexBytes = tilePixelCapacity * (maxDepth + 1) * PATH_VERTEX_RECORD_BYTES;
|
|
4654
4843
|
const sceneObjectBytes = sceneObjectCapacity * SCENE_OBJECT_RECORD_BYTES;
|
|
4655
|
-
const triangleBytes = triangleCapacity
|
|
4656
|
-
const materialTableBytes =
|
|
4844
|
+
const triangleBytes = allocatedRecordBytes(triangleCapacity, TRIANGLE_RECORD_BYTES);
|
|
4845
|
+
const materialTableBytes = 0;
|
|
4657
4846
|
const bvhNodeBytes = bvhNodeCapacity * BVH_NODE_RECORD_BYTES;
|
|
4658
|
-
const bvhLeafReferenceBytes =
|
|
4847
|
+
const bvhLeafReferenceBytes = allocatedRecordBytes(
|
|
4848
|
+
bvhLeafSortCapacity,
|
|
4849
|
+
BVH_LEAF_REF_RECORD_BYTES
|
|
4850
|
+
);
|
|
4659
4851
|
const emissiveTriangleMetadataBytes = emissiveTriangleCapacity * BVH_NODE_RECORD_BYTES;
|
|
4660
|
-
const
|
|
4852
|
+
const bvhCombinedBytes = allocatedRecordBytes(
|
|
4853
|
+
bvhNodeCapacity + emissiveTriangleCapacity,
|
|
4854
|
+
BVH_NODE_RECORD_BYTES
|
|
4855
|
+
);
|
|
4856
|
+
const meshVertexBytes = allocatedRecordBytes(meshVertexCount, MESH_VERTEX_RECORD_BYTES);
|
|
4857
|
+
const meshIndexBytes = allocatedRecordBytes(meshIndexCount, 4);
|
|
4858
|
+
const meshRangeBytes = allocatedRecordBytes(meshRangeCount, MESH_RANGE_RECORD_BYTES);
|
|
4859
|
+
const environmentPortalBytes = allocatedRecordBytes(
|
|
4860
|
+
environmentPortalCapacity,
|
|
4861
|
+
ENVIRONMENT_PORTAL_RECORD_BYTES
|
|
4862
|
+
);
|
|
4863
|
+
const tileCount = Math.ceil(width / tileSize) * Math.ceil(height / tileSize);
|
|
4864
|
+
const outputConfigSlotCount = deferredPathResolve ? 0 : tileCount;
|
|
4865
|
+
const frameConfigSlotCount = Math.max(
|
|
4866
|
+
1,
|
|
4867
|
+
tileCount * samplesPerPixel + outputConfigSlotCount + (denoise ? 1 : 0)
|
|
4868
|
+
);
|
|
4869
|
+
const configBufferStride = alignByteSize(
|
|
4870
|
+
CONFIG_BUFFER_BYTES,
|
|
4871
|
+
minUniformBufferOffsetAlignment
|
|
4872
|
+
);
|
|
4873
|
+
const frameConfigBytes = frameConfigSlotCount * configBufferStride;
|
|
4874
|
+
const bvhBuildConfigBytes = Math.max(
|
|
4875
|
+
1,
|
|
4876
|
+
1 + bvhSortStageCount + bvhBuildLevelCount
|
|
4877
|
+
) * configBufferStride;
|
|
4878
|
+
const sceneStorageBufferBindingBytes = Math.max(
|
|
4879
|
+
sceneObjectBytes,
|
|
4880
|
+
triangleBytes,
|
|
4881
|
+
bvhCombinedBytes,
|
|
4882
|
+
meshVertexBytes,
|
|
4883
|
+
meshIndexBytes,
|
|
4884
|
+
meshRangeBytes,
|
|
4885
|
+
environmentPortalBytes,
|
|
4886
|
+
bvhLeafReferenceBytes
|
|
4887
|
+
);
|
|
4888
|
+
const totalHotBufferBytes = queueBytes * 2 + hitBytes + accumulationBytes + pathVertexBytes + sceneObjectBytes + triangleBytes + bvhCombinedBytes + meshVertexBytes + meshIndexBytes + meshRangeBytes + bvhLeafReferenceBytes + environmentPortalBytes + frameConfigBytes + bvhBuildConfigBytes + COUNTER_BUFFER_BYTES + INDIRECT_DISPATCH_ARGS_BYTES;
|
|
4661
4889
|
return Object.freeze({
|
|
4662
4890
|
queueBytes,
|
|
4663
4891
|
queuePairBytes: queueBytes * 2,
|
|
@@ -4668,13 +4896,45 @@ function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
4668
4896
|
triangleBytes,
|
|
4669
4897
|
materialTableBytes,
|
|
4670
4898
|
bvhNodeBytes,
|
|
4899
|
+
bvhCombinedBytes,
|
|
4671
4900
|
bvhLeafReferenceBytes,
|
|
4672
4901
|
emissiveTriangleMetadataBytes,
|
|
4902
|
+
meshVertexBytes,
|
|
4903
|
+
meshIndexBytes,
|
|
4904
|
+
meshRangeBytes,
|
|
4673
4905
|
environmentPortalBytes,
|
|
4674
4906
|
configBytes: CONFIG_BUFFER_BYTES,
|
|
4907
|
+
configBufferStride,
|
|
4908
|
+
frameConfigBytes,
|
|
4909
|
+
bvhBuildConfigBytes,
|
|
4675
4910
|
counterBytes: COUNTER_BUFFER_BYTES,
|
|
4676
4911
|
indirectDispatchBytes: INDIRECT_DISPATCH_ARGS_BYTES,
|
|
4677
|
-
|
|
4912
|
+
sceneStorageBufferBindingBytes,
|
|
4913
|
+
totalHotBufferBytes
|
|
4914
|
+
});
|
|
4915
|
+
}
|
|
4916
|
+
function estimateWavefrontPathTracingMemoryForConfig(config, limits = {}) {
|
|
4917
|
+
return estimateWavefrontPathTracingMemory({
|
|
4918
|
+
width: config.width,
|
|
4919
|
+
height: config.height,
|
|
4920
|
+
tileSize: config.tileSize,
|
|
4921
|
+
samplesPerPixel: config.samplesPerPixel,
|
|
4922
|
+
tilePixelCapacity: config.tilePixelCapacity,
|
|
4923
|
+
maxDepth: config.maxDepth,
|
|
4924
|
+
sceneObjectCapacity: config.sceneObjectCapacity,
|
|
4925
|
+
triangleCapacity: config.triangleCapacity,
|
|
4926
|
+
bvhNodeCapacity: config.bvhNodeCapacity,
|
|
4927
|
+
bvhLeafSortCapacity: config.bvhLeafSortCapacity,
|
|
4928
|
+
emissiveTriangleCapacity: config.emissiveTriangleCapacity,
|
|
4929
|
+
environmentPortalCapacity: config.environmentPortalCapacity,
|
|
4930
|
+
meshVertexCount: config.gpuMeshSource.vertices.count,
|
|
4931
|
+
meshIndexCount: config.gpuMeshSource.indices.count,
|
|
4932
|
+
meshRangeCount: config.gpuMeshSource.meshes.count,
|
|
4933
|
+
bvhSortStageCount: config.bvhSortStages.length,
|
|
4934
|
+
bvhBuildLevelCount: config.bvhBuildLevels.length,
|
|
4935
|
+
denoise: config.denoise,
|
|
4936
|
+
deferredPathResolve: config.deferredPathResolve,
|
|
4937
|
+
minUniformBufferOffsetAlignment: limits.minUniformBufferOffsetAlignment ?? WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
4678
4938
|
});
|
|
4679
4939
|
}
|
|
4680
4940
|
function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
@@ -4819,15 +5079,25 @@ function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
|
4819
5079
|
denoise: options.denoise !== false,
|
|
4820
5080
|
frameIndex: readNonNegativeInteger2("frameIndex", options.frameIndex, 0),
|
|
4821
5081
|
memory: estimateWavefrontPathTracingMemory({
|
|
5082
|
+
width,
|
|
5083
|
+
height,
|
|
5084
|
+
tileSize,
|
|
5085
|
+
samplesPerPixel,
|
|
4822
5086
|
tilePixelCapacity,
|
|
4823
5087
|
maxDepth,
|
|
4824
5088
|
sceneObjectCapacity,
|
|
4825
5089
|
triangleCapacity,
|
|
4826
|
-
materialCapacity: gpuMaterialSource.count,
|
|
4827
5090
|
bvhNodeCapacity,
|
|
4828
5091
|
bvhLeafSortCapacity,
|
|
4829
5092
|
emissiveTriangleCapacity: emissiveTriangleIndices.capacity,
|
|
4830
|
-
environmentPortalCapacity
|
|
5093
|
+
environmentPortalCapacity,
|
|
5094
|
+
meshVertexCount: gpuMeshSource.vertices.count,
|
|
5095
|
+
meshIndexCount: gpuMeshSource.indices.count,
|
|
5096
|
+
meshRangeCount: gpuMeshSource.meshes.count,
|
|
5097
|
+
bvhSortStageCount: bvhSortStages.length,
|
|
5098
|
+
bvhBuildLevelCount: bvhBuildLevels.length,
|
|
5099
|
+
denoise: options.denoise !== false,
|
|
5100
|
+
deferredPathResolve
|
|
4831
5101
|
})
|
|
4832
5102
|
});
|
|
4833
5103
|
}
|
|
@@ -4918,7 +5188,13 @@ function clampTileSizeForDevice(config, device) {
|
|
|
4918
5188
|
}
|
|
4919
5189
|
const maxPixelsByRay = Math.floor(limit / RAY_RECORD_BYTES);
|
|
4920
5190
|
const maxPixelsByHit = Math.floor(limit / HIT_RECORD_BYTES);
|
|
4921
|
-
const
|
|
5191
|
+
const maxPixelsByPathVertex = Math.floor(
|
|
5192
|
+
limit / ((config.maxDepth + 1) * PATH_VERTEX_RECORD_BYTES)
|
|
5193
|
+
);
|
|
5194
|
+
const maxPixels = Math.max(
|
|
5195
|
+
256,
|
|
5196
|
+
Math.min(maxPixelsByRay, maxPixelsByHit, maxPixelsByPathVertex)
|
|
5197
|
+
);
|
|
4922
5198
|
if (config.tilePixelCapacity <= maxPixels) {
|
|
4923
5199
|
return config.tileSize;
|
|
4924
5200
|
}
|
|
@@ -5672,6 +5948,32 @@ function createWavefrontPresentBindGroup({
|
|
|
5672
5948
|
}
|
|
5673
5949
|
|
|
5674
5950
|
// src/wavefront-runtime-support.js
|
|
5951
|
+
var WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE = 128 * 1024 * 1024;
|
|
5952
|
+
var WEBGPU_DEFAULT_MAX_BUFFER_SIZE = 256 * 1024 * 1024;
|
|
5953
|
+
function readRequestedDeviceLimit(source, name) {
|
|
5954
|
+
const rawValue = source?.[name];
|
|
5955
|
+
if (rawValue === void 0 || rawValue === null) {
|
|
5956
|
+
return 0;
|
|
5957
|
+
}
|
|
5958
|
+
const value = Number(rawValue);
|
|
5959
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
5960
|
+
throw new Error(`${name} must be a non-negative safe integer.`);
|
|
5961
|
+
}
|
|
5962
|
+
return value;
|
|
5963
|
+
}
|
|
5964
|
+
function assertAdapterSupportsRequiredLimit(adapter, name, requiredValue) {
|
|
5965
|
+
const availableValue = Number(adapter?.limits?.[name]);
|
|
5966
|
+
if (!Number.isFinite(availableValue)) {
|
|
5967
|
+
throw new Error(
|
|
5968
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, but this adapter does not expose that limit.`
|
|
5969
|
+
);
|
|
5970
|
+
}
|
|
5971
|
+
if (availableValue < requiredValue) {
|
|
5972
|
+
throw new Error(
|
|
5973
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, but this adapter exposes ${availableValue} bytes.`
|
|
5974
|
+
);
|
|
5975
|
+
}
|
|
5976
|
+
}
|
|
5675
5977
|
function getGpuUsageConstants() {
|
|
5676
5978
|
if (typeof GPUBufferUsage === "undefined" || typeof GPUTextureUsage === "undefined" || typeof GPUShaderStage === "undefined") {
|
|
5677
5979
|
throw new Error("WebGPU runtime unavailable. Required GPU constants are missing.");
|
|
@@ -5769,8 +6071,13 @@ async function createRenderPipeline(device, descriptor) {
|
|
|
5769
6071
|
}
|
|
5770
6072
|
return device.createRenderPipeline(descriptor);
|
|
5771
6073
|
}
|
|
5772
|
-
function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
5773
|
-
const
|
|
6074
|
+
function createWavefrontDeviceDescriptor(adapter, options = {}, memory = null) {
|
|
6075
|
+
const descriptor = { ...options.deviceDescriptor ?? {} };
|
|
6076
|
+
const descriptorRequiredLimits = { ...descriptor.requiredLimits ?? {} };
|
|
6077
|
+
const requiredLimits = {
|
|
6078
|
+
...descriptorRequiredLimits,
|
|
6079
|
+
...options.requiredLimits ?? {}
|
|
6080
|
+
};
|
|
5774
6081
|
const exposedStorageBufferLimit = Number(adapter?.limits?.maxStorageBuffersPerShaderStage);
|
|
5775
6082
|
if (Number.isFinite(exposedStorageBufferLimit)) {
|
|
5776
6083
|
if (exposedStorageBufferLimit < TRACE_STORAGE_BUFFER_BINDINGS) {
|
|
@@ -5795,7 +6102,32 @@ function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
|
5795
6102
|
TRACE_SAMPLED_TEXTURE_BINDINGS
|
|
5796
6103
|
);
|
|
5797
6104
|
}
|
|
5798
|
-
const
|
|
6105
|
+
const sceneStorageBufferBindingBytes = Number(
|
|
6106
|
+
memory?.sceneStorageBufferBindingBytes ?? 0
|
|
6107
|
+
);
|
|
6108
|
+
const requestedStorageBufferBindingSize = Math.max(
|
|
6109
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxStorageBufferBindingSize"),
|
|
6110
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxStorageBufferBindingSize"),
|
|
6111
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE ? sceneStorageBufferBindingBytes : 0
|
|
6112
|
+
);
|
|
6113
|
+
if (requestedStorageBufferBindingSize > 0) {
|
|
6114
|
+
assertAdapterSupportsRequiredLimit(
|
|
6115
|
+
adapter,
|
|
6116
|
+
"maxStorageBufferBindingSize",
|
|
6117
|
+
requestedStorageBufferBindingSize
|
|
6118
|
+
);
|
|
6119
|
+
requiredLimits.maxStorageBufferBindingSize = requestedStorageBufferBindingSize;
|
|
6120
|
+
}
|
|
6121
|
+
const requestedMaxBufferSize = Math.max(
|
|
6122
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxBufferSize"),
|
|
6123
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxBufferSize"),
|
|
6124
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_BUFFER_SIZE ? sceneStorageBufferBindingBytes : 0,
|
|
6125
|
+
requestedStorageBufferBindingSize > WEBGPU_DEFAULT_MAX_BUFFER_SIZE ? requestedStorageBufferBindingSize : 0
|
|
6126
|
+
);
|
|
6127
|
+
if (requestedMaxBufferSize > 0) {
|
|
6128
|
+
assertAdapterSupportsRequiredLimit(adapter, "maxBufferSize", requestedMaxBufferSize);
|
|
6129
|
+
requiredLimits.maxBufferSize = requestedMaxBufferSize;
|
|
6130
|
+
}
|
|
5799
6131
|
const requiredFeatures = Array.from(descriptor.requiredFeatures ?? []);
|
|
5800
6132
|
const adapterFeatures = adapter?.features;
|
|
5801
6133
|
const timestampQuerySupported = typeof adapterFeatures?.has === "function" ? adapterFeatures.has("timestamp-query") : adapterFeatures && typeof adapterFeatures[Symbol.iterator] === "function" ? Array.from(adapterFeatures).includes("timestamp-query") : false;
|
|
@@ -5846,7 +6178,8 @@ function createGpuAdapterParallelismDiagnostics(adapter, device) {
|
|
|
5846
6178
|
maxComputeWorkgroupSizeZ: readGpuLimit(adapter, device, "maxComputeWorkgroupSizeZ"),
|
|
5847
6179
|
maxComputeWorkgroupsPerDimension: readGpuLimit(adapter, device, "maxComputeWorkgroupsPerDimension"),
|
|
5848
6180
|
maxStorageBuffersPerShaderStage: readGpuLimit(adapter, device, "maxStorageBuffersPerShaderStage"),
|
|
5849
|
-
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize")
|
|
6181
|
+
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize"),
|
|
6182
|
+
maxBufferSize: readGpuLimit(adapter, device, "maxBufferSize")
|
|
5850
6183
|
}),
|
|
5851
6184
|
configuredWorkgroupSize: WORKGROUP_SIZE
|
|
5852
6185
|
});
|
|
@@ -11152,7 +11485,9 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11152
11485
|
if (!adapter) {
|
|
11153
11486
|
throw new Error("Unable to acquire a WebGPU adapter for wavefront path tracing.");
|
|
11154
11487
|
}
|
|
11155
|
-
const device = await adapter.requestDevice(
|
|
11488
|
+
const device = await adapter.requestDevice(
|
|
11489
|
+
createWavefrontDeviceDescriptor(adapter, options, initialConfig.memory)
|
|
11490
|
+
);
|
|
11156
11491
|
const gpuAdapterParallelism = createGpuAdapterParallelismDiagnostics(adapter, device);
|
|
11157
11492
|
const context = canvas.getContext("webgpu");
|
|
11158
11493
|
if (!context || typeof context.configure !== "function") {
|
|
@@ -11167,9 +11502,17 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11167
11502
|
canvas,
|
|
11168
11503
|
width: config.width,
|
|
11169
11504
|
height: config.height,
|
|
11170
|
-
tileSize: safeTileSize
|
|
11505
|
+
tileSize: safeTileSize,
|
|
11506
|
+
tilePixelCapacity: Math.min(
|
|
11507
|
+
config.tilePixelCapacity,
|
|
11508
|
+
safeTileSize * safeTileSize
|
|
11509
|
+
)
|
|
11171
11510
|
});
|
|
11172
11511
|
}
|
|
11512
|
+
config = Object.freeze({
|
|
11513
|
+
...config,
|
|
11514
|
+
memory: estimateWavefrontPathTracingMemoryForConfig(config, device.limits)
|
|
11515
|
+
});
|
|
11173
11516
|
canvas.width = config.width;
|
|
11174
11517
|
canvas.height = config.height;
|
|
11175
11518
|
context.configure({
|
|
@@ -11178,79 +11521,72 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11178
11521
|
alphaMode: options.alpha === true ? "premultiplied" : "opaque"
|
|
11179
11522
|
});
|
|
11180
11523
|
const bufferUsage = constants.buffer.STORAGE | constants.buffer.COPY_DST;
|
|
11181
|
-
const
|
|
11182
|
-
const
|
|
11183
|
-
const
|
|
11184
|
-
const
|
|
11185
|
-
const activeQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.activeQueue");
|
|
11186
|
-
const nextQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.nextQueue");
|
|
11187
|
-
const hitBuffer = createBuffer(device, bufferUsage, hitBytes, "plasius.wavefront.hitBuffer");
|
|
11524
|
+
const memory = config.memory;
|
|
11525
|
+
const activeQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.activeQueue");
|
|
11526
|
+
const nextQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.nextQueue");
|
|
11527
|
+
const hitBuffer = createBuffer(device, bufferUsage, memory.hitBytes, "plasius.wavefront.hitBuffer");
|
|
11188
11528
|
const accumulationBuffer = createBuffer(
|
|
11189
11529
|
device,
|
|
11190
11530
|
bufferUsage,
|
|
11191
|
-
accumulationBytes,
|
|
11531
|
+
memory.accumulationBytes,
|
|
11192
11532
|
"plasius.wavefront.accumulation"
|
|
11193
11533
|
);
|
|
11194
11534
|
const pathVertexBuffer = createBuffer(
|
|
11195
11535
|
device,
|
|
11196
11536
|
bufferUsage,
|
|
11197
|
-
pathVertexBytes,
|
|
11537
|
+
memory.pathVertexBytes,
|
|
11198
11538
|
"plasius.wavefront.pathVertices"
|
|
11199
11539
|
);
|
|
11200
11540
|
const sceneObjectBuffer = createBuffer(
|
|
11201
11541
|
device,
|
|
11202
11542
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11203
|
-
|
|
11543
|
+
memory.sceneObjectBytes,
|
|
11204
11544
|
"plasius.wavefront.sceneObjects"
|
|
11205
11545
|
);
|
|
11206
11546
|
const triangleBuffer = createBuffer(
|
|
11207
11547
|
device,
|
|
11208
11548
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11209
|
-
|
|
11549
|
+
memory.triangleBytes,
|
|
11210
11550
|
"plasius.wavefront.triangles"
|
|
11211
11551
|
);
|
|
11212
11552
|
const bvhNodeBuffer = createBuffer(
|
|
11213
11553
|
device,
|
|
11214
11554
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11215
|
-
|
|
11555
|
+
memory.bvhCombinedBytes,
|
|
11216
11556
|
"plasius.wavefront.bvhNodes"
|
|
11217
11557
|
);
|
|
11218
11558
|
const meshVertexBuffer = createBuffer(
|
|
11219
11559
|
device,
|
|
11220
11560
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11221
|
-
|
|
11561
|
+
memory.meshVertexBytes,
|
|
11222
11562
|
"plasius.wavefront.meshVertices"
|
|
11223
11563
|
);
|
|
11224
11564
|
const meshIndexBuffer = createBuffer(
|
|
11225
11565
|
device,
|
|
11226
11566
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11227
|
-
|
|
11567
|
+
memory.meshIndexBytes,
|
|
11228
11568
|
"plasius.wavefront.meshIndices"
|
|
11229
11569
|
);
|
|
11230
11570
|
const meshRangeBuffer = createBuffer(
|
|
11231
11571
|
device,
|
|
11232
11572
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11233
|
-
|
|
11573
|
+
memory.meshRangeBytes,
|
|
11234
11574
|
"plasius.wavefront.meshRanges"
|
|
11235
11575
|
);
|
|
11236
11576
|
const environmentPortalBuffer = createBuffer(
|
|
11237
11577
|
device,
|
|
11238
11578
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11239
|
-
|
|
11579
|
+
memory.environmentPortalBytes,
|
|
11240
11580
|
"plasius.wavefront.environmentPortals"
|
|
11241
11581
|
);
|
|
11242
11582
|
const bvhLeafRefBuffer = createBuffer(
|
|
11243
11583
|
device,
|
|
11244
11584
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11245
|
-
|
|
11585
|
+
memory.bvhLeafReferenceBytes,
|
|
11246
11586
|
"plasius.wavefront.bvhLeafRefs"
|
|
11247
11587
|
);
|
|
11248
11588
|
const tiles = createTiles(config.width, config.height, config.tileSize);
|
|
11249
|
-
const
|
|
11250
|
-
const configBufferStride = alignTo(
|
|
11251
|
-
CONFIG_BUFFER_BYTES,
|
|
11252
|
-
Number.isFinite(uniformOffsetAlignment) && uniformOffsetAlignment > 0 ? uniformOffsetAlignment : CONFIG_BUFFER_BYTES
|
|
11253
|
-
);
|
|
11589
|
+
const configBufferStride = memory.configBufferStride;
|
|
11254
11590
|
const outputConfigSlotCount = config.deferredPathResolve ? 0 : tiles.length;
|
|
11255
11591
|
const frameConfigSlotCount = Math.max(
|
|
11256
11592
|
1,
|
|
@@ -11259,26 +11595,25 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11259
11595
|
const configBuffer = createBuffer(
|
|
11260
11596
|
device,
|
|
11261
11597
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11262
|
-
|
|
11598
|
+
memory.frameConfigBytes,
|
|
11263
11599
|
"plasius.wavefront.frameConfig"
|
|
11264
11600
|
);
|
|
11265
|
-
const bvhBuildConfigSlots = 1 + config.bvhSortStages.length + config.bvhBuildLevels.length;
|
|
11266
11601
|
const bvhBuildConfigBuffer = createBuffer(
|
|
11267
11602
|
device,
|
|
11268
11603
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11269
|
-
|
|
11604
|
+
memory.bvhBuildConfigBytes,
|
|
11270
11605
|
"plasius.wavefront.bvhBuildConfig"
|
|
11271
11606
|
);
|
|
11272
11607
|
const counterBuffer = createBuffer(
|
|
11273
11608
|
device,
|
|
11274
11609
|
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
11275
|
-
|
|
11610
|
+
memory.counterBytes,
|
|
11276
11611
|
"plasius.wavefront.counters"
|
|
11277
11612
|
);
|
|
11278
11613
|
const activeDispatchBuffer = createBuffer(
|
|
11279
11614
|
device,
|
|
11280
11615
|
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
11281
|
-
|
|
11616
|
+
memory.indirectDispatchBytes,
|
|
11282
11617
|
"plasius.wavefront.activeDispatchArgs"
|
|
11283
11618
|
);
|
|
11284
11619
|
let packedScene = packWavefrontSceneObjects(config.sceneObjects, config.sceneObjectCapacity);
|
|
@@ -12988,8 +13323,12 @@ export {
|
|
|
12988
13323
|
applyMediumTransmittance,
|
|
12989
13324
|
beerLambertTransmittance,
|
|
12990
13325
|
bindRendererToXrManager,
|
|
13326
|
+
bucketFeedbackGameFrameRate,
|
|
13327
|
+
bucketFeedbackGameFrameTime,
|
|
13328
|
+
bucketFeedbackGameViewport,
|
|
12991
13329
|
createAnimatedSceneRenderer,
|
|
12992
13330
|
createDefaultWavefrontSceneObjects,
|
|
13331
|
+
createFeedbackGameDiagnosticSnapshot,
|
|
12993
13332
|
createGpuRenderer,
|
|
12994
13333
|
createMediumStack,
|
|
12995
13334
|
createProfessionalAnimatedSceneRenderer,
|