@plasius/gpu-renderer 0.2.42 → 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 +22 -0
- package/README.md +11 -0
- package/dist/index.cjs +227 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +227 -40
- 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-runtime-support.js +73 -3
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,27 @@ 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
|
+
|
|
26
47
|
## [0.2.42] - 2026-08-31
|
|
27
48
|
|
|
28
49
|
- **Added**
|
|
@@ -1047,3 +1068,4 @@ All notable changes to this project will be documented in this file.
|
|
|
1047
1068
|
[0.2.40]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.40
|
|
1048
1069
|
[0.2.41]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.41
|
|
1049
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`,
|
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
|
});
|
|
@@ -11241,7 +11430,9 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11241
11430
|
if (!adapter) {
|
|
11242
11431
|
throw new Error("Unable to acquire a WebGPU adapter for wavefront path tracing.");
|
|
11243
11432
|
}
|
|
11244
|
-
const device = await adapter.requestDevice(
|
|
11433
|
+
const device = await adapter.requestDevice(
|
|
11434
|
+
createWavefrontDeviceDescriptor(adapter, options, initialConfig.memory)
|
|
11435
|
+
);
|
|
11245
11436
|
const gpuAdapterParallelism = createGpuAdapterParallelismDiagnostics(adapter, device);
|
|
11246
11437
|
const context = canvas.getContext("webgpu");
|
|
11247
11438
|
if (!context || typeof context.configure !== "function") {
|
|
@@ -11259,6 +11450,10 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11259
11450
|
tileSize: safeTileSize
|
|
11260
11451
|
});
|
|
11261
11452
|
}
|
|
11453
|
+
config = Object.freeze({
|
|
11454
|
+
...config,
|
|
11455
|
+
memory: estimateWavefrontPathTracingMemoryForConfig(config, device.limits)
|
|
11456
|
+
});
|
|
11262
11457
|
canvas.width = config.width;
|
|
11263
11458
|
canvas.height = config.height;
|
|
11264
11459
|
context.configure({
|
|
@@ -11267,79 +11462,72 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11267
11462
|
alphaMode: options.alpha === true ? "premultiplied" : "opaque"
|
|
11268
11463
|
});
|
|
11269
11464
|
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");
|
|
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");
|
|
11277
11469
|
const accumulationBuffer = createBuffer(
|
|
11278
11470
|
device,
|
|
11279
11471
|
bufferUsage,
|
|
11280
|
-
accumulationBytes,
|
|
11472
|
+
memory.accumulationBytes,
|
|
11281
11473
|
"plasius.wavefront.accumulation"
|
|
11282
11474
|
);
|
|
11283
11475
|
const pathVertexBuffer = createBuffer(
|
|
11284
11476
|
device,
|
|
11285
11477
|
bufferUsage,
|
|
11286
|
-
pathVertexBytes,
|
|
11478
|
+
memory.pathVertexBytes,
|
|
11287
11479
|
"plasius.wavefront.pathVertices"
|
|
11288
11480
|
);
|
|
11289
11481
|
const sceneObjectBuffer = createBuffer(
|
|
11290
11482
|
device,
|
|
11291
11483
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11292
|
-
|
|
11484
|
+
memory.sceneObjectBytes,
|
|
11293
11485
|
"plasius.wavefront.sceneObjects"
|
|
11294
11486
|
);
|
|
11295
11487
|
const triangleBuffer = createBuffer(
|
|
11296
11488
|
device,
|
|
11297
11489
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11298
|
-
|
|
11490
|
+
memory.triangleBytes,
|
|
11299
11491
|
"plasius.wavefront.triangles"
|
|
11300
11492
|
);
|
|
11301
11493
|
const bvhNodeBuffer = createBuffer(
|
|
11302
11494
|
device,
|
|
11303
11495
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11304
|
-
|
|
11496
|
+
memory.bvhCombinedBytes,
|
|
11305
11497
|
"plasius.wavefront.bvhNodes"
|
|
11306
11498
|
);
|
|
11307
11499
|
const meshVertexBuffer = createBuffer(
|
|
11308
11500
|
device,
|
|
11309
11501
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11310
|
-
|
|
11502
|
+
memory.meshVertexBytes,
|
|
11311
11503
|
"plasius.wavefront.meshVertices"
|
|
11312
11504
|
);
|
|
11313
11505
|
const meshIndexBuffer = createBuffer(
|
|
11314
11506
|
device,
|
|
11315
11507
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11316
|
-
|
|
11508
|
+
memory.meshIndexBytes,
|
|
11317
11509
|
"plasius.wavefront.meshIndices"
|
|
11318
11510
|
);
|
|
11319
11511
|
const meshRangeBuffer = createBuffer(
|
|
11320
11512
|
device,
|
|
11321
11513
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11322
|
-
|
|
11514
|
+
memory.meshRangeBytes,
|
|
11323
11515
|
"plasius.wavefront.meshRanges"
|
|
11324
11516
|
);
|
|
11325
11517
|
const environmentPortalBuffer = createBuffer(
|
|
11326
11518
|
device,
|
|
11327
11519
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11328
|
-
|
|
11520
|
+
memory.environmentPortalBytes,
|
|
11329
11521
|
"plasius.wavefront.environmentPortals"
|
|
11330
11522
|
);
|
|
11331
11523
|
const bvhLeafRefBuffer = createBuffer(
|
|
11332
11524
|
device,
|
|
11333
11525
|
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
11334
|
-
|
|
11526
|
+
memory.bvhLeafReferenceBytes,
|
|
11335
11527
|
"plasius.wavefront.bvhLeafRefs"
|
|
11336
11528
|
);
|
|
11337
11529
|
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
|
-
);
|
|
11530
|
+
const configBufferStride = memory.configBufferStride;
|
|
11343
11531
|
const outputConfigSlotCount = config.deferredPathResolve ? 0 : tiles.length;
|
|
11344
11532
|
const frameConfigSlotCount = Math.max(
|
|
11345
11533
|
1,
|
|
@@ -11348,26 +11536,25 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
11348
11536
|
const configBuffer = createBuffer(
|
|
11349
11537
|
device,
|
|
11350
11538
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11351
|
-
|
|
11539
|
+
memory.frameConfigBytes,
|
|
11352
11540
|
"plasius.wavefront.frameConfig"
|
|
11353
11541
|
);
|
|
11354
|
-
const bvhBuildConfigSlots = 1 + config.bvhSortStages.length + config.bvhBuildLevels.length;
|
|
11355
11542
|
const bvhBuildConfigBuffer = createBuffer(
|
|
11356
11543
|
device,
|
|
11357
11544
|
constants.buffer.UNIFORM | constants.buffer.COPY_DST,
|
|
11358
|
-
|
|
11545
|
+
memory.bvhBuildConfigBytes,
|
|
11359
11546
|
"plasius.wavefront.bvhBuildConfig"
|
|
11360
11547
|
);
|
|
11361
11548
|
const counterBuffer = createBuffer(
|
|
11362
11549
|
device,
|
|
11363
11550
|
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
11364
|
-
|
|
11551
|
+
memory.counterBytes,
|
|
11365
11552
|
"plasius.wavefront.counters"
|
|
11366
11553
|
);
|
|
11367
11554
|
const activeDispatchBuffer = createBuffer(
|
|
11368
11555
|
device,
|
|
11369
11556
|
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
11370
|
-
|
|
11557
|
+
memory.indirectDispatchBytes,
|
|
11371
11558
|
"plasius.wavefront.activeDispatchArgs"
|
|
11372
11559
|
);
|
|
11373
11560
|
let packedScene = packWavefrontSceneObjects(config.sceneObjects, config.sceneObjectCapacity);
|