@plasius/gpu-renderer 0.2.41 → 0.2.43
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 +40 -0
- package/README.md +14 -0
- package/dist/index.cjs +232 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +232 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.d.ts +24 -0
- package/src/wavefront-compute.js +27 -46
- package/src/wavefront-config.js +161 -23
- package/src/wavefront-frame-telemetry.js +5 -1
- package/src/wavefront-runtime-support.js +73 -3
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -960,12 +960,20 @@ export interface WavefrontPathTracingMemoryEstimate {
|
|
|
960
960
|
readonly triangleBytes: number;
|
|
961
961
|
readonly materialTableBytes: number;
|
|
962
962
|
readonly bvhNodeBytes: number;
|
|
963
|
+
readonly bvhCombinedBytes: number;
|
|
963
964
|
readonly bvhLeafReferenceBytes: number;
|
|
964
965
|
readonly emissiveTriangleMetadataBytes: number;
|
|
966
|
+
readonly meshVertexBytes: number;
|
|
967
|
+
readonly meshIndexBytes: number;
|
|
968
|
+
readonly meshRangeBytes: number;
|
|
965
969
|
readonly environmentPortalBytes: number;
|
|
966
970
|
readonly configBytes: number;
|
|
971
|
+
readonly configBufferStride: number;
|
|
972
|
+
readonly frameConfigBytes: number;
|
|
973
|
+
readonly bvhBuildConfigBytes: number;
|
|
967
974
|
readonly counterBytes: number;
|
|
968
975
|
readonly indirectDispatchBytes: number;
|
|
976
|
+
readonly sceneStorageBufferBindingBytes: number;
|
|
969
977
|
readonly totalHotBufferBytes: number;
|
|
970
978
|
}
|
|
971
979
|
|
|
@@ -987,6 +995,7 @@ export interface WavefrontGpuParallelismDiagnostics {
|
|
|
987
995
|
readonly maxComputeWorkgroupsPerDimension: number | null;
|
|
988
996
|
readonly maxStorageBuffersPerShaderStage: number | null;
|
|
989
997
|
readonly maxStorageBufferBindingSize: number | null;
|
|
998
|
+
readonly maxBufferSize: number | null;
|
|
990
999
|
}>;
|
|
991
1000
|
readonly configuredWorkgroupSize: number;
|
|
992
1001
|
readonly directDispatches: number;
|
|
@@ -1279,12 +1288,27 @@ export function createWavefrontGpuMaterialSource(
|
|
|
1279
1288
|
): WavefrontGpuMaterialSource;
|
|
1280
1289
|
export function createDefaultWavefrontSceneObjects(): readonly WavefrontSceneObject[];
|
|
1281
1290
|
export function estimateWavefrontPathTracingMemory(options?: {
|
|
1291
|
+
width?: number;
|
|
1292
|
+
height?: number;
|
|
1293
|
+
tileSize?: number;
|
|
1294
|
+
samplesPerPixel?: number;
|
|
1282
1295
|
tilePixelCapacity?: number;
|
|
1296
|
+
maxDepth?: number;
|
|
1283
1297
|
sceneObjectCapacity?: number;
|
|
1284
1298
|
triangleCapacity?: number;
|
|
1299
|
+
materialCapacity?: number;
|
|
1285
1300
|
bvhNodeCapacity?: number;
|
|
1286
1301
|
bvhLeafSortCapacity?: number;
|
|
1287
1302
|
emissiveTriangleCapacity?: number;
|
|
1303
|
+
environmentPortalCapacity?: number;
|
|
1304
|
+
meshVertexCount?: number;
|
|
1305
|
+
meshIndexCount?: number;
|
|
1306
|
+
meshRangeCount?: number;
|
|
1307
|
+
bvhSortStageCount?: number;
|
|
1308
|
+
bvhBuildLevelCount?: number;
|
|
1309
|
+
denoise?: boolean;
|
|
1310
|
+
deferredPathResolve?: boolean;
|
|
1311
|
+
minUniformBufferOffsetAlignment?: number;
|
|
1288
1312
|
}): WavefrontPathTracingMemoryEstimate;
|
|
1289
1313
|
export function normalizeWavefrontMesh(
|
|
1290
1314
|
input: WavefrontMeshInput,
|
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") {
|
|
@@ -224,6 +213,10 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
224
213
|
tileSize: safeTileSize,
|
|
225
214
|
});
|
|
226
215
|
}
|
|
216
|
+
config = Object.freeze({
|
|
217
|
+
...config,
|
|
218
|
+
memory: estimateWavefrontPathTracingMemoryForConfig(config, device.limits),
|
|
219
|
+
});
|
|
227
220
|
canvas.width = config.width;
|
|
228
221
|
canvas.height = config.height;
|
|
229
222
|
context.configure({
|
|
@@ -233,82 +226,72 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
233
226
|
});
|
|
234
227
|
|
|
235
228
|
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");
|
|
229
|
+
const memory = config.memory;
|
|
230
|
+
const activeQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.activeQueue");
|
|
231
|
+
const nextQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.nextQueue");
|
|
232
|
+
const hitBuffer = createBuffer(device, bufferUsage, memory.hitBytes, "plasius.wavefront.hitBuffer");
|
|
243
233
|
const accumulationBuffer = createBuffer(
|
|
244
234
|
device,
|
|
245
235
|
bufferUsage,
|
|
246
|
-
accumulationBytes,
|
|
236
|
+
memory.accumulationBytes,
|
|
247
237
|
"plasius.wavefront.accumulation"
|
|
248
238
|
);
|
|
249
239
|
const pathVertexBuffer = createBuffer(
|
|
250
240
|
device,
|
|
251
241
|
bufferUsage,
|
|
252
|
-
pathVertexBytes,
|
|
242
|
+
memory.pathVertexBytes,
|
|
253
243
|
"plasius.wavefront.pathVertices"
|
|
254
244
|
);
|
|
255
245
|
const sceneObjectBuffer = createBuffer(
|
|
256
246
|
device,
|
|
257
247
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
258
|
-
|
|
248
|
+
memory.sceneObjectBytes,
|
|
259
249
|
"plasius.wavefront.sceneObjects"
|
|
260
250
|
);
|
|
261
251
|
const triangleBuffer = createBuffer(
|
|
262
252
|
device,
|
|
263
253
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
264
|
-
|
|
254
|
+
memory.triangleBytes,
|
|
265
255
|
"plasius.wavefront.triangles"
|
|
266
256
|
);
|
|
267
257
|
const bvhNodeBuffer = createBuffer(
|
|
268
258
|
device,
|
|
269
259
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
270
|
-
|
|
271
|
-
BVH_NODE_RECORD_BYTES,
|
|
260
|
+
memory.bvhCombinedBytes,
|
|
272
261
|
"plasius.wavefront.bvhNodes"
|
|
273
262
|
);
|
|
274
263
|
const meshVertexBuffer = createBuffer(
|
|
275
264
|
device,
|
|
276
265
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
277
|
-
|
|
266
|
+
memory.meshVertexBytes,
|
|
278
267
|
"plasius.wavefront.meshVertices"
|
|
279
268
|
);
|
|
280
269
|
const meshIndexBuffer = createBuffer(
|
|
281
270
|
device,
|
|
282
271
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
283
|
-
|
|
272
|
+
memory.meshIndexBytes,
|
|
284
273
|
"plasius.wavefront.meshIndices"
|
|
285
274
|
);
|
|
286
275
|
const meshRangeBuffer = createBuffer(
|
|
287
276
|
device,
|
|
288
277
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
289
|
-
|
|
278
|
+
memory.meshRangeBytes,
|
|
290
279
|
"plasius.wavefront.meshRanges"
|
|
291
280
|
);
|
|
292
281
|
const environmentPortalBuffer = createBuffer(
|
|
293
282
|
device,
|
|
294
283
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
295
|
-
|
|
284
|
+
memory.environmentPortalBytes,
|
|
296
285
|
"plasius.wavefront.environmentPortals"
|
|
297
286
|
);
|
|
298
287
|
const bvhLeafRefBuffer = createBuffer(
|
|
299
288
|
device,
|
|
300
289
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
301
|
-
|
|
290
|
+
memory.bvhLeafReferenceBytes,
|
|
302
291
|
"plasius.wavefront.bvhLeafRefs"
|
|
303
292
|
);
|
|
304
293
|
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
|
-
);
|
|
294
|
+
const configBufferStride = memory.configBufferStride;
|
|
312
295
|
const outputConfigSlotCount = config.deferredPathResolve ? 0 : tiles.length;
|
|
313
296
|
const frameConfigSlotCount = Math.max(
|
|
314
297
|
1,
|
|
@@ -317,27 +300,25 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
317
300
|
const configBuffer = createBuffer(
|
|
318
301
|
device,
|
|
319
302
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
320
|
-
|
|
303
|
+
memory.frameConfigBytes,
|
|
321
304
|
"plasius.wavefront.frameConfig"
|
|
322
305
|
);
|
|
323
|
-
const bvhBuildConfigSlots =
|
|
324
|
-
1 + config.bvhSortStages.length + config.bvhBuildLevels.length;
|
|
325
306
|
const bvhBuildConfigBuffer = createBuffer(
|
|
326
307
|
device,
|
|
327
308
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
328
|
-
|
|
309
|
+
memory.bvhBuildConfigBytes,
|
|
329
310
|
"plasius.wavefront.bvhBuildConfig"
|
|
330
311
|
);
|
|
331
312
|
const counterBuffer = createBuffer(
|
|
332
313
|
device,
|
|
333
314
|
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
334
|
-
|
|
315
|
+
memory.counterBytes,
|
|
335
316
|
"plasius.wavefront.counters"
|
|
336
317
|
);
|
|
337
318
|
const activeDispatchBuffer = createBuffer(
|
|
338
319
|
device,
|
|
339
320
|
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
340
|
-
|
|
321
|
+
memory.indirectDispatchBytes,
|
|
341
322
|
"plasius.wavefront.activeDispatchArgs"
|
|
342
323
|
);
|
|
343
324
|
|
package/src/wavefront-config.js
CHANGED
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
EMISSIVE_TRIANGLE_INDEX_BYTES,
|
|
20
20
|
EMPTY_TERMINATION_METRICS,
|
|
21
21
|
ENVIRONMENT_PORTAL_RECORD_BYTES,
|
|
22
|
-
GPU_MATERIAL_RECORD_BYTES,
|
|
23
22
|
HIT_RECORD_BYTES,
|
|
24
23
|
INDIRECT_DISPATCH_ARGS_BYTES,
|
|
25
24
|
MAX_PATH_TRACING_DEPTH,
|
|
@@ -69,6 +68,16 @@ import {
|
|
|
69
68
|
resolveAccelerationBuildMode,
|
|
70
69
|
} from "./wavefront-scene-data.js";
|
|
71
70
|
|
|
71
|
+
const WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 256;
|
|
72
|
+
|
|
73
|
+
function allocatedRecordBytes(count, recordBytes) {
|
|
74
|
+
return Math.max(1, count) * recordBytes;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function alignByteSize(value, alignment) {
|
|
78
|
+
return Math.ceil(value / alignment) * alignment;
|
|
79
|
+
}
|
|
80
|
+
|
|
72
81
|
function resolveEnvironmentLighting(input, environmentColor, ambientColor) {
|
|
73
82
|
const source = input ?? {};
|
|
74
83
|
return Object.freeze({
|
|
@@ -257,6 +266,18 @@ function resolveCamera(input, width, height) {
|
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
export function estimateWavefrontPathTracingMemory(options = {}) {
|
|
269
|
+
const width = readPositiveInteger("width", options.width, DEFAULT_WIDTH);
|
|
270
|
+
const height = readPositiveInteger("height", options.height, DEFAULT_HEIGHT);
|
|
271
|
+
const tileSize = readPositiveInteger("tileSize", options.tileSize, DEFAULT_TILE_SIZE);
|
|
272
|
+
const samplesPerPixel = clamp(
|
|
273
|
+
readPositiveInteger(
|
|
274
|
+
"samplesPerPixel",
|
|
275
|
+
options.samplesPerPixel,
|
|
276
|
+
DEFAULT_SAMPLES_PER_PIXEL
|
|
277
|
+
),
|
|
278
|
+
1,
|
|
279
|
+
MAX_SAMPLES_PER_PIXEL
|
|
280
|
+
);
|
|
260
281
|
const tilePixelCapacity = readPositiveInteger(
|
|
261
282
|
"tilePixelCapacity",
|
|
262
283
|
options.tilePixelCapacity,
|
|
@@ -289,20 +310,106 @@ export function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
289
310
|
options.environmentPortalCapacity,
|
|
290
311
|
0
|
|
291
312
|
);
|
|
292
|
-
|
|
313
|
+
readNonNegativeInteger("materialCapacity", options.materialCapacity, 0);
|
|
314
|
+
const meshVertexCount = readNonNegativeInteger(
|
|
315
|
+
"meshVertexCount",
|
|
316
|
+
options.meshVertexCount,
|
|
317
|
+
0
|
|
318
|
+
);
|
|
319
|
+
const meshIndexCount = readNonNegativeInteger(
|
|
320
|
+
"meshIndexCount",
|
|
321
|
+
options.meshIndexCount,
|
|
322
|
+
0
|
|
323
|
+
);
|
|
324
|
+
const meshRangeCount = readNonNegativeInteger(
|
|
325
|
+
"meshRangeCount",
|
|
326
|
+
options.meshRangeCount,
|
|
327
|
+
0
|
|
328
|
+
);
|
|
329
|
+
const bvhSortStageCount = readNonNegativeInteger(
|
|
330
|
+
"bvhSortStageCount",
|
|
331
|
+
options.bvhSortStageCount,
|
|
332
|
+
0
|
|
333
|
+
);
|
|
334
|
+
const bvhBuildLevelCount = readNonNegativeInteger(
|
|
335
|
+
"bvhBuildLevelCount",
|
|
336
|
+
options.bvhBuildLevelCount,
|
|
337
|
+
0
|
|
338
|
+
);
|
|
339
|
+
const minUniformBufferOffsetAlignment = readPositiveInteger(
|
|
340
|
+
"minUniformBufferOffsetAlignment",
|
|
341
|
+
options.minUniformBufferOffsetAlignment,
|
|
342
|
+
WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
343
|
+
);
|
|
344
|
+
const denoise = options.denoise !== false;
|
|
345
|
+
const deferredPathResolve = options.deferredPathResolve !== false;
|
|
293
346
|
const queueBytes = tilePixelCapacity * RAY_RECORD_BYTES;
|
|
294
347
|
const hitBytes = tilePixelCapacity * HIT_RECORD_BYTES;
|
|
295
348
|
const accumulationBytes = tilePixelCapacity * ACCUMULATION_RECORD_BYTES;
|
|
296
349
|
const pathVertexBytes = tilePixelCapacity * (maxDepth + 1) * PATH_VERTEX_RECORD_BYTES;
|
|
297
350
|
const sceneObjectBytes = sceneObjectCapacity * SCENE_OBJECT_RECORD_BYTES;
|
|
298
|
-
const triangleBytes = triangleCapacity
|
|
299
|
-
const materialTableBytes =
|
|
351
|
+
const triangleBytes = allocatedRecordBytes(triangleCapacity, TRIANGLE_RECORD_BYTES);
|
|
352
|
+
const materialTableBytes = 0;
|
|
300
353
|
const bvhNodeBytes = bvhNodeCapacity * BVH_NODE_RECORD_BYTES;
|
|
301
|
-
const bvhLeafReferenceBytes =
|
|
354
|
+
const bvhLeafReferenceBytes = allocatedRecordBytes(
|
|
355
|
+
bvhLeafSortCapacity,
|
|
356
|
+
BVH_LEAF_REF_RECORD_BYTES
|
|
357
|
+
);
|
|
302
358
|
const emissiveTriangleMetadataBytes =
|
|
303
359
|
emissiveTriangleCapacity * BVH_NODE_RECORD_BYTES;
|
|
304
|
-
const
|
|
305
|
-
|
|
360
|
+
const bvhCombinedBytes = allocatedRecordBytes(
|
|
361
|
+
bvhNodeCapacity + emissiveTriangleCapacity,
|
|
362
|
+
BVH_NODE_RECORD_BYTES
|
|
363
|
+
);
|
|
364
|
+
const meshVertexBytes = allocatedRecordBytes(meshVertexCount, MESH_VERTEX_RECORD_BYTES);
|
|
365
|
+
const meshIndexBytes = allocatedRecordBytes(meshIndexCount, 4);
|
|
366
|
+
const meshRangeBytes = allocatedRecordBytes(meshRangeCount, MESH_RANGE_RECORD_BYTES);
|
|
367
|
+
const environmentPortalBytes = allocatedRecordBytes(
|
|
368
|
+
environmentPortalCapacity,
|
|
369
|
+
ENVIRONMENT_PORTAL_RECORD_BYTES
|
|
370
|
+
);
|
|
371
|
+
const tileCount = Math.ceil(width / tileSize) * Math.ceil(height / tileSize);
|
|
372
|
+
const outputConfigSlotCount = deferredPathResolve ? 0 : tileCount;
|
|
373
|
+
const frameConfigSlotCount = Math.max(
|
|
374
|
+
1,
|
|
375
|
+
tileCount * samplesPerPixel + outputConfigSlotCount + (denoise ? 1 : 0)
|
|
376
|
+
);
|
|
377
|
+
const configBufferStride = alignByteSize(
|
|
378
|
+
CONFIG_BUFFER_BYTES,
|
|
379
|
+
minUniformBufferOffsetAlignment
|
|
380
|
+
);
|
|
381
|
+
const frameConfigBytes = frameConfigSlotCount * configBufferStride;
|
|
382
|
+
const bvhBuildConfigBytes = Math.max(
|
|
383
|
+
1,
|
|
384
|
+
1 + bvhSortStageCount + bvhBuildLevelCount
|
|
385
|
+
) * configBufferStride;
|
|
386
|
+
const sceneStorageBufferBindingBytes = Math.max(
|
|
387
|
+
sceneObjectBytes,
|
|
388
|
+
triangleBytes,
|
|
389
|
+
bvhCombinedBytes,
|
|
390
|
+
meshVertexBytes,
|
|
391
|
+
meshIndexBytes,
|
|
392
|
+
meshRangeBytes,
|
|
393
|
+
environmentPortalBytes,
|
|
394
|
+
bvhLeafReferenceBytes
|
|
395
|
+
);
|
|
396
|
+
const totalHotBufferBytes =
|
|
397
|
+
queueBytes * 2 +
|
|
398
|
+
hitBytes +
|
|
399
|
+
accumulationBytes +
|
|
400
|
+
pathVertexBytes +
|
|
401
|
+
sceneObjectBytes +
|
|
402
|
+
triangleBytes +
|
|
403
|
+
bvhCombinedBytes +
|
|
404
|
+
meshVertexBytes +
|
|
405
|
+
meshIndexBytes +
|
|
406
|
+
meshRangeBytes +
|
|
407
|
+
bvhLeafReferenceBytes +
|
|
408
|
+
environmentPortalBytes +
|
|
409
|
+
frameConfigBytes +
|
|
410
|
+
bvhBuildConfigBytes +
|
|
411
|
+
COUNTER_BUFFER_BYTES +
|
|
412
|
+
INDIRECT_DISPATCH_ARGS_BYTES;
|
|
306
413
|
|
|
307
414
|
return Object.freeze({
|
|
308
415
|
queueBytes,
|
|
@@ -314,27 +421,48 @@ export function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
314
421
|
triangleBytes,
|
|
315
422
|
materialTableBytes,
|
|
316
423
|
bvhNodeBytes,
|
|
424
|
+
bvhCombinedBytes,
|
|
317
425
|
bvhLeafReferenceBytes,
|
|
318
426
|
emissiveTriangleMetadataBytes,
|
|
427
|
+
meshVertexBytes,
|
|
428
|
+
meshIndexBytes,
|
|
429
|
+
meshRangeBytes,
|
|
319
430
|
environmentPortalBytes,
|
|
320
431
|
configBytes: CONFIG_BUFFER_BYTES,
|
|
432
|
+
configBufferStride,
|
|
433
|
+
frameConfigBytes,
|
|
434
|
+
bvhBuildConfigBytes,
|
|
321
435
|
counterBytes: COUNTER_BUFFER_BYTES,
|
|
322
436
|
indirectDispatchBytes: INDIRECT_DISPATCH_ARGS_BYTES,
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
437
|
+
sceneStorageBufferBindingBytes,
|
|
438
|
+
totalHotBufferBytes,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export function estimateWavefrontPathTracingMemoryForConfig(config, limits = {}) {
|
|
443
|
+
return estimateWavefrontPathTracingMemory({
|
|
444
|
+
width: config.width,
|
|
445
|
+
height: config.height,
|
|
446
|
+
tileSize: config.tileSize,
|
|
447
|
+
samplesPerPixel: config.samplesPerPixel,
|
|
448
|
+
tilePixelCapacity: config.tilePixelCapacity,
|
|
449
|
+
maxDepth: config.maxDepth,
|
|
450
|
+
sceneObjectCapacity: config.sceneObjectCapacity,
|
|
451
|
+
triangleCapacity: config.triangleCapacity,
|
|
452
|
+
bvhNodeCapacity: config.bvhNodeCapacity,
|
|
453
|
+
bvhLeafSortCapacity: config.bvhLeafSortCapacity,
|
|
454
|
+
emissiveTriangleCapacity: config.emissiveTriangleCapacity,
|
|
455
|
+
environmentPortalCapacity: config.environmentPortalCapacity,
|
|
456
|
+
meshVertexCount: config.gpuMeshSource.vertices.count,
|
|
457
|
+
meshIndexCount: config.gpuMeshSource.indices.count,
|
|
458
|
+
meshRangeCount: config.gpuMeshSource.meshes.count,
|
|
459
|
+
bvhSortStageCount: config.bvhSortStages.length,
|
|
460
|
+
bvhBuildLevelCount: config.bvhBuildLevels.length,
|
|
461
|
+
denoise: config.denoise,
|
|
462
|
+
deferredPathResolve: config.deferredPathResolve,
|
|
463
|
+
minUniformBufferOffsetAlignment:
|
|
464
|
+
limits.minUniformBufferOffsetAlignment ??
|
|
465
|
+
WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
|
338
466
|
});
|
|
339
467
|
}
|
|
340
468
|
|
|
@@ -509,15 +637,25 @@ export function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
|
509
637
|
denoise: options.denoise !== false,
|
|
510
638
|
frameIndex: readNonNegativeInteger("frameIndex", options.frameIndex, 0),
|
|
511
639
|
memory: estimateWavefrontPathTracingMemory({
|
|
640
|
+
width,
|
|
641
|
+
height,
|
|
642
|
+
tileSize,
|
|
643
|
+
samplesPerPixel,
|
|
512
644
|
tilePixelCapacity,
|
|
513
645
|
maxDepth,
|
|
514
646
|
sceneObjectCapacity,
|
|
515
647
|
triangleCapacity,
|
|
516
|
-
materialCapacity: gpuMaterialSource.count,
|
|
517
648
|
bvhNodeCapacity,
|
|
518
649
|
bvhLeafSortCapacity,
|
|
519
650
|
emissiveTriangleCapacity: emissiveTriangleIndices.capacity,
|
|
520
651
|
environmentPortalCapacity,
|
|
652
|
+
meshVertexCount: gpuMeshSource.vertices.count,
|
|
653
|
+
meshIndexCount: gpuMeshSource.indices.count,
|
|
654
|
+
meshRangeCount: gpuMeshSource.meshes.count,
|
|
655
|
+
bvhSortStageCount: bvhSortStages.length,
|
|
656
|
+
bvhBuildLevelCount: bvhBuildLevels.length,
|
|
657
|
+
denoise: options.denoise !== false,
|
|
658
|
+
deferredPathResolve,
|
|
521
659
|
}),
|
|
522
660
|
});
|
|
523
661
|
}
|
|
@@ -297,7 +297,11 @@ export function createWavefrontFrameTelemetryResources({
|
|
|
297
297
|
rayCountReadbackBuffer.unmap();
|
|
298
298
|
rayReadbackMapped = false;
|
|
299
299
|
|
|
300
|
-
|
|
300
|
+
let maximumBounceIndex = 0;
|
|
301
|
+
for (const bounceIndex of bounceIndices) {
|
|
302
|
+
maximumBounceIndex = Math.max(maximumBounceIndex, bounceIndex);
|
|
303
|
+
}
|
|
304
|
+
const bounceHistogram = Array.from({ length: maximumBounceIndex + 1 }, () => 0);
|
|
301
305
|
let observedPrimaryRays = 0;
|
|
302
306
|
let secondaryRays = 0;
|
|
303
307
|
let totalPathSegments = 0;
|
|
@@ -10,6 +10,37 @@ import {
|
|
|
10
10
|
readPositiveInteger,
|
|
11
11
|
} from "./wavefront-core.js";
|
|
12
12
|
|
|
13
|
+
const WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE = 128 * 1024 * 1024;
|
|
14
|
+
const WEBGPU_DEFAULT_MAX_BUFFER_SIZE = 256 * 1024 * 1024;
|
|
15
|
+
|
|
16
|
+
function readRequestedDeviceLimit(source, name) {
|
|
17
|
+
const rawValue = source?.[name];
|
|
18
|
+
if (rawValue === undefined || rawValue === null) {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
const value = Number(rawValue);
|
|
22
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
23
|
+
throw new Error(`${name} must be a non-negative safe integer.`);
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function assertAdapterSupportsRequiredLimit(adapter, name, requiredValue) {
|
|
29
|
+
const availableValue = Number(adapter?.limits?.[name]);
|
|
30
|
+
if (!Number.isFinite(availableValue)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, ` +
|
|
33
|
+
"but this adapter does not expose that limit."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (availableValue < requiredValue) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, ` +
|
|
39
|
+
`but this adapter exposes ${availableValue} bytes.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
13
44
|
export function getGpuUsageConstants() {
|
|
14
45
|
if (
|
|
15
46
|
typeof GPUBufferUsage === "undefined" ||
|
|
@@ -123,8 +154,13 @@ export async function createRenderPipeline(device, descriptor) {
|
|
|
123
154
|
return device.createRenderPipeline(descriptor);
|
|
124
155
|
}
|
|
125
156
|
|
|
126
|
-
export function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
127
|
-
const
|
|
157
|
+
export function createWavefrontDeviceDescriptor(adapter, options = {}, memory = null) {
|
|
158
|
+
const descriptor = { ...(options.deviceDescriptor ?? {}) };
|
|
159
|
+
const descriptorRequiredLimits = { ...(descriptor.requiredLimits ?? {}) };
|
|
160
|
+
const requiredLimits = {
|
|
161
|
+
...descriptorRequiredLimits,
|
|
162
|
+
...(options.requiredLimits ?? {}),
|
|
163
|
+
};
|
|
128
164
|
const exposedStorageBufferLimit = Number(adapter?.limits?.maxStorageBuffersPerShaderStage);
|
|
129
165
|
if (Number.isFinite(exposedStorageBufferLimit)) {
|
|
130
166
|
if (exposedStorageBufferLimit < TRACE_STORAGE_BUFFER_BINDINGS) {
|
|
@@ -153,7 +189,40 @@ export function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
|
153
189
|
);
|
|
154
190
|
}
|
|
155
191
|
|
|
156
|
-
const
|
|
192
|
+
const sceneStorageBufferBindingBytes = Number(
|
|
193
|
+
memory?.sceneStorageBufferBindingBytes ?? 0
|
|
194
|
+
);
|
|
195
|
+
const requestedStorageBufferBindingSize = Math.max(
|
|
196
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxStorageBufferBindingSize"),
|
|
197
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxStorageBufferBindingSize"),
|
|
198
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE
|
|
199
|
+
? sceneStorageBufferBindingBytes
|
|
200
|
+
: 0
|
|
201
|
+
);
|
|
202
|
+
if (requestedStorageBufferBindingSize > 0) {
|
|
203
|
+
assertAdapterSupportsRequiredLimit(
|
|
204
|
+
adapter,
|
|
205
|
+
"maxStorageBufferBindingSize",
|
|
206
|
+
requestedStorageBufferBindingSize
|
|
207
|
+
);
|
|
208
|
+
requiredLimits.maxStorageBufferBindingSize = requestedStorageBufferBindingSize;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const requestedMaxBufferSize = Math.max(
|
|
212
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxBufferSize"),
|
|
213
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxBufferSize"),
|
|
214
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_BUFFER_SIZE
|
|
215
|
+
? sceneStorageBufferBindingBytes
|
|
216
|
+
: 0,
|
|
217
|
+
requestedStorageBufferBindingSize > WEBGPU_DEFAULT_MAX_BUFFER_SIZE
|
|
218
|
+
? requestedStorageBufferBindingSize
|
|
219
|
+
: 0
|
|
220
|
+
);
|
|
221
|
+
if (requestedMaxBufferSize > 0) {
|
|
222
|
+
assertAdapterSupportsRequiredLimit(adapter, "maxBufferSize", requestedMaxBufferSize);
|
|
223
|
+
requiredLimits.maxBufferSize = requestedMaxBufferSize;
|
|
224
|
+
}
|
|
225
|
+
|
|
157
226
|
const requiredFeatures = Array.from(descriptor.requiredFeatures ?? []);
|
|
158
227
|
const adapterFeatures = adapter?.features;
|
|
159
228
|
const timestampQuerySupported =
|
|
@@ -217,6 +286,7 @@ export function createGpuAdapterParallelismDiagnostics(adapter, device) {
|
|
|
217
286
|
maxComputeWorkgroupsPerDimension: readGpuLimit(adapter, device, "maxComputeWorkgroupsPerDimension"),
|
|
218
287
|
maxStorageBuffersPerShaderStage: readGpuLimit(adapter, device, "maxStorageBuffersPerShaderStage"),
|
|
219
288
|
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize"),
|
|
289
|
+
maxBufferSize: readGpuLimit(adapter, device, "maxBufferSize"),
|
|
220
290
|
}),
|
|
221
291
|
configuredWorkgroupSize: WORKGROUP_SIZE,
|
|
222
292
|
});
|