@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 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
- const materialCapacity = readNonNegativeInteger2("materialCapacity", options.materialCapacity, 0);
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 * TRIANGLE_RECORD_BYTES;
4745
- const materialTableBytes = materialCapacity * GPU_MATERIAL_RECORD_BYTES;
4795
+ const triangleBytes = allocatedRecordBytes(triangleCapacity, TRIANGLE_RECORD_BYTES);
4796
+ const materialTableBytes = 0;
4746
4797
  const bvhNodeBytes = bvhNodeCapacity * BVH_NODE_RECORD_BYTES;
4747
- const bvhLeafReferenceBytes = bvhLeafSortCapacity * BVH_LEAF_REF_RECORD_BYTES;
4798
+ const bvhLeafReferenceBytes = allocatedRecordBytes(
4799
+ bvhLeafSortCapacity,
4800
+ BVH_LEAF_REF_RECORD_BYTES
4801
+ );
4748
4802
  const emissiveTriangleMetadataBytes = emissiveTriangleCapacity * BVH_NODE_RECORD_BYTES;
4749
- const environmentPortalBytes = environmentPortalCapacity * ENVIRONMENT_PORTAL_RECORD_BYTES;
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
- totalHotBufferBytes: queueBytes * 2 + hitBytes + accumulationBytes + pathVertexBytes + sceneObjectBytes + triangleBytes + materialTableBytes + bvhNodeBytes + bvhLeafReferenceBytes + emissiveTriangleMetadataBytes + environmentPortalBytes + CONFIG_BUFFER_BYTES + COUNTER_BUFFER_BYTES + INDIRECT_DISPATCH_ARGS_BYTES
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 requiredLimits = { ...options.requiredLimits ?? {} };
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 descriptor = { ...options.deviceDescriptor ?? {} };
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(createWavefrontDeviceDescriptor(adapter, options));
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 rayQueueBytes = config.tilePixelCapacity * RAY_RECORD_BYTES;
11271
- const hitBytes = config.tilePixelCapacity * HIT_RECORD_BYTES;
11272
- const accumulationBytes = config.tilePixelCapacity * ACCUMULATION_RECORD_BYTES;
11273
- const pathVertexBytes = config.tilePixelCapacity * (config.maxDepth + 1) * PATH_VERTEX_RECORD_BYTES;
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
- config.sceneObjectCapacity * SCENE_OBJECT_RECORD_BYTES,
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
- Math.max(1, config.triangleCapacity) * TRIANGLE_RECORD_BYTES,
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
- Math.max(1, config.bvhNodeCapacity + config.emissiveTriangleCapacity) * BVH_NODE_RECORD_BYTES,
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
- Math.max(1, config.gpuMeshSource.vertices.count) * MESH_VERTEX_RECORD_BYTES,
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
- Math.max(1, config.gpuMeshSource.indices.count) * 4,
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
- Math.max(1, config.gpuMeshSource.meshes.count) * MESH_RANGE_RECORD_BYTES,
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
- Math.max(1, config.environmentPortalCapacity) * ENVIRONMENT_PORTAL_RECORD_BYTES,
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
- Math.max(1, config.bvhLeafSortCapacity) * BVH_LEAF_REF_RECORD_BYTES,
11526
+ memory.bvhLeafReferenceBytes,
11335
11527
  "plasius.wavefront.bvhLeafRefs"
11336
11528
  );
11337
11529
  const tiles = createTiles(config.width, config.height, config.tileSize);
11338
- const uniformOffsetAlignment = Number(device?.limits?.minUniformBufferOffsetAlignment);
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
- frameConfigSlotCount * configBufferStride,
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
- Math.max(1, bvhBuildConfigSlots) * configBufferStride,
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
- COUNTER_BUFFER_BYTES,
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
- INDIRECT_DISPATCH_ARGS_BYTES,
11557
+ memory.indirectDispatchBytes,
11371
11558
  "plasius.wavefront.activeDispatchArgs"
11372
11559
  );
11373
11560
  let packedScene = packWavefrontSceneObjects(config.sceneObjects, config.sceneObjectCapacity);