@bloopjs/toodle 0.0.103 → 0.1.1
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/Toodle.d.ts +50 -20
- package/dist/Toodle.d.ts.map +1 -1
- package/dist/backends/IBackendShader.d.ts +48 -0
- package/dist/backends/IBackendShader.d.ts.map +1 -0
- package/dist/backends/IRenderBackend.d.ts +92 -0
- package/dist/backends/IRenderBackend.d.ts.map +1 -0
- package/dist/backends/ITextureAtlas.d.ts +34 -0
- package/dist/backends/ITextureAtlas.d.ts.map +1 -0
- package/dist/backends/detection.d.ts +16 -0
- package/dist/backends/detection.d.ts.map +1 -0
- package/dist/backends/mod.d.ts +9 -0
- package/dist/backends/mod.d.ts.map +1 -0
- package/dist/backends/webgl2/WebGLBackend.d.ts +51 -0
- package/dist/backends/webgl2/WebGLBackend.d.ts.map +1 -0
- package/dist/backends/webgl2/WebGLQuadShader.d.ts +17 -0
- package/dist/backends/webgl2/WebGLQuadShader.d.ts.map +1 -0
- package/dist/backends/webgl2/glsl/quad.glsl.d.ts +12 -0
- package/dist/backends/webgl2/glsl/quad.glsl.d.ts.map +1 -0
- package/dist/backends/webgl2/mod.d.ts +3 -0
- package/dist/backends/webgl2/mod.d.ts.map +1 -0
- package/dist/backends/webgpu/ShaderDescriptor.d.ts.map +1 -0
- package/dist/{textures → backends/webgpu}/TextureComputeShader.d.ts +1 -1
- package/dist/backends/webgpu/TextureComputeShader.d.ts.map +1 -0
- package/dist/backends/webgpu/WebGPUBackend.d.ts +67 -0
- package/dist/backends/webgpu/WebGPUBackend.d.ts.map +1 -0
- package/dist/backends/webgpu/WebGPUQuadShader.d.ts +18 -0
- package/dist/backends/webgpu/WebGPUQuadShader.d.ts.map +1 -0
- package/dist/backends/webgpu/mod.d.ts +3 -0
- package/dist/backends/webgpu/mod.d.ts.map +1 -0
- package/dist/backends/webgpu/parser.d.ts.map +1 -0
- package/dist/{shaders → backends/webgpu}/postprocess/blur.d.ts +1 -1
- package/dist/backends/webgpu/postprocess/blur.d.ts.map +1 -0
- package/dist/{shaders → backends/webgpu}/postprocess/mod.d.ts +1 -1
- package/dist/backends/webgpu/postprocess/mod.d.ts.map +1 -0
- package/dist/backends/webgpu/samplers.d.ts.map +1 -0
- package/dist/backends/webgpu/wgsl/example.wgsl.d.ts.map +1 -0
- package/dist/backends/webgpu/wgsl/hello.wgsl.d.ts.map +1 -0
- package/dist/backends/webgpu/wgsl/helloInstanced.wgsl.d.ts.map +1 -0
- package/dist/backends/webgpu/wgsl/pixel-scraping.wgsl.d.ts.map +1 -0
- package/dist/backends/webgpu/wgsl/quad.wgsl.d.ts.map +1 -0
- package/dist/coreTypes/EngineUniform.d.ts.map +1 -0
- package/dist/mod.d.ts +3 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +6741 -6151
- package/dist/mod.js.map +28 -23
- package/dist/scene/Batcher.d.ts +2 -2
- package/dist/scene/Batcher.d.ts.map +1 -1
- package/dist/scene/QuadNode.d.ts +3 -2
- package/dist/scene/QuadNode.d.ts.map +1 -1
- package/dist/scene/RenderComponent.d.ts +2 -2
- package/dist/scene/RenderComponent.d.ts.map +1 -1
- package/dist/scene/SceneNode.d.ts +2 -2
- package/dist/scene/SceneNode.d.ts.map +1 -1
- package/dist/text/TextShader.d.ts +8 -6
- package/dist/text/TextShader.d.ts.map +1 -1
- package/dist/textures/AssetManager.d.ts +21 -5
- package/dist/textures/AssetManager.d.ts.map +1 -1
- package/dist/textures/types.d.ts +4 -2
- package/dist/textures/types.d.ts.map +1 -1
- package/dist/textures/util.d.ts.map +1 -1
- package/dist/utils/boilerplate.d.ts +1 -1
- package/dist/utils/boilerplate.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Toodle.ts +155 -171
- package/src/backends/IBackendShader.ts +52 -0
- package/src/backends/IRenderBackend.ts +118 -0
- package/src/backends/ITextureAtlas.ts +35 -0
- package/src/backends/detection.ts +46 -0
- package/src/backends/mod.ts +29 -0
- package/src/backends/webgl2/WebGLBackend.ts +256 -0
- package/src/backends/webgl2/WebGLQuadShader.ts +278 -0
- package/src/backends/webgl2/glsl/quad.glsl.ts +114 -0
- package/src/backends/webgl2/mod.ts +2 -0
- package/src/{textures → backends/webgpu}/TextureComputeShader.ts +2 -48
- package/src/backends/webgpu/WebGPUBackend.ts +350 -0
- package/src/{shaders/QuadShader.ts → backends/webgpu/WebGPUQuadShader.ts} +226 -170
- package/src/backends/webgpu/mod.ts +2 -0
- package/src/{shaders → backends/webgpu}/parser.ts +2 -2
- package/src/{shaders → backends/webgpu}/postprocess/blur.ts +2 -2
- package/src/{shaders → backends/webgpu}/postprocess/mod.ts +1 -1
- package/src/mod.ts +3 -2
- package/src/scene/Batcher.ts +3 -3
- package/src/scene/QuadNode.ts +7 -6
- package/src/scene/RenderComponent.ts +2 -2
- package/src/scene/SceneNode.ts +11 -12
- package/src/text/TextNode.ts +2 -2
- package/src/text/TextShader.ts +17 -11
- package/src/textures/AssetManager.ts +119 -94
- package/src/textures/types.ts +4 -2
- package/src/textures/util.ts +0 -65
- package/src/utils/boilerplate.ts +1 -1
- package/dist/shaders/EngineUniform.d.ts.map +0 -1
- package/dist/shaders/IShader.d.ts +0 -15
- package/dist/shaders/IShader.d.ts.map +0 -1
- package/dist/shaders/QuadShader.d.ts +0 -18
- package/dist/shaders/QuadShader.d.ts.map +0 -1
- package/dist/shaders/ShaderDescriptor.d.ts.map +0 -1
- package/dist/shaders/mod.d.ts +0 -6
- package/dist/shaders/mod.d.ts.map +0 -1
- package/dist/shaders/parser.d.ts.map +0 -1
- package/dist/shaders/postprocess/blur.d.ts.map +0 -1
- package/dist/shaders/postprocess/mod.d.ts.map +0 -1
- package/dist/shaders/samplers.d.ts.map +0 -1
- package/dist/shaders/wgsl/example.wgsl.d.ts.map +0 -1
- package/dist/shaders/wgsl/hello.wgsl.d.ts.map +0 -1
- package/dist/shaders/wgsl/helloInstanced.wgsl.d.ts.map +0 -1
- package/dist/shaders/wgsl/quad.wgsl.d.ts.map +0 -1
- package/dist/textures/TextureComputeShader.d.ts.map +0 -1
- package/dist/textures/pixel-scraping.wgsl.d.ts.map +0 -1
- package/src/shaders/IShader.ts +0 -20
- package/src/shaders/mod.ts +0 -5
- /package/dist/{shaders → backends/webgpu}/ShaderDescriptor.d.ts +0 -0
- /package/dist/{shaders → backends/webgpu}/parser.d.ts +0 -0
- /package/dist/{shaders → backends/webgpu}/samplers.d.ts +0 -0
- /package/dist/{shaders → backends/webgpu}/wgsl/example.wgsl.d.ts +0 -0
- /package/dist/{shaders → backends/webgpu}/wgsl/hello.wgsl.d.ts +0 -0
- /package/dist/{shaders → backends/webgpu}/wgsl/helloInstanced.wgsl.d.ts +0 -0
- /package/dist/{textures → backends/webgpu/wgsl}/pixel-scraping.wgsl.d.ts +0 -0
- /package/dist/{shaders → backends/webgpu}/wgsl/quad.wgsl.d.ts +0 -0
- /package/dist/{shaders → coreTypes}/EngineUniform.d.ts +0 -0
- /package/src/{shaders → backends/webgpu}/ShaderDescriptor.ts +0 -0
- /package/src/{shaders → backends/webgpu}/samplers.ts +0 -0
- /package/src/{shaders → backends/webgpu}/wgsl/example.wgsl.ts +0 -0
- /package/src/{shaders → backends/webgpu}/wgsl/hello.wgsl.ts +0 -0
- /package/src/{shaders → backends/webgpu}/wgsl/helloInstanced.wgsl.ts +0 -0
- /package/src/{textures → backends/webgpu/wgsl}/pixel-scraping.wgsl.ts +0 -0
- /package/src/{shaders → backends/webgpu}/wgsl/quad.wgsl.ts +0 -0
- /package/src/{shaders → coreTypes}/EngineUniform.ts +0 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import type { Color } from "../../coreTypes/Color";
|
|
2
|
+
import type { EngineUniform } from "../../coreTypes/EngineUniform";
|
|
3
|
+
import type { Size } from "../../coreTypes/Size";
|
|
4
|
+
import type { Limits, LimitsOptions } from "../../limits";
|
|
5
|
+
import { DEFAULT_LIMITS } from "../../limits";
|
|
6
|
+
import type { CpuTextureAtlas } from "../../textures/types";
|
|
7
|
+
import { assert } from "../../utils/assert";
|
|
8
|
+
import type { IBackendShader, QuadShaderCreationOpts } from "../IBackendShader";
|
|
9
|
+
import type { IRenderBackend } from "../IRenderBackend";
|
|
10
|
+
import type {
|
|
11
|
+
ITextureAtlas,
|
|
12
|
+
TextureAtlasFormat,
|
|
13
|
+
TextureAtlasOptions,
|
|
14
|
+
} from "../ITextureAtlas";
|
|
15
|
+
import type { PostProcess } from "./postprocess/mod";
|
|
16
|
+
import { WebGPUQuadShader } from "./WebGPUQuadShader";
|
|
17
|
+
|
|
18
|
+
export type WebGPUBackendOptions = {
|
|
19
|
+
limits?: LimitsOptions;
|
|
20
|
+
format?: "rgba8unorm" | "rg8unorm";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* WebGPU implementation of the render backend.
|
|
25
|
+
*/
|
|
26
|
+
export class WebGPUBackend implements IRenderBackend {
|
|
27
|
+
readonly type = "webgpu" as const;
|
|
28
|
+
readonly limits: Limits;
|
|
29
|
+
readonly atlasSize: Size;
|
|
30
|
+
readonly defaultAtlasId = "default";
|
|
31
|
+
|
|
32
|
+
#atlases = new Map<string, ITextureAtlas>();
|
|
33
|
+
|
|
34
|
+
#device: GPUDevice;
|
|
35
|
+
#context: GPUCanvasContext;
|
|
36
|
+
#presentationFormat: GPUTextureFormat;
|
|
37
|
+
#encoder: GPUCommandEncoder | null = null;
|
|
38
|
+
#renderPass: GPURenderPassEncoder | null = null;
|
|
39
|
+
#postprocess: PostProcess | null = null;
|
|
40
|
+
#pingpong: [GPUTexture, GPUTexture] | null = null;
|
|
41
|
+
#canvas: HTMLCanvasElement;
|
|
42
|
+
|
|
43
|
+
private constructor(
|
|
44
|
+
device: GPUDevice,
|
|
45
|
+
context: GPUCanvasContext,
|
|
46
|
+
presentationFormat: GPUTextureFormat,
|
|
47
|
+
limits: Limits,
|
|
48
|
+
canvas: HTMLCanvasElement,
|
|
49
|
+
) {
|
|
50
|
+
this.#device = device;
|
|
51
|
+
this.#context = context;
|
|
52
|
+
this.#presentationFormat = presentationFormat;
|
|
53
|
+
this.limits = limits;
|
|
54
|
+
this.atlasSize = {
|
|
55
|
+
width: limits.textureSize,
|
|
56
|
+
height: limits.textureSize,
|
|
57
|
+
};
|
|
58
|
+
this.#canvas = canvas;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a WebGPU backend attached to a canvas.
|
|
63
|
+
*/
|
|
64
|
+
static async create(
|
|
65
|
+
canvas: HTMLCanvasElement,
|
|
66
|
+
options: WebGPUBackendOptions = {},
|
|
67
|
+
): Promise<WebGPUBackend> {
|
|
68
|
+
const adapter = await navigator.gpu.requestAdapter();
|
|
69
|
+
if (!adapter) {
|
|
70
|
+
throw new Error("WebGPU not supported: no adapter found");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const device = await adapter.requestDevice();
|
|
74
|
+
device.lost.then((info) => {
|
|
75
|
+
console.error("GPU Device lost", info);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const context = canvas.getContext("webgpu");
|
|
79
|
+
assert(context, "Could not get WebGPU context from canvas");
|
|
80
|
+
|
|
81
|
+
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
82
|
+
|
|
83
|
+
context.configure({
|
|
84
|
+
device,
|
|
85
|
+
format: presentationFormat,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const limits: Limits = {
|
|
89
|
+
...DEFAULT_LIMITS,
|
|
90
|
+
...options.limits,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const backend = new WebGPUBackend(
|
|
94
|
+
device,
|
|
95
|
+
context,
|
|
96
|
+
presentationFormat,
|
|
97
|
+
limits,
|
|
98
|
+
canvas,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Create the default texture atlas
|
|
102
|
+
backend.createTextureAtlas("default", {
|
|
103
|
+
format: options.format ?? "rgba8unorm",
|
|
104
|
+
layers: limits.textureArrayLayers,
|
|
105
|
+
size: limits.textureSize,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return backend;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
startFrame(clearColor: Color, loadOp: "clear" | "load"): void {
|
|
112
|
+
this.#encoder = this.#device.createCommandEncoder();
|
|
113
|
+
|
|
114
|
+
// If postprocessing, render to ping-pong texture; otherwise render to canvas
|
|
115
|
+
const target = this.#postprocess
|
|
116
|
+
? this.#pingpong![0]
|
|
117
|
+
: this.#context.getCurrentTexture();
|
|
118
|
+
|
|
119
|
+
this.#renderPass = this.#encoder.beginRenderPass({
|
|
120
|
+
label: "toodle frame",
|
|
121
|
+
colorAttachments: [
|
|
122
|
+
{
|
|
123
|
+
view: target.createView(),
|
|
124
|
+
clearValue: clearColor,
|
|
125
|
+
loadOp,
|
|
126
|
+
storeOp: "store",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
endFrame(): void {
|
|
133
|
+
assert(this.#renderPass, "No render pass - did you call startFrame?");
|
|
134
|
+
assert(this.#encoder, "No encoder - did you call startFrame?");
|
|
135
|
+
|
|
136
|
+
this.#renderPass.end();
|
|
137
|
+
|
|
138
|
+
// Run postprocessing if set
|
|
139
|
+
if (this.#postprocess && this.#pingpong) {
|
|
140
|
+
this.#postprocess.process(
|
|
141
|
+
this.#device.queue,
|
|
142
|
+
this.#encoder,
|
|
143
|
+
this.#pingpong,
|
|
144
|
+
this.#context.getCurrentTexture(),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.#device.queue.submit([this.#encoder.finish()]);
|
|
149
|
+
|
|
150
|
+
this.#renderPass = null;
|
|
151
|
+
this.#encoder = null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
updateEngineUniform(_uniform: EngineUniform): void {
|
|
155
|
+
// Uniforms are updated per-shader in WebGPU, not at the backend level
|
|
156
|
+
// This is handled in WebGPUQuadShader.startFrame
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async uploadAtlas(
|
|
160
|
+
atlas: CpuTextureAtlas,
|
|
161
|
+
layerIndex: number,
|
|
162
|
+
atlasId?: string,
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
const targetAtlas = this.getTextureAtlas(atlasId ?? "default");
|
|
165
|
+
assert(targetAtlas, `Atlas "${atlasId ?? "default"}" not found`);
|
|
166
|
+
const texture = targetAtlas.handle as GPUTexture;
|
|
167
|
+
|
|
168
|
+
if (atlas.rg8Bytes) {
|
|
169
|
+
const w = texture.width;
|
|
170
|
+
const h = texture.height;
|
|
171
|
+
|
|
172
|
+
// WebGPU requires 256-byte bytesPerRow
|
|
173
|
+
const rowBytes = w * 2;
|
|
174
|
+
assert(rowBytes % 256 === 0, "rowBytes must be a multiple of 256");
|
|
175
|
+
|
|
176
|
+
this.#device.queue.writeTexture(
|
|
177
|
+
{
|
|
178
|
+
texture,
|
|
179
|
+
origin: { x: 0, y: 0, z: layerIndex },
|
|
180
|
+
},
|
|
181
|
+
atlas.rg8Bytes,
|
|
182
|
+
{ bytesPerRow: rowBytes, rowsPerImage: h },
|
|
183
|
+
{ width: w, height: h, depthOrArrayLayers: 1 },
|
|
184
|
+
);
|
|
185
|
+
} else {
|
|
186
|
+
this.#device.queue.copyExternalImageToTexture(
|
|
187
|
+
{
|
|
188
|
+
source: atlas.texture,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
texture,
|
|
192
|
+
origin: [0, 0, layerIndex],
|
|
193
|
+
},
|
|
194
|
+
[atlas.texture.width, atlas.texture.height, 1],
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
createQuadShader(opts: QuadShaderCreationOpts): IBackendShader {
|
|
200
|
+
return new WebGPUQuadShader(
|
|
201
|
+
opts.label,
|
|
202
|
+
this,
|
|
203
|
+
opts.instanceCount,
|
|
204
|
+
opts.userCode,
|
|
205
|
+
opts.blendMode,
|
|
206
|
+
opts.atlasId,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
createTextureAtlas(id: string, options?: TextureAtlasOptions): ITextureAtlas {
|
|
211
|
+
if (this.#atlases.has(id)) {
|
|
212
|
+
throw new Error(`Atlas "${id}" already exists`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const format: TextureAtlasFormat = options?.format ?? "rgba8unorm";
|
|
216
|
+
const layers = options?.layers ?? this.limits.textureArrayLayers;
|
|
217
|
+
const size = options?.size ?? this.limits.textureSize;
|
|
218
|
+
|
|
219
|
+
const texture = this.#device.createTexture({
|
|
220
|
+
label: `Toodle Atlas "${id}"`,
|
|
221
|
+
size: [size, size, layers],
|
|
222
|
+
format,
|
|
223
|
+
usage:
|
|
224
|
+
GPUTextureUsage.TEXTURE_BINDING |
|
|
225
|
+
GPUTextureUsage.COPY_DST |
|
|
226
|
+
GPUTextureUsage.RENDER_ATTACHMENT,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const atlas: ITextureAtlas = { id, format, layers, size, handle: texture };
|
|
230
|
+
this.#atlases.set(id, atlas);
|
|
231
|
+
return atlas;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
getTextureAtlas(id?: string): ITextureAtlas | null {
|
|
235
|
+
return this.#atlases.get(id ?? "default") ?? null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
destroyTextureAtlas(id: string): void {
|
|
239
|
+
const atlas = this.#atlases.get(id);
|
|
240
|
+
if (atlas) {
|
|
241
|
+
(atlas.handle as GPUTexture).destroy();
|
|
242
|
+
this.#atlases.delete(id);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
resize(_width: number, _height: number): void {
|
|
247
|
+
// Canvas resize is handled automatically by WebGPU context
|
|
248
|
+
// The presentation size updates on next getCurrentTexture()
|
|
249
|
+
|
|
250
|
+
// Recreate ping-pong textures if postprocessing is active
|
|
251
|
+
if (this.#postprocess && this.#pingpong) {
|
|
252
|
+
this.#destroyPingPongTextures();
|
|
253
|
+
this.#createPingPongTextures();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
destroy(): void {
|
|
258
|
+
this.#destroyPingPongTextures();
|
|
259
|
+
// Destroy all atlases
|
|
260
|
+
for (const atlas of this.#atlases.values()) {
|
|
261
|
+
(atlas.handle as GPUTexture).destroy();
|
|
262
|
+
}
|
|
263
|
+
this.#atlases.clear();
|
|
264
|
+
this.#device.destroy();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Set a post-processor for screen effects.
|
|
269
|
+
* Setting a post-processor will cause the main render to go to an offscreen texture.
|
|
270
|
+
* Note: Ping-pong textures are not destroyed when setting to null to avoid
|
|
271
|
+
* race conditions with in-flight command buffers. They are cleaned up on destroy().
|
|
272
|
+
*/
|
|
273
|
+
setPostprocess(processor: PostProcess | null): void {
|
|
274
|
+
this.#postprocess = processor;
|
|
275
|
+
if (processor && !this.#pingpong) {
|
|
276
|
+
this.#createPingPongTextures();
|
|
277
|
+
}
|
|
278
|
+
// Don't destroy pingpong textures when setting to null - they may still be
|
|
279
|
+
// referenced by in-flight command buffers. They'll be cleaned up on destroy().
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Get the current post-processor.
|
|
284
|
+
*/
|
|
285
|
+
getPostprocess(): PostProcess | null {
|
|
286
|
+
return this.#postprocess;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
#createPingPongTextures(): void {
|
|
290
|
+
const width = this.#canvas.width;
|
|
291
|
+
const height = this.#canvas.height;
|
|
292
|
+
|
|
293
|
+
const createTexture = (label: string) =>
|
|
294
|
+
this.#device.createTexture({
|
|
295
|
+
label,
|
|
296
|
+
size: [width, height],
|
|
297
|
+
format: this.#presentationFormat,
|
|
298
|
+
usage:
|
|
299
|
+
GPUTextureUsage.RENDER_ATTACHMENT |
|
|
300
|
+
GPUTextureUsage.TEXTURE_BINDING |
|
|
301
|
+
GPUTextureUsage.COPY_SRC,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
this.#pingpong = [
|
|
305
|
+
createTexture("toodle pingpong 0"),
|
|
306
|
+
createTexture("toodle pingpong 1"),
|
|
307
|
+
];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
#destroyPingPongTextures(): void {
|
|
311
|
+
if (this.#pingpong) {
|
|
312
|
+
this.#pingpong[0].destroy();
|
|
313
|
+
this.#pingpong[1].destroy();
|
|
314
|
+
this.#pingpong = null;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Get the GPU device for advanced operations.
|
|
320
|
+
*/
|
|
321
|
+
get device(): GPUDevice {
|
|
322
|
+
return this.#device;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Get the canvas context.
|
|
327
|
+
*/
|
|
328
|
+
get context(): GPUCanvasContext {
|
|
329
|
+
return this.#context;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Get the presentation format.
|
|
334
|
+
*/
|
|
335
|
+
get presentationFormat(): GPUTextureFormat {
|
|
336
|
+
return this.#presentationFormat;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get the current render pass encoder.
|
|
341
|
+
* Only available between startFrame() and endFrame().
|
|
342
|
+
*/
|
|
343
|
+
get renderPass(): GPURenderPassEncoder {
|
|
344
|
+
assert(
|
|
345
|
+
this.#renderPass,
|
|
346
|
+
"No render pass available - did you call startFrame?",
|
|
347
|
+
);
|
|
348
|
+
return this.#renderPass;
|
|
349
|
+
}
|
|
350
|
+
}
|