@yali-engine/render 0.0.0-stage → 0.4.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/dist/bvh.d.ts +66 -0
- package/dist/bvh.js +493 -0
- package/dist/bvh.js.map +1 -0
- package/dist/camera.d.ts +34 -0
- package/dist/camera.js +66 -0
- package/dist/camera.js.map +1 -0
- package/dist/cluster-build.d.ts +46 -0
- package/dist/cluster-build.js +179 -0
- package/dist/cluster-build.js.map +1 -0
- package/dist/cluster-pages.d.ts +70 -0
- package/dist/cluster-pages.js +203 -0
- package/dist/cluster-pages.js.map +1 -0
- package/dist/cluster-stream.d.ts +83 -0
- package/dist/cluster-stream.js +226 -0
- package/dist/cluster-stream.js.map +1 -0
- package/dist/culled-draws.d.ts +30 -0
- package/dist/culled-draws.js +103 -0
- package/dist/culled-draws.js.map +1 -0
- package/dist/debug-lines.d.ts +51 -0
- package/dist/debug-lines.js +158 -0
- package/dist/debug-lines.js.map +1 -0
- package/dist/device-profile.d.ts +100 -0
- package/dist/device-profile.js +131 -0
- package/dist/device-profile.js.map +1 -0
- package/dist/device.d.ts +39 -0
- package/dist/device.js +79 -0
- package/dist/device.js.map +1 -0
- package/dist/environment.d.ts +60 -0
- package/dist/environment.js +204 -0
- package/dist/environment.js.map +1 -0
- package/dist/extract.d.ts +74 -0
- package/dist/extract.js +194 -0
- package/dist/extract.js.map +1 -0
- package/dist/frame-graph.d.ts +112 -0
- package/dist/frame-graph.js +226 -0
- package/dist/frame-graph.js.map +1 -0
- package/dist/gpu-health.d.ts +74 -0
- package/dist/gpu-health.js +106 -0
- package/dist/gpu-health.js.map +1 -0
- package/dist/gpu-timer.d.ts +26 -0
- package/dist/gpu-timer.js +93 -0
- package/dist/gpu-timer.js.map +1 -0
- package/dist/headless.d.ts +28 -0
- package/dist/headless.js +91 -0
- package/dist/headless.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/lights.d.ts +81 -0
- package/dist/lights.js +247 -0
- package/dist/lights.js.map +1 -0
- package/dist/matrix.d.ts +6 -0
- package/dist/matrix.js +59 -0
- package/dist/matrix.js.map +1 -0
- package/dist/meshes.d.ts +411 -0
- package/dist/meshes.js +545 -0
- package/dist/meshes.js.map +1 -0
- package/dist/meshlets-decoder.d.ts +20 -0
- package/dist/meshlets-decoder.js +47 -0
- package/dist/meshlets-decoder.js.map +1 -0
- package/dist/meshlets.d.ts +186 -0
- package/dist/meshlets.js +1040 -0
- package/dist/meshlets.js.map +1 -0
- package/dist/occlusion.d.ts +51 -0
- package/dist/occlusion.js +188 -0
- package/dist/occlusion.js.map +1 -0
- package/dist/pick-decoder.d.ts +19 -0
- package/dist/pick-decoder.js +45 -0
- package/dist/pick-decoder.js.map +1 -0
- package/dist/pick.d.ts +86 -0
- package/dist/pick.js +452 -0
- package/dist/pick.js.map +1 -0
- package/dist/pipeline-cache.d.ts +53 -0
- package/dist/pipeline-cache.js +96 -0
- package/dist/pipeline-cache.js.map +1 -0
- package/dist/post-options.d.ts +109 -0
- package/dist/post-options.js +23 -0
- package/dist/post-options.js.map +1 -0
- package/dist/post-shaders.gen.d.ts +40 -0
- package/dist/post-shaders.gen.js +43 -0
- package/dist/post-shaders.gen.js.map +1 -0
- package/dist/post.d.ts +101 -0
- package/dist/post.js +555 -0
- package/dist/post.js.map +1 -0
- package/dist/render-plugin.d.ts +239 -0
- package/dist/render-plugin.js +633 -0
- package/dist/render-plugin.js.map +1 -0
- package/dist/scene.d.ts +406 -0
- package/dist/scene.js +2005 -0
- package/dist/scene.js.map +1 -0
- package/dist/shaders.gen.d.ts +40 -0
- package/dist/shaders.gen.js +43 -0
- package/dist/shaders.gen.js.map +1 -0
- package/dist/shadows.d.ts +104 -0
- package/dist/shadows.js +227 -0
- package/dist/shadows.js.map +1 -0
- package/dist/staging-ring.d.ts +41 -0
- package/dist/staging-ring.js +125 -0
- package/dist/staging-ring.js.map +1 -0
- package/dist/textures.d.ts +165 -0
- package/dist/textures.js +361 -0
- package/dist/textures.js.map +1 -0
- package/dist/tonemap.d.ts +45 -0
- package/dist/tonemap.js +141 -0
- package/dist/tonemap.js.map +1 -0
- package/dist/viewport.d.ts +78 -0
- package/dist/viewport.js +130 -0
- package/dist/viewport.js.map +1 -0
- package/dist/webgl2/plugin.d.ts +40 -0
- package/dist/webgl2/plugin.js +190 -0
- package/dist/webgl2/plugin.js.map +1 -0
- package/dist/webgl2/program.d.ts +27 -0
- package/dist/webgl2/program.js +74 -0
- package/dist/webgl2/program.js.map +1 -0
- package/dist/webgl2/renderer.d.ts +128 -0
- package/dist/webgl2/renderer.js +976 -0
- package/dist/webgl2/renderer.js.map +1 -0
- package/dist/webgl2/shaders.glsl.gen.d.ts +27 -0
- package/dist/webgl2/shaders.glsl.gen.js +20 -0
- package/dist/webgl2/shaders.glsl.gen.js.map +1 -0
- package/dist/webgl2/textures.d.ts +11 -0
- package/dist/webgl2/textures.js +82 -0
- package/dist/webgl2/textures.js.map +1 -0
- package/dist/webgl2/webgl2.d.ts +1 -0
- package/dist/webgl2/webgl2.js +4 -0
- package/dist/webgl2/webgl2.js.map +1 -0
- package/dist/worker-mode.d.ts +85 -0
- package/dist/worker-mode.js +204 -0
- package/dist/worker-mode.js.map +1 -0
- package/package.json +47 -3
- package/README.md +0 -3
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/** A texture as the store takes it: square, power of two, every mip level, level 0 first (`@yali-engine/ktx2`'s `DecodedTexture`). */
|
|
2
|
+
export interface TextureData {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
readonly format: GPUTextureFormat;
|
|
6
|
+
readonly srgb: boolean;
|
|
7
|
+
readonly block: 1 | 4;
|
|
8
|
+
readonly blockBytes: number;
|
|
9
|
+
readonly levels: readonly Uint8Array[];
|
|
10
|
+
}
|
|
11
|
+
/** Which array a texture lives in: colour data is sRGB (base colour, emissive), the rest linear (normals, ORM). */
|
|
12
|
+
export type ColorSpace = 'srgb' | 'linear';
|
|
13
|
+
/**
|
|
14
|
+
* A texture in the store: an array layer, and the first array mip it may sample. A material
|
|
15
|
+
* refers to it; `minMip` falls as larger levels finish uploading (mips stream in smallest first).
|
|
16
|
+
*/
|
|
17
|
+
export declare class TextureRef {
|
|
18
|
+
#private;
|
|
19
|
+
readonly space: ColorSpace;
|
|
20
|
+
readonly layer: number;
|
|
21
|
+
/** Array mips above this texture's size (0 when it is the array's size). */
|
|
22
|
+
readonly sizeOffset: number;
|
|
23
|
+
/** The first array mip whose data is on the GPU (`sizeOffset` once fully uploaded). */
|
|
24
|
+
minMip: number;
|
|
25
|
+
/** Bytes the texture's levels hold (what the asset budget counts). */
|
|
26
|
+
readonly bytes: number;
|
|
27
|
+
/** Set when removed: the layer may hold another texture. */
|
|
28
|
+
released: boolean;
|
|
29
|
+
/** True when the texture lives in the RGBA8 arrays beside the device's compressed ones (ADR-0066). */
|
|
30
|
+
readonly rgba8: boolean;
|
|
31
|
+
constructor(space: ColorSpace, layer: number, sizeOffset: number, mips: number, bytes: number, rgba8?: boolean);
|
|
32
|
+
/** True once at least the smallest level is on the GPU. */
|
|
33
|
+
get resident(): boolean;
|
|
34
|
+
/** True when every level is on the GPU. */
|
|
35
|
+
get complete(): boolean;
|
|
36
|
+
/** @internal Marks nothing resident (the device was replaced). */
|
|
37
|
+
evict(): void;
|
|
38
|
+
}
|
|
39
|
+
/** The compressed family a store holds, chosen once per device (`@yali-engine/ktx2`'s `pickVariant`). */
|
|
40
|
+
export type TextureFamily = 'bc7' | 'astc' | 'etc2' | 'rgba8';
|
|
41
|
+
/** The device feature each family needs. */
|
|
42
|
+
export declare const FAMILY_FEATURE: Readonly<Record<TextureFamily, GPUFeatureName | null>>;
|
|
43
|
+
/** The first family in `prefer` a device with `features` can sample (BC7 on desktop, ASTC, ETC2, RGBA8). */
|
|
44
|
+
export declare function pickFamily(features: ReadonlySet<string>, prefer?: readonly TextureFamily[]): TextureFamily;
|
|
45
|
+
/**
|
|
46
|
+
* Where a `TextureStore`'s arrays live (ADR-0070): WebGPU (`webgpuTextureBackend`) or the
|
|
47
|
+
* WebGL2 backend's. The store keeps the layers, the data and the upload queue; a backend only
|
|
48
|
+
* creates, writes, copies and destroys arrays. Its handles are opaque to the store.
|
|
49
|
+
*/
|
|
50
|
+
export interface TextureBackend {
|
|
51
|
+
/** The device's most array layers. */
|
|
52
|
+
readonly maxLayers: number;
|
|
53
|
+
/** A `size`² array of `layers` layers and `mips` levels in `family`'s format for `space`. */
|
|
54
|
+
create(label: string, family: TextureFamily, space: ColorSpace, size: number, mips: number, layers: number): unknown;
|
|
55
|
+
destroy(texture: unknown): void;
|
|
56
|
+
/**
|
|
57
|
+
* Writes level `mip` of layer `layer`: `size`² texels, `physical`² as whole blocks (a level
|
|
58
|
+
* under 4×4 is one block: WebGPU copies the block, GL ES takes the level's true size), rows
|
|
59
|
+
* of `bytesPerRow`.
|
|
60
|
+
*/
|
|
61
|
+
write(texture: unknown, family: TextureFamily, space: ColorSpace, mip: number, layer: number, data: Uint8Array, size: number, physical: number, bytesPerRow: number): void;
|
|
62
|
+
/**
|
|
63
|
+
* Copies every level of the first `layers` layers of `from` into `to` (an array that grew).
|
|
64
|
+
* Returns false when it cannot (WebGL2 copies compressed arrays no way): the store then
|
|
65
|
+
* uploads that array's textures again from their data.
|
|
66
|
+
*/
|
|
67
|
+
copy(from: unknown, to: unknown, family: TextureFamily, size: number, mips: number, layers: number): boolean;
|
|
68
|
+
/** A 4×4 RGBA8 array, bound in place of an RGBA8 set nobody has used yet. */
|
|
69
|
+
placeholder(): unknown;
|
|
70
|
+
}
|
|
71
|
+
/** The WebGPU texture backend: arrays viewed as `2d-array` (compatibility mode fixes the view at creation). */
|
|
72
|
+
export declare function webgpuTextureBackend(device: GPUDevice): TextureBackend;
|
|
73
|
+
/**
|
|
74
|
+
* Material textures as `texture_2d_array`s of one size class (ADR-0060: DESIGN.md §11's
|
|
75
|
+
* material sets): sRGB for colour, linear for data, in the family the device samples, plus
|
|
76
|
+
* RGBA8 arrays created on the first uncompressed texture (decoded PNG / JPEG, ADR-0066) when
|
|
77
|
+
* the device's family is a compressed one. A texture takes one layer; a smaller one fills the
|
|
78
|
+
* lower mips of its layer and the shader clamps to them, a larger one drops its top levels.
|
|
79
|
+
* So one bind group serves every material, and per-instance materials need no draw splitting.
|
|
80
|
+
*
|
|
81
|
+
* Levels upload smallest first inside a per-frame budget (`pump`); a texture is sampled from
|
|
82
|
+
* its first resident mip meanwhile (`TextureRef.minMip`), so a large texture sharpens in
|
|
83
|
+
* instead of holding up a frame. Arrays grow by doubling (one GPU copy) up to the device's
|
|
84
|
+
* `maxTextureArrayLayers`.
|
|
85
|
+
*
|
|
86
|
+
* The store outlives devices: it keeps each texture's levels, and `attach` (at start and
|
|
87
|
+
* after device recovery) recreates the arrays and uploads them again.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const textures = new TextureStore({ family: pickFamily(gpu.features), size: 1024 });
|
|
91
|
+
* textures.attach(gpu.device);
|
|
92
|
+
* const ref = textures.add(decoded); // a @yali-engine/ktx2 DecodedTexture
|
|
93
|
+
* materials.add({ baseColor: [1, 1, 1, 1], baseColorMap: ref });
|
|
94
|
+
*/
|
|
95
|
+
export declare class TextureStore {
|
|
96
|
+
#private;
|
|
97
|
+
readonly family: TextureFamily;
|
|
98
|
+
/** Texels per side of a layer (the tier's size class). */
|
|
99
|
+
readonly size: number;
|
|
100
|
+
/** Mip levels per layer (log2(size) + 1). */
|
|
101
|
+
readonly mips: number;
|
|
102
|
+
/** Bumped when a texture's resident mips change or the arrays change (materials re-pack). */
|
|
103
|
+
version: number;
|
|
104
|
+
/** Bumped when the GPU arrays are (re)created (bind groups must be rebuilt). */
|
|
105
|
+
arraysVersion: number;
|
|
106
|
+
readonly stats: {
|
|
107
|
+
uploads: number;
|
|
108
|
+
uploadBytes: number;
|
|
109
|
+
grows: number;
|
|
110
|
+
textures: number;
|
|
111
|
+
};
|
|
112
|
+
constructor(options: {
|
|
113
|
+
family: TextureFamily;
|
|
114
|
+
size: number;
|
|
115
|
+
layers?: number;
|
|
116
|
+
});
|
|
117
|
+
/** The GPU format of one of the device-family arrays. */
|
|
118
|
+
format(space: ColorSpace): GPUTextureFormat;
|
|
119
|
+
/** (Re)creates the arrays on a WebGPU `device` and queues every texture's levels again. */
|
|
120
|
+
attach(device: GPUDevice): void;
|
|
121
|
+
/** (Re)creates the arrays on `backend` (WebGPU or WebGL2) and queues every texture's levels again. */
|
|
122
|
+
attachBackend(backend: TextureBackend): void;
|
|
123
|
+
/** The device-family array of one colour space (bind it viewed as `2d-array`). WebGPU only. */
|
|
124
|
+
texture(space: ColorSpace): GPUTexture;
|
|
125
|
+
/**
|
|
126
|
+
* The backend's array of one colour space: the device family's, or (`rgba8`) the RGBA8 one,
|
|
127
|
+
* which is the device family's when that is RGBA8 and a 4×4 placeholder until the first
|
|
128
|
+
* uncompressed texture arrives (ADR-0066).
|
|
129
|
+
*/
|
|
130
|
+
array(space: ColorSpace, rgba8: boolean): unknown;
|
|
131
|
+
/**
|
|
132
|
+
* The RGBA8 array of one colour space: the device-family array when the family is RGBA8, a
|
|
133
|
+
* 4×4 placeholder until the first uncompressed texture arrives (ADR-0066).
|
|
134
|
+
*/
|
|
135
|
+
rgba8Texture(space: ColorSpace): GPUTexture;
|
|
136
|
+
/** The material sampler (trilinear, 4× anisotropic, repeat). */
|
|
137
|
+
get sampler(): GPUSampler;
|
|
138
|
+
/**
|
|
139
|
+
* Takes a layer for `t` and queues its levels (smallest first). A texture of the device's
|
|
140
|
+
* family goes to its arrays, an RGBA8 one to the RGBA8 arrays; any other format is refused.
|
|
141
|
+
* Throws when an array is full at the device's limit.
|
|
142
|
+
*/
|
|
143
|
+
add(t: TextureData): TextureRef;
|
|
144
|
+
/** Frees a texture's layer for reuse (its queued uploads are dropped). */
|
|
145
|
+
remove(ref: TextureRef): void;
|
|
146
|
+
/** Uploads queued levels for about `budgetMs` (at least one when any is queued). Returns how many. */
|
|
147
|
+
pump(budgetMs?: number): number;
|
|
148
|
+
/** Levels waiting for upload. */
|
|
149
|
+
get queued(): number;
|
|
150
|
+
/** GPU bytes of the arrays (the memory counter). */
|
|
151
|
+
get gpuBytes(): number;
|
|
152
|
+
/** Destroys the GPU arrays (the textures' data stays for a later `attach`). */
|
|
153
|
+
detach(): void;
|
|
154
|
+
}
|
|
155
|
+
/** A texture slot's state for the shader: none, sampled, or missing (drawn as a magenta checker). */
|
|
156
|
+
export declare const TEXTURE_SLOT: {
|
|
157
|
+
readonly none: 0;
|
|
158
|
+
readonly ok: 1;
|
|
159
|
+
readonly missing: 2;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Packs a material's texture slot for the shader: state << 24 | RGBA8 array << 21 | first mip
|
|
163
|
+
* << 16 | layer (bits 26–31 of the first slot carry the material's shader, ADR-0064).
|
|
164
|
+
*/
|
|
165
|
+
export declare function packTextureSlot(ref: TextureRef | null | undefined, missing?: boolean): number;
|
package/dist/textures.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { YaliError } from '@yali-engine/core';
|
|
2
|
+
/**
|
|
3
|
+
* A texture in the store: an array layer, and the first array mip it may sample. A material
|
|
4
|
+
* refers to it; `minMip` falls as larger levels finish uploading (mips stream in smallest first).
|
|
5
|
+
*/
|
|
6
|
+
export class TextureRef {
|
|
7
|
+
space;
|
|
8
|
+
layer;
|
|
9
|
+
/** Array mips above this texture's size (0 when it is the array's size). */
|
|
10
|
+
sizeOffset;
|
|
11
|
+
/** The first array mip whose data is on the GPU (`sizeOffset` once fully uploaded). */
|
|
12
|
+
minMip;
|
|
13
|
+
/** Bytes the texture's levels hold (what the asset budget counts). */
|
|
14
|
+
bytes;
|
|
15
|
+
/** Set when removed: the layer may hold another texture. */
|
|
16
|
+
released = false;
|
|
17
|
+
#mips;
|
|
18
|
+
/** True when the texture lives in the RGBA8 arrays beside the device's compressed ones (ADR-0066). */
|
|
19
|
+
rgba8;
|
|
20
|
+
constructor(space, layer, sizeOffset, mips, bytes, rgba8 = false) {
|
|
21
|
+
this.space = space;
|
|
22
|
+
this.layer = layer;
|
|
23
|
+
this.rgba8 = rgba8;
|
|
24
|
+
this.sizeOffset = sizeOffset;
|
|
25
|
+
this.bytes = bytes;
|
|
26
|
+
this.#mips = mips;
|
|
27
|
+
this.minMip = mips; // nothing resident yet
|
|
28
|
+
}
|
|
29
|
+
/** True once at least the smallest level is on the GPU. */
|
|
30
|
+
get resident() {
|
|
31
|
+
return this.minMip < this.#mips;
|
|
32
|
+
}
|
|
33
|
+
/** True when every level is on the GPU. */
|
|
34
|
+
get complete() {
|
|
35
|
+
return this.minMip === this.sizeOffset;
|
|
36
|
+
}
|
|
37
|
+
/** @internal Marks nothing resident (the device was replaced). */
|
|
38
|
+
evict() {
|
|
39
|
+
this.minMip = this.#mips;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const FORMATS = {
|
|
43
|
+
bc7: { srgb: 'bc7-rgba-unorm-srgb', linear: 'bc7-rgba-unorm' },
|
|
44
|
+
astc: { srgb: 'astc-4x4-unorm-srgb', linear: 'astc-4x4-unorm' },
|
|
45
|
+
etc2: { srgb: 'etc2-rgba8unorm-srgb', linear: 'etc2-rgba8unorm' },
|
|
46
|
+
rgba8: { srgb: 'rgba8unorm-srgb', linear: 'rgba8unorm' },
|
|
47
|
+
};
|
|
48
|
+
/** The device feature each family needs. */
|
|
49
|
+
export const FAMILY_FEATURE = {
|
|
50
|
+
bc7: 'texture-compression-bc',
|
|
51
|
+
astc: 'texture-compression-astc',
|
|
52
|
+
etc2: 'texture-compression-etc2',
|
|
53
|
+
rgba8: null,
|
|
54
|
+
};
|
|
55
|
+
/** The first family in `prefer` a device with `features` can sample (BC7 on desktop, ASTC, ETC2, RGBA8). */
|
|
56
|
+
export function pickFamily(features, prefer = ['bc7', 'astc', 'etc2', 'rgba8']) {
|
|
57
|
+
return prefer.find((f) => FAMILY_FEATURE[f] === null || features.has(FAMILY_FEATURE[f])) ?? 'rgba8';
|
|
58
|
+
}
|
|
59
|
+
/** The WebGPU texture backend: arrays viewed as `2d-array` (compatibility mode fixes the view at creation). */
|
|
60
|
+
export function webgpuTextureBackend(device) {
|
|
61
|
+
return {
|
|
62
|
+
maxLayers: device.limits.maxTextureArrayLayers,
|
|
63
|
+
create: (label, family, space, size, mips, layers) => device.createTexture({
|
|
64
|
+
label,
|
|
65
|
+
size: { width: size, height: size, depthOrArrayLayers: layers },
|
|
66
|
+
mipLevelCount: mips,
|
|
67
|
+
format: FORMATS[family][space],
|
|
68
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC,
|
|
69
|
+
textureBindingViewDimension: '2d-array',
|
|
70
|
+
}),
|
|
71
|
+
destroy: (t) => t.destroy(),
|
|
72
|
+
write: (t, _family, _space, mip, layer, data, _size, physical, bytesPerRow) => device.queue.writeTexture({ texture: t, mipLevel: mip, origin: { x: 0, y: 0, z: layer } }, data, { bytesPerRow, rowsPerImage: data.byteLength / bytesPerRow }, { width: physical, height: physical, depthOrArrayLayers: 1 }),
|
|
73
|
+
copy: (from, to, family, size, mips, layers) => {
|
|
74
|
+
const enc = device.createCommandEncoder({ label: 'yali:textures:grow' });
|
|
75
|
+
for (let m = 0; m < mips; m++) {
|
|
76
|
+
const s = Math.max(1, size >> m);
|
|
77
|
+
const physical = family === 'rgba8' ? s : Math.ceil(s / 4) * 4;
|
|
78
|
+
enc.copyTextureToTexture({ texture: from, mipLevel: m }, { texture: to, mipLevel: m }, { width: physical, height: physical, depthOrArrayLayers: layers });
|
|
79
|
+
}
|
|
80
|
+
device.queue.submit([enc.finish()]);
|
|
81
|
+
return true;
|
|
82
|
+
},
|
|
83
|
+
placeholder: () => device.createTexture({
|
|
84
|
+
label: 'yali:textures:placeholder',
|
|
85
|
+
size: { width: 4, height: 4, depthOrArrayLayers: 1 },
|
|
86
|
+
format: 'rgba8unorm',
|
|
87
|
+
usage: GPUTextureUsage.TEXTURE_BINDING,
|
|
88
|
+
textureBindingViewDimension: '2d-array',
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Material textures as `texture_2d_array`s of one size class (ADR-0060: DESIGN.md §11's
|
|
94
|
+
* material sets): sRGB for colour, linear for data, in the family the device samples, plus
|
|
95
|
+
* RGBA8 arrays created on the first uncompressed texture (decoded PNG / JPEG, ADR-0066) when
|
|
96
|
+
* the device's family is a compressed one. A texture takes one layer; a smaller one fills the
|
|
97
|
+
* lower mips of its layer and the shader clamps to them, a larger one drops its top levels.
|
|
98
|
+
* So one bind group serves every material, and per-instance materials need no draw splitting.
|
|
99
|
+
*
|
|
100
|
+
* Levels upload smallest first inside a per-frame budget (`pump`); a texture is sampled from
|
|
101
|
+
* its first resident mip meanwhile (`TextureRef.minMip`), so a large texture sharpens in
|
|
102
|
+
* instead of holding up a frame. Arrays grow by doubling (one GPU copy) up to the device's
|
|
103
|
+
* `maxTextureArrayLayers`.
|
|
104
|
+
*
|
|
105
|
+
* The store outlives devices: it keeps each texture's levels, and `attach` (at start and
|
|
106
|
+
* after device recovery) recreates the arrays and uploads them again.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* const textures = new TextureStore({ family: pickFamily(gpu.features), size: 1024 });
|
|
110
|
+
* textures.attach(gpu.device);
|
|
111
|
+
* const ref = textures.add(decoded); // a @yali-engine/ktx2 DecodedTexture
|
|
112
|
+
* materials.add({ baseColor: [1, 1, 1, 1], baseColorMap: ref });
|
|
113
|
+
*/
|
|
114
|
+
export class TextureStore {
|
|
115
|
+
family;
|
|
116
|
+
/** Texels per side of a layer (the tier's size class). */
|
|
117
|
+
size;
|
|
118
|
+
/** Mip levels per layer (log2(size) + 1). */
|
|
119
|
+
mips;
|
|
120
|
+
/** Bumped when a texture's resident mips change or the arrays change (materials re-pack). */
|
|
121
|
+
version = 0;
|
|
122
|
+
/** Bumped when the GPU arrays are (re)created (bind groups must be rebuilt). */
|
|
123
|
+
arraysVersion = 0;
|
|
124
|
+
stats = { uploads: 0, uploadBytes: 0, grows: 0, textures: 0 };
|
|
125
|
+
#backend = null;
|
|
126
|
+
#sampler = null;
|
|
127
|
+
/** `srgb`, `linear` (the device's family) and, once used, `srgb+rgba8`, `linear+rgba8`. */
|
|
128
|
+
#sets = new Map();
|
|
129
|
+
/** Bound in place of an RGBA8 set nobody has used yet. */
|
|
130
|
+
#placeholder = null;
|
|
131
|
+
#data = new Map();
|
|
132
|
+
#queue = [];
|
|
133
|
+
#initialLayers;
|
|
134
|
+
constructor(options) {
|
|
135
|
+
const pow2 = (n) => n > 0 && (n & (n - 1)) === 0;
|
|
136
|
+
if (!pow2(options.size))
|
|
137
|
+
throw new YaliError('TEXTURE_SIZE', `The texture size class ${options.size} is not a power of two.`, 'Use 256, 512, 1024 or 2048.');
|
|
138
|
+
this.family = options.family;
|
|
139
|
+
this.size = options.size;
|
|
140
|
+
this.mips = Math.log2(options.size) + 1;
|
|
141
|
+
this.#initialLayers = Math.max(1, options.layers ?? 1);
|
|
142
|
+
for (const space of ['srgb', 'linear'])
|
|
143
|
+
this.#set(space, this.family);
|
|
144
|
+
}
|
|
145
|
+
/** The GPU format of one of the device-family arrays. */
|
|
146
|
+
format(space) {
|
|
147
|
+
return FORMATS[this.family][space];
|
|
148
|
+
}
|
|
149
|
+
#key(space, family) {
|
|
150
|
+
return family === this.family ? space : `${space}+${family}`;
|
|
151
|
+
}
|
|
152
|
+
#set(space, family) {
|
|
153
|
+
const key = this.#key(space, family);
|
|
154
|
+
let s = this.#sets.get(key);
|
|
155
|
+
if (!s) {
|
|
156
|
+
s = { space, family, texture: null, count: this.#initialLayers, free: [], next: 0 };
|
|
157
|
+
this.#sets.set(key, s);
|
|
158
|
+
if (this.#backend) {
|
|
159
|
+
s.texture = this.#create(s, s.count);
|
|
160
|
+
this.arraysVersion++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return s;
|
|
164
|
+
}
|
|
165
|
+
/** (Re)creates the arrays on a WebGPU `device` and queues every texture's levels again. */
|
|
166
|
+
attach(device) {
|
|
167
|
+
this.attachBackend(webgpuTextureBackend(device));
|
|
168
|
+
this.#sampler = device.createSampler({ label: 'yali:textures', addressModeU: 'repeat', addressModeV: 'repeat', magFilter: 'linear', minFilter: 'linear', mipmapFilter: 'linear', maxAnisotropy: 4 });
|
|
169
|
+
}
|
|
170
|
+
/** (Re)creates the arrays on `backend` (WebGPU or WebGL2) and queues every texture's levels again. */
|
|
171
|
+
attachBackend(backend) {
|
|
172
|
+
this.#release();
|
|
173
|
+
this.#backend = backend;
|
|
174
|
+
this.#sampler = null;
|
|
175
|
+
for (const s of this.#sets.values()) {
|
|
176
|
+
s.count = Math.min(Math.max(s.count, s.next), backend.maxLayers);
|
|
177
|
+
s.texture = this.#create(s, s.count);
|
|
178
|
+
}
|
|
179
|
+
this.#placeholder = backend.placeholder();
|
|
180
|
+
this.#queue = [];
|
|
181
|
+
for (const [ref, t] of this.#data) {
|
|
182
|
+
ref.evict();
|
|
183
|
+
this.#enqueue(ref, t);
|
|
184
|
+
}
|
|
185
|
+
this.arraysVersion++;
|
|
186
|
+
this.version++;
|
|
187
|
+
}
|
|
188
|
+
/** The device-family array of one colour space (bind it viewed as `2d-array`). WebGPU only. */
|
|
189
|
+
texture(space) {
|
|
190
|
+
return this.array(space, false);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The backend's array of one colour space: the device family's, or (`rgba8`) the RGBA8 one,
|
|
194
|
+
* which is the device family's when that is RGBA8 and a 4×4 placeholder until the first
|
|
195
|
+
* uncompressed texture arrives (ADR-0066).
|
|
196
|
+
*/
|
|
197
|
+
array(space, rgba8) {
|
|
198
|
+
const t = rgba8 && this.family !== 'rgba8' ? (this.#sets.get(this.#key(space, 'rgba8'))?.texture ?? this.#placeholder) : this.#sets.get(space)?.texture;
|
|
199
|
+
if (!t)
|
|
200
|
+
throw new YaliError('TEXTURES_DETACHED', 'The texture store has no device yet.', 'Call textures.attach(device) first (the render plugin does).');
|
|
201
|
+
return t;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The RGBA8 array of one colour space: the device-family array when the family is RGBA8, a
|
|
205
|
+
* 4×4 placeholder until the first uncompressed texture arrives (ADR-0066).
|
|
206
|
+
*/
|
|
207
|
+
rgba8Texture(space) {
|
|
208
|
+
return this.array(space, true);
|
|
209
|
+
}
|
|
210
|
+
/** The material sampler (trilinear, 4× anisotropic, repeat). */
|
|
211
|
+
get sampler() {
|
|
212
|
+
if (!this.#sampler)
|
|
213
|
+
throw new YaliError('TEXTURES_DETACHED', 'The texture store has no device yet.', 'Call textures.attach(device) first (the render plugin does).');
|
|
214
|
+
return this.#sampler;
|
|
215
|
+
}
|
|
216
|
+
#create(s, layers) {
|
|
217
|
+
return this.#backend.create(`yali:textures:${s.space}:${s.family}`, s.family, s.space, this.size, this.mips, layers);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Takes a layer for `t` and queues its levels (smallest first). A texture of the device's
|
|
221
|
+
* family goes to its arrays, an RGBA8 one to the RGBA8 arrays; any other format is refused.
|
|
222
|
+
* Throws when an array is full at the device's limit.
|
|
223
|
+
*/
|
|
224
|
+
add(t) {
|
|
225
|
+
const space = t.srgb ? 'srgb' : 'linear';
|
|
226
|
+
const family = t.format === FORMATS[this.family][space] ? this.family : t.format === FORMATS.rgba8[space] ? 'rgba8' : null;
|
|
227
|
+
if (!family) {
|
|
228
|
+
throw new YaliError('TEXTURE_FORMAT', `The texture is ${t.format}; this device's ${space} textures are ${this.format(space)} (or ${FORMATS.rgba8[space]}).`, 'Load the variant for this device (`variantPath(path, pickVariant(features))` from @yali-engine/ktx2), or convert the texture (`yali convert`).');
|
|
229
|
+
}
|
|
230
|
+
const s = this.#set(space, family);
|
|
231
|
+
let layer = s.free.pop();
|
|
232
|
+
if (layer === undefined) {
|
|
233
|
+
if (s.next === s.count)
|
|
234
|
+
this.#grow(s, s.count * 2);
|
|
235
|
+
layer = s.next++;
|
|
236
|
+
}
|
|
237
|
+
const sizeOffset = Math.max(0, this.mips - 1 - Math.log2(t.width));
|
|
238
|
+
const ref = new TextureRef(space, layer, sizeOffset, this.mips, t.levels.reduce((n, lv) => n + lv.byteLength, 0), family === 'rgba8' && this.family !== 'rgba8');
|
|
239
|
+
this.#data.set(ref, t);
|
|
240
|
+
if (this.#backend)
|
|
241
|
+
this.#enqueue(ref, t);
|
|
242
|
+
this.stats.textures++;
|
|
243
|
+
return ref;
|
|
244
|
+
}
|
|
245
|
+
#enqueue(ref, t) {
|
|
246
|
+
const drop = Math.max(0, Math.log2(t.width) - (this.mips - 1)); // levels too large for the array
|
|
247
|
+
for (let lv = t.levels.length - 1; lv >= drop; lv--) {
|
|
248
|
+
this.#queue.push({ ref, mip: ref.sizeOffset + lv - drop, data: t.levels[lv], size: Math.max(1, t.width >> lv), block: t.block, blockBytes: t.blockBytes });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
#setOf(ref) {
|
|
252
|
+
return this.#sets.get(this.#key(ref.space, ref.rgba8 ? 'rgba8' : this.family));
|
|
253
|
+
}
|
|
254
|
+
/** Frees a texture's layer for reuse (its queued uploads are dropped). */
|
|
255
|
+
remove(ref) {
|
|
256
|
+
if (ref.released)
|
|
257
|
+
return;
|
|
258
|
+
ref.released = true;
|
|
259
|
+
this.#data.delete(ref);
|
|
260
|
+
this.#queue = this.#queue.filter((u) => u.ref !== ref);
|
|
261
|
+
this.#setOf(ref).free.push(ref.layer);
|
|
262
|
+
this.stats.textures--;
|
|
263
|
+
this.version++;
|
|
264
|
+
}
|
|
265
|
+
/** Uploads queued levels for about `budgetMs` (at least one when any is queued). Returns how many. */
|
|
266
|
+
pump(budgetMs = 1) {
|
|
267
|
+
if (this.#queue.length === 0 || !this.#backend)
|
|
268
|
+
return 0;
|
|
269
|
+
const start = performance.now();
|
|
270
|
+
let n = 0;
|
|
271
|
+
while (this.#queue.length > 0 && (n === 0 || performance.now() - start < budgetMs)) {
|
|
272
|
+
const u = this.#queue.shift();
|
|
273
|
+
const blocks = Math.ceil(u.size / u.block);
|
|
274
|
+
const physical = blocks * u.block; // a mip under 4×4 is copied as one whole block
|
|
275
|
+
const s = this.#setOf(u.ref);
|
|
276
|
+
this.#backend.write(s.texture, s.family, s.space, u.mip, u.ref.layer, u.data, u.size, physical, blocks * u.blockBytes);
|
|
277
|
+
u.ref.minMip = Math.min(u.ref.minMip, u.mip);
|
|
278
|
+
this.stats.uploads++;
|
|
279
|
+
this.stats.uploadBytes += u.data.byteLength;
|
|
280
|
+
n++;
|
|
281
|
+
}
|
|
282
|
+
this.version++;
|
|
283
|
+
return n;
|
|
284
|
+
}
|
|
285
|
+
/** Levels waiting for upload. */
|
|
286
|
+
get queued() {
|
|
287
|
+
return this.#queue.length;
|
|
288
|
+
}
|
|
289
|
+
#grow(s, layers) {
|
|
290
|
+
const max = this.#backend?.maxLayers ?? 256;
|
|
291
|
+
if (s.count >= max) {
|
|
292
|
+
throw new YaliError('TEXTURES_FULL', `The ${s.space} ${s.family} texture array is full: ${s.count} layers, the device's maxTextureArrayLayers.`, 'Lower the texture count, or let the asset budget evict unused textures.');
|
|
293
|
+
}
|
|
294
|
+
const count = Math.min(layers, max);
|
|
295
|
+
const old = s.texture;
|
|
296
|
+
if (this.#backend && old) {
|
|
297
|
+
const next = this.#create(s, count);
|
|
298
|
+
const copied = this.#backend.copy(old, next, s.family, this.size, this.mips, s.count);
|
|
299
|
+
this.#backend.destroy(old);
|
|
300
|
+
s.texture = next;
|
|
301
|
+
if (!copied) {
|
|
302
|
+
for (const [ref, t] of this.#data) {
|
|
303
|
+
if (this.#setOf(ref) !== s)
|
|
304
|
+
continue;
|
|
305
|
+
ref.evict();
|
|
306
|
+
this.#queue = this.#queue.filter((u) => u.ref !== ref);
|
|
307
|
+
this.#enqueue(ref, t);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
this.arraysVersion++;
|
|
311
|
+
this.version++;
|
|
312
|
+
}
|
|
313
|
+
s.count = count;
|
|
314
|
+
this.stats.grows++;
|
|
315
|
+
}
|
|
316
|
+
/** GPU bytes of the arrays (the memory counter). */
|
|
317
|
+
get gpuBytes() {
|
|
318
|
+
let n = 0;
|
|
319
|
+
for (const s of this.#sets.values()) {
|
|
320
|
+
if (!s.texture)
|
|
321
|
+
continue;
|
|
322
|
+
for (let m = 0; m < this.mips; m++) {
|
|
323
|
+
const size = Math.max(1, this.size >> m);
|
|
324
|
+
n += (s.family === 'rgba8' ? size * size * 4 : Math.ceil(size / 4) ** 2 * 16) * s.count;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return n;
|
|
328
|
+
}
|
|
329
|
+
#release() {
|
|
330
|
+
const b = this.#backend;
|
|
331
|
+
for (const s of this.#sets.values()) {
|
|
332
|
+
if (b && s.texture)
|
|
333
|
+
b.destroy(s.texture);
|
|
334
|
+
s.texture = null;
|
|
335
|
+
}
|
|
336
|
+
if (b && this.#placeholder)
|
|
337
|
+
b.destroy(this.#placeholder);
|
|
338
|
+
this.#placeholder = null;
|
|
339
|
+
}
|
|
340
|
+
/** Destroys the GPU arrays (the textures' data stays for a later `attach`). */
|
|
341
|
+
detach() {
|
|
342
|
+
this.#release();
|
|
343
|
+
this.#backend = null;
|
|
344
|
+
this.#sampler = null;
|
|
345
|
+
this.#queue = [];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/** A texture slot's state for the shader: none, sampled, or missing (drawn as a magenta checker). */
|
|
349
|
+
export const TEXTURE_SLOT = { none: 0, ok: 1, missing: 2 };
|
|
350
|
+
/**
|
|
351
|
+
* Packs a material's texture slot for the shader: state << 24 | RGBA8 array << 21 | first mip
|
|
352
|
+
* << 16 | layer (bits 26–31 of the first slot carry the material's shader, ADR-0064).
|
|
353
|
+
*/
|
|
354
|
+
export function packTextureSlot(ref, missing = false) {
|
|
355
|
+
if (missing)
|
|
356
|
+
return TEXTURE_SLOT.missing << 24;
|
|
357
|
+
if (!ref || ref.released || !ref.resident)
|
|
358
|
+
return TEXTURE_SLOT.none;
|
|
359
|
+
return (TEXTURE_SLOT.ok << 24) | ((ref.rgba8 ? 1 : 0) << 21) | ((ref.minMip & 0x1f) << 16) | (ref.layer & 0xffff);
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=textures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textures.js","sourceRoot":"","sources":["../src/textures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FrameGraph } from './frame-graph.ts';
|
|
2
|
+
import type { PipelineCache } from './pipeline-cache.ts';
|
|
3
|
+
import { type GradingOptions } from './post-options.ts';
|
|
4
|
+
/** Tone curves (`shaders/post/curves.wesl`). */
|
|
5
|
+
export type ToneCurve = 'neutral' | 'aces' | 'none';
|
|
6
|
+
/** Each curve's number in the shaders. */
|
|
7
|
+
export declare const CURVES: Readonly<Record<ToneCurve, number>>;
|
|
8
|
+
/**
|
|
9
|
+
* `tone_map` of `shaders/post/curves.wesl` in TS: linear `rgb` times `exposure`, through
|
|
10
|
+
* `curve`, sRGB-encoded, into `out`. For colours the CPU hands the display directly (the clear
|
|
11
|
+
* colour when the draw tone-maps inline, ADR-0071).
|
|
12
|
+
*/
|
|
13
|
+
export declare function toneMapColor(rgb: readonly number[], exposure: number, curve: ToneCurve, out?: number[]): number[];
|
|
14
|
+
/** Bytes of `ToneParams` (`shaders/post/tonemap.wesl`). */
|
|
15
|
+
export declare const TONE_PARAMS_BYTES = 80;
|
|
16
|
+
/**
|
|
17
|
+
* Writes `ToneParams`: exposure and curve, the bloom's weight (0: none) and the grading
|
|
18
|
+
* (`grading.enabled` false: none, so the pass is the plain tone map).
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeToneParams(out: DataView, exposure: number, curve: ToneCurve, bloom: number, grading: (Required<GradingOptions> & {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
}) | null): void;
|
|
23
|
+
/**
|
|
24
|
+
* The tone-mapping pass (M2 increment 5): reads the scene's linear HDR target and writes the
|
|
25
|
+
* swapchain through exposure, a curve (Khronos PBR Neutral by default) and the sRGB transfer
|
|
26
|
+
* function. One full-screen triangle; its bind group follows the graph's reallocations.
|
|
27
|
+
*/
|
|
28
|
+
export declare class ToneMapper {
|
|
29
|
+
#private;
|
|
30
|
+
readonly device: GPUDevice;
|
|
31
|
+
/** Linear multiplier before the curve. */
|
|
32
|
+
exposure: number;
|
|
33
|
+
curve: ToneCurve;
|
|
34
|
+
/** The bloom chain's weight (set by the post chain; 0 without bloom). */
|
|
35
|
+
bloom: number;
|
|
36
|
+
/** Colour grading (ADR-0092), or null. */
|
|
37
|
+
grading: (Required<GradingOptions> & {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
}) | null;
|
|
40
|
+
constructor(device: GPUDevice, format: GPUTextureFormat);
|
|
41
|
+
init(cache: PipelineCache): Promise<void>;
|
|
42
|
+
/** Adds `post.tonemap`, reading `input` (and `bloom`'s chain, if any) and writing `output`. */
|
|
43
|
+
addPass(graph: FrameGraph, input: string, output: string, bloom?: string): void;
|
|
44
|
+
destroy(): void;
|
|
45
|
+
}
|