@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/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,44 @@ All notable changes to this project will be documented in this file.
|
|
|
23
23
|
- **Security**
|
|
24
24
|
- (placeholder)
|
|
25
25
|
|
|
26
|
+
## [0.2.43] - 2026-08-31
|
|
27
|
+
|
|
28
|
+
- **Added**
|
|
29
|
+
- (placeholder)
|
|
30
|
+
|
|
31
|
+
- **Changed**
|
|
32
|
+
- (placeholder)
|
|
33
|
+
|
|
34
|
+
- **Fixed**
|
|
35
|
+
- Negotiated scene-derived `maxStorageBufferBindingSize` and, when required,
|
|
36
|
+
`maxBufferSize` before WebGPU device creation so large mesh/BVH scenes fail
|
|
37
|
+
early on unsupported adapters and render on adapters that expose sufficient
|
|
38
|
+
non-default limits.
|
|
39
|
+
- Corrected wavefront memory telemetry to match every persistent GPU buffer
|
|
40
|
+
descriptor exactly once, including placeholder records, combined BVH and
|
|
41
|
+
emissive metadata, mesh sources, and aligned frame/build config buffers,
|
|
42
|
+
while removing the nonexistent material-table allocation.
|
|
43
|
+
|
|
44
|
+
- **Security**
|
|
45
|
+
- (placeholder)
|
|
46
|
+
|
|
47
|
+
## [0.2.42] - 2026-08-31
|
|
48
|
+
|
|
49
|
+
- **Added**
|
|
50
|
+
- (placeholder)
|
|
51
|
+
|
|
52
|
+
- **Changed**
|
|
53
|
+
- (placeholder)
|
|
54
|
+
|
|
55
|
+
- **Fixed**
|
|
56
|
+
- Made fixed-SPP ray-count reduction stack-safe for the supported
|
|
57
|
+
4K/eight-bounce/128-SPP envelope by replacing unbounded argument spreading
|
|
58
|
+
with a constant-stack linear maximum scan.
|
|
59
|
+
- (placeholder)
|
|
60
|
+
|
|
61
|
+
- **Security**
|
|
62
|
+
- (placeholder)
|
|
63
|
+
|
|
26
64
|
## [0.2.41] - 2026-08-30
|
|
27
65
|
|
|
28
66
|
- **Added**
|
|
@@ -1029,3 +1067,5 @@ All notable changes to this project will be documented in this file.
|
|
|
1029
1067
|
[0.2.39]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.39
|
|
1030
1068
|
[0.2.40]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.40
|
|
1031
1069
|
[0.2.41]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.41
|
|
1070
|
+
[0.2.42]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.42
|
|
1071
|
+
[0.2.43]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.43
|
package/README.md
CHANGED
|
@@ -429,6 +429,17 @@ without rebuilding scene buffers. `renderFrame(...)` also accepts an optional
|
|
|
429
429
|
guarantees at least the minimum full-screen pass, and frame stats report both
|
|
430
430
|
configured `samplesPerPixel` and actual `renderedSamplesPerPixel` so realtime
|
|
431
431
|
callers can budget motion frames without overstating delivered quality.
|
|
432
|
+
Before requesting a WebGPU device, the renderer derives the largest scene
|
|
433
|
+
storage binding from the normalized scene, mesh, and BVH records. It requests
|
|
434
|
+
the smallest sufficient `maxStorageBufferBindingSize` (and `maxBufferSize` only
|
|
435
|
+
when the WebGPU default is also exceeded), preserves stricter caller limits,
|
|
436
|
+
and rejects unsupported adapters before device creation. Default-sized scenes
|
|
437
|
+
do not elevate either size limit. `config.memory` and snapshot memory telemetry
|
|
438
|
+
describe the actual persistent GPU buffer descriptors: placeholder records,
|
|
439
|
+
combined BVH/emissive storage, mesh source buffers, aligned frame/build uniform
|
|
440
|
+
buffers, counters, and dispatch arguments are each counted exactly once;
|
|
441
|
+
`materialTableBytes` is zero because material data is packed into mesh and
|
|
442
|
+
triangle records rather than a standalone GPU buffer.
|
|
432
443
|
For consumers that want to hand wavefront SPP adaptation to
|
|
433
444
|
`@plasius/gpu-performance`, `createWavefrontAdaptiveSamplingLevels(...)` exposes
|
|
434
445
|
a bounded low-to-high ladder of per-frame `samplesPerPixel`,
|
|
@@ -478,6 +489,9 @@ lazily allocated telemetry buffer; it does not add diagnostic shader atomics or
|
|
|
478
489
|
change WGSL transport. `rayCounts.status` distinguishes available,
|
|
479
490
|
unavailable, failed, and not-requested evidence. A mismatch between scheduled
|
|
480
491
|
and observed primary rays fails the `ray-count-telemetry` transport guardrail.
|
|
492
|
+
Ray-count reduction uses constant call-stack space, including the supported
|
|
493
|
+
4K/eight-bounce/128-SPP stress envelope where hundreds of thousands of
|
|
494
|
+
tile/sample/depth records collapse into a small per-bounce histogram.
|
|
481
495
|
|
|
482
496
|
When the adapter exposes `timestamp-query`, the device requests it
|
|
483
497
|
opportunistically and two timestamps measure the GPU span from the first
|
package/dist/index.cjs
CHANGED
|
@@ -4527,6 +4527,13 @@ function dispatchWavefrontGpuAccelerationBuild({
|
|
|
4527
4527
|
}
|
|
4528
4528
|
|
|
4529
4529
|
// src/wavefront-config.js
|
|
4530
|
+
var WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 256;
|
|
4531
|
+
function allocatedRecordBytes(count, recordBytes) {
|
|
4532
|
+
return Math.max(1, count) * recordBytes;
|
|
4533
|
+
}
|
|
4534
|
+
function alignByteSize(value, alignment) {
|
|
4535
|
+
return Math.ceil(value / alignment) * alignment;
|
|
4536
|
+
}
|
|
4530
4537
|
function resolveEnvironmentLighting(input, environmentColor, ambientColor) {
|
|
4531
4538
|
const source = input ?? {};
|
|
4532
4539
|
return Object.freeze({
|
|
@@ -4703,6 +4710,18 @@ function resolveCamera(input, width, height) {
|
|
|
4703
4710
|
});
|
|
4704
4711
|
}
|
|
4705
4712
|
function estimateWavefrontPathTracingMemory(options = {}) {
|
|
4713
|
+
const width = readPositiveInteger2("width", options.width, DEFAULT_WIDTH);
|
|
4714
|
+
const height = readPositiveInteger2("height", options.height, DEFAULT_HEIGHT);
|
|
4715
|
+
const tileSize = readPositiveInteger2("tileSize", options.tileSize, DEFAULT_TILE_SIZE);
|
|
4716
|
+
const samplesPerPixel = clamp2(
|
|
4717
|
+
readPositiveInteger2(
|
|
4718
|
+
"samplesPerPixel",
|
|
4719
|
+
options.samplesPerPixel,
|
|
4720
|
+
DEFAULT_SAMPLES_PER_PIXEL
|
|
4721
|
+
),
|
|
4722
|
+
1,
|
|
4723
|
+
MAX_SAMPLES_PER_PIXEL
|
|
4724
|
+
);
|
|
4706
4725
|
const tilePixelCapacity = readPositiveInteger2(
|
|
4707
4726
|
"tilePixelCapacity",
|
|
4708
4727
|
options.tilePixelCapacity,
|
|
@@ -4735,18 +4754,89 @@ function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
4735
4754
|
options.environmentPortalCapacity,
|
|
4736
4755
|
0
|
|
4737
4756
|
);
|
|
4738
|
-
|
|
4757
|
+
readNonNegativeInteger2("materialCapacity", options.materialCapacity, 0);
|
|
4758
|
+
const meshVertexCount = readNonNegativeInteger2(
|
|
4759
|
+
"meshVertexCount",
|
|
4760
|
+
options.meshVertexCount,
|
|
4761
|
+
0
|
|
4762
|
+
);
|
|
4763
|
+
const meshIndexCount = readNonNegativeInteger2(
|
|
4764
|
+
"meshIndexCount",
|
|
4765
|
+
options.meshIndexCount,
|
|
4766
|
+
0
|
|
4767
|
+
);
|
|
4768
|
+
const meshRangeCount = readNonNegativeInteger2(
|
|
4769
|
+
"meshRangeCount",
|
|
4770
|
+
options.meshRangeCount,
|
|
4771
|
+
0
|
|
4772
|
+
);
|
|
4773
|
+
const bvhSortStageCount = readNonNegativeInteger2(
|
|
4774
|
+
"bvhSortStageCount",
|
|
4775
|
+
options.bvhSortStageCount,
|
|
4776
|
+
0
|
|
4777
|
+
);
|
|
4778
|
+
const bvhBuildLevelCount = readNonNegativeInteger2(
|
|
4779
|
+
"bvhBuildLevelCount",
|
|
4780
|
+
options.bvhBuildLevelCount,
|
|
4781
|
+
0
|
|
4782
|
+
);
|
|
4783
|
+
const minUniformBufferOffsetAlignment = readPositiveInteger2(
|
|
4784
|
+
"minUniformBufferOffsetAlignment",
|
|
4785
|
+
options.minUniformBufferOffsetAlignment,
|
|
4786
|
+
WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
4787
|
+
);
|
|
4788
|
+
const denoise = options.denoise !== false;
|
|
4789
|
+
const deferredPathResolve = options.deferredPathResolve !== false;
|
|
4739
4790
|
const queueBytes = tilePixelCapacity * RAY_RECORD_BYTES;
|
|
4740
4791
|
const hitBytes = tilePixelCapacity * HIT_RECORD_BYTES;
|
|
4741
4792
|
const accumulationBytes = tilePixelCapacity * ACCUMULATION_RECORD_BYTES;
|
|
4742
4793
|
const pathVertexBytes = tilePixelCapacity * (maxDepth + 1) * PATH_VERTEX_RECORD_BYTES;
|
|
4743
4794
|
const sceneObjectBytes = sceneObjectCapacity * SCENE_OBJECT_RECORD_BYTES;
|
|
4744
|
-
const triangleBytes = triangleCapacity
|
|
4745
|
-
const materialTableBytes =
|
|
4795
|
+
const triangleBytes = allocatedRecordBytes(triangleCapacity, TRIANGLE_RECORD_BYTES);
|
|
4796
|
+
const materialTableBytes = 0;
|
|
4746
4797
|
const bvhNodeBytes = bvhNodeCapacity * BVH_NODE_RECORD_BYTES;
|
|
4747
|
-
const bvhLeafReferenceBytes =
|
|
4798
|
+
const bvhLeafReferenceBytes = allocatedRecordBytes(
|
|
4799
|
+
bvhLeafSortCapacity,
|
|
4800
|
+
BVH_LEAF_REF_RECORD_BYTES
|
|
4801
|
+
);
|
|
4748
4802
|
const emissiveTriangleMetadataBytes = emissiveTriangleCapacity * BVH_NODE_RECORD_BYTES;
|
|
4749
|
-
const
|
|
4803
|
+
const bvhCombinedBytes = allocatedRecordBytes(
|
|
4804
|
+
bvhNodeCapacity + emissiveTriangleCapacity,
|
|
4805
|
+
BVH_NODE_RECORD_BYTES
|
|
4806
|
+
);
|
|
4807
|
+
const meshVertexBytes = allocatedRecordBytes(meshVertexCount, MESH_VERTEX_RECORD_BYTES);
|
|
4808
|
+
const meshIndexBytes = allocatedRecordBytes(meshIndexCount, 4);
|
|
4809
|
+
const meshRangeBytes = allocatedRecordBytes(meshRangeCount, MESH_RANGE_RECORD_BYTES);
|
|
4810
|
+
const environmentPortalBytes = allocatedRecordBytes(
|
|
4811
|
+
environmentPortalCapacity,
|
|
4812
|
+
ENVIRONMENT_PORTAL_RECORD_BYTES
|
|
4813
|
+
);
|
|
4814
|
+
const tileCount = Math.ceil(width / tileSize) * Math.ceil(height / tileSize);
|
|
4815
|
+
const outputConfigSlotCount = deferredPathResolve ? 0 : tileCount;
|
|
4816
|
+
const frameConfigSlotCount = Math.max(
|
|
4817
|
+
1,
|
|
4818
|
+
tileCount * samplesPerPixel + outputConfigSlotCount + (denoise ? 1 : 0)
|
|
4819
|
+
);
|
|
4820
|
+
const configBufferStride = alignByteSize(
|
|
4821
|
+
CONFIG_BUFFER_BYTES,
|
|
4822
|
+
minUniformBufferOffsetAlignment
|
|
4823
|
+
);
|
|
4824
|
+
const frameConfigBytes = frameConfigSlotCount * configBufferStride;
|
|
4825
|
+
const bvhBuildConfigBytes = Math.max(
|
|
4826
|
+
1,
|
|
4827
|
+
1 + bvhSortStageCount + bvhBuildLevelCount
|
|
4828
|
+
) * configBufferStride;
|
|
4829
|
+
const sceneStorageBufferBindingBytes = Math.max(
|
|
4830
|
+
sceneObjectBytes,
|
|
4831
|
+
triangleBytes,
|
|
4832
|
+
bvhCombinedBytes,
|
|
4833
|
+
meshVertexBytes,
|
|
4834
|
+
meshIndexBytes,
|
|
4835
|
+
meshRangeBytes,
|
|
4836
|
+
environmentPortalBytes,
|
|
4837
|
+
bvhLeafReferenceBytes
|
|
4838
|
+
);
|
|
4839
|
+
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
4840
|
return Object.freeze({
|
|
4751
4841
|
queueBytes,
|
|
4752
4842
|
queuePairBytes: queueBytes * 2,
|
|
@@ -4757,13 +4847,45 @@ function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
4757
4847
|
triangleBytes,
|
|
4758
4848
|
materialTableBytes,
|
|
4759
4849
|
bvhNodeBytes,
|
|
4850
|
+
bvhCombinedBytes,
|
|
4760
4851
|
bvhLeafReferenceBytes,
|
|
4761
4852
|
emissiveTriangleMetadataBytes,
|
|
4853
|
+
meshVertexBytes,
|
|
4854
|
+
meshIndexBytes,
|
|
4855
|
+
meshRangeBytes,
|
|
4762
4856
|
environmentPortalBytes,
|
|
4763
4857
|
configBytes: CONFIG_BUFFER_BYTES,
|
|
4858
|
+
configBufferStride,
|
|
4859
|
+
frameConfigBytes,
|
|
4860
|
+
bvhBuildConfigBytes,
|
|
4764
4861
|
counterBytes: COUNTER_BUFFER_BYTES,
|
|
4765
4862
|
indirectDispatchBytes: INDIRECT_DISPATCH_ARGS_BYTES,
|
|
4766
|
-
|
|
4863
|
+
sceneStorageBufferBindingBytes,
|
|
4864
|
+
totalHotBufferBytes
|
|
4865
|
+
});
|
|
4866
|
+
}
|
|
4867
|
+
function estimateWavefrontPathTracingMemoryForConfig(config, limits = {}) {
|
|
4868
|
+
return estimateWavefrontPathTracingMemory({
|
|
4869
|
+
width: config.width,
|
|
4870
|
+
height: config.height,
|
|
4871
|
+
tileSize: config.tileSize,
|
|
4872
|
+
samplesPerPixel: config.samplesPerPixel,
|
|
4873
|
+
tilePixelCapacity: config.tilePixelCapacity,
|
|
4874
|
+
maxDepth: config.maxDepth,
|
|
4875
|
+
sceneObjectCapacity: config.sceneObjectCapacity,
|
|
4876
|
+
triangleCapacity: config.triangleCapacity,
|
|
4877
|
+
bvhNodeCapacity: config.bvhNodeCapacity,
|
|
4878
|
+
bvhLeafSortCapacity: config.bvhLeafSortCapacity,
|
|
4879
|
+
emissiveTriangleCapacity: config.emissiveTriangleCapacity,
|
|
4880
|
+
environmentPortalCapacity: config.environmentPortalCapacity,
|
|
4881
|
+
meshVertexCount: config.gpuMeshSource.vertices.count,
|
|
4882
|
+
meshIndexCount: config.gpuMeshSource.indices.count,
|
|
4883
|
+
meshRangeCount: config.gpuMeshSource.meshes.count,
|
|
4884
|
+
bvhSortStageCount: config.bvhSortStages.length,
|
|
4885
|
+
bvhBuildLevelCount: config.bvhBuildLevels.length,
|
|
4886
|
+
denoise: config.denoise,
|
|
4887
|
+
deferredPathResolve: config.deferredPathResolve,
|
|
4888
|
+
minUniformBufferOffsetAlignment: limits.minUniformBufferOffsetAlignment ?? WEBGPU_DEFAULT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
|
4767
4889
|
});
|
|
4768
4890
|
}
|
|
4769
4891
|
function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
@@ -4908,15 +5030,25 @@ function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
|
4908
5030
|
denoise: options.denoise !== false,
|
|
4909
5031
|
frameIndex: readNonNegativeInteger2("frameIndex", options.frameIndex, 0),
|
|
4910
5032
|
memory: estimateWavefrontPathTracingMemory({
|
|
5033
|
+
width,
|
|
5034
|
+
height,
|
|
5035
|
+
tileSize,
|
|
5036
|
+
samplesPerPixel,
|
|
4911
5037
|
tilePixelCapacity,
|
|
4912
5038
|
maxDepth,
|
|
4913
5039
|
sceneObjectCapacity,
|
|
4914
5040
|
triangleCapacity,
|
|
4915
|
-
materialCapacity: gpuMaterialSource.count,
|
|
4916
5041
|
bvhNodeCapacity,
|
|
4917
5042
|
bvhLeafSortCapacity,
|
|
4918
5043
|
emissiveTriangleCapacity: emissiveTriangleIndices.capacity,
|
|
4919
|
-
environmentPortalCapacity
|
|
5044
|
+
environmentPortalCapacity,
|
|
5045
|
+
meshVertexCount: gpuMeshSource.vertices.count,
|
|
5046
|
+
meshIndexCount: gpuMeshSource.indices.count,
|
|
5047
|
+
meshRangeCount: gpuMeshSource.meshes.count,
|
|
5048
|
+
bvhSortStageCount: bvhSortStages.length,
|
|
5049
|
+
bvhBuildLevelCount: bvhBuildLevels.length,
|
|
5050
|
+
denoise: options.denoise !== false,
|
|
5051
|
+
deferredPathResolve
|
|
4920
5052
|
})
|
|
4921
5053
|
});
|
|
4922
5054
|
}
|
|
@@ -5761,6 +5893,32 @@ function createWavefrontPresentBindGroup({
|
|
|
5761
5893
|
}
|
|
5762
5894
|
|
|
5763
5895
|
// src/wavefront-runtime-support.js
|
|
5896
|
+
var WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE = 128 * 1024 * 1024;
|
|
5897
|
+
var WEBGPU_DEFAULT_MAX_BUFFER_SIZE = 256 * 1024 * 1024;
|
|
5898
|
+
function readRequestedDeviceLimit(source, name) {
|
|
5899
|
+
const rawValue = source?.[name];
|
|
5900
|
+
if (rawValue === void 0 || rawValue === null) {
|
|
5901
|
+
return 0;
|
|
5902
|
+
}
|
|
5903
|
+
const value = Number(rawValue);
|
|
5904
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
5905
|
+
throw new Error(`${name} must be a non-negative safe integer.`);
|
|
5906
|
+
}
|
|
5907
|
+
return value;
|
|
5908
|
+
}
|
|
5909
|
+
function assertAdapterSupportsRequiredLimit(adapter, name, requiredValue) {
|
|
5910
|
+
const availableValue = Number(adapter?.limits?.[name]);
|
|
5911
|
+
if (!Number.isFinite(availableValue)) {
|
|
5912
|
+
throw new Error(
|
|
5913
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, but this adapter does not expose that limit.`
|
|
5914
|
+
);
|
|
5915
|
+
}
|
|
5916
|
+
if (availableValue < requiredValue) {
|
|
5917
|
+
throw new Error(
|
|
5918
|
+
`Wavefront scene buffers require ${name}>=${requiredValue} bytes, but this adapter exposes ${availableValue} bytes.`
|
|
5919
|
+
);
|
|
5920
|
+
}
|
|
5921
|
+
}
|
|
5764
5922
|
function getGpuUsageConstants() {
|
|
5765
5923
|
if (typeof GPUBufferUsage === "undefined" || typeof GPUTextureUsage === "undefined" || typeof GPUShaderStage === "undefined") {
|
|
5766
5924
|
throw new Error("WebGPU runtime unavailable. Required GPU constants are missing.");
|
|
@@ -5858,8 +6016,13 @@ async function createRenderPipeline(device, descriptor) {
|
|
|
5858
6016
|
}
|
|
5859
6017
|
return device.createRenderPipeline(descriptor);
|
|
5860
6018
|
}
|
|
5861
|
-
function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
5862
|
-
const
|
|
6019
|
+
function createWavefrontDeviceDescriptor(adapter, options = {}, memory = null) {
|
|
6020
|
+
const descriptor = { ...options.deviceDescriptor ?? {} };
|
|
6021
|
+
const descriptorRequiredLimits = { ...descriptor.requiredLimits ?? {} };
|
|
6022
|
+
const requiredLimits = {
|
|
6023
|
+
...descriptorRequiredLimits,
|
|
6024
|
+
...options.requiredLimits ?? {}
|
|
6025
|
+
};
|
|
5863
6026
|
const exposedStorageBufferLimit = Number(adapter?.limits?.maxStorageBuffersPerShaderStage);
|
|
5864
6027
|
if (Number.isFinite(exposedStorageBufferLimit)) {
|
|
5865
6028
|
if (exposedStorageBufferLimit < TRACE_STORAGE_BUFFER_BINDINGS) {
|
|
@@ -5884,7 +6047,32 @@ function createWavefrontDeviceDescriptor(adapter, options = {}) {
|
|
|
5884
6047
|
TRACE_SAMPLED_TEXTURE_BINDINGS
|
|
5885
6048
|
);
|
|
5886
6049
|
}
|
|
5887
|
-
const
|
|
6050
|
+
const sceneStorageBufferBindingBytes = Number(
|
|
6051
|
+
memory?.sceneStorageBufferBindingBytes ?? 0
|
|
6052
|
+
);
|
|
6053
|
+
const requestedStorageBufferBindingSize = Math.max(
|
|
6054
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxStorageBufferBindingSize"),
|
|
6055
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxStorageBufferBindingSize"),
|
|
6056
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_STORAGE_BUFFER_BINDING_SIZE ? sceneStorageBufferBindingBytes : 0
|
|
6057
|
+
);
|
|
6058
|
+
if (requestedStorageBufferBindingSize > 0) {
|
|
6059
|
+
assertAdapterSupportsRequiredLimit(
|
|
6060
|
+
adapter,
|
|
6061
|
+
"maxStorageBufferBindingSize",
|
|
6062
|
+
requestedStorageBufferBindingSize
|
|
6063
|
+
);
|
|
6064
|
+
requiredLimits.maxStorageBufferBindingSize = requestedStorageBufferBindingSize;
|
|
6065
|
+
}
|
|
6066
|
+
const requestedMaxBufferSize = Math.max(
|
|
6067
|
+
readRequestedDeviceLimit(descriptorRequiredLimits, "maxBufferSize"),
|
|
6068
|
+
readRequestedDeviceLimit(options.requiredLimits, "maxBufferSize"),
|
|
6069
|
+
sceneStorageBufferBindingBytes > WEBGPU_DEFAULT_MAX_BUFFER_SIZE ? sceneStorageBufferBindingBytes : 0,
|
|
6070
|
+
requestedStorageBufferBindingSize > WEBGPU_DEFAULT_MAX_BUFFER_SIZE ? requestedStorageBufferBindingSize : 0
|
|
6071
|
+
);
|
|
6072
|
+
if (requestedMaxBufferSize > 0) {
|
|
6073
|
+
assertAdapterSupportsRequiredLimit(adapter, "maxBufferSize", requestedMaxBufferSize);
|
|
6074
|
+
requiredLimits.maxBufferSize = requestedMaxBufferSize;
|
|
6075
|
+
}
|
|
5888
6076
|
const requiredFeatures = Array.from(descriptor.requiredFeatures ?? []);
|
|
5889
6077
|
const adapterFeatures = adapter?.features;
|
|
5890
6078
|
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 +6123,8 @@ function createGpuAdapterParallelismDiagnostics(adapter, device) {
|
|
|
5935
6123
|
maxComputeWorkgroupSizeZ: readGpuLimit(adapter, device, "maxComputeWorkgroupSizeZ"),
|
|
5936
6124
|
maxComputeWorkgroupsPerDimension: readGpuLimit(adapter, device, "maxComputeWorkgroupsPerDimension"),
|
|
5937
6125
|
maxStorageBuffersPerShaderStage: readGpuLimit(adapter, device, "maxStorageBuffersPerShaderStage"),
|
|
5938
|
-
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize")
|
|
6126
|
+
maxStorageBufferBindingSize: readGpuLimit(adapter, device, "maxStorageBufferBindingSize"),
|
|
6127
|
+
maxBufferSize: readGpuLimit(adapter, device, "maxBufferSize")
|
|
5939
6128
|
}),
|
|
5940
6129
|
configuredWorkgroupSize: WORKGROUP_SIZE
|
|
5941
6130
|
});
|
|
@@ -6345,7 +6534,11 @@ function createWavefrontFrameTelemetryResources({
|
|
|
6345
6534
|
const rayCounts = new Uint32Array(rayCopy, 0, recordCount);
|
|
6346
6535
|
rayCountReadbackBuffer.unmap();
|
|
6347
6536
|
rayReadbackMapped = false;
|
|
6348
|
-
|
|
6537
|
+
let maximumBounceIndex = 0;
|
|
6538
|
+
for (const bounceIndex of bounceIndices) {
|
|
6539
|
+
maximumBounceIndex = Math.max(maximumBounceIndex, bounceIndex);
|
|
6540
|
+
}
|
|
6541
|
+
const bounceHistogram = Array.from({ length: maximumBounceIndex + 1 }, () => 0);
|
|
6349
6542
|
let observedPrimaryRays = 0;
|
|
6350
6543
|
let secondaryRays = 0;
|
|
6351
6544
|
let totalPathSegments = 0;
|
|
@@ -11237,7 +11430,9 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11237
11430
|
if (!adapter) {
|
|
11238
11431
|
throw new Error("Unable to acquire a WebGPU adapter for wavefront path tracing.");
|
|
11239
11432
|
}
|
|
11240
|
-
const device = await adapter.requestDevice(
|
|
11433
|
+
const device = await adapter.requestDevice(
|
|
11434
|
+
createWavefrontDeviceDescriptor(adapter, options, initialConfig.memory)
|
|
11435
|
+
);
|
|
11241
11436
|
const gpuAdapterParallelism = createGpuAdapterParallelismDiagnostics(adapter, device);
|
|
11242
11437
|
const context = canvas.getContext("webgpu");
|
|
11243
11438
|
if (!context || typeof context.configure !== "function") {
|
|
@@ -11255,6 +11450,10 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11255
11450
|
tileSize: safeTileSize
|
|
11256
11451
|
});
|
|
11257
11452
|
}
|
|
11453
|
+
config = Object.freeze({
|
|
11454
|
+
...config,
|
|
11455
|
+
memory: estimateWavefrontPathTracingMemoryForConfig(config, device.limits)
|
|
11456
|
+
});
|
|
11258
11457
|
canvas.width = config.width;
|
|
11259
11458
|
canvas.height = config.height;
|
|
11260
11459
|
context.configure({
|
|
@@ -11263,79 +11462,72 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11263
11462
|
alphaMode: options.alpha === true ? "premultiplied" : "opaque"
|
|
11264
11463
|
});
|
|
11265
11464
|
const bufferUsage = constants.buffer.STORAGE | constants.buffer.COPY_DST;
|
|
11266
|
-
const
|
|
11267
|
-
const
|
|
11268
|
-
const
|
|
11269
|
-
const
|
|
11270
|
-
const activeQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.activeQueue");
|
|
11271
|
-
const nextQueue = createBuffer(device, bufferUsage, rayQueueBytes, "plasius.wavefront.nextQueue");
|
|
11272
|
-
const hitBuffer = createBuffer(device, bufferUsage, hitBytes, "plasius.wavefront.hitBuffer");
|
|
11465
|
+
const memory = config.memory;
|
|
11466
|
+
const activeQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.activeQueue");
|
|
11467
|
+
const nextQueue = createBuffer(device, bufferUsage, memory.queueBytes, "plasius.wavefront.nextQueue");
|
|
11468
|
+
const hitBuffer = createBuffer(device, bufferUsage, memory.hitBytes, "plasius.wavefront.hitBuffer");
|
|
11273
11469
|
const accumulationBuffer = createBuffer(
|
|
11274
11470
|
device,
|
|
11275
11471
|
bufferUsage,
|
|
11276
|
-
accumulationBytes,
|
|
11472
|
+
memory.accumulationBytes,
|
|
11277
11473
|
"plasius.wavefront.accumulation"
|
|
11278
11474
|
);
|
|
11279
11475
|
const pathVertexBuffer = createBuffer(
|
|
11280
11476
|
device,
|
|
11281
11477
|
bufferUsage,
|
|
11282
|
-
pathVertexBytes,
|
|
11478
|
+
memory.pathVertexBytes,
|
|
11283
11479
|
"plasius.wavefront.pathVertices"
|
|
11284
11480
|
);
|
|
11285
11481
|
const sceneObjectBuffer = createBuffer(
|
|
11286
11482
|
device,
|
|
11287
11483
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11288
|
-
|
|
11484
|
+
memory.sceneObjectBytes,
|
|
11289
11485
|
"plasius.wavefront.sceneObjects"
|
|
11290
11486
|
);
|
|
11291
11487
|
const triangleBuffer = createBuffer(
|
|
11292
11488
|
device,
|
|
11293
11489
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11294
|
-
|
|
11490
|
+
memory.triangleBytes,
|
|
11295
11491
|
"plasius.wavefront.triangles"
|
|
11296
11492
|
);
|
|
11297
11493
|
const bvhNodeBuffer = createBuffer(
|
|
11298
11494
|
device,
|
|
11299
11495
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11300
|
-
|
|
11496
|
+
memory.bvhCombinedBytes,
|
|
11301
11497
|
"plasius.wavefront.bvhNodes"
|
|
11302
11498
|
);
|
|
11303
11499
|
const meshVertexBuffer = createBuffer(
|
|
11304
11500
|
device,
|
|
11305
11501
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11306
|
-
|
|
11502
|
+
memory.meshVertexBytes,
|
|
11307
11503
|
"plasius.wavefront.meshVertices"
|
|
11308
11504
|
);
|
|
11309
11505
|
const meshIndexBuffer = createBuffer(
|
|
11310
11506
|
device,
|
|
11311
11507
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11312
|
-
|
|
11508
|
+
memory.meshIndexBytes,
|
|
11313
11509
|
"plasius.wavefront.meshIndices"
|
|
11314
11510
|
);
|
|
11315
11511
|
const meshRangeBuffer = createBuffer(
|
|
11316
11512
|
device,
|
|
11317
11513
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11318
|
-
|
|
11514
|
+
memory.meshRangeBytes,
|
|
11319
11515
|
"plasius.wavefront.meshRanges"
|
|
11320
11516
|
);
|
|
11321
11517
|
const environmentPortalBuffer = createBuffer(
|
|
11322
11518
|
device,
|
|
11323
11519
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11324
|
-
|
|
11520
|
+
memory.environmentPortalBytes,
|
|
11325
11521
|
"plasius.wavefront.environmentPortals"
|
|
11326
11522
|
);
|
|
11327
11523
|
const bvhLeafRefBuffer = createBuffer(
|
|
11328
11524
|
device,
|
|
11329
11525
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11330
|
-
|
|
11526
|
+
memory.bvhLeafReferenceBytes,
|
|
11331
11527
|
"plasius.wavefront.bvhLeafRefs"
|
|
11332
11528
|
);
|
|
11333
11529
|
const tiles = createTiles(config.width, config.height, config.tileSize);
|
|
11334
|
-
const
|
|
11335
|
-
const configBufferStride = alignTo(
|
|
11336
|
-
CONFIG_BUFFER_BYTES,
|
|
11337
|
-
Number.isFinite(uniformOffsetAlignment) && uniformOffsetAlignment > 0 ? uniformOffsetAlignment : CONFIG_BUFFER_BYTES
|
|
11338
|
-
);
|
|
11530
|
+
const configBufferStride = memory.configBufferStride;
|
|
11339
11531
|
const outputConfigSlotCount = config.deferredPathResolve ? 0 : tiles.length;
|
|
11340
11532
|
const frameConfigSlotCount = Math.max(
|
|
11341
11533
|
1,
|
|
@@ -11344,26 +11536,25 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11344
11536
|
const configBuffer = createBuffer(
|
|
11345
11537
|
device,
|
|
11346
11538
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11347
|
-
|
|
11539
|
+
memory.frameConfigBytes,
|
|
11348
11540
|
"plasius.wavefront.frameConfig"
|
|
11349
11541
|
);
|
|
11350
|
-
const bvhBuildConfigSlots = 1 + config.bvhSortStages.length + config.bvhBuildLevels.length;
|
|
11351
11542
|
const bvhBuildConfigBuffer = createBuffer(
|
|
11352
11543
|
device,
|
|
11353
11544
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11354
|
-
|
|
11545
|
+
memory.bvhBuildConfigBytes,
|
|
11355
11546
|
"plasius.wavefront.bvhBuildConfig"
|
|
11356
11547
|
);
|
|
11357
11548
|
const counterBuffer = createBuffer(
|
|
11358
11549
|
device,
|
|
11359
11550
|
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
11360
|
-
|
|
11551
|
+
memory.counterBytes,
|
|
11361
11552
|
"plasius.wavefront.counters"
|
|
11362
11553
|
);
|
|
11363
11554
|
const activeDispatchBuffer = createBuffer(
|
|
11364
11555
|
device,
|
|
11365
11556
|
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
11366
|
-
|
|
11557
|
+
memory.indirectDispatchBytes,
|
|
11367
11558
|
"plasius.wavefront.activeDispatchArgs"
|
|
11368
11559
|
);
|
|
11369
11560
|
let packedScene = packWavefrontSceneObjects(config.sceneObjects, config.sceneObjectCapacity);
|