@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
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a lamp's light keeps through glass, on this device: an `rgba8unorm` array of one layer a
|
|
3
|
+
* light, the face-sized colour scratch a face's glass is multiplied into, and the resolve that
|
|
4
|
+
* copies a face into its octahedral region. The twin of `pointGlassTint.ts`, which says what the
|
|
5
|
+
* channels hold and why the chain exists.
|
|
6
|
+
*
|
|
7
|
+
* **The chain is a `SnapshotMips` per layer**, made the first time that layer is touched and
|
|
8
|
+
* recorded once a round for the layers the round touched — a layer's levels are its own
|
|
9
|
+
* subresources here, so nothing is staged the way the other backend must.
|
|
10
|
+
*/
|
|
11
|
+
import { mat3 } from 'gl-matrix';
|
|
12
|
+
import { pointShadowFaceRotation } from '../../pointShadowImage.js';
|
|
13
|
+
import { OCTAHEDRAL_RESOLVE_TINT_FRAG_WGSL, OCTAHEDRAL_RESOLVE_VERT_WGSL, OCTAHEDRALRESOLVE_BINDINGS, } from '../../shaders/generated/octahedralResolve.wgsl.js';
|
|
14
|
+
import { SnapshotMips } from './snapshotMips.js';
|
|
15
|
+
import { UniformRing } from './uniformRing.js';
|
|
16
|
+
const USAGE_RENDER_ATTACHMENT = 0x10;
|
|
17
|
+
const USAGE_TEXTURE_BINDING = 0x4;
|
|
18
|
+
const USAGE_UNIFORM_DST = 0x40 | 0x8; // UNIFORM | COPY_DST
|
|
19
|
+
const VISIBILITY_FRAGMENT = 0x2;
|
|
20
|
+
const TINT = OCTAHEDRALRESOLVE_BINDINGS.OCTAHEDRAL_RESOLVE_TINT_FRAG;
|
|
21
|
+
const faceRotation = mat3.create();
|
|
22
|
+
const rotationColumn = new Float32Array(3);
|
|
23
|
+
export class GpuPointGlassTint {
|
|
24
|
+
texture;
|
|
25
|
+
/** The whole array, for the lit pass. */
|
|
26
|
+
view;
|
|
27
|
+
/** The colour scratch a face's glass is multiplied into. */
|
|
28
|
+
scratchView;
|
|
29
|
+
edge;
|
|
30
|
+
device;
|
|
31
|
+
pipelines;
|
|
32
|
+
scratch;
|
|
33
|
+
layerViews = [];
|
|
34
|
+
mips = [];
|
|
35
|
+
pipeline;
|
|
36
|
+
bindGroup;
|
|
37
|
+
ring;
|
|
38
|
+
heldFaces;
|
|
39
|
+
dirty;
|
|
40
|
+
constructor(device, pipelines, faceSize, edge, layers,
|
|
41
|
+
/** Resolves a frame can make: the array's own figure, since every face resolves once. */
|
|
42
|
+
slots, encoder) {
|
|
43
|
+
this.device = device;
|
|
44
|
+
this.pipelines = pipelines;
|
|
45
|
+
this.edge = edge;
|
|
46
|
+
this.heldFaces = new Uint8Array(layers);
|
|
47
|
+
/* Every layer's chain is filled once at birth, so a level nothing has touched is white too. */
|
|
48
|
+
this.dirty = new Uint8Array(layers).fill(1);
|
|
49
|
+
this.texture = device.createTexture({
|
|
50
|
+
label: 'pointShadow.tint',
|
|
51
|
+
size: [edge, edge, layers],
|
|
52
|
+
format: 'rgba8unorm',
|
|
53
|
+
mipLevelCount: Math.floor(Math.log2(Math.max(1, edge))) + 1,
|
|
54
|
+
usage: USAGE_RENDER_ATTACHMENT | USAGE_TEXTURE_BINDING,
|
|
55
|
+
});
|
|
56
|
+
this.view = this.texture.createView({ dimension: '2d-array' });
|
|
57
|
+
for (let layer = 0; layer < layers; layer++) {
|
|
58
|
+
this.layerViews.push(this.texture.createView({
|
|
59
|
+
label: `pointShadow.tint.layer${layer}`,
|
|
60
|
+
dimension: '2d',
|
|
61
|
+
baseArrayLayer: layer,
|
|
62
|
+
arrayLayerCount: 1,
|
|
63
|
+
baseMipLevel: 0,
|
|
64
|
+
mipLevelCount: 1,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
this.scratch = device.createTexture({
|
|
68
|
+
label: 'pointShadow.tint.scratch',
|
|
69
|
+
size: [faceSize, faceSize],
|
|
70
|
+
format: 'rgba8unorm',
|
|
71
|
+
usage: USAGE_RENDER_ATTACHMENT | USAGE_TEXTURE_BINDING,
|
|
72
|
+
});
|
|
73
|
+
this.scratchView = this.scratch.createView();
|
|
74
|
+
this.ring = new UniformRing(device, TINT.uniformSize, slots, USAGE_UNIFORM_DST, 'pointShadow.tint.uniforms');
|
|
75
|
+
const layout = device.createBindGroupLayout({
|
|
76
|
+
label: 'pointShadow.tint.resolve.layout',
|
|
77
|
+
entries: [
|
|
78
|
+
{
|
|
79
|
+
binding: TINT.uniforms,
|
|
80
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
81
|
+
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: TINT.uniformSize },
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
binding: TINT.textures.uFace.texture,
|
|
85
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
86
|
+
texture: { sampleType: 'float' },
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
binding: TINT.textures.uFace.sampler,
|
|
90
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
91
|
+
sampler: { type: 'non-filtering' },
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
this.bindGroup = device.createBindGroup({
|
|
96
|
+
label: 'pointShadow.tint.resolve',
|
|
97
|
+
layout,
|
|
98
|
+
entries: [
|
|
99
|
+
{ binding: TINT.uniforms, resource: { buffer: this.ring.buffer, size: TINT.uniformSize } },
|
|
100
|
+
{ binding: TINT.textures.uFace.texture, resource: this.scratchView },
|
|
101
|
+
{
|
|
102
|
+
binding: TINT.textures.uFace.sampler,
|
|
103
|
+
resource: device.createSampler({ label: 'pointShadow.tint.resolve.sampler' }),
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
this.pipeline = device.createRenderPipeline({
|
|
108
|
+
label: 'pointShadow.tint.resolve',
|
|
109
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
110
|
+
vertex: {
|
|
111
|
+
module: device.createShaderModule({ code: OCTAHEDRAL_RESOLVE_VERT_WGSL }),
|
|
112
|
+
entryPoint: 'main',
|
|
113
|
+
},
|
|
114
|
+
fragment: {
|
|
115
|
+
module: device.createShaderModule({ code: OCTAHEDRAL_RESOLVE_TINT_FRAG_WGSL }),
|
|
116
|
+
entryPoint: 'main',
|
|
117
|
+
targets: [{ format: 'rgba8unorm' }],
|
|
118
|
+
},
|
|
119
|
+
primitive: { topology: 'triangle-list' },
|
|
120
|
+
});
|
|
121
|
+
/* Every layer born clear: a light no pane has reached lets everything through. */
|
|
122
|
+
for (const view of this.layerViews) {
|
|
123
|
+
encoder
|
|
124
|
+
.beginRenderPass({
|
|
125
|
+
label: 'pointShadow.tint.clear',
|
|
126
|
+
colorAttachments: [{ view, loadOp: 'clear', clearValue: [1, 1, 1, 1], storeOp: 'store' }],
|
|
127
|
+
})
|
|
128
|
+
.end();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Whether `face` of `layer` holds glass: a face that does must be cleared before it is reused. */
|
|
132
|
+
held(layer, face) {
|
|
133
|
+
return (((this.heldFaces[layer] ?? 0) >> face) & 1) === 1;
|
|
134
|
+
}
|
|
135
|
+
/** Copy the colour scratch into `face`'s region of `layer`, and remember whether it held glass. */
|
|
136
|
+
resolve(encoder, layer, face, drawn) {
|
|
137
|
+
const view = this.layerViews[layer];
|
|
138
|
+
if (view === undefined)
|
|
139
|
+
return;
|
|
140
|
+
const slot = this.ring.allocate();
|
|
141
|
+
if (slot === null)
|
|
142
|
+
return;
|
|
143
|
+
pointShadowFaceRotation(face, faceRotation);
|
|
144
|
+
/* WGSL pads a mat3x3 to three four-float columns; the generated struct expects that. */
|
|
145
|
+
const rotation = TINT.fields.uFaceRotation.offset;
|
|
146
|
+
for (let column = 0; column < 3; column++) {
|
|
147
|
+
rotationColumn[0] = faceRotation[column * 3];
|
|
148
|
+
rotationColumn[1] = faceRotation[column * 3 + 1];
|
|
149
|
+
rotationColumn[2] = faceRotation[column * 3 + 2];
|
|
150
|
+
this.ring.writeFloats(slot, rotation + column * 16, rotationColumn);
|
|
151
|
+
}
|
|
152
|
+
this.ring.writeInt(slot, TINT.fields.uFaceIndex.offset, face);
|
|
153
|
+
this.ring.writeFloat(slot, TINT.fields.uEdge.offset, this.edge);
|
|
154
|
+
const pass = encoder.beginRenderPass({
|
|
155
|
+
label: 'pointShadow.tint.resolve',
|
|
156
|
+
colorAttachments: [{ view, loadOp: 'load', storeOp: 'store' }],
|
|
157
|
+
});
|
|
158
|
+
pass.setPipeline(this.pipeline);
|
|
159
|
+
pass.setBindGroup(0, this.bindGroup, [slot]);
|
|
160
|
+
pass.draw(3);
|
|
161
|
+
pass.end();
|
|
162
|
+
const bit = 1 << face;
|
|
163
|
+
const was = this.heldFaces[layer] ?? 0;
|
|
164
|
+
this.heldFaces[layer] = drawn ? was | bit : was & ~bit;
|
|
165
|
+
this.dirty[layer] = 1;
|
|
166
|
+
}
|
|
167
|
+
/** The chain frost reads, for every layer touched since the last call. */
|
|
168
|
+
recordMips(encoder) {
|
|
169
|
+
for (let layer = 0; layer < this.dirty.length; layer++) {
|
|
170
|
+
if (this.dirty[layer] !== 1)
|
|
171
|
+
continue;
|
|
172
|
+
this.dirty[layer] = 0;
|
|
173
|
+
let chain = this.mips[layer];
|
|
174
|
+
if (chain === undefined) {
|
|
175
|
+
chain = new SnapshotMips(this.device, this.pipelines, this.texture, 'rgba8unorm', layer, 'pointShadow.tint.mips');
|
|
176
|
+
this.mips[layer] = chain;
|
|
177
|
+
}
|
|
178
|
+
chain.record(encoder);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
beginFrame() {
|
|
182
|
+
this.ring.reset();
|
|
183
|
+
}
|
|
184
|
+
/** Before the round's submit: the slots are written and must be up before any pass reads. */
|
|
185
|
+
flush() {
|
|
186
|
+
this.ring.flush();
|
|
187
|
+
}
|
|
188
|
+
dispose() {
|
|
189
|
+
this.texture.destroy();
|
|
190
|
+
this.scratch.destroy();
|
|
191
|
+
this.ring.dispose();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type mat4 } from 'gl-matrix';
|
|
2
2
|
import { type PointShadowSource } from '../../pointShadowImage.ts';
|
|
3
|
+
import { GpuPointGlassTint } from './pointGlassTintPass.ts';
|
|
4
|
+
import type { MipPipelines } from './surfaceTexturePass.ts';
|
|
3
5
|
/**
|
|
4
6
|
* Every point light's shadow as one array texture, and the scratch that fills it.
|
|
5
7
|
*
|
|
@@ -10,14 +12,18 @@ import { type PointShadowSource } from '../../pointShadowImage.ts';
|
|
|
10
12
|
* both say the resolve reads the scratch.
|
|
11
13
|
*/
|
|
12
14
|
export declare class GpuPointShadowArray {
|
|
13
|
-
/**
|
|
14
|
-
readonly view: GPUTextureView;
|
|
15
|
+
/** Lights this array holds; the storage doubles under it once glass arrives. */
|
|
15
16
|
readonly layers: number;
|
|
16
17
|
/** Where a face is rendered before it is resolved. One, shared by every light. */
|
|
17
18
|
readonly scratchView: GPUTextureView;
|
|
18
|
-
|
|
19
|
+
/** Replaced once, when glass first casts: see `growForGlass`. */
|
|
20
|
+
private texture;
|
|
21
|
+
private arrayView;
|
|
22
|
+
private tint;
|
|
23
|
+
private readonly device;
|
|
24
|
+
private readonly faceSize;
|
|
19
25
|
private readonly scratch;
|
|
20
|
-
private
|
|
26
|
+
private layerViews;
|
|
21
27
|
private readonly pipeline;
|
|
22
28
|
private readonly bindGroup;
|
|
23
29
|
/**
|
|
@@ -46,6 +52,26 @@ export declare class GpuPointShadowArray {
|
|
|
46
52
|
* keeps this face to its own region.
|
|
47
53
|
*/
|
|
48
54
|
resolve(encoder: GPUCommandEncoder, layer: number, face: number, far: number, near: number): void;
|
|
55
|
+
/** The face's glass depth into light `layer`'s glass layer, 2L + 1. */
|
|
56
|
+
resolveGlass(encoder: GPUCommandEncoder, layer: number, face: number, far: number, near: number): void;
|
|
57
|
+
/** The array, as the shader samples it. Replaced once, when glass first casts. */
|
|
58
|
+
get view(): GPUTextureView;
|
|
59
|
+
get hasGlass(): boolean;
|
|
60
|
+
/** Physical layers a light: 1, or 2 once glass has interleaved the array. */
|
|
61
|
+
get stride(): number;
|
|
62
|
+
/** The lights' glass tint, once glass has cast. */
|
|
63
|
+
get glassTint(): GpuPointGlassTint | null;
|
|
64
|
+
/**
|
|
65
|
+
* Interleave the array for glass, on `encoder`: light L's depth moves to 2L and its glass takes
|
|
66
|
+
* 2L + 1, every glass layer born at the far plane, and the tint made. The reasoning, and why no
|
|
67
|
+
* map re-bakes, is `PointShadowArray.growForGlass`'s.
|
|
68
|
+
*
|
|
69
|
+
* Returns the texture it replaced, which the caller destroys once `encoder` is submitted — the
|
|
70
|
+
* copies out of it are recorded there — or null when the array had already grown.
|
|
71
|
+
*/
|
|
72
|
+
growForGlass(encoder: GPUCommandEncoder, tintEdge: number, pipelines: MipPipelines): GPUTexture | null;
|
|
73
|
+
/** The scratch into physical layer `physical`'s region for `face`. */
|
|
74
|
+
private resolveInto;
|
|
49
75
|
/** Start a frame's bakes. See the ring: slots are reused and nothing is freed. */
|
|
50
76
|
beginFrame(): void;
|
|
51
77
|
/** Upload every slot this frame's resolves took, in one write, before the encoder is submitted. */
|
|
@@ -54,8 +80,11 @@ export declare class GpuPointShadowArray {
|
|
|
54
80
|
}
|
|
55
81
|
/** What a face's pass needs from the caller: somewhere to record, and the casters to record. */
|
|
56
82
|
export type PointShadowFacePass = (view: GPUTextureView, viewProj: mat4) => void;
|
|
57
|
-
/**
|
|
58
|
-
|
|
83
|
+
/**
|
|
84
|
+
* And what turns that face into its region of the light's octahedral layer — and, where the face
|
|
85
|
+
* offered glass, draws and resolves that too, lit from the bake origin `x`, `y`, `z`.
|
|
86
|
+
*/
|
|
87
|
+
export type PointShadowResolve = (layer: number, face: number, far: number, near: number, x: number, y: number, z: number) => void;
|
|
59
88
|
export declare class GpuPointShadowMap implements PointShadowSource {
|
|
60
89
|
readonly size: number;
|
|
61
90
|
/** Which layer of the shared array this map's image lives in. See `pointShadowMap.ts`. */
|
|
@@ -4,6 +4,7 @@ import { OCTAHEDRAL_EDGE } from '../../pointShadowArray.js';
|
|
|
4
4
|
import { createFaceRange, DEFAULT_SOURCE_RADIUS, FACE_COUNT, POINT_SHADOW_NEAR, PointShadowImage, pointShadowFaceRotation, pointShadowFaceViewProj, } from '../../pointShadowImage.js';
|
|
5
5
|
import { OCTAHEDRAL_RESOLVE_FRAG_WGSL, OCTAHEDRAL_RESOLVE_VERT_WGSL, } from '../../shaders/generated/octahedralResolve.wgsl.js';
|
|
6
6
|
import { SHADOW_FORMAT } from './depthPass.js';
|
|
7
|
+
import { GpuPointGlassTint } from './pointGlassTintPass.js';
|
|
7
8
|
import { UniformRing } from './uniformRing.js';
|
|
8
9
|
/**
|
|
9
10
|
* A point light's shadow on this device: one octahedral layer, filled a face at a time.
|
|
@@ -30,6 +31,9 @@ const VISIBILITY_FRAGMENT = 0x2;
|
|
|
30
31
|
* silently not landing in its layer.
|
|
31
32
|
*/
|
|
32
33
|
const RESOLVE_SLOTS = (POINT_SHADOW_POOL + LIVE_POINT_SHADOW_MAPS) * FACE_COUNT;
|
|
34
|
+
/** Twice once glass arrives: a face resolves its opaque depth and then its glass. */
|
|
35
|
+
const DEPTH_RESOLVE_SLOTS = 2 * RESOLVE_SLOTS;
|
|
36
|
+
const USAGE_COPY = 0x01 | 0x02; // COPY_SRC | COPY_DST
|
|
33
37
|
/** `mat3x3<f32>` then four scalars, at std140's sixteen-byte columns: see the generated struct. */
|
|
34
38
|
const RESOLVE_UNIFORM_SIZE = 64;
|
|
35
39
|
/** Filled per resolved face, at module scope, because a bake runs inside the frame's budget. */
|
|
@@ -46,12 +50,16 @@ const rotationColumn = new Float32Array(3);
|
|
|
46
50
|
* both say the resolve reads the scratch.
|
|
47
51
|
*/
|
|
48
52
|
export class GpuPointShadowArray {
|
|
49
|
-
/**
|
|
50
|
-
view;
|
|
53
|
+
/** Lights this array holds; the storage doubles under it once glass arrives. */
|
|
51
54
|
layers;
|
|
52
55
|
/** Where a face is rendered before it is resolved. One, shared by every light. */
|
|
53
56
|
scratchView;
|
|
57
|
+
/** Replaced once, when glass first casts: see `growForGlass`. */
|
|
54
58
|
texture;
|
|
59
|
+
arrayView;
|
|
60
|
+
tint = null;
|
|
61
|
+
device;
|
|
62
|
+
faceSize;
|
|
55
63
|
scratch;
|
|
56
64
|
layerViews = [];
|
|
57
65
|
pipeline;
|
|
@@ -76,21 +84,11 @@ export class GpuPointShadowArray {
|
|
|
76
84
|
extraLayers = 0) {
|
|
77
85
|
this.layers =
|
|
78
86
|
Math.min(lightCount, POINT_SHADOW_POOL) + LIVE_POINT_SHADOW_MAPS + Math.max(0, extraLayers);
|
|
79
|
-
this.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
85
|
-
this.view = this.texture.createView({ dimension: '2d-array' });
|
|
86
|
-
for (let layer = 0; layer < this.layers; layer++) {
|
|
87
|
-
this.layerViews.push(this.texture.createView({
|
|
88
|
-
label: `pointShadow.layer${layer}`,
|
|
89
|
-
dimension: '2d',
|
|
90
|
-
baseArrayLayer: layer,
|
|
91
|
-
arrayLayerCount: 1,
|
|
92
|
-
}));
|
|
93
|
-
}
|
|
87
|
+
this.device = device;
|
|
88
|
+
this.faceSize = faceSize;
|
|
89
|
+
this.texture = depthArray(device, this.layers);
|
|
90
|
+
this.arrayView = this.texture.createView({ dimension: '2d-array' });
|
|
91
|
+
this.layerViews = layerViewsOf(this.texture, this.layers);
|
|
94
92
|
this.scratch = device.createTexture({
|
|
95
93
|
label: 'pointShadow.scratch',
|
|
96
94
|
size: [faceSize, faceSize],
|
|
@@ -98,7 +96,7 @@ export class GpuPointShadowArray {
|
|
|
98
96
|
usage: USAGE_RENDER_ATTACHMENT | USAGE_TEXTURE_BINDING,
|
|
99
97
|
});
|
|
100
98
|
this.scratchView = this.scratch.createView();
|
|
101
|
-
this.ring = new UniformRing(device, RESOLVE_UNIFORM_SIZE,
|
|
99
|
+
this.ring = new UniformRing(device, RESOLVE_UNIFORM_SIZE, DEPTH_RESOLVE_SLOTS, USAGE_UNIFORM_DST, 'pointShadow.resolve.uniforms');
|
|
102
100
|
/*
|
|
103
101
|
* `non-filtering` and `unfilterable-float`, matching `flatPass.ts`: the scratch is a depth
|
|
104
102
|
* format, whose supported sample types are UnfilterableFloat and Depth and never plain
|
|
@@ -162,7 +160,69 @@ export class GpuPointShadowArray {
|
|
|
162
160
|
* keeps this face to its own region.
|
|
163
161
|
*/
|
|
164
162
|
resolve(encoder, layer, face, far, near) {
|
|
165
|
-
|
|
163
|
+
this.resolveInto(encoder, layer * this.stride, face, far, near);
|
|
164
|
+
}
|
|
165
|
+
/** The face's glass depth into light `layer`'s glass layer, 2L + 1. */
|
|
166
|
+
resolveGlass(encoder, layer, face, far, near) {
|
|
167
|
+
if (this.tint === null)
|
|
168
|
+
return;
|
|
169
|
+
this.resolveInto(encoder, 2 * layer + 1, face, far, near);
|
|
170
|
+
}
|
|
171
|
+
/** The array, as the shader samples it. Replaced once, when glass first casts. */
|
|
172
|
+
get view() {
|
|
173
|
+
return this.arrayView;
|
|
174
|
+
}
|
|
175
|
+
get hasGlass() {
|
|
176
|
+
return this.tint !== null;
|
|
177
|
+
}
|
|
178
|
+
/** Physical layers a light: 1, or 2 once glass has interleaved the array. */
|
|
179
|
+
get stride() {
|
|
180
|
+
return this.tint === null ? 1 : 2;
|
|
181
|
+
}
|
|
182
|
+
/** The lights' glass tint, once glass has cast. */
|
|
183
|
+
get glassTint() {
|
|
184
|
+
return this.tint;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Interleave the array for glass, on `encoder`: light L's depth moves to 2L and its glass takes
|
|
188
|
+
* 2L + 1, every glass layer born at the far plane, and the tint made. The reasoning, and why no
|
|
189
|
+
* map re-bakes, is `PointShadowArray.growForGlass`'s.
|
|
190
|
+
*
|
|
191
|
+
* Returns the texture it replaced, which the caller destroys once `encoder` is submitted — the
|
|
192
|
+
* copies out of it are recorded there — or null when the array had already grown.
|
|
193
|
+
*/
|
|
194
|
+
growForGlass(encoder, tintEdge, pipelines) {
|
|
195
|
+
if (this.tint !== null)
|
|
196
|
+
return null;
|
|
197
|
+
const old = this.texture;
|
|
198
|
+
const texture = depthArray(this.device, this.layers * 2);
|
|
199
|
+
for (let layer = 0; layer < this.layers; layer++) {
|
|
200
|
+
encoder.copyTextureToTexture({ texture: old, origin: { x: 0, y: 0, z: layer } }, { texture, origin: { x: 0, y: 0, z: 2 * layer } }, [OCTAHEDRAL_EDGE, OCTAHEDRAL_EDGE, 1]);
|
|
201
|
+
}
|
|
202
|
+
this.texture = texture;
|
|
203
|
+
this.arrayView = texture.createView({ dimension: '2d-array' });
|
|
204
|
+
this.layerViews = layerViewsOf(texture, this.layers * 2);
|
|
205
|
+
/* Nothing is nearer a lamp than a pane that has not been drawn. */
|
|
206
|
+
for (let layer = 0; layer < this.layers; layer++) {
|
|
207
|
+
encoder
|
|
208
|
+
.beginRenderPass({
|
|
209
|
+
label: 'pointShadow.glass.clear',
|
|
210
|
+
colorAttachments: [],
|
|
211
|
+
depthStencilAttachment: {
|
|
212
|
+
view: this.layerViews[2 * layer + 1],
|
|
213
|
+
depthClearValue: 1,
|
|
214
|
+
depthLoadOp: 'clear',
|
|
215
|
+
depthStoreOp: 'store',
|
|
216
|
+
},
|
|
217
|
+
})
|
|
218
|
+
.end();
|
|
219
|
+
}
|
|
220
|
+
this.tint = new GpuPointGlassTint(this.device, pipelines, this.faceSize, tintEdge, this.layers, RESOLVE_SLOTS, encoder);
|
|
221
|
+
return old;
|
|
222
|
+
}
|
|
223
|
+
/** The scratch into physical layer `physical`'s region for `face`. */
|
|
224
|
+
resolveInto(encoder, physical, face, far, near) {
|
|
225
|
+
const view = this.layerViews[physical];
|
|
166
226
|
if (view === undefined)
|
|
167
227
|
return;
|
|
168
228
|
const slot = this.ring.allocate();
|
|
@@ -197,15 +257,18 @@ export class GpuPointShadowArray {
|
|
|
197
257
|
/** Start a frame's bakes. See the ring: slots are reused and nothing is freed. */
|
|
198
258
|
beginFrame() {
|
|
199
259
|
this.ring.reset();
|
|
260
|
+
this.tint?.beginFrame();
|
|
200
261
|
}
|
|
201
262
|
/** Upload every slot this frame's resolves took, in one write, before the encoder is submitted. */
|
|
202
263
|
flush() {
|
|
203
264
|
this.ring.flush();
|
|
265
|
+
this.tint?.flush();
|
|
204
266
|
}
|
|
205
267
|
dispose() {
|
|
206
268
|
this.texture.destroy();
|
|
207
269
|
this.scratch.destroy();
|
|
208
270
|
this.ring.dispose();
|
|
271
|
+
this.tint?.dispose();
|
|
209
272
|
}
|
|
210
273
|
}
|
|
211
274
|
export class GpuPointShadowMap {
|
|
@@ -280,7 +343,7 @@ export class GpuPointShadowMap {
|
|
|
280
343
|
return 0;
|
|
281
344
|
for (let face = first; face < last; face++) {
|
|
282
345
|
renderFace(array.scratchView, pointShadowFaceViewProj(face, plan.x, plan.y, plan.z, plan.near, plan.range, scratch));
|
|
283
|
-
resolveFace(this.layer, face, plan.range, plan.near);
|
|
346
|
+
resolveFace(this.layer, face, plan.range, plan.near, plan.x, plan.y, plan.z);
|
|
284
347
|
}
|
|
285
348
|
this.image.completeBake(last, plan.x, plan.y, plan.z, plan.range, plan.near, plan.sourceRadius);
|
|
286
349
|
return last - first;
|
|
@@ -288,3 +351,25 @@ export class GpuPointShadowMap {
|
|
|
288
351
|
/** Nothing to free: every GPU object belongs to `GpuPointShadowArray` now. */
|
|
289
352
|
dispose() { }
|
|
290
353
|
}
|
|
354
|
+
/** The depth array, copyable so glass can interleave it without a re-bake. */
|
|
355
|
+
function depthArray(device, layers) {
|
|
356
|
+
return device.createTexture({
|
|
357
|
+
label: 'pointShadow.array',
|
|
358
|
+
size: [OCTAHEDRAL_EDGE, OCTAHEDRAL_EDGE, layers],
|
|
359
|
+
format: SHADOW_FORMAT,
|
|
360
|
+
usage: USAGE_RENDER_ATTACHMENT | USAGE_TEXTURE_BINDING | USAGE_COPY,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
/** One single-layer view per physical layer: a depth attachment takes exactly one. */
|
|
364
|
+
function layerViewsOf(texture, layers) {
|
|
365
|
+
const views = [];
|
|
366
|
+
for (let layer = 0; layer < layers; layer++) {
|
|
367
|
+
views.push(texture.createView({
|
|
368
|
+
label: `pointShadow.layer${layer}`,
|
|
369
|
+
dimension: '2d',
|
|
370
|
+
baseArrayLayer: layer,
|
|
371
|
+
arrayLayerCount: 1,
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
374
|
+
return views;
|
|
375
|
+
}
|
|
@@ -174,14 +174,20 @@ export declare const ADDITIVE_BLEND: GPUBlendState;
|
|
|
174
174
|
/** A fullscreen pass over one or more inputs, writing to one colour target. */
|
|
175
175
|
export declare function postPipeline(cache: PipelineCache, device: GPUDevice, layout: GPUBindGroupLayout, key: string, fragment: string, format: GPUTextureFormat, blend?: GPUBlendState): GPURenderPipeline;
|
|
176
176
|
/**
|
|
177
|
-
* The
|
|
177
|
+
* The same over several colour targets, in the fragment's output order: the temporal resolve
|
|
178
|
+
* writes its picture and each pixel's flicker record in one pass. `targets` is the caller's, held
|
|
179
|
+
* rather than built per call, since this is asked for every frame.
|
|
180
|
+
*/
|
|
181
|
+
export declare function postPipelineTargets(cache: PipelineCache, device: GPUDevice, layout: GPUBindGroupLayout, key: string, fragment: string, targets: GPUColorTargetState[]): GPURenderPipeline;
|
|
182
|
+
/**
|
|
183
|
+
* The temporal resolve's block and its four inputs.
|
|
178
184
|
*
|
|
179
185
|
* Named like the occlusion's beside it, and for the same reason `BLOOM_DOWNSAMPLE_FIELDS` is: a
|
|
180
186
|
* block read by assumption rather than by name is a uniform written to the wrong offset, which
|
|
181
187
|
* draws a plausible picture.
|
|
182
188
|
*/
|
|
183
189
|
export declare const TAA_FRAG_FIELDS: UniformFields;
|
|
184
|
-
export declare const TAA_FRAG_SIZE:
|
|
190
|
+
export declare const TAA_FRAG_SIZE: 112;
|
|
185
191
|
export declare const TAA_UNIFORMS: 1;
|
|
186
192
|
export declare const TAA_TEXTURES: {
|
|
187
193
|
readonly uScene: {
|
|
@@ -194,11 +200,21 @@ export declare const TAA_TEXTURES: {
|
|
|
194
200
|
readonly sampler: 35;
|
|
195
201
|
readonly type: "sampler2D";
|
|
196
202
|
};
|
|
197
|
-
readonly
|
|
203
|
+
readonly uFlicker: {
|
|
198
204
|
readonly texture: 36;
|
|
199
205
|
readonly sampler: 37;
|
|
200
206
|
readonly type: "sampler2D";
|
|
201
207
|
};
|
|
208
|
+
readonly uFlickerMotion: {
|
|
209
|
+
readonly texture: 38;
|
|
210
|
+
readonly sampler: 39;
|
|
211
|
+
readonly type: "sampler2D";
|
|
212
|
+
};
|
|
213
|
+
readonly uDepth: {
|
|
214
|
+
readonly texture: 40;
|
|
215
|
+
readonly sampler: 41;
|
|
216
|
+
readonly type: "sampler2D";
|
|
217
|
+
};
|
|
202
218
|
};
|
|
203
219
|
/**
|
|
204
220
|
* The order-independent resolve's inputs. It has no uniform block of its own — the whole pass is
|
|
@@ -289,20 +305,10 @@ export declare const MEDIUM_TEXTURES: {
|
|
|
289
305
|
readonly sampler: 33;
|
|
290
306
|
readonly type: "sampler2D";
|
|
291
307
|
};
|
|
292
|
-
readonly
|
|
308
|
+
readonly uSunShadows: {
|
|
293
309
|
readonly texture: 34;
|
|
294
310
|
readonly sampler: 35;
|
|
295
|
-
readonly type: "
|
|
296
|
-
};
|
|
297
|
-
readonly uPeeledShadowMap: {
|
|
298
|
-
readonly texture: 36;
|
|
299
|
-
readonly sampler: 37;
|
|
300
|
-
readonly type: "sampler2D";
|
|
301
|
-
};
|
|
302
|
-
readonly uDynamicShadowMap: {
|
|
303
|
-
readonly texture: 38;
|
|
304
|
-
readonly sampler: 39;
|
|
305
|
-
readonly type: "sampler2D";
|
|
311
|
+
readonly type: "sampler2DArray";
|
|
306
312
|
};
|
|
307
313
|
};
|
|
308
314
|
export declare const MEDIUM_UPSAMPLE_UNIFORMS: 1;
|
|
@@ -244,7 +244,20 @@ export const ADDITIVE_BLEND = {
|
|
|
244
244
|
};
|
|
245
245
|
/** A fullscreen pass over one or more inputs, writing to one colour target. */
|
|
246
246
|
export function postPipeline(cache, device, layout, key, fragment, format, blend) {
|
|
247
|
-
return cache.get(key, () => (
|
|
247
|
+
return cache.get(key, () => describePost(device, layout, key, fragment, [
|
|
248
|
+
blend === undefined ? { format } : { format, blend },
|
|
249
|
+
]));
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* The same over several colour targets, in the fragment's output order: the temporal resolve
|
|
253
|
+
* writes its picture and each pixel's flicker record in one pass. `targets` is the caller's, held
|
|
254
|
+
* rather than built per call, since this is asked for every frame.
|
|
255
|
+
*/
|
|
256
|
+
export function postPipelineTargets(cache, device, layout, key, fragment, targets) {
|
|
257
|
+
return cache.get(key, () => describePost(device, layout, key, fragment, targets));
|
|
258
|
+
}
|
|
259
|
+
function describePost(device, layout, key, fragment, targets) {
|
|
260
|
+
return {
|
|
248
261
|
label: key,
|
|
249
262
|
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
250
263
|
vertex: {
|
|
@@ -254,7 +267,7 @@ export function postPipeline(cache, device, layout, key, fragment, format, blend
|
|
|
254
267
|
fragment: {
|
|
255
268
|
module: shaderModule(device, { label: key, code: fragment }),
|
|
256
269
|
entryPoint: 'main',
|
|
257
|
-
targets
|
|
270
|
+
targets,
|
|
258
271
|
},
|
|
259
272
|
/*
|
|
260
273
|
* No depth at all, which is what makes this different from every other pipeline here: the
|
|
@@ -262,10 +275,10 @@ export function postPipeline(cache, device, layout, key, fragment, format, blend
|
|
|
262
275
|
* disables the test, the write and culling by hand for the same draw.
|
|
263
276
|
*/
|
|
264
277
|
primitive: { topology: 'triangle-list', cullMode: 'none' },
|
|
265
|
-
}
|
|
278
|
+
};
|
|
266
279
|
}
|
|
267
280
|
/**
|
|
268
|
-
* The temporal resolve's block and its
|
|
281
|
+
* The temporal resolve's block and its four inputs.
|
|
269
282
|
*
|
|
270
283
|
* Named like the occlusion's beside it, and for the same reason `BLOOM_DOWNSAMPLE_FIELDS` is: a
|
|
271
284
|
* block read by assumption rather than by name is a uniform written to the wrong offset, which
|