@plasius/gpu-renderer 0.2.0 → 0.2.1
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 +26 -4
- package/README.md +17 -1
- package/dist/index.cjs +131 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +126 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/index.d.ts +68 -26
- package/src/index.js +5 -0
- package/src/wavefront-compute.js +127 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plasius/gpu-renderer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Framework-agnostic WebGPU renderer runtime for Plasius projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"author": "Plasius LTD <development@plasius.co.uk>",
|
|
50
50
|
"license": "Apache-2.0",
|
|
51
51
|
"dependencies": {
|
|
52
|
+
"@plasius/gpu-shared": "^0.1.11",
|
|
52
53
|
"@plasius/gpu-xr": "^0.1.11"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
package/src/index.d.ts
CHANGED
|
@@ -309,6 +309,7 @@ export interface WavefrontEnvironmentPortalRecord {
|
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
export interface WavefrontPathTracingComputeConfig {
|
|
312
|
+
readonly mode: typeof rendererWavefrontComputeMode;
|
|
312
313
|
readonly width: number;
|
|
313
314
|
readonly height: number;
|
|
314
315
|
readonly maxDepth: number;
|
|
@@ -394,6 +395,7 @@ export interface WavefrontPathTracingMemoryEstimate {
|
|
|
394
395
|
readonly environmentPortalBytes: number;
|
|
395
396
|
readonly configBytes: number;
|
|
396
397
|
readonly counterBytes: number;
|
|
398
|
+
readonly indirectDispatchBytes: number;
|
|
397
399
|
readonly totalHotBufferBytes: number;
|
|
398
400
|
}
|
|
399
401
|
|
|
@@ -441,32 +443,12 @@ export interface WavefrontPathTracingComputeRenderer {
|
|
|
441
443
|
readonly device: GPUDevice;
|
|
442
444
|
readonly format: GPUTextureFormat | string;
|
|
443
445
|
readonly config: WavefrontPathTracingComputeConfig;
|
|
444
|
-
renderOnce():
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
tileSize: number;
|
|
451
|
-
samplesPerPixel: number;
|
|
452
|
-
screenRays: number;
|
|
453
|
-
primaryRays: number;
|
|
454
|
-
sceneObjectCount: number;
|
|
455
|
-
triangleCount: number;
|
|
456
|
-
emissiveTriangleCount: number;
|
|
457
|
-
environmentPortalCount: number;
|
|
458
|
-
environmentPortalMode: 0 | 1 | 2;
|
|
459
|
-
bvhNodeCount: number;
|
|
460
|
-
displayQuality: boolean;
|
|
461
|
-
accelerationBuildMode: WavefrontAccelerationBuildMode;
|
|
462
|
-
gpuAccelerationBuildRequired: boolean;
|
|
463
|
-
accelerationBuildSubmitted: boolean;
|
|
464
|
-
accelerationBuilt: boolean;
|
|
465
|
-
accelerationBuildCount: number;
|
|
466
|
-
commandSubmissions: number;
|
|
467
|
-
frameConfigSlots: number;
|
|
468
|
-
memory: WavefrontPathTracingMemoryEstimate;
|
|
469
|
-
}>;
|
|
446
|
+
renderOnce(): WavefrontPathTracingComputeFrameStats;
|
|
447
|
+
renderFrame(options?: {
|
|
448
|
+
readStats?: boolean;
|
|
449
|
+
readOutputProbe?: boolean;
|
|
450
|
+
probe?: { x?: number; y?: number };
|
|
451
|
+
}): Promise<WavefrontPathTracingComputeFrameStats>;
|
|
470
452
|
readOutputProbe(options?: { x?: number; y?: number }): Promise<
|
|
471
453
|
Readonly<{
|
|
472
454
|
x: number;
|
|
@@ -501,6 +483,50 @@ export interface WavefrontPathTracingComputeRenderer {
|
|
|
501
483
|
destroy(): void;
|
|
502
484
|
}
|
|
503
485
|
|
|
486
|
+
export interface WavefrontPathTracingComputeFrameStats {
|
|
487
|
+
readonly frame: number;
|
|
488
|
+
readonly width: number;
|
|
489
|
+
readonly height: number;
|
|
490
|
+
readonly maxDepth: number;
|
|
491
|
+
readonly tiles: number;
|
|
492
|
+
readonly tileSize: number;
|
|
493
|
+
readonly samplesPerPixel: number;
|
|
494
|
+
readonly screenRays: number;
|
|
495
|
+
readonly primaryRays: number;
|
|
496
|
+
readonly sceneObjectCount: number;
|
|
497
|
+
readonly triangleCount: number;
|
|
498
|
+
readonly emissiveTriangleCount: number;
|
|
499
|
+
readonly environmentPortalCount: number;
|
|
500
|
+
readonly environmentPortalMode: 0 | 1 | 2;
|
|
501
|
+
readonly bvhNodeCount: number;
|
|
502
|
+
readonly displayQuality: boolean;
|
|
503
|
+
readonly accelerationBuildMode: WavefrontAccelerationBuildMode;
|
|
504
|
+
readonly gpuAccelerationBuildRequired: boolean;
|
|
505
|
+
readonly accelerationBuildSubmitted: boolean;
|
|
506
|
+
readonly accelerationBuilt: boolean;
|
|
507
|
+
readonly accelerationBuildCount: number;
|
|
508
|
+
readonly commandSubmissions: number;
|
|
509
|
+
readonly frameConfigSlots: number;
|
|
510
|
+
readonly memory: WavefrontPathTracingMemoryEstimate;
|
|
511
|
+
readonly outputProbe?: Readonly<{
|
|
512
|
+
x: number;
|
|
513
|
+
y: number;
|
|
514
|
+
rgba: readonly number[];
|
|
515
|
+
luminance: number;
|
|
516
|
+
sampledPixels: number;
|
|
517
|
+
nonZeroSamples: number;
|
|
518
|
+
maxChannel: number;
|
|
519
|
+
}> | null;
|
|
520
|
+
readonly bounces?: readonly unknown[];
|
|
521
|
+
readonly termination?: Readonly<{
|
|
522
|
+
emissive: number;
|
|
523
|
+
environment: number;
|
|
524
|
+
ambientFallback: number;
|
|
525
|
+
maxDepth: number;
|
|
526
|
+
}>;
|
|
527
|
+
readonly queueOverflow?: number;
|
|
528
|
+
}
|
|
529
|
+
|
|
504
530
|
export function normalizeWavefrontSceneObject(
|
|
505
531
|
input?: WavefrontSceneObjectInput,
|
|
506
532
|
index?: number
|
|
@@ -601,6 +627,20 @@ export function supportsWavefrontPathTracingCompute(options?: {
|
|
|
601
627
|
export function createWavefrontPathTracingComputeRenderer(
|
|
602
628
|
options?: CreateWavefrontPathTracingComputeRendererOptions
|
|
603
629
|
): Promise<WavefrontPathTracingComputeRenderer>;
|
|
630
|
+
export function renderWavefrontPathTracingComputeFrame(
|
|
631
|
+
options?: CreateWavefrontPathTracingComputeRendererOptions & {
|
|
632
|
+
readStats?: boolean;
|
|
633
|
+
readOutputProbe?: boolean;
|
|
634
|
+
}
|
|
635
|
+
): Promise<WavefrontPathTracingComputeFrameStats>;
|
|
636
|
+
export function createWavefrontPathTracingComputeShaderSource(options?: {
|
|
637
|
+
workgroupSize?: number;
|
|
638
|
+
outputTextureFormat?: GPUTextureFormat | "rgba8unorm";
|
|
639
|
+
}): string;
|
|
640
|
+
|
|
641
|
+
export const rendererWavefrontComputeMode: "webgpu-compute";
|
|
642
|
+
export const rendererWavefrontComputeWorkgroupSize: 64;
|
|
643
|
+
export const rendererWavefrontComputeStatsStride: 8;
|
|
604
644
|
|
|
605
645
|
export const wavefrontPathTracingComputeLimits: Readonly<{
|
|
606
646
|
workgroupSize: 64;
|
|
@@ -616,6 +656,8 @@ export const wavefrontPathTracingComputeLimits: Readonly<{
|
|
|
616
656
|
emissiveTriangleMetadataRecordBytes: 48;
|
|
617
657
|
environmentPortalRecordBytes: 96;
|
|
618
658
|
accumulationRecordBytes: 16;
|
|
659
|
+
counterRecordBytes: 32;
|
|
660
|
+
indirectDispatchRecordBytes: 12;
|
|
619
661
|
}>;
|
|
620
662
|
export const wavefrontSceneObjectKinds: Readonly<{
|
|
621
663
|
sphere: 1;
|
package/src/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export {
|
|
|
9
9
|
createWavefrontMeshAcceleration,
|
|
10
10
|
createWavefrontPathTracingComputeConfig,
|
|
11
11
|
createWavefrontPathTracingComputeRenderer,
|
|
12
|
+
createWavefrontPathTracingComputeShaderSource,
|
|
12
13
|
createWavefrontReferenceRay,
|
|
13
14
|
estimateWavefrontPathTracingMemory,
|
|
14
15
|
intersectWavefrontReferenceTriangle,
|
|
@@ -17,6 +18,10 @@ export {
|
|
|
17
18
|
packWavefrontBvhNodes,
|
|
18
19
|
packWavefrontSceneObjects,
|
|
19
20
|
packWavefrontTriangles,
|
|
21
|
+
renderWavefrontPathTracingComputeFrame,
|
|
22
|
+
rendererWavefrontComputeMode,
|
|
23
|
+
rendererWavefrontComputeStatsStride,
|
|
24
|
+
rendererWavefrontComputeWorkgroupSize,
|
|
20
25
|
supportsWavefrontPathTracingCompute,
|
|
21
26
|
traceWavefrontReferenceTriangles,
|
|
22
27
|
wavefrontMaterialKinds,
|
package/src/wavefront-compute.js
CHANGED
|
@@ -6,6 +6,9 @@ const DEFAULT_SAMPLES_PER_PIXEL = 1;
|
|
|
6
6
|
const DEFAULT_SCENE_OBJECT_CAPACITY = 128;
|
|
7
7
|
const DEFAULT_ENVIRONMENT_PORTAL_CAPACITY = 32;
|
|
8
8
|
const WORKGROUP_SIZE = 64;
|
|
9
|
+
export const rendererWavefrontComputeMode = "webgpu-compute";
|
|
10
|
+
export const rendererWavefrontComputeWorkgroupSize = WORKGROUP_SIZE;
|
|
11
|
+
export const rendererWavefrontComputeStatsStride = 8;
|
|
9
12
|
const RAY_RECORD_BYTES = 80;
|
|
10
13
|
const HIT_RECORD_BYTES = 208;
|
|
11
14
|
const SCENE_OBJECT_RECORD_BYTES = 96;
|
|
@@ -18,7 +21,9 @@ const EMISSIVE_TRIANGLE_INDEX_BYTES = 4;
|
|
|
18
21
|
const ENVIRONMENT_PORTAL_RECORD_BYTES = 96;
|
|
19
22
|
const ACCUMULATION_RECORD_BYTES = 16;
|
|
20
23
|
const CONFIG_BUFFER_BYTES = 272;
|
|
21
|
-
const
|
|
24
|
+
const COUNTER_DISPATCH_ARGS_OFFSET = 16;
|
|
25
|
+
const INDIRECT_DISPATCH_ARGS_BYTES = 12;
|
|
26
|
+
const COUNTER_BUFFER_BYTES = 32;
|
|
22
27
|
const TRACE_STORAGE_BUFFER_BINDINGS = 9;
|
|
23
28
|
const HIT_TYPE_SURFACE = 0;
|
|
24
29
|
const HIT_TYPE_EMISSIVE = 1;
|
|
@@ -64,6 +69,8 @@ export const wavefrontPathTracingComputeLimits = Object.freeze({
|
|
|
64
69
|
emissiveTriangleMetadataRecordBytes: BVH_NODE_RECORD_BYTES,
|
|
65
70
|
environmentPortalRecordBytes: ENVIRONMENT_PORTAL_RECORD_BYTES,
|
|
66
71
|
accumulationRecordBytes: ACCUMULATION_RECORD_BYTES,
|
|
72
|
+
counterRecordBytes: COUNTER_BUFFER_BYTES,
|
|
73
|
+
indirectDispatchRecordBytes: INDIRECT_DISPATCH_ARGS_BYTES,
|
|
67
74
|
});
|
|
68
75
|
|
|
69
76
|
export const wavefrontSceneObjectKinds = Object.freeze({
|
|
@@ -1156,6 +1163,7 @@ export function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
1156
1163
|
environmentPortalBytes,
|
|
1157
1164
|
configBytes: CONFIG_BUFFER_BYTES,
|
|
1158
1165
|
counterBytes: COUNTER_BUFFER_BYTES,
|
|
1166
|
+
indirectDispatchBytes: INDIRECT_DISPATCH_ARGS_BYTES,
|
|
1159
1167
|
totalHotBufferBytes:
|
|
1160
1168
|
queueBytes * 2 +
|
|
1161
1169
|
hitBytes +
|
|
@@ -1167,7 +1175,8 @@ export function estimateWavefrontPathTracingMemory(options = {}) {
|
|
|
1167
1175
|
emissiveTriangleMetadataBytes +
|
|
1168
1176
|
environmentPortalBytes +
|
|
1169
1177
|
CONFIG_BUFFER_BYTES +
|
|
1170
|
-
COUNTER_BUFFER_BYTES
|
|
1178
|
+
COUNTER_BUFFER_BYTES +
|
|
1179
|
+
INDIRECT_DISPATCH_ARGS_BYTES,
|
|
1171
1180
|
});
|
|
1172
1181
|
}
|
|
1173
1182
|
|
|
@@ -1269,6 +1278,7 @@ export function createWavefrontPathTracingComputeConfig(options = {}) {
|
|
|
1269
1278
|
);
|
|
1270
1279
|
|
|
1271
1280
|
return Object.freeze({
|
|
1281
|
+
mode: rendererWavefrontComputeMode,
|
|
1272
1282
|
width,
|
|
1273
1283
|
height,
|
|
1274
1284
|
maxDepth,
|
|
@@ -1329,6 +1339,9 @@ function getGpuUsageConstants() {
|
|
|
1329
1339
|
) {
|
|
1330
1340
|
throw new Error("WebGPU runtime unavailable. Required GPU constants are missing.");
|
|
1331
1341
|
}
|
|
1342
|
+
if (typeof GPUBufferUsage.INDIRECT !== "number") {
|
|
1343
|
+
throw new Error("WebGPU runtime unavailable. GPUBufferUsage.INDIRECT is missing.");
|
|
1344
|
+
}
|
|
1332
1345
|
|
|
1333
1346
|
return {
|
|
1334
1347
|
buffer: GPUBufferUsage,
|
|
@@ -2018,6 +2031,10 @@ struct Counters {
|
|
|
2018
2031
|
nextCount: atomic<u32>,
|
|
2019
2032
|
terminatedCount: atomic<u32>,
|
|
2020
2033
|
hitCount: atomic<u32>,
|
|
2034
|
+
dispatchX: u32,
|
|
2035
|
+
dispatchY: u32,
|
|
2036
|
+
dispatchZ: u32,
|
|
2037
|
+
dispatchPad: u32,
|
|
2021
2038
|
};
|
|
2022
2039
|
|
|
2023
2040
|
struct Candidate {
|
|
@@ -2180,6 +2197,18 @@ fn gated_environment_radiance(origin: vec3<f32>, direction: vec3<f32>) -> vec3<f
|
|
|
2180
2197
|
return environment_radiance(origin, direction);
|
|
2181
2198
|
}
|
|
2182
2199
|
|
|
2200
|
+
fn terminal_surface_environment_contribution(ray: RayRecord, hit: HitRecord) -> vec3<f32> {
|
|
2201
|
+
let normal = safe_normalize(hit.shadingNormal.xyz, vec3<f32>(0.0, 1.0, 0.0));
|
|
2202
|
+
let surfaceColor = max(hit.color.xyz, config.ambientColor.xyz);
|
|
2203
|
+
let normalEnvironment = gated_environment_radiance(
|
|
2204
|
+
hit.position.xyz + normal * 0.003,
|
|
2205
|
+
normal
|
|
2206
|
+
);
|
|
2207
|
+
let environmentFloor = max(config.ambientColor.xyz, normalEnvironment * 0.12);
|
|
2208
|
+
let materialFloor = select(0.7, 1.0, hit.materialKind == 0u || hit.materialKind == 3u);
|
|
2209
|
+
return clamp_sample_radiance(ray.throughput.xyz * surfaceColor * environmentFloor * materialFloor);
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2183
2212
|
fn default_mesh_range() -> MeshRange {
|
|
2184
2213
|
return MeshRange(
|
|
2185
2214
|
0u,
|
|
@@ -2751,6 +2780,17 @@ fn tone_map_radiance(value: vec3<f32>) -> vec3<f32> {
|
|
|
2751
2780
|
return pow(clamp(mapped, vec3<f32>(0.0), vec3<f32>(1.0)), vec3<f32>(1.0 / 2.2));
|
|
2752
2781
|
}
|
|
2753
2782
|
|
|
2783
|
+
fn ray_workgroups_for_count(rayCount: u32) -> u32 {
|
|
2784
|
+
return max(1u, (rayCount + 63u) / 64u);
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
fn write_active_dispatch_args(activeCount: u32) {
|
|
2788
|
+
counters.dispatchX = ray_workgroups_for_count(activeCount);
|
|
2789
|
+
counters.dispatchY = 1u;
|
|
2790
|
+
counters.dispatchZ = 1u;
|
|
2791
|
+
counters.dispatchPad = 0u;
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2754
2794
|
fn denoise_range_space(value: vec3<f32>) -> vec3<f32> {
|
|
2755
2795
|
return value / (vec3<f32>(1.0) + value);
|
|
2756
2796
|
}
|
|
@@ -2763,6 +2803,7 @@ fn generatePrimaryRays(@builtin(global_invocation_id) globalId: vec3<u32>) {
|
|
|
2763
2803
|
atomicStore(&counters.nextCount, 0u);
|
|
2764
2804
|
atomicStore(&counters.terminatedCount, 0u);
|
|
2765
2805
|
atomicStore(&counters.hitCount, 0u);
|
|
2806
|
+
write_active_dispatch_args(config.tilePixelCount);
|
|
2766
2807
|
}
|
|
2767
2808
|
if (index >= config.tilePixelCount) {
|
|
2768
2809
|
return;
|
|
@@ -3038,9 +3079,9 @@ fn resolveSurfaceRecords(@builtin(global_invocation_id) globalId: vec3<u32>) {
|
|
|
3038
3079
|
}
|
|
3039
3080
|
|
|
3040
3081
|
if (ray.bounce + 1u >= config.maxDepth) {
|
|
3082
|
+
let terminalEnvironment = terminal_surface_environment_contribution(ray, hit);
|
|
3041
3083
|
accumulation[ray.rayId] =
|
|
3042
|
-
accumulation[ray.rayId] +
|
|
3043
|
-
vec4<f32>(ray.throughput.xyz * config.ambientColor.xyz * sample_weight(), 1.0);
|
|
3084
|
+
accumulation[ray.rayId] + vec4<f32>(terminalEnvironment * sample_weight(), 1.0);
|
|
3044
3085
|
atomicAdd(&counters.terminatedCount, 1u);
|
|
3045
3086
|
return;
|
|
3046
3087
|
}
|
|
@@ -3049,6 +3090,10 @@ fn resolveSurfaceRecords(@builtin(global_invocation_id) globalId: vec3<u32>) {
|
|
|
3049
3090
|
let scatter = scatter_direction(ray, hit, seed);
|
|
3050
3091
|
let nextIndex = atomicAdd(&counters.nextCount, 1u);
|
|
3051
3092
|
if (nextIndex >= config.tilePixelCount) {
|
|
3093
|
+
let overflowEnvironment = terminal_surface_environment_contribution(ray, hit);
|
|
3094
|
+
accumulation[ray.rayId] =
|
|
3095
|
+
accumulation[ray.rayId] + vec4<f32>(overflowEnvironment * sample_weight(), 1.0);
|
|
3096
|
+
atomicAdd(&counters.terminatedCount, 1u);
|
|
3052
3097
|
return;
|
|
3053
3098
|
}
|
|
3054
3099
|
let color = clamp(hit.color.xyz, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
@@ -3077,8 +3122,10 @@ fn compactAndSwapQueues(@builtin(global_invocation_id) globalId: vec3<u32>) {
|
|
|
3077
3122
|
return;
|
|
3078
3123
|
}
|
|
3079
3124
|
let nextCount = atomicLoad(&counters.nextCount);
|
|
3080
|
-
|
|
3125
|
+
let activeCount = min(nextCount, config.tilePixelCount);
|
|
3126
|
+
atomicStore(&counters.activeCount, activeCount);
|
|
3081
3127
|
atomicStore(&counters.nextCount, 0u);
|
|
3128
|
+
write_active_dispatch_args(activeCount);
|
|
3082
3129
|
}
|
|
3083
3130
|
|
|
3084
3131
|
@compute @workgroup_size(64)
|
|
@@ -3373,10 +3420,16 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
3373
3420
|
);
|
|
3374
3421
|
const counterBuffer = createBuffer(
|
|
3375
3422
|
device,
|
|
3376
|
-
constants.buffer.STORAGE | constants.buffer.COPY_DST,
|
|
3423
|
+
constants.buffer.STORAGE | constants.buffer.COPY_DST | constants.buffer.COPY_SRC,
|
|
3377
3424
|
COUNTER_BUFFER_BYTES,
|
|
3378
3425
|
"plasius.wavefront.counters"
|
|
3379
3426
|
);
|
|
3427
|
+
const activeDispatchBuffer = createBuffer(
|
|
3428
|
+
device,
|
|
3429
|
+
constants.buffer.INDIRECT | constants.buffer.COPY_DST,
|
|
3430
|
+
INDIRECT_DISPATCH_ARGS_BYTES,
|
|
3431
|
+
"plasius.wavefront.activeDispatchArgs"
|
|
3432
|
+
);
|
|
3380
3433
|
|
|
3381
3434
|
let packedScene = packWavefrontSceneObjects(config.sceneObjects, config.sceneObjectCapacity);
|
|
3382
3435
|
device.queue.writeBuffer(sceneObjectBuffer, 0, packedScene.buffer);
|
|
@@ -3818,27 +3871,36 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
3818
3871
|
}
|
|
3819
3872
|
|
|
3820
3873
|
function encodeTileSample(encoder, tile, configOffset) {
|
|
3821
|
-
const
|
|
3822
|
-
label: "plasius.wavefront.
|
|
3874
|
+
const generatePass = encoder.beginComputePass({
|
|
3875
|
+
label: "plasius.wavefront.generatePrimaryRaysPass",
|
|
3823
3876
|
});
|
|
3824
3877
|
const tileWorkgroups = Math.ceil((tile.width * tile.height) / WORKGROUP_SIZE);
|
|
3825
|
-
const capacityWorkgroups = Math.ceil(config.tilePixelCapacity / WORKGROUP_SIZE);
|
|
3826
3878
|
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3879
|
+
generatePass.setBindGroup(0, bindGroups[0], [configOffset]);
|
|
3880
|
+
generatePass.setPipeline(pipelines.generatePrimaryRays);
|
|
3881
|
+
generatePass.dispatchWorkgroups(tileWorkgroups);
|
|
3882
|
+
generatePass.end();
|
|
3830
3883
|
|
|
3831
3884
|
for (let bounceIndex = 0; bounceIndex < config.maxDepth; bounceIndex += 1) {
|
|
3885
|
+
encoder.copyBufferToBuffer(
|
|
3886
|
+
counterBuffer,
|
|
3887
|
+
COUNTER_DISPATCH_ARGS_OFFSET,
|
|
3888
|
+
activeDispatchBuffer,
|
|
3889
|
+
0,
|
|
3890
|
+
INDIRECT_DISPATCH_ARGS_BYTES
|
|
3891
|
+
);
|
|
3892
|
+
const passEncoder = encoder.beginComputePass({
|
|
3893
|
+
label: `plasius.wavefront.bounce.${bounceIndex}`,
|
|
3894
|
+
});
|
|
3832
3895
|
passEncoder.setBindGroup(0, bindGroups[bounceIndex % 2], [configOffset]);
|
|
3833
3896
|
passEncoder.setPipeline(pipelines.intersectActiveQueue);
|
|
3834
|
-
passEncoder.
|
|
3897
|
+
passEncoder.dispatchWorkgroupsIndirect(activeDispatchBuffer, 0);
|
|
3835
3898
|
passEncoder.setPipeline(pipelines.resolveSurfaceRecords);
|
|
3836
|
-
passEncoder.
|
|
3899
|
+
passEncoder.dispatchWorkgroupsIndirect(activeDispatchBuffer, 0);
|
|
3837
3900
|
passEncoder.setPipeline(pipelines.compactAndSwapQueues);
|
|
3838
3901
|
passEncoder.dispatchWorkgroups(1);
|
|
3902
|
+
passEncoder.end();
|
|
3839
3903
|
}
|
|
3840
|
-
|
|
3841
|
-
passEncoder.end();
|
|
3842
3904
|
}
|
|
3843
3905
|
|
|
3844
3906
|
function encodeTileOutput(encoder, tile, configOffset) {
|
|
@@ -3990,6 +4052,32 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
3990
4052
|
});
|
|
3991
4053
|
}
|
|
3992
4054
|
|
|
4055
|
+
async function renderFrame(renderOptions = {}) {
|
|
4056
|
+
const frameStats = renderOnce();
|
|
4057
|
+
const probe =
|
|
4058
|
+
renderOptions.readOutputProbe === false ? null : await readOutputProbe(renderOptions.probe);
|
|
4059
|
+
const maxChannel = probe ? Math.max(...probe.rgba.slice(0, 3)) : 0;
|
|
4060
|
+
return Object.freeze({
|
|
4061
|
+
...frameStats,
|
|
4062
|
+
outputProbe: probe
|
|
4063
|
+
? Object.freeze({
|
|
4064
|
+
...probe,
|
|
4065
|
+
sampledPixels: 1,
|
|
4066
|
+
nonZeroSamples: maxChannel > 0 ? 1 : 0,
|
|
4067
|
+
maxChannel,
|
|
4068
|
+
})
|
|
4069
|
+
: null,
|
|
4070
|
+
bounces: [],
|
|
4071
|
+
termination: Object.freeze({
|
|
4072
|
+
emissive: 0,
|
|
4073
|
+
environment: 0,
|
|
4074
|
+
ambientFallback: 0,
|
|
4075
|
+
maxDepth: 0,
|
|
4076
|
+
}),
|
|
4077
|
+
queueOverflow: 0,
|
|
4078
|
+
});
|
|
4079
|
+
}
|
|
4080
|
+
|
|
3993
4081
|
function updateSceneObjects(sceneObjects) {
|
|
3994
4082
|
const nextPackedScene = packWavefrontSceneObjects(sceneObjects, config.sceneObjectCapacity);
|
|
3995
4083
|
packedScene = nextPackedScene;
|
|
@@ -4050,6 +4138,7 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
4050
4138
|
configBuffer.destroy?.();
|
|
4051
4139
|
bvhBuildConfigBuffer.destroy?.();
|
|
4052
4140
|
counterBuffer.destroy?.();
|
|
4141
|
+
activeDispatchBuffer.destroy?.();
|
|
4053
4142
|
radianceTexture.destroy?.();
|
|
4054
4143
|
denoiseScratchTexture.destroy?.();
|
|
4055
4144
|
outputTexture.destroy?.();
|
|
@@ -4063,9 +4152,31 @@ export async function createWavefrontPathTracingComputeRenderer(options = {}) {
|
|
|
4063
4152
|
format,
|
|
4064
4153
|
config,
|
|
4065
4154
|
renderOnce,
|
|
4155
|
+
renderFrame,
|
|
4066
4156
|
readOutputProbe,
|
|
4067
4157
|
updateSceneObjects,
|
|
4068
4158
|
getSnapshot,
|
|
4069
4159
|
destroy,
|
|
4070
4160
|
});
|
|
4071
4161
|
}
|
|
4162
|
+
|
|
4163
|
+
export async function renderWavefrontPathTracingComputeFrame(options = {}) {
|
|
4164
|
+
const renderer = await createWavefrontPathTracingComputeRenderer(options);
|
|
4165
|
+
try {
|
|
4166
|
+
return await renderer.renderFrame(options);
|
|
4167
|
+
} finally {
|
|
4168
|
+
renderer.destroy();
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
|
|
4172
|
+
export function createWavefrontPathTracingComputeShaderSource(options = {}) {
|
|
4173
|
+
const workgroupSize = readPositiveInteger(
|
|
4174
|
+
"workgroupSize",
|
|
4175
|
+
options.workgroupSize ?? rendererWavefrontComputeWorkgroupSize,
|
|
4176
|
+
rendererWavefrontComputeWorkgroupSize
|
|
4177
|
+
);
|
|
4178
|
+
if (workgroupSize !== rendererWavefrontComputeWorkgroupSize) {
|
|
4179
|
+
throw new Error(`wavefront mesh compute currently requires workgroupSize=${rendererWavefrontComputeWorkgroupSize}.`);
|
|
4180
|
+
}
|
|
4181
|
+
return WAVEFRONT_COMPUTE_WGSL;
|
|
4182
|
+
}
|