@driftengine/core 4.8.7 → 4.10.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 +123 -11
- package/README.md +43 -38
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -3
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/atmosphere.d.ts +13 -0
- package/dist/render/atmosphere.js +9 -1
- package/dist/render/backend/api.d.ts +19 -4
- package/dist/render/backend/createRenderer.d.ts +6 -0
- package/dist/render/backend/createRenderer.js +4 -1
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +180 -4
- package/dist/render/backend/webgl2/renderer.js +550 -40
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +19 -4
- package/dist/render/backend/webgpu/buffers.js +18 -11
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/device.d.ts +7 -1
- package/dist/render/backend/webgpu/device.js +31 -3
- package/dist/render/backend/webgpu/drawCommand.d.ts +18 -4
- package/dist/render/backend/webgpu/drawCommand.js +10 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +100 -42
- package/dist/render/backend/webgpu/flatPass.js +191 -43
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +6 -0
- package/dist/render/backend/webgpu/pipelineCache.js +7 -0
- package/dist/render/backend/webgpu/postPass.d.ts +51 -9
- package/dist/render/backend/webgpu/postPass.js +16 -2
- package/dist/render/backend/webgpu/reflectionSurfacePass.d.ts +30 -0
- package/dist/render/backend/webgpu/reflectionSurfacePass.js +100 -0
- package/dist/render/backend/webgpu/renderer.d.ts +283 -37
- package/dist/render/backend/webgpu/renderer.js +1363 -202
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +241 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/displayRange.d.ts +31 -0
- package/dist/render/displayRange.js +47 -0
- package/dist/render/filmicCurve.d.ts +74 -0
- package/dist/render/filmicCurve.js +203 -0
- package/dist/render/fog.d.ts +4 -1
- package/dist/render/fog.js +12 -2
- package/dist/render/frame/resources.d.ts +2 -2
- package/dist/render/frame/resources.js +6 -0
- package/dist/render/frameReflections.d.ts +40 -0
- package/dist/render/frameReflections.js +48 -0
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +5 -0
- package/dist/render/mesh.js +6 -0
- package/dist/render/pass.d.ts +49 -0
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/reflectionSurfaceTargets.d.ts +28 -0
- package/dist/render/reflectionSurfaceTargets.js +99 -0
- package/dist/render/renderQuality.d.ts +39 -8
- package/dist/render/renderQuality.js +4 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +24 -1
- package/dist/render/screenSpaceReflection.d.ts +7 -1
- package/dist/render/screenSpaceReflection.js +5 -0
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/filmLook.js +2 -1
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +2 -0
- package/dist/render/shaders/flat/index.d.ts +16 -0
- package/dist/render/shaders/flat/index.js +33 -5
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +43 -5
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/overlay.d.ts +16 -0
- package/dist/render/shaders/flat/overlay.js +117 -0
- package/dist/render/shaders/flat/pointShadow.js +3 -3
- package/dist/render/shaders/flat/preamble.js +38 -24
- package/dist/render/shaders/flat/reflectionSurface.d.ts +21 -0
- package/dist/render/shaders/flat/reflectionSurface.js +61 -0
- package/dist/render/shaders/fog.d.ts +1 -1
- package/dist/render/shaders/fog.js +9 -2
- package/dist/render/shaders/fringe.d.ts +29 -0
- package/dist/render/shaders/fringe.js +55 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.js +1 -1
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/film.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/film.wgsl.js +1 -1
- package/dist/render/shaders/generated/fire.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/fire.wgsl.js +1 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3254 -2920
- package/dist/render/shaders/generated/flat.wgsl.js +3292 -2957
- 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 +4 -4
- package/dist/render/shaders/generated/particle.wgsl.js +4 -4
- package/dist/render/shaders/generated/rush.wgsl.d.ts +56 -26
- package/dist/render/shaders/generated/rush.wgsl.js +56 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/scatter.wgsl.js +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +1 -1
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +22 -2
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +22 -2
- package/dist/render/shaders/generated/water.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/water.wgsl.js +1 -1
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +2 -2
- package/dist/render/shaders/gpudriven/fog.wgsl.js +11 -3
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/rush.js +54 -11
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/ssrResolve.d.ts +17 -0
- package/dist/render/shaders/ssrResolve.js +51 -0
- package/dist/render/shaders/ssrTrace.js +26 -0
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/ssrPass.d.ts +16 -0
- package/dist/render/ssrPass.js +106 -1
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceOverlay.d.ts +132 -0
- package/dist/render/surfaceOverlay.js +85 -0
- package/dist/render/surfaceTexture.d.ts +57 -7
- package/dist/render/surfaceTexture.js +125 -17
- package/dist/render/temporalAa.d.ts +14 -0
- package/dist/render/temporalAa.js +20 -0
- package/dist/render/vertexDefaults.d.ts +17 -0
- package/dist/render/vertexDefaults.js +24 -0
- package/package.json +6 -6
- package/src/index.ts +24 -2
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/atmosphere.ts +22 -1
- package/src/render/backend/api.ts +22 -3
- package/src/render/backend/createRenderer.ts +18 -1
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +672 -37
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +42 -16
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/device.ts +42 -3
- package/src/render/backend/webgpu/drawCommand.ts +22 -4
- package/src/render/backend/webgpu/flatPass.ts +250 -40
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/pipelineCache.ts +7 -0
- package/src/render/backend/webgpu/postPass.ts +18 -0
- package/src/render/backend/webgpu/reflectionSurfacePass.ts +114 -0
- package/src/render/backend/webgpu/renderer.ts +1655 -230
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +363 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/displayRange.ts +61 -0
- package/src/render/filmicCurve.ts +229 -0
- package/src/render/fog.ts +19 -3
- package/src/render/frame/resources.ts +6 -0
- package/src/render/frameReflections.ts +72 -0
- package/src/render/glCompressed.ts +83 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +6 -0
- package/src/render/pass.ts +53 -1
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/reflectionSurfaceTargets.ts +105 -0
- package/src/render/renderQuality.ts +44 -8
- package/src/render/sceneTarget.ts +30 -2
- package/src/render/screenSpaceReflection.ts +7 -1
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/filmLook.ts +2 -1
- package/src/render/shaders/flat/glassTint.ts +5 -1
- package/src/render/shaders/flat/index.ts +49 -5
- package/src/render/shaders/flat/main.ts +43 -5
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/overlay.ts +117 -0
- package/src/render/shaders/flat/pointShadow.ts +3 -3
- package/src/render/shaders/flat/preamble.ts +38 -24
- package/src/render/shaders/flat/reflectionSurface.ts +61 -0
- package/src/render/shaders/fog.ts +9 -2
- package/src/render/shaders/fringe.ts +59 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +1 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/caustics.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/film.wgsl.ts +1 -1
- package/src/render/shaders/generated/fire.wgsl.ts +1 -1
- package/src/render/shaders/generated/flat.wgsl.ts +3292 -2957
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +4 -4
- package/src/render/shaders/generated/rush.wgsl.ts +56 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +1 -1
- package/src/render/shaders/generated/smoke.wgsl.ts +1 -1
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +22 -2
- package/src/render/shaders/generated/water.wgsl.ts +1 -1
- package/src/render/shaders/gpudriven/fog.wgsl.ts +11 -3
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/rush.ts +54 -11
- package/src/render/shaders/ssrResolve.ts +52 -0
- package/src/render/shaders/ssrTrace.ts +26 -0
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/ssrPass.ts +138 -1
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceOverlay.ts +195 -0
- package/src/render/surfaceTexture.ts +161 -27
- package/src/render/temporalAa.ts +20 -0
- package/src/render/vertexDefaults.ts +28 -0
|
@@ -19,9 +19,11 @@ export declare class SkinPaletteTexture {
|
|
|
19
19
|
/**
|
|
20
20
|
* Upload a palette, reallocating only when the joint count changes.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* **The texture grows and never shrinks**, so the steady state is one `texSubImage2D` whatever
|
|
23
|
+
* mix of rigs a frame draws. It was rebuilt whenever the joint count changed, which with one
|
|
24
|
+
* texture for every skinned draw meant a character and a prop drawn in turn reallocated it at
|
|
25
|
+
* every draw: a GPU allocation in the frame loop. The shader reads joints by index, so a texture
|
|
26
|
+
* wider than the rig is read exactly as one that fits.
|
|
25
27
|
*/
|
|
26
28
|
update(gl: WebGL2RenderingContext, palette: Float32Array): void;
|
|
27
29
|
/** Bind to a **vertex-stage** unit. See `SKIN_PALETTE_TEXTURE_UNIT` for why that is free. */
|
|
@@ -20,15 +20,17 @@ export class SkinPaletteTexture {
|
|
|
20
20
|
/**
|
|
21
21
|
* Upload a palette, reallocating only when the joint count changes.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* **The texture grows and never shrinks**, so the steady state is one `texSubImage2D` whatever
|
|
24
|
+
* mix of rigs a frame draws. It was rebuilt whenever the joint count changed, which with one
|
|
25
|
+
* texture for every skinned draw meant a character and a prop drawn in turn reallocated it at
|
|
26
|
+
* every draw: a GPU allocation in the frame loop. The shader reads joints by index, so a texture
|
|
27
|
+
* wider than the rig is read exactly as one that fits.
|
|
26
28
|
*/
|
|
27
29
|
update(gl, palette) {
|
|
28
30
|
validateSkinPalette(palette);
|
|
29
31
|
const joints = palette.length / 16;
|
|
30
32
|
const width = paletteTextureWidth(joints);
|
|
31
|
-
if (this.texture === null ||
|
|
33
|
+
if (this.texture === null || joints > this.joints) {
|
|
32
34
|
if (this.texture !== null)
|
|
33
35
|
gl.deleteTexture(this.texture);
|
|
34
36
|
const created = gl.createTexture();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bone animation's textures on this backend, and a batch's clocks: what
|
|
3
|
+
* `shaders/boneAnimation.ts` reads by index, made once and never filtered.
|
|
4
|
+
*
|
|
5
|
+
* **`rgba32float` places and turns, and `rg32float` clocks**, all read with `textureLoad` and bound
|
|
6
|
+
* `unfilterable-float`, as the joint palette is: a turn in half floats moves a crowd's hands by a
|
|
7
|
+
* thousandth of their reach, a jitter at the frame's rate, and the bytes are a clip's, once.
|
|
8
|
+
*/
|
|
9
|
+
import { type BoneAnimationHandle, type BoneAnimationTexels } from '../../boneAnimation.ts';
|
|
10
|
+
/** A clip on the device, from `createBoneAnimation`. */
|
|
11
|
+
export declare class GpuBoneAnimation implements BoneAnimationHandle {
|
|
12
|
+
readonly bones: number;
|
|
13
|
+
readonly frames: number;
|
|
14
|
+
readonly framesPerSecond: number;
|
|
15
|
+
readonly boneScale: number;
|
|
16
|
+
readonly placesView: GPUTextureView;
|
|
17
|
+
readonly turnsView: GPUTextureView;
|
|
18
|
+
disposed: boolean;
|
|
19
|
+
private readonly places;
|
|
20
|
+
private readonly turns;
|
|
21
|
+
constructor(device: GPUDevice, texels: BoneAnimationTexels);
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
24
|
+
/** A batch's clocks: two floats an instance, wrapped onto rows `CLOCK_TEXTURE_WIDTH` wide. */
|
|
25
|
+
export declare class GpuInstanceClocks {
|
|
26
|
+
readonly view: GPUTextureView;
|
|
27
|
+
readonly staging: Float32Array;
|
|
28
|
+
private readonly texture;
|
|
29
|
+
private readonly width;
|
|
30
|
+
constructor(device: GPUDevice, capacity: number, label: string);
|
|
31
|
+
/** The rows that hold the first `count` instances, from `staging`. */
|
|
32
|
+
upload(queue: GPUQueue, count: number): void;
|
|
33
|
+
dispose(): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bone animation's textures on this backend, and a batch's clocks: what
|
|
3
|
+
* `shaders/boneAnimation.ts` reads by index, made once and never filtered.
|
|
4
|
+
*
|
|
5
|
+
* **`rgba32float` places and turns, and `rg32float` clocks**, all read with `textureLoad` and bound
|
|
6
|
+
* `unfilterable-float`, as the joint palette is: a turn in half floats moves a crowd's hands by a
|
|
7
|
+
* thousandth of their reach, a jitter at the frame's rate, and the bytes are a clip's, once.
|
|
8
|
+
*/
|
|
9
|
+
import { CLOCK_TEXTURE_WIDTH, } from '../../boneAnimation.js';
|
|
10
|
+
const USAGE_TEXTURE = 0x4 | 0x2; // TEXTURE_BINDING | COPY_DST
|
|
11
|
+
/** A clip on the device, from `createBoneAnimation`. */
|
|
12
|
+
export class GpuBoneAnimation {
|
|
13
|
+
bones;
|
|
14
|
+
frames;
|
|
15
|
+
framesPerSecond;
|
|
16
|
+
boneScale;
|
|
17
|
+
placesView;
|
|
18
|
+
turnsView;
|
|
19
|
+
disposed = false;
|
|
20
|
+
places;
|
|
21
|
+
turns;
|
|
22
|
+
constructor(device, texels) {
|
|
23
|
+
this.bones = texels.bones;
|
|
24
|
+
this.frames = texels.frames;
|
|
25
|
+
this.framesPerSecond = texels.framesPerSecond;
|
|
26
|
+
this.boneScale = texels.boneScale;
|
|
27
|
+
const make = (label, data) => {
|
|
28
|
+
const texture = device.createTexture({
|
|
29
|
+
label,
|
|
30
|
+
size: [texels.bones, texels.frames],
|
|
31
|
+
format: 'rgba32float',
|
|
32
|
+
usage: USAGE_TEXTURE,
|
|
33
|
+
});
|
|
34
|
+
device.queue.writeTexture({ texture }, data, { bytesPerRow: texels.bones * 16, rowsPerImage: texels.frames }, [texels.bones, texels.frames]);
|
|
35
|
+
return texture;
|
|
36
|
+
};
|
|
37
|
+
this.places = make('bones.places', texels.places);
|
|
38
|
+
this.turns = make('bones.turns', texels.turns);
|
|
39
|
+
this.placesView = this.places.createView();
|
|
40
|
+
this.turnsView = this.turns.createView();
|
|
41
|
+
}
|
|
42
|
+
dispose() {
|
|
43
|
+
this.disposed = true;
|
|
44
|
+
this.places.destroy();
|
|
45
|
+
this.turns.destroy();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** A batch's clocks: two floats an instance, wrapped onto rows `CLOCK_TEXTURE_WIDTH` wide. */
|
|
49
|
+
export class GpuInstanceClocks {
|
|
50
|
+
view;
|
|
51
|
+
staging;
|
|
52
|
+
texture;
|
|
53
|
+
width;
|
|
54
|
+
constructor(device, capacity, label) {
|
|
55
|
+
this.width = Math.max(1, Math.min(capacity, CLOCK_TEXTURE_WIDTH));
|
|
56
|
+
const rows = Math.max(1, Math.ceil(capacity / this.width));
|
|
57
|
+
this.staging = new Float32Array(this.width * rows * 2);
|
|
58
|
+
this.texture = device.createTexture({
|
|
59
|
+
label,
|
|
60
|
+
size: [this.width, rows],
|
|
61
|
+
format: 'rg32float',
|
|
62
|
+
usage: USAGE_TEXTURE,
|
|
63
|
+
});
|
|
64
|
+
this.view = this.texture.createView();
|
|
65
|
+
}
|
|
66
|
+
/** The rows that hold the first `count` instances, from `staging`. */
|
|
67
|
+
upload(queue, count) {
|
|
68
|
+
if (count <= 0)
|
|
69
|
+
return;
|
|
70
|
+
const rows = Math.ceil(count / this.width);
|
|
71
|
+
queue.writeTexture({ texture: this.texture }, this.staging, { bytesPerRow: this.width * 8, rowsPerImage: rows }, [this.width, rows]);
|
|
72
|
+
}
|
|
73
|
+
dispose() {
|
|
74
|
+
this.texture.destroy();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -156,18 +156,33 @@ export interface GpuMesh {
|
|
|
156
156
|
* changed, reported at 2.8 MB a frame for one character. What the split costs is a pipeline per
|
|
157
157
|
* layout, keyed by `:dynamic`, and two more buffers bound per draw of such a mesh.
|
|
158
158
|
*/
|
|
159
|
-
readonly update: ((device: GPUDevice, positions: Float32Array, normals?: Float32Array,
|
|
159
|
+
readonly update: ((device: GPUDevice, positions: Float32Array, normals?: Float32Array, staged?: StagedRewrite | null) => void) | null;
|
|
160
160
|
/**
|
|
161
|
-
* A dynamic mesh's motion state, which the renderer owns: a buffer for last frame's positions
|
|
162
|
-
*
|
|
163
|
-
*
|
|
161
|
+
* A dynamic mesh's motion state, which the renderer owns: a buffer for last frame's positions and
|
|
162
|
+
* one the new positions are staged in, each made the first time a reconstructing renderer
|
|
163
|
+
* rewrites the mesh, and the frame of the last rewrite. Null on a mesh created without
|
|
164
|
+
* `{ dynamic: true }`, which never moves a vertex.
|
|
164
165
|
*/
|
|
165
166
|
readonly motion: {
|
|
166
167
|
previous: GPUBuffer | null;
|
|
168
|
+
staging: GPUBuffer | null;
|
|
167
169
|
changed: number;
|
|
168
170
|
} | null;
|
|
169
171
|
dispose(): void;
|
|
170
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* A rewrite a reconstructing renderer stages rather than writes, so last frame's positions can be
|
|
175
|
+
* kept with no submit of the rewrite's own: the new positions are written into `staging`, and two
|
|
176
|
+
* copies are recorded into `encoder` — the live positions into `previous` first, where the frame's
|
|
177
|
+
* first rewrite keeps them, then the staged ones in. The renderer submits that encoder at the head
|
|
178
|
+
* of the frame's next submit, which is what keeps both copies ahead of every draw that reads the
|
|
179
|
+
* mesh. A `writeBuffer` straight to the live positions would land before the copy aside could run.
|
|
180
|
+
*/
|
|
181
|
+
export interface StagedRewrite {
|
|
182
|
+
encoder: GPUCommandEncoder;
|
|
183
|
+
staging: GPUBuffer;
|
|
184
|
+
previous: GPUBuffer | null;
|
|
185
|
+
}
|
|
171
186
|
/** A mesh on its way to the device, and the iterator that gets it there. */
|
|
172
187
|
export interface IncrementalGpuMesh {
|
|
173
188
|
/**
|
|
@@ -408,7 +408,9 @@ function skinOffsetsOf(supplied) {
|
|
|
408
408
|
}
|
|
409
409
|
/** The handle, made where it can see only what it hands out. */
|
|
410
410
|
function gpuMeshOf(parts) {
|
|
411
|
-
const motion = parts.update === null
|
|
411
|
+
const motion = parts.update === null
|
|
412
|
+
? null
|
|
413
|
+
: { previous: null, staging: null, changed: -1 };
|
|
412
414
|
const { vertices, constants, streams, indexBuffer, progress } = parts;
|
|
413
415
|
return {
|
|
414
416
|
vertexBuffers: streams === null
|
|
@@ -433,6 +435,7 @@ function gpuMeshOf(parts) {
|
|
|
433
435
|
motion,
|
|
434
436
|
dispose() {
|
|
435
437
|
motion?.previous?.destroy();
|
|
438
|
+
motion?.staging?.destroy();
|
|
436
439
|
streams?.positions.destroy();
|
|
437
440
|
streams?.normals.destroy();
|
|
438
441
|
vertices.destroy();
|
|
@@ -447,12 +450,12 @@ function isStreamed(attribute) {
|
|
|
447
450
|
}
|
|
448
451
|
/**
|
|
449
452
|
* A dynamic mesh's `update`: the caller's positions, and its normals where it has them, each
|
|
450
|
-
* written to its own buffer as it came
|
|
451
|
-
*
|
|
452
|
-
* of
|
|
453
|
+
* written to its own buffer as it came — or, where a reconstruction keeps last frame's positions,
|
|
454
|
+
* the positions staged and copied in on the device behind the copy aside (`StagedRewrite`), so no
|
|
455
|
+
* CPU copy of anything is kept and the rewrite submits nothing of its own.
|
|
453
456
|
*/
|
|
454
457
|
function streamUpdate(positionsBuffer, normalsBuffer, streamBytes, bounds, vertexCount) {
|
|
455
|
-
return (target, positions, normals,
|
|
458
|
+
return (target, positions, normals, staged = null) => {
|
|
456
459
|
for (const [name, values] of [
|
|
457
460
|
['update', positions],
|
|
458
461
|
['normals', normals],
|
|
@@ -463,15 +466,19 @@ function streamUpdate(positionsBuffer, normalsBuffer, streamBytes, bounds, verte
|
|
|
463
466
|
"A mesh's vertex count is fixed at creation: the index buffer, the pipeline and " +
|
|
464
467
|
'every other attribute are sized against it.');
|
|
465
468
|
}
|
|
466
|
-
if (previous !== null) {
|
|
467
|
-
const encoder = target.createCommandEncoder({ label: 'mesh.previousPositions' });
|
|
468
|
-
encoder.copyBufferToBuffer(positionsBuffer, 0, previous, 0, streamBytes);
|
|
469
|
-
target.queue.submit([encoder.finish()]);
|
|
470
|
-
}
|
|
471
469
|
/* Everything that decides whether this is on screen starts from the bounds, so a cloth
|
|
472
470
|
that blew sideways out of its original box would be culled while still visible. */
|
|
473
471
|
boundsOfPositions(positions, bounds);
|
|
474
|
-
|
|
472
|
+
if (staged === null) {
|
|
473
|
+
target.queue.writeBuffer(positionsBuffer, 0, positions);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
target.queue.writeBuffer(staged.staging, 0, positions);
|
|
477
|
+
if (staged.previous !== null) {
|
|
478
|
+
staged.encoder.copyBufferToBuffer(positionsBuffer, 0, staged.previous, 0, streamBytes);
|
|
479
|
+
}
|
|
480
|
+
staged.encoder.copyBufferToBuffer(staged.staging, 0, positionsBuffer, 0, streamBytes);
|
|
481
|
+
}
|
|
475
482
|
if (normals !== undefined)
|
|
476
483
|
target.queue.writeBuffer(normalsBuffer, 0, normals);
|
|
477
484
|
};
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
* the level nominally has.
|
|
13
13
|
*/
|
|
14
14
|
import type { CompressedTextureFormat, CompressedTextureSource } from '../../compressedSource.ts';
|
|
15
|
-
/** Every BC format, where the device carries the feature; none where it does not. */
|
|
16
15
|
export declare function gpuCompressedFormats(device: GPUDevice): CompressedTextureFormat[];
|
|
17
16
|
/** A texture holding `layers` as `name`, `levels` levels of each, written as they are. */
|
|
18
17
|
export declare function createCompressedTexture(device: GPUDevice, name: CompressedTextureFormat, layers: readonly CompressedTextureSource[], levels: number): GPUTexture;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BLOCK_SHAPES, blockFamily } from '../../compressedSource.js';
|
|
2
2
|
const GPU_FORMAT = {
|
|
3
3
|
bc1: 'bc1-rgba-unorm',
|
|
4
4
|
'bc1-srgb': 'bc1-rgba-unorm-srgb',
|
|
@@ -10,28 +10,73 @@ const GPU_FORMAT = {
|
|
|
10
10
|
bc5: 'bc5-rg-unorm',
|
|
11
11
|
bc7: 'bc7-rgba-unorm',
|
|
12
12
|
'bc7-srgb': 'bc7-rgba-unorm-srgb',
|
|
13
|
+
'etc2-rgb8': 'etc2-rgb8unorm',
|
|
14
|
+
'etc2-rgb8-srgb': 'etc2-rgb8unorm-srgb',
|
|
15
|
+
'etc2-rgb8a1': 'etc2-rgb8a1unorm',
|
|
16
|
+
'etc2-rgb8a1-srgb': 'etc2-rgb8a1unorm-srgb',
|
|
17
|
+
'etc2-rgba8': 'etc2-rgba8unorm',
|
|
18
|
+
'etc2-rgba8-srgb': 'etc2-rgba8unorm-srgb',
|
|
19
|
+
'eac-r11': 'eac-r11unorm',
|
|
20
|
+
'eac-rg11': 'eac-rg11unorm',
|
|
21
|
+
'astc-4x4': 'astc-4x4-unorm',
|
|
22
|
+
'astc-4x4-srgb': 'astc-4x4-unorm-srgb',
|
|
23
|
+
'astc-5x4': 'astc-5x4-unorm',
|
|
24
|
+
'astc-5x4-srgb': 'astc-5x4-unorm-srgb',
|
|
25
|
+
'astc-5x5': 'astc-5x5-unorm',
|
|
26
|
+
'astc-5x5-srgb': 'astc-5x5-unorm-srgb',
|
|
27
|
+
'astc-6x5': 'astc-6x5-unorm',
|
|
28
|
+
'astc-6x5-srgb': 'astc-6x5-unorm-srgb',
|
|
29
|
+
'astc-6x6': 'astc-6x6-unorm',
|
|
30
|
+
'astc-6x6-srgb': 'astc-6x6-unorm-srgb',
|
|
31
|
+
'astc-8x5': 'astc-8x5-unorm',
|
|
32
|
+
'astc-8x5-srgb': 'astc-8x5-unorm-srgb',
|
|
33
|
+
'astc-8x6': 'astc-8x6-unorm',
|
|
34
|
+
'astc-8x6-srgb': 'astc-8x6-unorm-srgb',
|
|
35
|
+
'astc-8x8': 'astc-8x8-unorm',
|
|
36
|
+
'astc-8x8-srgb': 'astc-8x8-unorm-srgb',
|
|
37
|
+
'astc-10x5': 'astc-10x5-unorm',
|
|
38
|
+
'astc-10x5-srgb': 'astc-10x5-unorm-srgb',
|
|
39
|
+
'astc-10x6': 'astc-10x6-unorm',
|
|
40
|
+
'astc-10x6-srgb': 'astc-10x6-unorm-srgb',
|
|
41
|
+
'astc-10x8': 'astc-10x8-unorm',
|
|
42
|
+
'astc-10x8-srgb': 'astc-10x8-unorm-srgb',
|
|
43
|
+
'astc-10x10': 'astc-10x10-unorm',
|
|
44
|
+
'astc-10x10-srgb': 'astc-10x10-unorm-srgb',
|
|
45
|
+
'astc-12x10': 'astc-12x10-unorm',
|
|
46
|
+
'astc-12x10-srgb': 'astc-12x10-unorm-srgb',
|
|
47
|
+
'astc-12x12': 'astc-12x12-unorm',
|
|
48
|
+
'astc-12x12-srgb': 'astc-12x12-unorm-srgb',
|
|
13
49
|
};
|
|
14
50
|
/** Every BC format, where the device carries the feature; none where it does not. */
|
|
51
|
+
/** The feature that grants each family, which `select.ts` asks for wherever the adapter offers it. */
|
|
52
|
+
const FEATURE = {
|
|
53
|
+
bc: 'texture-compression-bc',
|
|
54
|
+
etc2: 'texture-compression-etc2',
|
|
55
|
+
astc: 'texture-compression-astc',
|
|
56
|
+
};
|
|
15
57
|
export function gpuCompressedFormats(device) {
|
|
16
|
-
return device.features.has(
|
|
17
|
-
|
|
18
|
-
|
|
58
|
+
return Object.keys(GPU_FORMAT).filter((name) => device.features.has(FEATURE[blockFamily(baseOf(name))]));
|
|
59
|
+
}
|
|
60
|
+
/** The format a name is of, without its colour space. */
|
|
61
|
+
function baseOf(name) {
|
|
62
|
+
return (name.endsWith('-srgb') ? name.slice(0, -'-srgb'.length) : name);
|
|
19
63
|
}
|
|
20
64
|
/** A texture holding `layers` as `name`, `levels` levels of each, written as they are. */
|
|
21
65
|
export function createCompressedTexture(device, name, layers, levels) {
|
|
22
66
|
const { format, width, height } = layers[0];
|
|
23
67
|
const texture = device.createTexture({
|
|
24
|
-
label:
|
|
68
|
+
label: `surface.texture.${format}`,
|
|
25
69
|
size: [width, height, layers.length],
|
|
26
70
|
format: GPU_FORMAT[name],
|
|
27
71
|
mipLevelCount: levels,
|
|
28
72
|
usage: 0x2 | 0x4, // COPY_DST | TEXTURE_BINDING
|
|
29
73
|
});
|
|
74
|
+
const block = BLOCK_SHAPES[format];
|
|
30
75
|
for (let level = 0; level < levels; level++) {
|
|
31
|
-
const across = Math.ceil(Math.max(1, width >> level) /
|
|
32
|
-
const down = Math.ceil(Math.max(1, height >> level) /
|
|
76
|
+
const across = Math.ceil(Math.max(1, width >> level) / block.width);
|
|
77
|
+
const down = Math.ceil(Math.max(1, height >> level) / block.height);
|
|
33
78
|
for (let layer = 0; layer < layers.length; layer++) {
|
|
34
|
-
device.queue.writeTexture({ texture, mipLevel: level, origin: [0, 0, layer] }, layers[layer].levels[level], { bytesPerRow: across *
|
|
79
|
+
device.queue.writeTexture({ texture, mipLevel: level, origin: [0, 0, layer] }, layers[layer].levels[level], { bytesPerRow: across * block.bytes, rowsPerImage: down }, { width: across * block.width, height: down * block.height, depthOrArrayLayers: 1 });
|
|
35
80
|
}
|
|
36
81
|
}
|
|
37
82
|
return texture;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEPTH_FRAG_WGSL } from '../../shaders/generated/depth.wgsl.ts';
|
|
2
2
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
3
3
|
import type { ClothViews } from './clothTextures.ts';
|
|
4
|
+
import type { AnimationViews } from './flatPass.ts';
|
|
4
5
|
/**
|
|
5
6
|
* The shadow pass: the world drawn from the light, into a depth map.
|
|
6
7
|
*
|
|
@@ -136,6 +137,55 @@ export declare const DEPTH_PALETTE_BINDING: {
|
|
|
136
137
|
readonly sampler: 17;
|
|
137
138
|
readonly type: "sampler2D";
|
|
138
139
|
};
|
|
140
|
+
export declare const DEPTH_INSTANCED_ANIMATED_VERT_FIELDS: {
|
|
141
|
+
readonly uLightViewProj: {
|
|
142
|
+
readonly offset: 0;
|
|
143
|
+
readonly size: 64;
|
|
144
|
+
readonly type: "mat4";
|
|
145
|
+
};
|
|
146
|
+
readonly uSceneTime: {
|
|
147
|
+
readonly offset: 64;
|
|
148
|
+
readonly size: 4;
|
|
149
|
+
readonly type: "float";
|
|
150
|
+
};
|
|
151
|
+
readonly uBoneClip: {
|
|
152
|
+
readonly offset: 72;
|
|
153
|
+
readonly size: 8;
|
|
154
|
+
readonly type: "vec2";
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
export declare const DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT_FIELDS: {
|
|
158
|
+
readonly uLightViewProj: {
|
|
159
|
+
readonly offset: 0;
|
|
160
|
+
readonly size: 64;
|
|
161
|
+
readonly type: "mat4";
|
|
162
|
+
};
|
|
163
|
+
readonly uUvScale: {
|
|
164
|
+
readonly offset: 64;
|
|
165
|
+
readonly size: 8;
|
|
166
|
+
readonly type: "vec2";
|
|
167
|
+
};
|
|
168
|
+
readonly uUvOffset: {
|
|
169
|
+
readonly offset: 72;
|
|
170
|
+
readonly size: 8;
|
|
171
|
+
readonly type: "vec2";
|
|
172
|
+
};
|
|
173
|
+
readonly uAlphaCutout: {
|
|
174
|
+
readonly offset: 80;
|
|
175
|
+
readonly size: 8;
|
|
176
|
+
readonly type: "vec2";
|
|
177
|
+
};
|
|
178
|
+
readonly uSceneTime: {
|
|
179
|
+
readonly offset: 88;
|
|
180
|
+
readonly size: 4;
|
|
181
|
+
readonly type: "float";
|
|
182
|
+
};
|
|
183
|
+
readonly uBoneClip: {
|
|
184
|
+
readonly offset: 96;
|
|
185
|
+
readonly size: 8;
|
|
186
|
+
readonly type: "vec2";
|
|
187
|
+
};
|
|
188
|
+
};
|
|
139
189
|
/**
|
|
140
190
|
* The format the shadow map is stored in.
|
|
141
191
|
*
|
|
@@ -160,7 +210,9 @@ skinned?: boolean,
|
|
|
160
210
|
* Separate for the palette's reason: the plain layout stays exactly what it was, and a frame with
|
|
161
211
|
* no cutout caster pays nothing.
|
|
162
212
|
*/
|
|
163
|
-
cutout?: boolean
|
|
213
|
+
cutout?: boolean,
|
|
214
|
+
/** An instanced caster playing a bone animation: its three vertex textures. */
|
|
215
|
+
animated?: boolean): GPUBindGroupLayout;
|
|
164
216
|
export declare function createDepthBindGroup(device: GPUDevice, layout: GPUBindGroupLayout, perDraw: GPUBuffer, perPass: GPUBuffer, previous: GPUTextureView, sampler: GPUSampler,
|
|
165
217
|
/** The joint palette, for a layout built with `skinned`. Omit for the rigid layout. */
|
|
166
218
|
palette?: GPUTextureView | null,
|
|
@@ -170,7 +222,9 @@ cutout?: {
|
|
|
170
222
|
readonly sampler: GPUSampler;
|
|
171
223
|
} | null,
|
|
172
224
|
/** A skinned group's cloth views: the caster's, or the stand-in where it has none. */
|
|
173
|
-
cloth?: ClothViews | null
|
|
225
|
+
cloth?: ClothViews | null,
|
|
226
|
+
/** An animated caster's clip and clocks. See `AnimationViews`. */
|
|
227
|
+
animation?: AnimationViews | null): GPUBindGroup;
|
|
174
228
|
/**
|
|
175
229
|
* The depth pipeline.
|
|
176
230
|
*
|
|
@@ -209,4 +263,6 @@ cutout?: boolean,
|
|
|
209
263
|
*/
|
|
210
264
|
skinEight?: boolean,
|
|
211
265
|
/** Whether a skinned caster is placed by a cloth binding, as its visible draw is. The key carries it. */
|
|
212
|
-
cloth?: boolean
|
|
266
|
+
cloth?: boolean,
|
|
267
|
+
/** An instanced caster playing a bone animation. The key must carry it. */
|
|
268
|
+
animated?: boolean): GPURenderPipeline;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEPTH_BINDINGS, DEPTH_CUTOUT_FRAG_WGSL, DEPTH_CUTOUT_VERT_WGSL, DEPTH_FRAG_WGSL, DEPTH_INSTANCED_CUTOUT_VERT_WGSL, DEPTH_INSTANCED_VERT_WGSL, DEPTH_SKINNED_VERT_WGSL, DEPTH_VERT_WGSL, } from '../../shaders/generated/depth.wgsl.js';
|
|
1
|
+
import { DEPTH_BINDINGS, DEPTH_CUTOUT_FRAG_WGSL, DEPTH_CUTOUT_VERT_WGSL, DEPTH_FRAG_WGSL, DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT_WGSL, DEPTH_INSTANCED_ANIMATED_VERT_WGSL, DEPTH_INSTANCED_CUTOUT_VERT_WGSL, DEPTH_INSTANCED_VERT_WGSL, DEPTH_SKINNED_VERT_WGSL, DEPTH_VERT_WGSL, } from '../../shaders/generated/depth.wgsl.js';
|
|
2
2
|
import { vertexBufferLayouts } from './buffers.js';
|
|
3
3
|
import { vertexConstants } from './flatPass.js';
|
|
4
4
|
import { shaderModule } from './shaderModules.js';
|
|
@@ -37,6 +37,14 @@ const CLOTH_TEXTURES = [
|
|
|
37
37
|
DEPTH_BINDINGS.DEPTH_SKINNED_VERT.textures.uClothParticles,
|
|
38
38
|
DEPTH_BINDINGS.DEPTH_SKINNED_VERT.textures.uClothRest,
|
|
39
39
|
];
|
|
40
|
+
/** A bone animation's three textures, at the bindings both animated depth variants declare them. */
|
|
41
|
+
const ANIMATION_TEXTURES = [
|
|
42
|
+
DEPTH_BINDINGS.DEPTH_INSTANCED_ANIMATED_VERT.textures.uBonePlaces,
|
|
43
|
+
DEPTH_BINDINGS.DEPTH_INSTANCED_ANIMATED_VERT.textures.uBoneTurns,
|
|
44
|
+
DEPTH_BINDINGS.DEPTH_INSTANCED_ANIMATED_VERT.textures.uInstanceClocks,
|
|
45
|
+
];
|
|
46
|
+
export const DEPTH_INSTANCED_ANIMATED_VERT_FIELDS = DEPTH_BINDINGS.DEPTH_INSTANCED_ANIMATED_VERT.fields;
|
|
47
|
+
export const DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT_FIELDS = DEPTH_BINDINGS.DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT.fields;
|
|
40
48
|
const VISIBILITY_VERTEX = 0x1;
|
|
41
49
|
const VISIBILITY_FRAGMENT = 0x2;
|
|
42
50
|
/**
|
|
@@ -63,10 +71,19 @@ skinned = false,
|
|
|
63
71
|
* Separate for the palette's reason: the plain layout stays exactly what it was, and a frame with
|
|
64
72
|
* no cutout caster pays nothing.
|
|
65
73
|
*/
|
|
66
|
-
cutout = false
|
|
74
|
+
cutout = false,
|
|
75
|
+
/** An instanced caster playing a bone animation: its three vertex textures. */
|
|
76
|
+
animated = false) {
|
|
67
77
|
return device.createBindGroupLayout({
|
|
68
|
-
label: skinned ? 'depth.layout.skinned' : cutout ? 'depth.layout.cutout' : 'depth.layout'
|
|
78
|
+
label: `${skinned ? 'depth.layout.skinned' : cutout ? 'depth.layout.cutout' : 'depth.layout'}${animated ? '.animated' : ''}`,
|
|
69
79
|
entries: [
|
|
80
|
+
...(animated
|
|
81
|
+
? ANIMATION_TEXTURES.map((binding) => ({
|
|
82
|
+
binding: binding.texture,
|
|
83
|
+
visibility: VISIBILITY_VERTEX,
|
|
84
|
+
texture: { sampleType: 'unfilterable-float' },
|
|
85
|
+
}))
|
|
86
|
+
: []),
|
|
70
87
|
/* The texture and no sampler: the shader reads the palette with `textureLoad`, an integer
|
|
71
88
|
coordinate with nothing to filter, which is what `flatPass.ts` binds for the same
|
|
72
89
|
palette. naga declares a sampler for it and nothing ever reads one. */
|
|
@@ -147,7 +164,9 @@ palette = null,
|
|
|
147
164
|
/** The cutout map and its sampler, for a layout built with `cutout`. */
|
|
148
165
|
cutout = null,
|
|
149
166
|
/** A skinned group's cloth views: the caster's, or the stand-in where it has none. */
|
|
150
|
-
cloth = null
|
|
167
|
+
cloth = null,
|
|
168
|
+
/** An animated caster's clip and clocks. See `AnimationViews`. */
|
|
169
|
+
animation = null) {
|
|
151
170
|
return device.createBindGroup({
|
|
152
171
|
label: palette !== null
|
|
153
172
|
? 'depth.bindGroup.skinned'
|
|
@@ -180,6 +199,13 @@ cloth = null) {
|
|
|
180
199
|
{ binding: CUTOUT_MAP.sampler, resource: cutout.sampler },
|
|
181
200
|
]
|
|
182
201
|
: []),
|
|
202
|
+
...(animation !== null
|
|
203
|
+
? [
|
|
204
|
+
{ binding: ANIMATION_TEXTURES[0].texture, resource: animation.places },
|
|
205
|
+
{ binding: ANIMATION_TEXTURES[1].texture, resource: animation.turns },
|
|
206
|
+
{ binding: ANIMATION_TEXTURES[2].texture, resource: animation.clocks },
|
|
207
|
+
]
|
|
208
|
+
: []),
|
|
183
209
|
],
|
|
184
210
|
});
|
|
185
211
|
}
|
|
@@ -221,20 +247,29 @@ cutout = false,
|
|
|
221
247
|
*/
|
|
222
248
|
skinEight = false,
|
|
223
249
|
/** Whether a skinned caster is placed by a cloth binding, as its visible draw is. The key carries it. */
|
|
224
|
-
cloth = false
|
|
250
|
+
cloth = false,
|
|
251
|
+
/** An instanced caster playing a bone animation. The key must carry it. */
|
|
252
|
+
animated = false) {
|
|
225
253
|
return cache.get(key, () => ({
|
|
226
254
|
label: key,
|
|
227
255
|
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
228
256
|
vertex: {
|
|
229
|
-
module: shaderModule(device,
|
|
230
|
-
?
|
|
231
|
-
? {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
:
|
|
236
|
-
|
|
237
|
-
|
|
257
|
+
module: shaderModule(device, animated
|
|
258
|
+
? cutout
|
|
259
|
+
? {
|
|
260
|
+
label: 'depth.instanced.animated.cutout.vert',
|
|
261
|
+
code: DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT_WGSL,
|
|
262
|
+
}
|
|
263
|
+
: { label: 'depth.instanced.animated.vert', code: DEPTH_INSTANCED_ANIMATED_VERT_WGSL }
|
|
264
|
+
: cutout
|
|
265
|
+
? instanced
|
|
266
|
+
? { label: 'depth.instanced.cutout.vert', code: DEPTH_INSTANCED_CUTOUT_VERT_WGSL }
|
|
267
|
+
: { label: 'depth.cutout.vert', code: DEPTH_CUTOUT_VERT_WGSL }
|
|
268
|
+
: instanced
|
|
269
|
+
? { label: 'depth.instanced.vert', code: DEPTH_INSTANCED_VERT_WGSL }
|
|
270
|
+
: skinned
|
|
271
|
+
? { label: 'depth.skinned.vert', code: DEPTH_SKINNED_VERT_WGSL }
|
|
272
|
+
: { label: 'depth.vert', code: DEPTH_VERT_WGSL }),
|
|
238
273
|
entryPoint: 'main',
|
|
239
274
|
buffers: vertexBufferLayouts(present, instanced),
|
|
240
275
|
...(skinned && !instanced && !cutout
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* split matters because these two fail for unrelated reasons: a device is lost by a driver
|
|
7
7
|
* reset the page did not cause, and a frame is wrong because of something the frame did.
|
|
8
8
|
*/
|
|
9
|
+
import type { DisplayRange, DisplayRangeChoice } from '../../displayRange.ts';
|
|
9
10
|
/** What the renderer needs from the canvas it draws into, with the API's shape absorbed. */
|
|
10
11
|
export interface GpuSurface {
|
|
11
12
|
readonly device: GPUDevice;
|
|
@@ -21,6 +22,9 @@ export interface GpuSurface {
|
|
|
21
22
|
readonly canvas: HTMLCanvasElement;
|
|
22
23
|
/** The swap chain's format, which every render pipeline has to be built against. */
|
|
23
24
|
readonly format: GPUTextureFormat;
|
|
25
|
+
/** The range the canvas was configured in, and why. See `displayRange.ts`. */
|
|
26
|
+
readonly displayRange: DisplayRange;
|
|
27
|
+
readonly displayRangeReason: string;
|
|
24
28
|
/** Whether the device has gone. Read per frame; never throws. */
|
|
25
29
|
readonly lost: boolean;
|
|
26
30
|
/** Called when the device is lost. Fires immediately if it already has been. */
|
|
@@ -49,4 +53,6 @@ export interface GpuSurface {
|
|
|
49
53
|
* consumer its GPU had failed every time it unmounted a canvas on purpose, so a disposed
|
|
50
54
|
* surface stays silent.
|
|
51
55
|
*/
|
|
52
|
-
export declare function createGpuSurface(canvas: HTMLCanvasElement, device: GPUDevice
|
|
56
|
+
export declare function createGpuSurface(canvas: HTMLCanvasElement, device: GPUDevice,
|
|
57
|
+
/** The range the profile and the display allow (`chooseDisplayRange`); standard unless given. */
|
|
58
|
+
wanted?: DisplayRangeChoice): GpuSurface;
|
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
* split matters because these two fail for unrelated reasons: a device is lost by a driver
|
|
7
7
|
* reset the page did not cause, and a frame is wrong because of something the frame did.
|
|
8
8
|
*/
|
|
9
|
+
/** A canvas nobody asked to extend. */
|
|
10
|
+
const STANDARD_RANGE = {
|
|
11
|
+
range: 'standard',
|
|
12
|
+
reason: 'highDynamicRange was not asked for',
|
|
13
|
+
};
|
|
9
14
|
/**
|
|
10
15
|
* Take a canvas and a device, and hand back the surface the renderer draws into.
|
|
11
16
|
*
|
|
@@ -25,12 +30,23 @@
|
|
|
25
30
|
* consumer its GPU had failed every time it unmounted a canvas on purpose, so a disposed
|
|
26
31
|
* surface stays silent.
|
|
27
32
|
*/
|
|
28
|
-
export function createGpuSurface(canvas, device
|
|
33
|
+
export function createGpuSurface(canvas, device,
|
|
34
|
+
/** The range the profile and the display allow (`chooseDisplayRange`); standard unless given. */
|
|
35
|
+
wanted = STANDARD_RANGE) {
|
|
29
36
|
const context = canvas.getContext('webgpu');
|
|
30
37
|
if (context === null) {
|
|
31
38
|
throw new Error('createGpuSurface: the canvas would not give a webgpu context');
|
|
32
39
|
}
|
|
33
|
-
|
|
40
|
+
/*
|
|
41
|
+
* **A high range is half floats with extended tone mapping**: a value of 1 is the display's
|
|
42
|
+
* paper white, and what lies above it is shown up to the display's peak instead of clipped. The
|
|
43
|
+
* colour space stays sRGB, so the composite's encoding is the one it always wrote, carried past 1.
|
|
44
|
+
*/
|
|
45
|
+
const extended = wanted.range === 'high';
|
|
46
|
+
const format = extended
|
|
47
|
+
? 'rgba16float'
|
|
48
|
+
: navigator.gpu.getPreferredCanvasFormat();
|
|
49
|
+
let range = wanted;
|
|
34
50
|
const listeners = [];
|
|
35
51
|
let lost = false;
|
|
36
52
|
let disposed = false;
|
|
@@ -89,14 +105,26 @@ export function createGpuSurface(canvas, device) {
|
|
|
89
105
|
* has no use for a transparent canvas, and the opaque path is the one a compositor can
|
|
90
106
|
* take without a blend.
|
|
91
107
|
*/
|
|
92
|
-
context.configure(
|
|
108
|
+
context.configure(extended
|
|
109
|
+
? { device, format, alphaMode: 'opaque', toneMapping: { mode: 'extended' } }
|
|
110
|
+
: { device, format, alphaMode: 'opaque' });
|
|
93
111
|
};
|
|
94
112
|
configure(canvas.width, canvas.height);
|
|
113
|
+
/*
|
|
114
|
+
* **Read back, because a browser that does not know the option ignores it** and draws the
|
|
115
|
+
* standard range from an extended-range frame, clipped at paper white, which is the frame a game
|
|
116
|
+
* would grade for the standard range if it knew. So it is told.
|
|
117
|
+
*/
|
|
118
|
+
if (extended && context.getConfiguration?.()?.toneMapping?.mode !== 'extended') {
|
|
119
|
+
range = { range: 'standard', reason: 'this browser has no extended-range canvas' };
|
|
120
|
+
}
|
|
95
121
|
return {
|
|
96
122
|
device,
|
|
97
123
|
context,
|
|
98
124
|
canvas,
|
|
99
125
|
format,
|
|
126
|
+
displayRange: range.range,
|
|
127
|
+
displayRangeReason: range.reason,
|
|
100
128
|
get lost() {
|
|
101
129
|
return lost;
|
|
102
130
|
},
|