@driftengine/core 4.4.1 → 4.5.0
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.json +72 -0
- package/README.md +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -0
- package/dist/render/backend/api.d.ts +17 -11
- package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
- package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
- package/dist/render/backend/webgl2/renderer.d.ts +82 -8
- package/dist/render/backend/webgl2/renderer.js +373 -105
- package/dist/render/backend/webgpu/buffers.d.ts +19 -1
- package/dist/render/backend/webgpu/buffers.js +27 -1
- package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
- package/dist/render/backend/webgpu/depthPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +2 -0
- package/dist/render/backend/webgpu/flatPass.js +20 -1
- package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
- package/dist/render/backend/webgpu/glassTintPass.js +205 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +60 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.js +305 -5
- package/dist/render/backend/webgpu/instanced.d.ts +12 -1
- package/dist/render/backend/webgpu/instanced.js +20 -1
- package/dist/render/backend/webgpu/latePass.d.ts +26 -0
- package/dist/render/backend/webgpu/latePass.js +133 -0
- package/dist/render/backend/webgpu/lightVolumePass.js +5 -1
- package/dist/render/backend/webgpu/motionPass.d.ts +95 -0
- package/dist/render/backend/webgpu/motionPass.js +491 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +10 -1
- package/dist/render/backend/webgpu/pipelineCache.js +11 -1
- package/dist/render/backend/webgpu/pointGlassTintPass.d.ts +32 -0
- package/dist/render/backend/webgpu/pointGlassTintPass.js +193 -0
- package/dist/render/backend/webgpu/pointShadowPass.d.ts +35 -6
- package/dist/render/backend/webgpu/pointShadowPass.js +105 -20
- package/dist/render/backend/webgpu/postPass.d.ts +21 -15
- package/dist/render/backend/webgpu/postPass.js +17 -4
- package/dist/render/backend/webgpu/renderer.d.ts +181 -54
- package/dist/render/backend/webgpu/renderer.js +1011 -394
- package/dist/render/backend/webgpu/scatterPass.js +2 -1
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
- package/dist/render/backend/webgpu/skinPaletteRing.js +4 -0
- package/dist/render/backend/webgpu/snapshotMips.d.ts +29 -0
- package/dist/render/backend/webgpu/snapshotMips.js +52 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +5 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.js +1 -1
- package/dist/render/flameLight.js +15 -2
- package/dist/render/glass.d.ts +45 -0
- package/dist/render/glass.js +39 -0
- package/dist/render/glassCasters.d.ts +40 -0
- package/dist/render/glassCasters.js +84 -0
- package/dist/render/glassShadow.d.ts +78 -0
- package/dist/render/glassShadow.js +125 -0
- package/dist/render/globalMediumPass.d.ts +2 -3
- package/dist/render/globalMediumPass.js +2 -8
- package/dist/render/gpudriven/lit.d.ts +12 -0
- package/dist/render/gpudriven/lit.js +23 -0
- package/dist/render/gpudriven/materialTable.d.ts +15 -5
- package/dist/render/gpudriven/materialTable.js +26 -6
- package/dist/render/gpudriven/pipeline.d.ts +1 -1
- package/dist/render/gpudriven/pipeline.js +4 -3
- package/dist/render/gpudriven/sunGlass.d.ts +35 -0
- package/dist/render/gpudriven/sunGlass.js +89 -0
- package/dist/render/lightBudget.d.ts +17 -5
- package/dist/render/lightBudget.js +17 -5
- package/dist/render/pointGlassTint.d.ts +59 -0
- package/dist/render/pointGlassTint.js +198 -0
- package/dist/render/pointShadowArray.d.ts +56 -3
- package/dist/render/pointShadowArray.js +127 -16
- package/dist/render/pointShadowBudget.js +51 -41
- package/dist/render/pointShadowMap.d.ts +23 -1
- package/dist/render/pointShadowMap.js +27 -1
- package/dist/render/recon/changeFrames.d.ts +15 -0
- package/dist/render/recon/changeFrames.js +21 -0
- package/dist/render/recon/disocclusion.d.ts +36 -3
- package/dist/render/recon/disocclusion.js +56 -4
- package/dist/render/recon/lateRouting.d.ts +14 -0
- package/dist/render/recon/lateRouting.js +18 -0
- package/dist/render/recon/mover.d.ts +57 -0
- package/dist/render/recon/mover.js +86 -0
- package/dist/render/recon/resolve.js +95 -12
- package/dist/render/renderQuality.d.ts +35 -0
- package/dist/render/renderQuality.js +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/sceneTarget.d.ts +9 -1
- package/dist/render/sceneTarget.js +59 -13
- package/dist/render/shaders/depth.d.ts +16 -1
- package/dist/render/shaders/depth.js +85 -9
- package/dist/render/shaders/flat/directionalShadow.js +91 -6
- package/dist/render/shaders/flat/glassTint.d.ts +6 -0
- package/dist/render/shaders/flat/glassTint.js +25 -0
- package/dist/render/shaders/flat/index.d.ts +13 -0
- package/dist/render/shaders/flat/index.js +4 -0
- package/dist/render/shaders/flat/lampGlass.d.ts +1 -0
- package/dist/render/shaders/flat/lampGlass.js +183 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +115 -15
- package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
- package/dist/render/shaders/flat/pointShadow.js +2 -0
- package/dist/render/shaders/flat/preamble.js +21 -6
- package/dist/render/shaders/generated/depth.wgsl.d.ts +227 -4
- package/dist/render/shaders/generated/depth.wgsl.js +227 -4
- package/dist/render/shaders/generated/flat.wgsl.d.ts +360 -312
- package/dist/render/shaders/generated/flat.wgsl.js +376 -328
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/globalMedium.wgsl.js +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.js +4 -14
- package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/octahedralResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +31 -6
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +31 -6
- package/dist/render/shaders/globalMedium.js +6 -6
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +7 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +86 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.js +11 -2
- package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/materialTable.wgsl.js +3 -1
- package/dist/render/shaders/gpudriven/shade.wgsl.js +50 -1
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.d.ts +9 -0
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.js +133 -0
- package/dist/render/shaders/lightVolume.js +6 -6
- package/dist/render/shaders/octahedralResolve.d.ts +8 -0
- package/dist/render/shaders/octahedralResolve.js +48 -17
- package/dist/render/shaders/recon/lateDepth.wgsl.d.ts +1 -0
- package/dist/render/shaders/recon/lateDepth.wgsl.js +44 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +84 -0
- package/dist/render/shaders/recon/resolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/resolve.wgsl.js +112 -8
- package/dist/render/shaders/temporalResolve.js +133 -5
- package/dist/render/shadowCasters.d.ts +20 -1
- package/dist/render/shadowCasters.js +15 -1
- package/dist/render/shadowMap.d.ts +54 -5
- package/dist/render/shadowMap.js +190 -36
- package/dist/render/sunGlassTint.d.ts +25 -0
- package/dist/render/sunGlassTint.js +79 -0
- package/dist/render/temporalAa.d.ts +145 -0
- package/dist/render/temporalAa.js +190 -0
- package/dist/render/temporalPass.d.ts +16 -14
- package/dist/render/temporalPass.js +59 -14
- package/dist/render/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +15 -1
- package/package.json +6 -6
- package/src/index.ts +10 -0
- package/src/render/backend/api.ts +15 -9
- package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
- package/src/render/backend/webgl2/renderer.ts +422 -109
- package/src/render/backend/webgpu/buffers.ts +50 -2
- package/src/render/backend/webgpu/depthPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +22 -1
- package/src/render/backend/webgpu/glassTintPass.ts +244 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
- package/src/render/backend/webgpu/instanced.ts +21 -1
- package/src/render/backend/webgpu/latePass.ts +152 -0
- package/src/render/backend/webgpu/lightVolumePass.ts +5 -1
- package/src/render/backend/webgpu/motionPass.ts +535 -0
- package/src/render/backend/webgpu/pipelineCache.ts +12 -1
- package/src/render/backend/webgpu/pointGlassTintPass.ts +233 -0
- package/src/render/backend/webgpu/pointShadowPass.ts +158 -26
- package/src/render/backend/webgpu/postPass.ts +34 -4
- package/src/render/backend/webgpu/renderer.ts +1178 -425
- package/src/render/backend/webgpu/scatterPass.ts +2 -1
- package/src/render/backend/webgpu/skinPaletteRing.ts +4 -0
- package/src/render/backend/webgpu/snapshotMips.ts +80 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +1 -1
- package/src/render/flameLight.ts +15 -2
- package/src/render/glass.ts +74 -0
- package/src/render/glassCasters.ts +164 -0
- package/src/render/glassShadow.ts +153 -0
- package/src/render/globalMediumPass.ts +4 -11
- package/src/render/gpudriven/lit.ts +31 -0
- package/src/render/gpudriven/materialTable.ts +28 -6
- package/src/render/gpudriven/pipeline.ts +4 -3
- package/src/render/gpudriven/sunGlass.ts +117 -0
- package/src/render/lightBudget.ts +19 -5
- package/src/render/pointGlassTint.ts +250 -0
- package/src/render/pointShadowArray.ts +188 -22
- package/src/render/pointShadowBudget.ts +49 -39
- package/src/render/pointShadowMap.ts +41 -0
- package/src/render/recon/changeFrames.ts +24 -0
- package/src/render/recon/disocclusion.ts +54 -3
- package/src/render/recon/lateRouting.ts +29 -0
- package/src/render/recon/mover.ts +118 -0
- package/src/render/recon/resolve.ts +137 -10
- package/src/render/renderQuality.ts +47 -0
- package/src/render/rendererHarness.ts +12 -0
- package/src/render/sceneTarget.ts +66 -12
- package/src/render/shaders/depth.ts +109 -9
- package/src/render/shaders/flat/directionalShadow.ts +97 -6
- package/src/render/shaders/flat/glassTint.ts +25 -0
- package/src/render/shaders/flat/index.ts +17 -0
- package/src/render/shaders/flat/lampGlass.ts +185 -0
- package/src/render/shaders/flat/main.ts +115 -15
- package/src/render/shaders/flat/pointShadow.ts +2 -0
- package/src/render/shaders/flat/preamble.ts +21 -6
- package/src/render/shaders/generated/depth.wgsl.ts +234 -4
- package/src/render/shaders/generated/flat.wgsl.ts +376 -328
- package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
- package/src/render/shaders/generated/lightVolume.wgsl.ts +4 -14
- package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +31 -6
- package/src/render/shaders/globalMedium.ts +6 -6
- package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +88 -1
- package/src/render/shaders/gpudriven/cull.wgsl.ts +11 -2
- package/src/render/shaders/gpudriven/materialTable.wgsl.ts +3 -1
- package/src/render/shaders/gpudriven/shade.wgsl.ts +50 -1
- package/src/render/shaders/gpudriven/sunGlass.wgsl.ts +139 -0
- package/src/render/shaders/lightVolume.ts +6 -6
- package/src/render/shaders/octahedralResolve.ts +50 -17
- package/src/render/shaders/recon/lateDepth.wgsl.ts +47 -0
- package/src/render/shaders/recon/motion.wgsl.ts +84 -0
- package/src/render/shaders/recon/resolve.wgsl.ts +112 -8
- package/src/render/shaders/temporalResolve.ts +141 -5
- package/src/render/shadowCasters.ts +28 -1
- package/src/render/shadowMap.ts +231 -37
- package/src/render/sunGlassTint.ts +86 -0
- package/src/render/temporalAa.ts +227 -0
- package/src/render/temporalPass.ts +88 -12
- package/src/render/translucentQueue.ts +20 -1
|
@@ -70,6 +70,9 @@ import { FRUSTUM_FLOATS, frustumPlanes } from '../../gpudriven/frustum.js';
|
|
|
70
70
|
import { VIS_EMPTY } from '../../gpudriven/visbuffer.js';
|
|
71
71
|
import { jitterClip } from '../../recon/jitter.js';
|
|
72
72
|
import { GPU_DRIVEN_ORDERED, GPU_DRIVEN_PASSES, GPU_DRIVEN_RESOURCES, gpuDrivenLive, gpuDrivenRefusal, gpuDrivenSupported, recordGpuDrivenStages, } from '../../gpudriven/pipeline.js';
|
|
73
|
+
import { resolveGlass } from '../../glass.js';
|
|
74
|
+
import { GLASS_TINT_BLEND } from './glassTintPass.js';
|
|
75
|
+
import { SnapshotMips } from './snapshotMips.js';
|
|
73
76
|
import { createDeps, resetDeps } from '../../frame/deps.js';
|
|
74
77
|
import { createGraphPasses, createGraphScratch, scheduleGraph } from '../../frame/graphSchedule.js';
|
|
75
78
|
import { hzbMipCount, hzbMipSize } from '../../gpudriven/hzb.js';
|
|
@@ -384,6 +387,30 @@ export class GpuDrivenPass {
|
|
|
384
387
|
latentClamp = null;
|
|
385
388
|
latentRepeat = null;
|
|
386
389
|
shadowView = null;
|
|
390
|
+
/** The nearest pane's depth from the sun: the shadow texture's second layer, where glass casts. */
|
|
391
|
+
glassDepthView = null;
|
|
392
|
+
/** What the panes let through, as the sun sees them, with the chain frost reads. */
|
|
393
|
+
glassTintTexture = null;
|
|
394
|
+
glassTintTarget = null;
|
|
395
|
+
glassTintSampled = null;
|
|
396
|
+
glassTintMips = null;
|
|
397
|
+
/** One white texel, bound where no glass casts, which the lookup reads as none. */
|
|
398
|
+
glassTintNone = null;
|
|
399
|
+
glassMode;
|
|
400
|
+
/** Whether the sun's glass pass runs at all: a glass material, and glass shadows not off. */
|
|
401
|
+
castsGlass;
|
|
402
|
+
glassList = null;
|
|
403
|
+
glassArgs = null;
|
|
404
|
+
glassLodBuffer = null;
|
|
405
|
+
lodParamsGlass = new Float32Array(8);
|
|
406
|
+
shadowCullSettingsGlass = null;
|
|
407
|
+
glassLodGroup = null;
|
|
408
|
+
glassCullGroup = null;
|
|
409
|
+
glassCompactGroup = null;
|
|
410
|
+
glassDepthPipeline = null;
|
|
411
|
+
glassDepthGroup = null;
|
|
412
|
+
glassTintPipeline = null;
|
|
413
|
+
glassTintGroup = null;
|
|
387
414
|
/**
|
|
388
415
|
* What is bound as the probe where the frame has none.
|
|
389
416
|
*
|
|
@@ -497,7 +524,27 @@ export class GpuDrivenPass {
|
|
|
497
524
|
visibilityTexture = null;
|
|
498
525
|
depthTexture = null;
|
|
499
526
|
colourTexture = null;
|
|
527
|
+
/** Level 0: what the shading writes, the resolve lays over and the blit presents. */
|
|
500
528
|
colourView = null;
|
|
529
|
+
/** Every level, for glass to read at the level its frost picks. Level 0 alone with no glass. */
|
|
530
|
+
colourSampledView = null;
|
|
531
|
+
/** The chain glass reads, filled from the shaded picture each frame; null in a scene with none. */
|
|
532
|
+
colourMips = null;
|
|
533
|
+
/** Whether any material is glass, which is what earns the colour its chain: see `buildTargets`. */
|
|
534
|
+
hasGlass;
|
|
535
|
+
/** The pipelines the chain draws with, one a format. */
|
|
536
|
+
mipPipelineCache = new Map();
|
|
537
|
+
mipPipelines = {
|
|
538
|
+
get: (key, describe) => {
|
|
539
|
+
const held = this.mipPipelineCache.get(key);
|
|
540
|
+
if (held !== undefined)
|
|
541
|
+
return held;
|
|
542
|
+
const made = this.device.createRenderPipeline(describe());
|
|
543
|
+
this.mipPipelineCache.set(key, made);
|
|
544
|
+
return made;
|
|
545
|
+
},
|
|
546
|
+
};
|
|
547
|
+
glassSampler = null;
|
|
501
548
|
visibility = null;
|
|
502
549
|
hzb = null;
|
|
503
550
|
levelStart = null;
|
|
@@ -613,7 +660,10 @@ export class GpuDrivenPass {
|
|
|
613
660
|
this.decode = packDecodeTables(this.programs.programs);
|
|
614
661
|
this.scene = scene;
|
|
615
662
|
this.materials = materials;
|
|
663
|
+
this.hasGlass = materials.some((material) => resolveGlass(material.glass, glassProbe));
|
|
616
664
|
this.shadowSize = shadow.mapSize ?? DEFAULT_RENDER_QUALITY.directionalShadowMapSize;
|
|
665
|
+
this.glassMode = shadow.glass ?? DEFAULT_RENDER_QUALITY.glassShadows;
|
|
666
|
+
this.castsGlass = this.hasGlass && this.glassMode !== 'off';
|
|
617
667
|
this.shadowMaxDistance =
|
|
618
668
|
shadow.maxDistance ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxDistance;
|
|
619
669
|
this.shadowMaxSlope = shadow.maxSlope ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxSlope;
|
|
@@ -840,6 +890,10 @@ export class GpuDrivenPass {
|
|
|
840
890
|
this.shadowArgs = this.storage(device, 'draw shadow', shadowArgs, INDIRECT | COPY_SRC);
|
|
841
891
|
this.shadowArgsTwo = this.storage(device, 'draw shadow two', shadowArgs, INDIRECT | COPY_SRC);
|
|
842
892
|
this.shadowSelected = this.empty(device, 'shadow selected', count * 4);
|
|
893
|
+
/* The sun's glass: its own list and arguments, over the light's selection once the map is done. */
|
|
894
|
+
this.glassList = this.empty(device, 'shadow glass list', count * 4);
|
|
895
|
+
this.glassArgs = this.storage(device, 'draw shadow glass', shadowArgs, INDIRECT | COPY_SRC);
|
|
896
|
+
this.glassLodBuffer = this.empty(device, 'lod params glass', 8 * 4);
|
|
843
897
|
this.shadowKeep = this.empty(device, 'shadow keep', count * 4);
|
|
844
898
|
this.shadowPlanes = this.empty(device, 'shadow planes', FRUSTUM_FLOATS * 4);
|
|
845
899
|
this.shadowHistories = [
|
|
@@ -862,6 +916,8 @@ export class GpuDrivenPass {
|
|
|
862
916
|
this.shadowCullValues[CULL_CONES] = 1;
|
|
863
917
|
this.shadowCullSettings = this.storage(device, 'cull settings, shadow', this.shadowCullValues);
|
|
864
918
|
this.shadowCullSettingsTwo = this.storage(device, 'cull settings, shadow two', this.shadowCullValues);
|
|
919
|
+
/* The glass pass's: no pyramid and no cones, since a pane casts from either side. */
|
|
920
|
+
this.shadowCullSettingsGlass = this.storage(device, 'cull settings, shadow glass', this.shadowCullValues);
|
|
865
921
|
this.shadowCompactSettings = this.storage(device, 'phase shadow', Uint32Array.from([PHASE_ONE, count]));
|
|
866
922
|
this.shadowCompactSettingsTwo = this.storage(device, 'phase shadow two', Uint32Array.from([PHASE_TWO, count]));
|
|
867
923
|
/* Nonzero is hidden, and the light hides nothing: see `CULL_INSTANCES_WGSL`. */
|
|
@@ -875,11 +931,47 @@ export class GpuDrivenPass {
|
|
|
875
931
|
*/
|
|
876
932
|
this.shadowTexture = device.createTexture({
|
|
877
933
|
label: 'gpu-driven shadow',
|
|
878
|
-
|
|
934
|
+
/* A second layer for the nearest pane where a material is glass, and none where none is. */
|
|
935
|
+
size: {
|
|
936
|
+
width: this.shadowSize,
|
|
937
|
+
height: this.shadowSize,
|
|
938
|
+
depthOrArrayLayers: this.castsGlass ? 2 : 1,
|
|
939
|
+
},
|
|
879
940
|
format: SHADOW_FORMAT,
|
|
880
941
|
usage: RENDER_ATTACHMENT | TEXTURE_BINDING,
|
|
881
942
|
});
|
|
882
|
-
|
|
943
|
+
const layer = (at) => this.shadowTexture.createView({
|
|
944
|
+
dimension: '2d',
|
|
945
|
+
baseArrayLayer: at,
|
|
946
|
+
arrayLayerCount: 1,
|
|
947
|
+
});
|
|
948
|
+
this.shadowView = layer(0);
|
|
949
|
+
this.glassDepthView = this.castsGlass ? layer(1) : null;
|
|
950
|
+
const tintSize = this.glassMode === 'half' ? Math.max(1, this.shadowSize >> 1) : this.shadowSize;
|
|
951
|
+
this.glassTintTexture = this.castsGlass
|
|
952
|
+
? device.createTexture({
|
|
953
|
+
label: 'gpu-driven glass tint',
|
|
954
|
+
size: { width: tintSize, height: tintSize },
|
|
955
|
+
format: 'rgba8unorm',
|
|
956
|
+
mipLevelCount: Math.floor(Math.log2(tintSize)) + 1,
|
|
957
|
+
usage: RENDER_ATTACHMENT | TEXTURE_BINDING,
|
|
958
|
+
})
|
|
959
|
+
: null;
|
|
960
|
+
if (this.glassTintTexture !== null) {
|
|
961
|
+
this.glassTintTarget = this.glassTintTexture.createView({
|
|
962
|
+
baseMipLevel: 0,
|
|
963
|
+
mipLevelCount: 1,
|
|
964
|
+
});
|
|
965
|
+
this.glassTintSampled = this.glassTintTexture.createView();
|
|
966
|
+
this.glassTintMips = new SnapshotMips(device, this.mipPipelines, this.glassTintTexture, 'rgba8unorm', null, 'gpu-driven glass tint mips');
|
|
967
|
+
}
|
|
968
|
+
this.glassTintNone = device.createTexture({
|
|
969
|
+
label: 'gpu-driven no glass',
|
|
970
|
+
size: { width: 1, height: 1 },
|
|
971
|
+
format: 'rgba8unorm',
|
|
972
|
+
usage: TEXTURE_BINDING | TEXTURE_COPY_DST,
|
|
973
|
+
});
|
|
974
|
+
device.queue.writeTexture({ texture: this.glassTintNone }, new Uint8Array([255, 255, 255, 255]), { bytesPerRow: 4 }, { width: 1, height: 1 });
|
|
883
975
|
this.emptyEnvironment = device.createTexture({
|
|
884
976
|
label: 'gpu-driven no environment',
|
|
885
977
|
size: { width: 1, height: 1, depthOrArrayLayers: 1 },
|
|
@@ -1171,6 +1263,37 @@ export class GpuDrivenPass {
|
|
|
1171
1263
|
});
|
|
1172
1264
|
this.shadowGroup = shadowRasterFor(this.shadowList);
|
|
1173
1265
|
this.shadowGroupTwo = shadowRasterFor(this.shadowListTwo);
|
|
1266
|
+
/*
|
|
1267
|
+
* **The nearest pane, from the sun: the same raster, culling nothing**, since a pane casts from
|
|
1268
|
+
* either side; into the shadow texture's second layer. Built only where glass casts.
|
|
1269
|
+
*/
|
|
1270
|
+
if (this.castsGlass) {
|
|
1271
|
+
this.glassDepthPipeline = device.createRenderPipeline({
|
|
1272
|
+
label: 'gpu-driven shadow glass',
|
|
1273
|
+
layout: 'auto',
|
|
1274
|
+
vertex: { module: raster, entryPoint: 'vertexMain' },
|
|
1275
|
+
primitive: { topology: 'triangle-list', cullMode: 'none', frontFace: 'cw' },
|
|
1276
|
+
depthStencil: {
|
|
1277
|
+
format: SHADOW_FORMAT,
|
|
1278
|
+
depthWriteEnabled: true,
|
|
1279
|
+
depthCompare: 'less',
|
|
1280
|
+
depthBias: 4,
|
|
1281
|
+
depthBiasSlopeScale: 1.1,
|
|
1282
|
+
},
|
|
1283
|
+
});
|
|
1284
|
+
this.glassDepthGroup = device.createBindGroup({
|
|
1285
|
+
layout: this.glassDepthPipeline.getBindGroupLayout(0),
|
|
1286
|
+
entries: [
|
|
1287
|
+
{ binding: 0, resource: { buffer: this.shadowMatrix } },
|
|
1288
|
+
{ binding: 1, resource: { buffer: this.glassList } },
|
|
1289
|
+
{ binding: 2, resource: { buffer: this.clusterMeta } },
|
|
1290
|
+
{ binding: 3, resource: { buffer: this.indices } },
|
|
1291
|
+
{ binding: 4, resource: { buffer: this.vertices } },
|
|
1292
|
+
{ binding: 5, resource: { buffer: this.transformBuffer } },
|
|
1293
|
+
{ binding: 6, resource: { buffer: this.materialOf } },
|
|
1294
|
+
],
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1174
1297
|
/*
|
|
1175
1298
|
* **The transparent half's raster: one indirect draw into two targets at once.**
|
|
1176
1299
|
*
|
|
@@ -1236,6 +1359,38 @@ export class GpuDrivenPass {
|
|
|
1236
1359
|
},
|
|
1237
1360
|
});
|
|
1238
1361
|
this.watchBlendPipeline(device);
|
|
1362
|
+
/*
|
|
1363
|
+
* **What a pane lets through, from the sun**: the blended raster's vertex stage handed the
|
|
1364
|
+
* light's matrix and the glass list, and \`glassTintFrag\` for the colour — white target, a
|
|
1365
|
+
* multiplying blend, no depth, so every pane on a ray counts in any order.
|
|
1366
|
+
*/
|
|
1367
|
+
if (this.castsGlass) {
|
|
1368
|
+
this.glassTintPipeline = device.createRenderPipeline({
|
|
1369
|
+
label: 'gpu-driven shadow tint',
|
|
1370
|
+
layout: 'auto',
|
|
1371
|
+
vertex: { module: blend, entryPoint: 'blendVert' },
|
|
1372
|
+
fragment: {
|
|
1373
|
+
module: blend,
|
|
1374
|
+
entryPoint: 'glassTintFrag',
|
|
1375
|
+
targets: [{ format: 'rgba8unorm', blend: GLASS_TINT_BLEND }],
|
|
1376
|
+
},
|
|
1377
|
+
primitive: { topology: 'triangle-list', cullMode: 'none' },
|
|
1378
|
+
});
|
|
1379
|
+
this.glassTintGroup = device.createBindGroup({
|
|
1380
|
+
layout: this.glassTintPipeline.getBindGroupLayout(0),
|
|
1381
|
+
entries: [
|
|
1382
|
+
{ binding: 0, resource: { buffer: this.shadowMatrix } },
|
|
1383
|
+
{ binding: 1, resource: { buffer: this.glassList } },
|
|
1384
|
+
{ binding: 2, resource: { buffer: this.clusterMeta } },
|
|
1385
|
+
{ binding: 3, resource: { buffer: this.indices } },
|
|
1386
|
+
{ binding: 4, resource: { buffer: this.vertices } },
|
|
1387
|
+
{ binding: 5, resource: { buffer: this.transformBuffer } },
|
|
1388
|
+
{ binding: 6, resource: { buffer: this.materialOf } },
|
|
1389
|
+
{ binding: 7, resource: { buffer: this.materialTable } },
|
|
1390
|
+
{ binding: 8, resource: { buffer: this.frameBuffer } },
|
|
1391
|
+
],
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1239
1394
|
/*
|
|
1240
1395
|
* **Premultiplied over, where `renderer.ts`'s composite is a lerp**, and `blendRaster.wgsl.ts`
|
|
1241
1396
|
* carries why: this pipeline's colour target has a coverage mask in its alpha, which the blit
|
|
@@ -1402,6 +1557,39 @@ export class GpuDrivenPass {
|
|
|
1402
1557
|
shadowCullFor(this.shadowCullSettings),
|
|
1403
1558
|
shadowCullFor(this.shadowCullSettingsTwo),
|
|
1404
1559
|
];
|
|
1560
|
+
/*
|
|
1561
|
+
* **The sun's glass cut: the light's selection again, of the glass alone**, once the map is
|
|
1562
|
+
* drawn and those buffers are free. The camera's level of detail, as the map's; every pane in
|
|
1563
|
+
* the light's frustum kept, as the blended half keeps every pane — so compacted as phase two
|
|
1564
|
+
* against a history of zeros, exactly as that half is.
|
|
1565
|
+
*/
|
|
1566
|
+
if (this.castsGlass) {
|
|
1567
|
+
this.glassLodGroup = device.createBindGroup({
|
|
1568
|
+
layout: this.lodPipeline.getBindGroupLayout(0),
|
|
1569
|
+
entries: [
|
|
1570
|
+
{ binding: 0, resource: { buffer: this.glassLodBuffer } },
|
|
1571
|
+
{ binding: 1, resource: { buffer: this.clusterLod } },
|
|
1572
|
+
{ binding: 2, resource: { buffer: this.shadowSelected } },
|
|
1573
|
+
{ binding: 3, resource: { buffer: this.clusterMeta } },
|
|
1574
|
+
{ binding: 4, resource: { buffer: this.instanceNone } },
|
|
1575
|
+
{ binding: 5, resource: { buffer: this.materialOf } },
|
|
1576
|
+
{ binding: 6, resource: { buffer: this.materialTable } },
|
|
1577
|
+
],
|
|
1578
|
+
});
|
|
1579
|
+
this.glassCullGroup = shadowCullFor(this.shadowCullSettingsGlass);
|
|
1580
|
+
this.glassCompactGroup = device.createBindGroup({
|
|
1581
|
+
layout: this.compactPipeline.getBindGroupLayout(0),
|
|
1582
|
+
entries: [
|
|
1583
|
+
{ binding: 0, resource: { buffer: this.blendCompactSettings } },
|
|
1584
|
+
{ binding: 1, resource: { buffer: this.shadowSelected } },
|
|
1585
|
+
{ binding: 2, resource: { buffer: this.shadowKeep } },
|
|
1586
|
+
{ binding: 3, resource: { buffer: this.zeroHistory } },
|
|
1587
|
+
{ binding: 4, resource: { buffer: this.glassList } },
|
|
1588
|
+
{ binding: 5, resource: { buffer: this.historySink } },
|
|
1589
|
+
{ binding: 6, resource: { buffer: this.glassArgs } },
|
|
1590
|
+
],
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1405
1593
|
this.shadowSeedGroup = device.createBindGroup({
|
|
1406
1594
|
layout: this.shadowSeedPipeline.getBindGroupLayout(0),
|
|
1407
1595
|
entries: [
|
|
@@ -1582,11 +1770,22 @@ export class GpuDrivenPass {
|
|
|
1582
1770
|
label: 'gpu-driven colour',
|
|
1583
1771
|
size: { width: stride, height },
|
|
1584
1772
|
format: 'rgba16float',
|
|
1773
|
+
/*
|
|
1774
|
+
* **A chain only where a material is glass**, which a frosted pane reads a coarser level of,
|
|
1775
|
+
* as the forward path's refraction copy does. A scene with no glass allocates exactly the one
|
|
1776
|
+
* level it always did.
|
|
1777
|
+
*/
|
|
1778
|
+
mipLevelCount: this.hasGlass ? Math.floor(Math.log2(Math.max(stride, height))) + 1 : 1,
|
|
1585
1779
|
/* `RENDER_ATTACHMENT` only so a clear-only render pass can empty it each frame: a storage
|
|
1586
1780
|
texture has no clear, and the alternative is a dispatch over every pixel. */
|
|
1587
1781
|
usage: STORAGE_BINDING | TEXTURE_BINDING | RENDER_ATTACHMENT,
|
|
1588
1782
|
});
|
|
1589
|
-
|
|
1783
|
+
/* A storage binding takes one level, so everything that writes or presents reads level 0. */
|
|
1784
|
+
this.colourView = this.colourTexture.createView({ baseMipLevel: 0, mipLevelCount: 1 });
|
|
1785
|
+
this.colourSampledView = this.colourTexture.createView();
|
|
1786
|
+
this.colourMips = this.hasGlass
|
|
1787
|
+
? new SnapshotMips(device, this.mipPipelines, this.colourTexture, 'rgba16float', null, 'gpu-driven colour mips')
|
|
1788
|
+
: null;
|
|
1590
1789
|
this.oitAccum = device.createTexture({
|
|
1591
1790
|
label: 'gpu-driven oit accum',
|
|
1592
1791
|
size: { width: stride, height },
|
|
@@ -1726,12 +1925,22 @@ export class GpuDrivenPass {
|
|
|
1726
1925
|
{ binding: 16, resource: this.latentRepeat },
|
|
1727
1926
|
{ binding: 17, resource: { buffer: this.decodeNodes } },
|
|
1728
1927
|
{ binding: 18, resource: { buffer: this.decodeWeights } },
|
|
1928
|
+
/* The sun's glass, or the opaque map and a white texel where none casts. */
|
|
1929
|
+
{
|
|
1930
|
+
binding: 19,
|
|
1931
|
+
resource: this.glassDepthView ?? this.shadowView,
|
|
1932
|
+
},
|
|
1933
|
+
{
|
|
1934
|
+
binding: 20,
|
|
1935
|
+
resource: this.glassTintSampled ?? this.glassTintNone.createView(),
|
|
1936
|
+
},
|
|
1937
|
+
{ binding: 21, resource: this.glassSamplerFor(device) },
|
|
1729
1938
|
],
|
|
1730
1939
|
});
|
|
1731
1940
|
this.blitGroup = device.createBindGroup({
|
|
1732
1941
|
layout: this.blitPipeline.getBindGroupLayout(0),
|
|
1733
1942
|
entries: [
|
|
1734
|
-
{ binding: 0, resource: this.
|
|
1943
|
+
{ binding: 0, resource: this.colourView },
|
|
1735
1944
|
/* The depth the raster wrote, sampled so the blit can hand it to the frame. */
|
|
1736
1945
|
...(this.presentDepth
|
|
1737
1946
|
? [
|
|
@@ -1774,6 +1983,12 @@ export class GpuDrivenPass {
|
|
|
1774
1983
|
{ binding: 13, resource: this.latentRepeat },
|
|
1775
1984
|
{ binding: 14, resource: { buffer: this.decodeNodes } },
|
|
1776
1985
|
{ binding: 15, resource: { buffer: this.decodeWeights } },
|
|
1986
|
+
/* What the opaque half drew, for glass to show: `blendRaster.wgsl.ts`. */
|
|
1987
|
+
{ binding: 16, resource: this.colourSampledView },
|
|
1988
|
+
{
|
|
1989
|
+
binding: 17,
|
|
1990
|
+
resource: this.glassSamplerFor(device),
|
|
1991
|
+
},
|
|
1777
1992
|
],
|
|
1778
1993
|
});
|
|
1779
1994
|
/*
|
|
@@ -1979,6 +2194,16 @@ export class GpuDrivenPass {
|
|
|
1979
2194
|
queue.writeBuffer(this.shadowCullSettings, 0, this.shadowCullValues);
|
|
1980
2195
|
this.shadowCullValues[3] = this.occlusion ? 1 : 0;
|
|
1981
2196
|
queue.writeBuffer(this.shadowCullSettingsTwo, 0, this.shadowCullValues);
|
|
2197
|
+
if (this.castsGlass) {
|
|
2198
|
+
/* No pyramid and no cones, and the cones put back for the next frame's first write. */
|
|
2199
|
+
this.shadowCullValues[3] = 0;
|
|
2200
|
+
this.shadowCullValues[CULL_CONES] = 0;
|
|
2201
|
+
queue.writeBuffer(this.shadowCullSettingsGlass, 0, this.shadowCullValues);
|
|
2202
|
+
this.shadowCullValues[CULL_CONES] = 1;
|
|
2203
|
+
this.lodParamsGlass.set(this.lodParamsBlend);
|
|
2204
|
+
this.lodParamsGlass[7] = 1;
|
|
2205
|
+
queue.writeBuffer(this.glassLodBuffer, 0, this.lodParamsGlass);
|
|
2206
|
+
}
|
|
1982
2207
|
queue.writeBuffer(this.planesBuffer, 0, this.planes);
|
|
1983
2208
|
queue.writeBuffer(this.frameBuffer, 0, params);
|
|
1984
2209
|
queue.writeBuffer(this.lodBuffer, 0, this.lodParams);
|
|
@@ -2038,7 +2263,9 @@ export class GpuDrivenPass {
|
|
|
2038
2263
|
* one: the table is written when the pass is built. A scene with nothing blended schedules the
|
|
2039
2264
|
* three transparent stages away entirely and encodes the frame it encoded before they existed.
|
|
2040
2265
|
*/
|
|
2041
|
-
|
|
2266
|
+
/* Glass is the blended half's whatever its flag says: a visibility buffer holds one surface. */
|
|
2267
|
+
this.shape.blended =
|
|
2268
|
+
this.hasGlass || this.materials.some((material) => material.blend === true);
|
|
2042
2269
|
/* `instanceCount` is the one word the compaction touches; the other three never change. */
|
|
2043
2270
|
encoder.clearBuffer(argsOne, 4, 4);
|
|
2044
2271
|
encoder.clearBuffer(argsTwo, 4, 4);
|
|
@@ -2212,6 +2439,8 @@ export class GpuDrivenPass {
|
|
|
2212
2439
|
*/
|
|
2213
2440
|
if (!this.blendUsable || this.blendPipeline === null || this.blendRasterGroup === null)
|
|
2214
2441
|
return;
|
|
2442
|
+
/* The shaded picture's chain, which glass reads: after `shade`, before the panes. */
|
|
2443
|
+
this.colourMips?.record(encoder);
|
|
2215
2444
|
const pass = encoder.beginRenderPass({
|
|
2216
2445
|
label: 'gpu-driven blend draw',
|
|
2217
2446
|
colorAttachments: [
|
|
@@ -2519,6 +2748,57 @@ export class GpuDrivenPass {
|
|
|
2519
2748
|
second.end();
|
|
2520
2749
|
this.drawShadowHalf(encoder, 1, writes);
|
|
2521
2750
|
this.shadowFlipped = !this.shadowFlipped;
|
|
2751
|
+
if (this.castsGlass && this.blendUsable)
|
|
2752
|
+
this.drawShadowGlass(encoder, groups);
|
|
2753
|
+
}
|
|
2754
|
+
/**
|
|
2755
|
+
* The sun's glass, after its opaque map: the glass cut from the light, then the panes drawn
|
|
2756
|
+
* twice — where the nearest one is, and what they let through, multiplied — and the tint's
|
|
2757
|
+
* chain filled for frost to read. The forward path's `flushSunGlass`, in this pipeline's terms.
|
|
2758
|
+
*/
|
|
2759
|
+
drawShadowGlass(encoder, groups) {
|
|
2760
|
+
encoder.clearBuffer(this.glassArgs, 4, 4);
|
|
2761
|
+
const cut = encoder.beginComputePass({ label: 'gpu-driven shadow glass cut' });
|
|
2762
|
+
cut.setPipeline(this.lodPipeline);
|
|
2763
|
+
cut.setBindGroup(0, this.glassLodGroup);
|
|
2764
|
+
cut.dispatchWorkgroups(groups);
|
|
2765
|
+
cut.setPipeline(this.cullPipeline);
|
|
2766
|
+
cut.setBindGroup(0, this.glassCullGroup);
|
|
2767
|
+
cut.dispatchWorkgroups(groups);
|
|
2768
|
+
cut.setPipeline(this.compactPipeline);
|
|
2769
|
+
cut.setBindGroup(0, this.glassCompactGroup);
|
|
2770
|
+
cut.dispatchWorkgroups(groups);
|
|
2771
|
+
cut.end();
|
|
2772
|
+
const depth = encoder.beginRenderPass({
|
|
2773
|
+
label: 'gpu-driven shadow glass',
|
|
2774
|
+
colorAttachments: [],
|
|
2775
|
+
depthStencilAttachment: {
|
|
2776
|
+
view: this.glassDepthView,
|
|
2777
|
+
depthClearValue: SHADOW_DEPTH_CLEAR,
|
|
2778
|
+
depthLoadOp: 'clear',
|
|
2779
|
+
depthStoreOp: 'store',
|
|
2780
|
+
},
|
|
2781
|
+
});
|
|
2782
|
+
depth.setPipeline(this.glassDepthPipeline);
|
|
2783
|
+
depth.setBindGroup(0, this.glassDepthGroup);
|
|
2784
|
+
depth.drawIndirect(this.glassArgs, 0);
|
|
2785
|
+
depth.end();
|
|
2786
|
+
const tint = encoder.beginRenderPass({
|
|
2787
|
+
label: 'gpu-driven shadow tint',
|
|
2788
|
+
colorAttachments: [
|
|
2789
|
+
{
|
|
2790
|
+
view: this.glassTintTarget,
|
|
2791
|
+
clearValue: { r: 1, g: 1, b: 1, a: 1 },
|
|
2792
|
+
loadOp: 'clear',
|
|
2793
|
+
storeOp: 'store',
|
|
2794
|
+
},
|
|
2795
|
+
],
|
|
2796
|
+
});
|
|
2797
|
+
tint.setPipeline(this.glassTintPipeline);
|
|
2798
|
+
tint.setBindGroup(0, this.glassTintGroup);
|
|
2799
|
+
tint.drawIndirect(this.glassArgs, 0);
|
|
2800
|
+
tint.end();
|
|
2801
|
+
this.glassTintMips?.record(encoder);
|
|
2522
2802
|
}
|
|
2523
2803
|
/** One half of the map: the first clears it, the second draws over it and closes the stage's time. */
|
|
2524
2804
|
drawShadowHalf(encoder, half, writes) {
|
|
@@ -2540,6 +2820,18 @@ export class GpuDrivenPass {
|
|
|
2540
2820
|
pass.drawIndirect((half === 0 ? this.shadowArgs : this.shadowArgsTwo), 0);
|
|
2541
2821
|
pass.end();
|
|
2542
2822
|
}
|
|
2823
|
+
/** The linear sampler glass reads the colour's and the tint's chains through, made once. */
|
|
2824
|
+
glassSamplerFor(device) {
|
|
2825
|
+
this.glassSampler ??= device.createSampler({
|
|
2826
|
+
label: 'gpu-driven glass',
|
|
2827
|
+
magFilter: 'linear',
|
|
2828
|
+
minFilter: 'linear',
|
|
2829
|
+
mipmapFilter: 'linear',
|
|
2830
|
+
addressModeU: 'clamp-to-edge',
|
|
2831
|
+
addressModeV: 'clamp-to-edge',
|
|
2832
|
+
});
|
|
2833
|
+
return this.glassSampler;
|
|
2834
|
+
}
|
|
2543
2835
|
drawPhase(encoder, phase, clear) {
|
|
2544
2836
|
const pass = encoder.beginRenderPass({
|
|
2545
2837
|
label: `gpu-driven phase ${phase + 1}`,
|
|
@@ -2597,6 +2889,8 @@ export class GpuDrivenPass {
|
|
|
2597
2889
|
return;
|
|
2598
2890
|
this.disposeTargets();
|
|
2599
2891
|
this.shadowTexture?.destroy();
|
|
2892
|
+
this.glassTintTexture?.destroy();
|
|
2893
|
+
this.glassTintNone?.destroy();
|
|
2600
2894
|
this.emptyEnvironment?.destroy();
|
|
2601
2895
|
this.latents?.destroy();
|
|
2602
2896
|
this.queries?.destroy();
|
|
@@ -2635,6 +2929,10 @@ export class GpuDrivenPass {
|
|
|
2635
2929
|
this.shadowListTwo,
|
|
2636
2930
|
this.shadowSelected,
|
|
2637
2931
|
this.shadowKeep,
|
|
2932
|
+
this.glassList,
|
|
2933
|
+
this.glassArgs,
|
|
2934
|
+
this.glassLodBuffer,
|
|
2935
|
+
this.shadowCullSettingsGlass,
|
|
2638
2936
|
this.shadowPlanes,
|
|
2639
2937
|
this.shadowCullSettings,
|
|
2640
2938
|
this.shadowCullSettingsTwo,
|
|
@@ -2678,3 +2976,5 @@ function multiply(out, a, b) {
|
|
|
2678
2976
|
}
|
|
2679
2977
|
}
|
|
2680
2978
|
}
|
|
2979
|
+
/** Where `hasGlass` reads each material's glass through; only the answer is kept. */
|
|
2980
|
+
const glassProbe = { transmission: 0, frost: 0, tint: [1, 1, 1] };
|
|
@@ -16,12 +16,23 @@ export declare class GpuInstancedBatch {
|
|
|
16
16
|
readonly capacity: number;
|
|
17
17
|
private readonly staging;
|
|
18
18
|
constructor(device: GPUDevice, mesh: GpuMesh, capacity: number, label: string);
|
|
19
|
+
/** Last frame's packed slots, for a reconstruction; made on first use by the renderer. */
|
|
20
|
+
previousBuffer: GPUBuffer | null;
|
|
21
|
+
/** How many slots the upload before the last one held, and how many the last one holds. */
|
|
22
|
+
previousCount: number;
|
|
23
|
+
liveCount: number;
|
|
24
|
+
/** The frame of the last upload. See `changeFrames.ts`. */
|
|
25
|
+
changed: number;
|
|
19
26
|
/**
|
|
20
27
|
* Pack and push `data.count` instances, in one write.
|
|
21
28
|
*
|
|
22
29
|
* Only the live prefix, for the reason `uploadScatter` gives: the rest is not drawn and
|
|
23
30
|
* uploading it would be per-frame waste with nothing reading it.
|
|
31
|
+
*
|
|
32
|
+
* **Given `previous`, the placement still in the staging array — the last upload, which is last
|
|
33
|
+
* frame's — is written there first**, so a reconstruction can pair each slot with where it was.
|
|
34
|
+
* `writeBuffer` copies at the call, so packing afterwards cannot reach that copy.
|
|
24
35
|
*/
|
|
25
|
-
upload(queue: GPUQueue, data: MeshInstances): void;
|
|
36
|
+
upload(queue: GPUQueue, data: MeshInstances, previous?: GPUBuffer | null): void;
|
|
26
37
|
dispose(): void;
|
|
27
38
|
}
|
|
@@ -30,20 +30,39 @@ export class GpuInstancedBatch {
|
|
|
30
30
|
usage: USAGE_VERTEX,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
/** Last frame's packed slots, for a reconstruction; made on first use by the renderer. */
|
|
34
|
+
previousBuffer = null;
|
|
35
|
+
/** How many slots the upload before the last one held, and how many the last one holds. */
|
|
36
|
+
previousCount = 0;
|
|
37
|
+
liveCount = 0;
|
|
38
|
+
/** The frame of the last upload. See `changeFrames.ts`. */
|
|
39
|
+
changed = -1;
|
|
33
40
|
/**
|
|
34
41
|
* Pack and push `data.count` instances, in one write.
|
|
35
42
|
*
|
|
36
43
|
* Only the live prefix, for the reason `uploadScatter` gives: the rest is not drawn and
|
|
37
44
|
* uploading it would be per-frame waste with nothing reading it.
|
|
45
|
+
*
|
|
46
|
+
* **Given `previous`, the placement still in the staging array — the last upload, which is last
|
|
47
|
+
* frame's — is written there first**, so a reconstruction can pair each slot with where it was.
|
|
48
|
+
* `writeBuffer` copies at the call, so packing afterwards cannot reach that copy.
|
|
38
49
|
*/
|
|
39
|
-
upload(queue, data) {
|
|
50
|
+
upload(queue, data, previous = null) {
|
|
40
51
|
const count = Math.min(data.count, this.capacity);
|
|
52
|
+
if (previous !== null) {
|
|
53
|
+
if (this.liveCount > 0) {
|
|
54
|
+
queue.writeBuffer(previous, 0, this.staging, 0, this.liveCount * INSTANCE_FLOATS);
|
|
55
|
+
}
|
|
56
|
+
this.previousCount = this.liveCount;
|
|
57
|
+
}
|
|
58
|
+
this.liveCount = count;
|
|
41
59
|
if (count === 0)
|
|
42
60
|
return;
|
|
43
61
|
packInstances(data, this.staging);
|
|
44
62
|
queue.writeBuffer(this.buffer, 0, this.staging, 0, count * INSTANCE_FLOATS);
|
|
45
63
|
}
|
|
46
64
|
dispose() {
|
|
65
|
+
this.previousBuffer?.destroy();
|
|
47
66
|
this.buffer.destroy();
|
|
48
67
|
}
|
|
49
68
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DrawCommand } from './drawCommand.ts';
|
|
2
|
+
export declare class LatePass {
|
|
3
|
+
private readonly device;
|
|
4
|
+
private readonly commands;
|
|
5
|
+
private depth;
|
|
6
|
+
private depthTextureView;
|
|
7
|
+
private readonly layout;
|
|
8
|
+
private readonly pipeline;
|
|
9
|
+
private readonly sizes;
|
|
10
|
+
private readonly sizeStaging;
|
|
11
|
+
private group;
|
|
12
|
+
private groupSource;
|
|
13
|
+
constructor(device: GPUDevice);
|
|
14
|
+
/** The output-size depth, (re)made when the output changes size. */
|
|
15
|
+
depthView(width: number, height: number): GPUTextureView;
|
|
16
|
+
/** Fill the output-size depth from `source`, the render's single-sample depth. */
|
|
17
|
+
upscale(encoder: GPUCommandEncoder, source: GPUTextureView, renderWidth: number, renderHeight: number, outputWidth: number, outputHeight: number): void;
|
|
18
|
+
/** A command slot for one late draw. Every field a caller uses it fills; see `takeCommand`. */
|
|
19
|
+
take(): DrawCommand;
|
|
20
|
+
/** Late draws recorded this frame. */
|
|
21
|
+
get pending(): number;
|
|
22
|
+
/** Every late draw, in the order it was recorded, through the renderer's own issue. */
|
|
23
|
+
replay(pass: GPURenderPassEncoder, issue: (pass: GPURenderPassEncoder, command: DrawCommand) => void): void;
|
|
24
|
+
reset(): void;
|
|
25
|
+
dispose(): void;
|
|
26
|
+
}
|