@driftengine/core 4.8.1 → 4.8.3
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 +142 -0
- package/README.md +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8 -0
- package/dist/input/actionMap.d.ts +6 -1
- package/dist/input/actionMap.js +20 -7
- package/dist/input/input.d.ts +28 -0
- package/dist/input/input.js +71 -9
- package/dist/input/inputHarness.d.ts +9 -0
- package/dist/input/inputHarness.js +34 -2
- package/dist/render/backend/materialChanges.d.ts +7 -2
- package/dist/render/backend/materialChanges.js +8 -3
- package/dist/render/backend/webgl2/renderer.d.ts +75 -3
- package/dist/render/backend/webgl2/renderer.js +209 -22
- package/dist/render/backend/webgpu/buffers.d.ts +2 -0
- package/dist/render/backend/webgpu/buffers.js +2 -0
- package/dist/render/backend/webgpu/causticsPass.js +2 -1
- package/dist/render/backend/webgpu/depthPass.d.ts +13 -3
- package/dist/render/backend/webgpu/depthPass.js +4 -3
- package/dist/render/backend/webgpu/filmPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +5 -0
- package/dist/render/backend/webgpu/flatPass.js +18 -8
- package/dist/render/backend/webgpu/linePass.js +2 -1
- package/dist/render/backend/webgpu/panelPass.js +2 -1
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/pipelineCache.d.ts +40 -8
- package/dist/render/backend/webgpu/pipelineCache.js +76 -9
- package/dist/render/backend/webgpu/plumePass.js +2 -1
- package/dist/render/backend/webgpu/postPass.d.ts +12 -2
- package/dist/render/backend/webgpu/postPass.js +19 -5
- package/dist/render/backend/webgpu/renderer.d.ts +66 -2
- package/dist/render/backend/webgpu/renderer.js +189 -38
- package/dist/render/backend/webgpu/sdfTextPass.js +2 -1
- package/dist/render/backend/webgpu/textPass.js +2 -1
- package/dist/render/backend/webgpu/waterPass.js +2 -1
- package/dist/render/backend/webgpu/windStreakPass.js +2 -1
- package/dist/render/boltBatch.js +2 -1
- package/dist/render/causticsRenderer.js +2 -1
- package/dist/render/cutoutCaster.d.ts +3 -1
- package/dist/render/cutoutCaster.js +4 -0
- package/dist/render/decalPass.js +2 -1
- package/dist/render/globalMediumPass.js +3 -2
- package/dist/render/lineBatch.js +5 -1
- package/dist/render/mapsWithoutUvs.d.ts +24 -0
- package/dist/render/mapsWithoutUvs.js +24 -0
- package/dist/render/mesh.d.ts +2 -0
- package/dist/render/mesh.js +3 -0
- package/dist/render/oitPass.js +2 -1
- package/dist/render/particleBatch.js +3 -2
- package/dist/render/particlePool.d.ts +21 -2
- package/dist/render/particlePool.js +72 -37
- package/dist/render/pass.d.ts +12 -0
- package/dist/render/plumeRenderer.js +3 -2
- package/dist/render/renderQuality.d.ts +16 -8
- package/dist/render/sceneCoverage.d.ts +54 -0
- package/dist/render/sceneCoverage.js +72 -0
- package/dist/render/sdfTextRenderer.js +2 -1
- package/dist/render/shaders/depth.js +3 -2
- package/dist/render/shaders/flat/glassTint.d.ts +28 -0
- package/dist/render/shaders/flat/glassTint.js +31 -0
- package/dist/render/shaders/flat/index.d.ts +12 -0
- package/dist/render/shaders/flat/index.js +13 -2
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +60 -25
- package/dist/render/shaders/flat/surfaceEffects.d.ts +1 -1
- package/dist/render/shaders/flat/surfaceEffects.js +6 -2
- package/dist/render/shaders/generated/depth.wgsl.d.ts +32 -12
- package/dist/render/shaders/generated/depth.wgsl.js +32 -12
- package/dist/render/shaders/generated/flat.wgsl.d.ts +89 -0
- package/dist/render/shaders/generated/flat.wgsl.js +127 -38
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +3 -3
- package/dist/render/shaders/generated/particle.wgsl.js +3 -3
- package/dist/render/shaders/generated/rush.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/rush.wgsl.js +1 -1
- package/dist/render/shaders/generated/sdfText.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/sdfText.wgsl.js +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +1 -1
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +14 -1
- package/dist/render/shaders/outputTransform.js +23 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/recon/resolve.wgsl.js +15 -1
- package/dist/render/shaders/rush.js +13 -2
- package/dist/render/shaders/sdfText.d.ts +1 -1
- package/dist/render/shaders/temporalResolve.js +12 -5
- package/dist/render/ssrPass.js +2 -1
- package/dist/render/surfaceTexture.d.ts +13 -0
- package/dist/render/surfaceTexture.js +4 -0
- package/dist/render/textRenderer.js +2 -1
- package/dist/render/vertexDefaults.js +1 -0
- package/dist/render/viewModel.d.ts +29 -0
- package/dist/render/viewModel.js +35 -0
- package/dist/render/waterRenderer.js +2 -1
- package/dist/render/windStreakRenderer.js +2 -1
- package/package.json +6 -6
- package/src/index.ts +22 -1
- package/src/input/actionMap.ts +23 -8
- package/src/input/input.ts +79 -9
- package/src/input/inputHarness.ts +27 -2
- package/src/render/backend/materialChanges.ts +8 -3
- package/src/render/backend/webgl2/renderer.ts +223 -29
- package/src/render/backend/webgpu/buffers.ts +5 -0
- package/src/render/backend/webgpu/causticsPass.ts +2 -1
- package/src/render/backend/webgpu/depthPass.ts +4 -3
- package/src/render/backend/webgpu/filmPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +43 -26
- package/src/render/backend/webgpu/linePass.ts +2 -1
- package/src/render/backend/webgpu/panelPass.ts +2 -1
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/pipelineCache.ts +82 -8
- package/src/render/backend/webgpu/plumePass.ts +2 -1
- package/src/render/backend/webgpu/postPass.ts +20 -5
- package/src/render/backend/webgpu/renderer.ts +191 -37
- package/src/render/backend/webgpu/sdfTextPass.ts +2 -1
- package/src/render/backend/webgpu/textPass.ts +2 -1
- package/src/render/backend/webgpu/waterPass.ts +2 -1
- package/src/render/backend/webgpu/windStreakPass.ts +2 -1
- package/src/render/boltBatch.ts +2 -1
- package/src/render/causticsRenderer.ts +2 -1
- package/src/render/cutoutCaster.ts +15 -2
- package/src/render/decalPass.ts +2 -1
- package/src/render/globalMediumPass.ts +3 -2
- package/src/render/lineBatch.ts +3 -1
- package/src/render/mapsWithoutUvs.ts +43 -0
- package/src/render/mesh.ts +3 -0
- package/src/render/oitPass.ts +2 -1
- package/src/render/particleBatch.ts +3 -2
- package/src/render/particlePool.ts +107 -56
- package/src/render/pass.ts +12 -0
- package/src/render/plumeRenderer.ts +3 -2
- package/src/render/renderQuality.ts +16 -8
- package/src/render/sceneCoverage.ts +78 -0
- package/src/render/sdfTextRenderer.ts +2 -1
- package/src/render/shaders/depth.ts +3 -2
- package/src/render/shaders/flat/glassTint.ts +48 -0
- package/src/render/shaders/flat/index.ts +25 -2
- package/src/render/shaders/flat/main.ts +60 -25
- package/src/render/shaders/flat/surfaceEffects.ts +6 -2
- package/src/render/shaders/generated/depth.wgsl.ts +32 -12
- package/src/render/shaders/generated/flat.wgsl.ts +127 -38
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +3 -3
- package/src/render/shaders/generated/rush.wgsl.ts +1 -1
- package/src/render/shaders/generated/sdfText.wgsl.ts +1 -1
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +1 -1
- package/src/render/shaders/outputTransform.ts +24 -1
- package/src/render/shaders/recon/resolve.wgsl.ts +15 -1
- package/src/render/shaders/rush.ts +13 -2
- package/src/render/shaders/temporalResolve.ts +12 -5
- package/src/render/ssrPass.ts +2 -1
- package/src/render/surfaceTexture.ts +16 -0
- package/src/render/textRenderer.ts +2 -1
- package/src/render/vertexDefaults.ts +1 -0
- package/src/render/viewModel.ts +41 -0
- package/src/render/waterRenderer.ts +2 -1
- package/src/render/windStreakRenderer.ts +2 -1
|
@@ -87,13 +87,18 @@ export declare const DEPTH_CUTOUT_VERT_FIELDS: {
|
|
|
87
87
|
readonly size: 8;
|
|
88
88
|
readonly type: "vec2";
|
|
89
89
|
};
|
|
90
|
-
readonly
|
|
90
|
+
readonly uUvOffset: {
|
|
91
91
|
readonly offset: 168;
|
|
92
|
+
readonly size: 8;
|
|
93
|
+
readonly type: "vec2";
|
|
94
|
+
};
|
|
95
|
+
readonly uAlphaCutout: {
|
|
96
|
+
readonly offset: 176;
|
|
92
97
|
readonly size: 4;
|
|
93
98
|
readonly type: "float";
|
|
94
99
|
};
|
|
95
100
|
};
|
|
96
|
-
export declare const DEPTH_CUTOUT_VERT_SIZE:
|
|
101
|
+
export declare const DEPTH_CUTOUT_VERT_SIZE: 192;
|
|
97
102
|
export declare const DEPTH_INSTANCED_CUTOUT_VERT_FIELDS: {
|
|
98
103
|
readonly uLightViewProj: {
|
|
99
104
|
readonly offset: 0;
|
|
@@ -105,8 +110,13 @@ export declare const DEPTH_INSTANCED_CUTOUT_VERT_FIELDS: {
|
|
|
105
110
|
readonly size: 8;
|
|
106
111
|
readonly type: "vec2";
|
|
107
112
|
};
|
|
108
|
-
readonly
|
|
113
|
+
readonly uUvOffset: {
|
|
109
114
|
readonly offset: 72;
|
|
115
|
+
readonly size: 8;
|
|
116
|
+
readonly type: "vec2";
|
|
117
|
+
};
|
|
118
|
+
readonly uAlphaCutout: {
|
|
119
|
+
readonly offset: 80;
|
|
110
120
|
readonly size: 4;
|
|
111
121
|
readonly type: "float";
|
|
112
122
|
};
|
|
@@ -12,9 +12,10 @@ export const DEPTH_VERT_FIELDS = DEPTH_BINDINGS.DEPTH_VERT.fields;
|
|
|
12
12
|
export const DEPTH_VERT_SIZE = DEPTH_BINDINGS.DEPTH_VERT.uniformSize;
|
|
13
13
|
export const DEPTH_FRAG_SIZE = DEPTH_BINDINGS.DEPTH_FRAG.uniformSize;
|
|
14
14
|
/*
|
|
15
|
-
* The cutout variants' vertex blocks. The rigid one is the plain block with `uUvScale
|
|
16
|
-
* `uAlphaCutout` after every other field, so a slot written for it is written with
|
|
17
|
-
* offsets plus these
|
|
15
|
+
* The cutout variants' vertex blocks. The rigid one is the plain block with `uUvScale`,
|
|
16
|
+
* `uUvOffset` and `uAlphaCutout` after every other field, so a slot written for it is written with
|
|
17
|
+
* the plain offsets plus these three; the instanced one has no model and no wind, so its three sit
|
|
18
|
+
* earlier.
|
|
18
19
|
*/
|
|
19
20
|
export const DEPTH_CUTOUT_VERT_FIELDS = DEPTH_BINDINGS.DEPTH_CUTOUT_VERT.fields;
|
|
20
21
|
export const DEPTH_CUTOUT_VERT_SIZE = DEPTH_BINDINGS.DEPTH_CUTOUT_VERT.uniformSize;
|
|
@@ -3,6 +3,7 @@ import { FILM_BINDINGS, FILM_FRAG_WGSL, FILM_VERT_WGSL, } from '../../shaders/ge
|
|
|
3
3
|
import { vertexBufferLayouts } from './buffers.js';
|
|
4
4
|
import { DEPTH_FORMAT } from './flatPass.js';
|
|
5
5
|
import { shaderModule } from './shaderModules.js';
|
|
6
|
+
import { SCENE_ALPHA_KEEPS } from '../../sceneCoverage.js';
|
|
6
7
|
/**
|
|
7
8
|
* The film pass: a thin wet layer — an oil slick, a puddle — lying over the world.
|
|
8
9
|
*
|
|
@@ -85,7 +86,7 @@ export function filmPipeline(cache, device, layout, key, present) {
|
|
|
85
86
|
format: cache.format,
|
|
86
87
|
blend: {
|
|
87
88
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
88
|
-
alpha:
|
|
89
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
89
90
|
},
|
|
90
91
|
},
|
|
91
92
|
],
|
|
@@ -86,6 +86,11 @@ export declare const FLAT_VERT_FIELDS: {
|
|
|
86
86
|
readonly size: 8;
|
|
87
87
|
readonly type: "vec2";
|
|
88
88
|
};
|
|
89
|
+
readonly uUvOffset: {
|
|
90
|
+
readonly offset: 152;
|
|
91
|
+
readonly size: 8;
|
|
92
|
+
readonly type: "vec2";
|
|
93
|
+
};
|
|
89
94
|
readonly uModel: {
|
|
90
95
|
readonly offset: 160;
|
|
91
96
|
readonly size: 64;
|
|
@@ -2,6 +2,7 @@ import { DEPTH_COMPARE, DEPTH_FORMAT, depthOffsetForLayer } from '../../depthCon
|
|
|
2
2
|
import { FLAT_BINDINGS, FLAT_FRAG_WGSL, FLAT_VERT_WGSL, } from '../../shaders/generated/flat.wgsl.js';
|
|
3
3
|
import { vertexBufferLayouts } from './buffers.js';
|
|
4
4
|
import { shaderModule } from './shaderModules.js';
|
|
5
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.js';
|
|
5
6
|
/** The material maps the flat pass reads: `2d-array` colour, filtered, not shadow maps. */
|
|
6
7
|
const SURFACE_MAPS = new Set([
|
|
7
8
|
'uAlbedo',
|
|
@@ -115,18 +116,27 @@ export function flatFragmentBindings(variant) {
|
|
|
115
116
|
return found;
|
|
116
117
|
}
|
|
117
118
|
/**
|
|
118
|
-
* The lit fragment stage's constants, set from the cache
|
|
119
|
+
* The lit fragment stage's constants, set from the cache's switches, keyed by each one's **id**.
|
|
119
120
|
*
|
|
120
121
|
* Not by its name, because an override declared with `@id` answers to the id alone — WebGPU's
|
|
121
122
|
* "pipeline-overridable constant identifier string" — and naga writes one on every specialisation
|
|
122
123
|
* constant. Keyed by name, Chrome refused every lit pipeline: *Pipeline overridable constant
|
|
123
|
-
* "GLASS_SHADOWS" not found*, and the frame drew nothing.
|
|
124
|
+
* "GLASS_SHADOWS" not found*, and the frame drew nothing. Every override the variant declares is
|
|
125
|
+
* set, so a switch added to the shader and not to the cache is refused here rather than defaulted.
|
|
124
126
|
*/
|
|
125
127
|
function flatFragmentConstants(variant, cache) {
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
+
const overrides = flatFragmentBindings(variant).overrides;
|
|
129
|
+
if (overrides?.['GLASS_SHADOWS'] === undefined) {
|
|
128
130
|
throw new Error(`flatPass: variant "${variant}" has no glass switch`);
|
|
129
|
-
|
|
131
|
+
}
|
|
132
|
+
const constants = {};
|
|
133
|
+
for (const [name, id] of Object.entries(overrides)) {
|
|
134
|
+
if (!(name in cache.litSwitches)) {
|
|
135
|
+
throw new Error(`flatPass: variant "${variant}" declares a switch "${name}" no cache sets`);
|
|
136
|
+
}
|
|
137
|
+
constants[String(id)] = cache.litSwitches[name] ? 1 : 0;
|
|
138
|
+
}
|
|
139
|
+
return constants;
|
|
130
140
|
}
|
|
131
141
|
/** The depth format both backends compare with. */
|
|
132
142
|
/* Re-exported so the twenty passes that already import it from here do not each learn a new
|
|
@@ -391,7 +401,7 @@ instanced = false,
|
|
|
391
401
|
oit = 'none',
|
|
392
402
|
/** Culls nothing, for a surface seen from both faces. The key must carry it: `|2s`. */
|
|
393
403
|
doubleSided = false) {
|
|
394
|
-
return cache.get(key, () => flatDescriptor(cache, device, layout, variant, key, present, translucent, skinned, morphed, depthWrite, depthLayer, instanced, oit, doubleSided));
|
|
404
|
+
return cache.get(key, () => flatDescriptor(cache, device, layout, variant, key, present, translucent, skinned, morphed, depthWrite, depthLayer, instanced, oit, doubleSided), true);
|
|
395
405
|
}
|
|
396
406
|
/**
|
|
397
407
|
* The same pipeline, compiled off the main thread.
|
|
@@ -407,7 +417,7 @@ export function flatPipelineAsync(cache, device, layout, variant, key, present,
|
|
|
407
417
|
skinned = false,
|
|
408
418
|
/** Whether this pipeline reads morph deltas. See `FlatVertexOptions`. */
|
|
409
419
|
morphed = false) {
|
|
410
|
-
return cache.getAsync(key, () => flatDescriptor(cache, device, layout, variant, key, present, translucent, skinned, morphed));
|
|
420
|
+
return cache.getAsync(key, () => flatDescriptor(cache, device, layout, variant, key, present, translucent, skinned, morphed), true);
|
|
411
421
|
}
|
|
412
422
|
/**
|
|
413
423
|
* The colour target for an order-independent pass, or null where this is an ordinary draw.
|
|
@@ -508,7 +518,7 @@ doubleSided = false) {
|
|
|
508
518
|
dstFactor: 'one-minus-src-alpha',
|
|
509
519
|
operation: 'add',
|
|
510
520
|
},
|
|
511
|
-
alpha:
|
|
521
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
512
522
|
},
|
|
513
523
|
}
|
|
514
524
|
: { format: cache.format }),
|
|
@@ -3,6 +3,7 @@ import { LINE_BINDINGS, LINE_FRAG_WGSL, LINE_VERT_WGSL, } from '../../shaders/ge
|
|
|
3
3
|
import { buildSegmentQuads } from '../../segmentQuads.js';
|
|
4
4
|
import { DEPTH_FORMAT } from './flatPass.js';
|
|
5
5
|
import { shaderModule } from './shaderModules.js';
|
|
6
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.js';
|
|
6
7
|
/**
|
|
7
8
|
* The line pass: a polyline with a real width, four vertices a segment.
|
|
8
9
|
*
|
|
@@ -179,7 +180,7 @@ additive = false) {
|
|
|
179
180
|
dstFactor: 'one-minus-src-alpha',
|
|
180
181
|
operation: 'add',
|
|
181
182
|
},
|
|
182
|
-
alpha:
|
|
183
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
183
184
|
},
|
|
184
185
|
},
|
|
185
186
|
],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PANEL_BINDINGS, PANEL_FRAG_WGSL, PANEL_VERT_WGSL, } from '../../shaders/generated/panel.wgsl.js';
|
|
2
2
|
import { DEPTH_FORMAT } from './flatPass.js';
|
|
3
3
|
import { shaderModule } from './shaderModules.js';
|
|
4
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.js';
|
|
4
5
|
/**
|
|
5
6
|
* The panel pass: two triangles in screen space, one colour, one alpha.
|
|
6
7
|
*
|
|
@@ -97,7 +98,7 @@ export function panelPipeline(cache, device, layout) {
|
|
|
97
98
|
format: cache.format,
|
|
98
99
|
blend: {
|
|
99
100
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
100
|
-
alpha:
|
|
101
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
101
102
|
},
|
|
102
103
|
},
|
|
103
104
|
],
|
|
@@ -4,6 +4,7 @@ import { PARTICLE_BINDINGS } from '../../shaders/generated/particle.wgsl.js';
|
|
|
4
4
|
import { PARTICLE_BLADES, PARTICLE_INDICES, PARTICLE_VERTS } from '../../shaders/particle.js';
|
|
5
5
|
import { DEPTH_FORMAT } from './flatPass.js';
|
|
6
6
|
import { shaderModule } from './shaderModules.js';
|
|
7
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.js';
|
|
7
8
|
/**
|
|
8
9
|
* The particle pass: a crossed pair of quads per live particle, rebuilt every frame.
|
|
9
10
|
*
|
|
@@ -269,7 +270,7 @@ export function particlePipeline(cache, device, layout, material, blend) {
|
|
|
269
270
|
dstFactor: 'one-minus-src-alpha',
|
|
270
271
|
operation: 'add',
|
|
271
272
|
},
|
|
272
|
-
alpha:
|
|
273
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
273
274
|
},
|
|
274
275
|
},
|
|
275
276
|
],
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type LitSwitch } from '../../shaders/flat/glassTint.ts';
|
|
2
|
+
export type { LitSwitch };
|
|
1
3
|
/**
|
|
2
4
|
* Render pipelines, built once and looked up by name.
|
|
3
5
|
*
|
|
@@ -33,14 +35,27 @@ export declare class PipelineCache {
|
|
|
33
35
|
*/
|
|
34
36
|
readonly sampleCount: number;
|
|
35
37
|
/**
|
|
36
|
-
*
|
|
38
|
+
* Which of the lit stage's switches the pipelines built now have on: the pipeline-overridable
|
|
39
|
+
* constants the generated lit shader branches on (`GLASS_SHADOWS` and `litSwitchesGlsl`), which
|
|
40
|
+
* the device compiles away where they are off. Read by `flatPass` when it describes a pipeline.
|
|
37
41
|
*
|
|
38
|
-
* **
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
+
* **Each is code a scene pays for in every lit pixel's registers whether it uses it or not**, so
|
|
43
|
+
* each is off until it is used: glass until the renderer is offered a pane, a fixture until one is
|
|
44
|
+
* loaded, the effects until a material carries a table, DriftLight until a volume is set — and
|
|
45
|
+
* then on for good, through `enable`. Clustering is the profile's, fixed at construction. Every
|
|
46
|
+
* scene paid for all of it from 4.5.0 to 4.8.1, and on a phone that was the lit pass: about 30%
|
|
47
|
+
* of the lit shader's instructions for glass alone, measured on RADV. **What it costs** is the
|
|
48
|
+
* frames between a feature's first use and its recompiled pipelines, which draw without it.
|
|
42
49
|
*/
|
|
50
|
+
readonly litSwitches: Record<LitSwitch, boolean>;
|
|
51
|
+
/** Whether glass may ever be switched on here: `glassShadows` other than `'off'`. */
|
|
43
52
|
readonly glassShadows: boolean;
|
|
53
|
+
/** How to describe each lit pipeline again, so `enable` can rebuild every one. */
|
|
54
|
+
private readonly litDescribers;
|
|
55
|
+
/** Bumped by every switch, so a lit build started before one is not kept after it. */
|
|
56
|
+
private litGeneration;
|
|
57
|
+
/** The last rebuild, which the next one waits for so they land in the order they were asked. */
|
|
58
|
+
private litRebuild;
|
|
44
59
|
private readonly device;
|
|
45
60
|
private readonly pipelines;
|
|
46
61
|
/**
|
|
@@ -58,7 +73,9 @@ export declare class PipelineCache {
|
|
|
58
73
|
* wait for readiness rather than discovering it mid-frame.
|
|
59
74
|
*/
|
|
60
75
|
private readonly compiling;
|
|
61
|
-
constructor(device: GPUDevice, format: GPUTextureFormat, sampleCount?: number, glassShadows?: boolean
|
|
76
|
+
constructor(device: GPUDevice, format: GPUTextureFormat, sampleCount?: number, glassShadows?: boolean,
|
|
77
|
+
/** The profile's `clusteredLights`, which compiles the clustered arm in or leaves it out. */
|
|
78
|
+
clusteredLights?: boolean);
|
|
62
79
|
/** How many distinct pipelines have been built. Read by tests and diagnostics. */
|
|
63
80
|
get size(): number;
|
|
64
81
|
/**
|
|
@@ -69,7 +86,9 @@ export declare class PipelineCache {
|
|
|
69
86
|
* difference is only *when* the driver does the work, and that difference is the whole bug
|
|
70
87
|
* this exists for.
|
|
71
88
|
*/
|
|
72
|
-
getAsync(key: string, describe: () => GPURenderPipelineDescriptor
|
|
89
|
+
getAsync(key: string, describe: () => GPURenderPipelineDescriptor,
|
|
90
|
+
/** Whether this is a lit pipeline, which `enable` rebuilds. See `litSwitches`. */
|
|
91
|
+
lit?: boolean): Promise<GPURenderPipeline>;
|
|
73
92
|
/**
|
|
74
93
|
* Resolve once every pipeline asked for so far has finished compiling.
|
|
75
94
|
*
|
|
@@ -90,7 +109,20 @@ export declare class PipelineCache {
|
|
|
90
109
|
* too**: a nested object with vertex buffer layouts and blend state, constructed to be
|
|
91
110
|
* thrown away on every hit. Passing a function means a hit costs one `Map` lookup.
|
|
92
111
|
*/
|
|
93
|
-
get(key: string, describe: () => GPURenderPipelineDescriptor
|
|
112
|
+
get(key: string, describe: () => GPURenderPipelineDescriptor,
|
|
113
|
+
/** Whether this is a lit pipeline, which `enable` rebuilds. See `litSwitches`. */
|
|
114
|
+
lit?: boolean): GPURenderPipeline;
|
|
115
|
+
/**
|
|
116
|
+
* Turn one of the lit stage's switches on, for every lit pipeline built from now on and every one
|
|
117
|
+
* already built. See `litSwitches`.
|
|
118
|
+
*
|
|
119
|
+
* **The rebuilt set lands at once**, when every one of them has compiled, so no frame draws some
|
|
120
|
+
* surfaces with a feature and others without. Until then the pipelines already built go on drawing
|
|
121
|
+
* as they were. Once only: a switch is not turned off again when the last user of it leaves,
|
|
122
|
+
* because a second switch would cost a second compile for a saving the first use showed was not
|
|
123
|
+
* needed. Glass is never turned on where the profile asked for no glass shadows.
|
|
124
|
+
*/
|
|
125
|
+
enable(feature: LitSwitch): Promise<void>;
|
|
94
126
|
/**
|
|
95
127
|
* Drop every pipeline.
|
|
96
128
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { noLitSwitches } from '../../shaders/flat/glassTint.js';
|
|
1
2
|
/**
|
|
2
3
|
* Render pipelines, built once and looked up by name.
|
|
3
4
|
*
|
|
@@ -33,14 +34,27 @@ export class PipelineCache {
|
|
|
33
34
|
*/
|
|
34
35
|
sampleCount;
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
+
* Which of the lit stage's switches the pipelines built now have on: the pipeline-overridable
|
|
38
|
+
* constants the generated lit shader branches on (`GLASS_SHADOWS` and `litSwitchesGlsl`), which
|
|
39
|
+
* the device compiles away where they are off. Read by `flatPass` when it describes a pipeline.
|
|
37
40
|
*
|
|
38
|
-
* **
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
41
|
+
* **Each is code a scene pays for in every lit pixel's registers whether it uses it or not**, so
|
|
42
|
+
* each is off until it is used: glass until the renderer is offered a pane, a fixture until one is
|
|
43
|
+
* loaded, the effects until a material carries a table, DriftLight until a volume is set — and
|
|
44
|
+
* then on for good, through `enable`. Clustering is the profile's, fixed at construction. Every
|
|
45
|
+
* scene paid for all of it from 4.5.0 to 4.8.1, and on a phone that was the lit pass: about 30%
|
|
46
|
+
* of the lit shader's instructions for glass alone, measured on RADV. **What it costs** is the
|
|
47
|
+
* frames between a feature's first use and its recompiled pipelines, which draw without it.
|
|
42
48
|
*/
|
|
49
|
+
litSwitches = noLitSwitches();
|
|
50
|
+
/** Whether glass may ever be switched on here: `glassShadows` other than `'off'`. */
|
|
43
51
|
glassShadows;
|
|
52
|
+
/** How to describe each lit pipeline again, so `enable` can rebuild every one. */
|
|
53
|
+
litDescribers = new Map();
|
|
54
|
+
/** Bumped by every switch, so a lit build started before one is not kept after it. */
|
|
55
|
+
litGeneration = 0;
|
|
56
|
+
/** The last rebuild, which the next one waits for so they land in the order they were asked. */
|
|
57
|
+
litRebuild = Promise.resolve();
|
|
44
58
|
device;
|
|
45
59
|
pipelines = new Map();
|
|
46
60
|
/**
|
|
@@ -58,11 +72,14 @@ export class PipelineCache {
|
|
|
58
72
|
* wait for readiness rather than discovering it mid-frame.
|
|
59
73
|
*/
|
|
60
74
|
compiling = new Map();
|
|
61
|
-
constructor(device, format, sampleCount = 1, glassShadows = true
|
|
75
|
+
constructor(device, format, sampleCount = 1, glassShadows = true,
|
|
76
|
+
/** The profile's `clusteredLights`, which compiles the clustered arm in or leaves it out. */
|
|
77
|
+
clusteredLights = false) {
|
|
62
78
|
this.device = device;
|
|
63
79
|
this.format = format;
|
|
64
80
|
this.sampleCount = sampleCount;
|
|
65
81
|
this.glassShadows = glassShadows;
|
|
82
|
+
this.litSwitches.CLUSTERED_LIGHTS = clusteredLights;
|
|
66
83
|
}
|
|
67
84
|
/** How many distinct pipelines have been built. Read by tests and diagnostics. */
|
|
68
85
|
get size() {
|
|
@@ -76,13 +93,18 @@ export class PipelineCache {
|
|
|
76
93
|
* difference is only *when* the driver does the work, and that difference is the whole bug
|
|
77
94
|
* this exists for.
|
|
78
95
|
*/
|
|
79
|
-
async getAsync(key, describe
|
|
96
|
+
async getAsync(key, describe,
|
|
97
|
+
/** Whether this is a lit pipeline, which `enable` rebuilds. See `litSwitches`. */
|
|
98
|
+
lit = false) {
|
|
99
|
+
if (lit)
|
|
100
|
+
this.litDescribers.set(key, describe);
|
|
80
101
|
const existing = this.pipelines.get(key);
|
|
81
102
|
if (existing !== undefined)
|
|
82
103
|
return existing;
|
|
83
104
|
const inFlight = this.compiling.get(key);
|
|
84
105
|
if (inFlight !== undefined)
|
|
85
106
|
return inFlight;
|
|
107
|
+
const generation = this.litGeneration;
|
|
86
108
|
/*
|
|
87
109
|
* **Falls back where the async form is missing.** It is part of the standard, but a device
|
|
88
110
|
* can be a test double, a polyfill or an older implementation, and a renderer that throws
|
|
@@ -94,7 +116,9 @@ export class PipelineCache {
|
|
|
94
116
|
? this.device.createRenderPipelineAsync(describe())
|
|
95
117
|
: Promise.resolve(this.device.createRenderPipeline(describe()));
|
|
96
118
|
const promise = build.then((built) => {
|
|
97
|
-
|
|
119
|
+
/* A lit pipeline started before a switch is not kept: the switch rebuilds it. */
|
|
120
|
+
if (!lit || generation === this.litGeneration)
|
|
121
|
+
this.pipelines.set(key, built);
|
|
98
122
|
this.compiling.delete(key);
|
|
99
123
|
return built;
|
|
100
124
|
});
|
|
@@ -129,7 +153,11 @@ export class PipelineCache {
|
|
|
129
153
|
* too**: a nested object with vertex buffer layouts and blend state, constructed to be
|
|
130
154
|
* thrown away on every hit. Passing a function means a hit costs one `Map` lookup.
|
|
131
155
|
*/
|
|
132
|
-
get(key, describe
|
|
156
|
+
get(key, describe,
|
|
157
|
+
/** Whether this is a lit pipeline, which `enable` rebuilds. See `litSwitches`. */
|
|
158
|
+
lit = false) {
|
|
159
|
+
if (lit)
|
|
160
|
+
this.litDescribers.set(key, describe);
|
|
133
161
|
const existing = this.pipelines.get(key);
|
|
134
162
|
if (existing !== undefined)
|
|
135
163
|
return existing;
|
|
@@ -137,6 +165,45 @@ export class PipelineCache {
|
|
|
137
165
|
this.pipelines.set(key, built);
|
|
138
166
|
return built;
|
|
139
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Turn one of the lit stage's switches on, for every lit pipeline built from now on and every one
|
|
170
|
+
* already built. See `litSwitches`.
|
|
171
|
+
*
|
|
172
|
+
* **The rebuilt set lands at once**, when every one of them has compiled, so no frame draws some
|
|
173
|
+
* surfaces with a feature and others without. Until then the pipelines already built go on drawing
|
|
174
|
+
* as they were. Once only: a switch is not turned off again when the last user of it leaves,
|
|
175
|
+
* because a second switch would cost a second compile for a saving the first use showed was not
|
|
176
|
+
* needed. Glass is never turned on where the profile asked for no glass shadows.
|
|
177
|
+
*/
|
|
178
|
+
enable(feature) {
|
|
179
|
+
if (this.litSwitches[feature])
|
|
180
|
+
return this.litRebuild;
|
|
181
|
+
if (feature === 'GLASS_SHADOWS' && !this.glassShadows)
|
|
182
|
+
return this.litRebuild;
|
|
183
|
+
this.litSwitches[feature] = true;
|
|
184
|
+
this.litGeneration += 1;
|
|
185
|
+
const generation = this.litGeneration;
|
|
186
|
+
this.litRebuild = this.litRebuild.then(async () => {
|
|
187
|
+
/* A later switch has its own rebuild, which describes every pipeline with this one on too. */
|
|
188
|
+
if (generation !== this.litGeneration)
|
|
189
|
+
return;
|
|
190
|
+
const rebuilt = [...this.litDescribers].map(([key, describe]) => {
|
|
191
|
+
const descriptor = describe();
|
|
192
|
+
const build = typeof this.device.createRenderPipelineAsync === 'function'
|
|
193
|
+
? this.device.createRenderPipelineAsync(descriptor)
|
|
194
|
+
: Promise.resolve(this.device.createRenderPipeline(descriptor));
|
|
195
|
+
return build.then((pipeline) => [key, pipeline]);
|
|
196
|
+
});
|
|
197
|
+
const results = await Promise.allSettled(rebuilt);
|
|
198
|
+
if (generation !== this.litGeneration)
|
|
199
|
+
return;
|
|
200
|
+
for (const result of results) {
|
|
201
|
+
if (result.status === 'fulfilled')
|
|
202
|
+
this.pipelines.set(result.value[0], result.value[1]);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return this.litRebuild;
|
|
206
|
+
}
|
|
140
207
|
/**
|
|
141
208
|
* Drop every pipeline.
|
|
142
209
|
*
|
|
@@ -6,6 +6,7 @@ import { FIRE_BINDINGS } from '../../shaders/generated/fire.wgsl.js';
|
|
|
6
6
|
import { SMOKE_BINDINGS } from '../../shaders/generated/smoke.wgsl.js';
|
|
7
7
|
import { DEPTH_FORMAT } from './flatPass.js';
|
|
8
8
|
import { shaderModule } from './shaderModules.js';
|
|
9
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.js';
|
|
9
10
|
/**
|
|
10
11
|
* The plume pass: crossed quads per plume, displaced and faded in the shaders.
|
|
11
12
|
*
|
|
@@ -179,7 +180,7 @@ function blendState(blend) {
|
|
|
179
180
|
}
|
|
180
181
|
: {
|
|
181
182
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
182
|
-
alpha:
|
|
183
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
183
184
|
};
|
|
184
185
|
}
|
|
185
186
|
/**
|
|
@@ -156,8 +156,10 @@ export declare const OIT_COMPOSITE_BLEND: GPUBlendState;
|
|
|
156
156
|
* exactly the integral — and the composite therefore never samples the colour it is modifying,
|
|
157
157
|
* which is the read both backends are entitled to call undefined.
|
|
158
158
|
*
|
|
159
|
-
* Alpha is
|
|
160
|
-
*
|
|
159
|
+
* Alpha is the transmittance again, `share * a`: the scene's alpha is how much of the pixel is
|
|
160
|
+
* still the opaque surface, which is what the composite lets ambient occlusion darken, and a
|
|
161
|
+
* medium thick enough to hide a corner hides its occlusion too (`sceneCoverage.ts`). It reaches
|
|
162
|
+
* no canvas: both are opaque, and the composite writes 1.
|
|
161
163
|
*/
|
|
162
164
|
export declare const MEDIUM_TRANSMIT_BLEND: GPUBlendState;
|
|
163
165
|
export declare const DECAL_MULTIPLY_BLEND: GPUBlendState;
|
|
@@ -170,6 +172,14 @@ export declare const DECAL_MULTIPLY_BLEND: GPUBlendState;
|
|
|
170
172
|
* sample the colour it is compositing onto.
|
|
171
173
|
*/
|
|
172
174
|
export declare const PREMULTIPLIED_OVER_BLEND: GPUBlendState;
|
|
175
|
+
/**
|
|
176
|
+
* The same `over` for the resolve that lands a reflection on the scene, keeping the scene's alpha.
|
|
177
|
+
*
|
|
178
|
+
* A reflection is a layer of the surface it is seen in, so the surface's share of the pixel is
|
|
179
|
+
* unchanged (`sceneCoverage.ts`). The trace keeps `PREMULTIPLIED_OVER_BLEND`, because its target is
|
|
180
|
+
* the reflection's own and its alpha is the coverage this resolve reads.
|
|
181
|
+
*/
|
|
182
|
+
export declare const REFLECTION_OVER_BLEND: GPUBlendState;
|
|
173
183
|
export declare const ADDITIVE_BLEND: GPUBlendState;
|
|
174
184
|
/** A fullscreen pass over one or more inputs, writing to one colour target. */
|
|
175
185
|
export declare function postPipeline(cache: PipelineCache, device: GPUDevice, layout: GPUBindGroupLayout, key: string, fragment: string, format: GPUTextureFormat, blend?: GPUBlendState): GPURenderPipeline;
|
|
@@ -9,6 +9,7 @@ import { SSRTRACE_BINDINGS as SSR_BINDINGS, SSR_TRACE_FRAG_WGSL, } from '../../s
|
|
|
9
9
|
import { SSRRESOLVE_BINDINGS as SSR_RESOLVE_BINDINGS, SSR_RESOLVE_FRAG_WGSL, } from '../../shaders/generated/ssrResolve.wgsl.js';
|
|
10
10
|
import { GLOBALMEDIUM_BINDINGS as MEDIUM_BINDINGS, MEDIUM_FRAG_WGSL, MEDIUM_UPSAMPLE_FRAG_WGSL, } from '../../shaders/generated/globalMedium.wgsl.js';
|
|
11
11
|
import { shaderModule } from './shaderModules.js';
|
|
12
|
+
import { SCENE_ALPHA_KEEPS, SCENE_ALPHA_TRANSMITS } from '../../sceneCoverage.js';
|
|
12
13
|
/**
|
|
13
14
|
* The composite: everything that happens to the frame after the world is drawn.
|
|
14
15
|
*
|
|
@@ -197,7 +198,7 @@ export function createPostStageLayout(device, uniformBinding, uniformSize, textu
|
|
|
197
198
|
*/
|
|
198
199
|
export const OIT_COMPOSITE_BLEND = {
|
|
199
200
|
color: { srcFactor: 'one-minus-src-alpha', dstFactor: 'src-alpha', operation: 'add' },
|
|
200
|
-
alpha:
|
|
201
|
+
alpha: SCENE_ALPHA_TRANSMITS,
|
|
201
202
|
};
|
|
202
203
|
/**
|
|
203
204
|
* What a drawn decal does to the pixel under it: `dst * src`.
|
|
@@ -215,16 +216,18 @@ export const OIT_COMPOSITE_BLEND = {
|
|
|
215
216
|
* exactly the integral — and the composite therefore never samples the colour it is modifying,
|
|
216
217
|
* which is the read both backends are entitled to call undefined.
|
|
217
218
|
*
|
|
218
|
-
* Alpha is
|
|
219
|
-
*
|
|
219
|
+
* Alpha is the transmittance again, `share * a`: the scene's alpha is how much of the pixel is
|
|
220
|
+
* still the opaque surface, which is what the composite lets ambient occlusion darken, and a
|
|
221
|
+
* medium thick enough to hide a corner hides its occlusion too (`sceneCoverage.ts`). It reaches
|
|
222
|
+
* no canvas: both are opaque, and the composite writes 1.
|
|
220
223
|
*/
|
|
221
224
|
export const MEDIUM_TRANSMIT_BLEND = {
|
|
222
225
|
color: { srcFactor: 'one', dstFactor: 'src-alpha', operation: 'add' },
|
|
223
|
-
alpha:
|
|
226
|
+
alpha: SCENE_ALPHA_TRANSMITS,
|
|
224
227
|
};
|
|
225
228
|
export const DECAL_MULTIPLY_BLEND = {
|
|
226
229
|
color: { srcFactor: 'zero', dstFactor: 'src', operation: 'add' },
|
|
227
|
-
alpha:
|
|
230
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
228
231
|
};
|
|
229
232
|
/**
|
|
230
233
|
* `over`, against colour a pass has already multiplied by its own coverage.
|
|
@@ -238,6 +241,17 @@ export const PREMULTIPLIED_OVER_BLEND = {
|
|
|
238
241
|
color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
239
242
|
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
240
243
|
};
|
|
244
|
+
/**
|
|
245
|
+
* The same `over` for the resolve that lands a reflection on the scene, keeping the scene's alpha.
|
|
246
|
+
*
|
|
247
|
+
* A reflection is a layer of the surface it is seen in, so the surface's share of the pixel is
|
|
248
|
+
* unchanged (`sceneCoverage.ts`). The trace keeps `PREMULTIPLIED_OVER_BLEND`, because its target is
|
|
249
|
+
* the reflection's own and its alpha is the coverage this resolve reads.
|
|
250
|
+
*/
|
|
251
|
+
export const REFLECTION_OVER_BLEND = {
|
|
252
|
+
color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
253
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
254
|
+
};
|
|
241
255
|
export const ADDITIVE_BLEND = {
|
|
242
256
|
color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|
|
243
257
|
alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|