@vunk/plus 1.3.11 → 1.3.13

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.
Files changed (44) hide show
  1. package/components/SharedSystems.mjs +3195 -0
  2. package/components/WebGLRenderer.mjs +3617 -0
  3. package/components/WebGPURenderer.mjs +2103 -0
  4. package/components/_commonjsHelpers.mjs +7 -0
  5. package/components/agent-chat-provider/src/types.d.ts +2 -1
  6. package/components/broadcasting-markdown/index.d.ts +2 -0
  7. package/components/broadcasting-markdown/index.mjs +238 -306
  8. package/components/broadcasting-markdown/src/const.d.ts +2 -7
  9. package/components/broadcasting-markdown/src/ctx.d.ts +28 -15
  10. package/components/broadcasting-markdown/src/howler-speech.vue.d.ts +24 -44
  11. package/components/broadcasting-markdown/src/index.vue.d.ts +31 -167
  12. package/components/broadcasting-markdown/src/paragraph.vue.d.ts +1 -14
  13. package/components/broadcasting-markdown/src/types.d.ts +10 -2
  14. package/components/broadcasting-markdown/src/use.d.ts +18 -0
  15. package/components/browserAll.mjs +3187 -0
  16. package/components/bubble-list/index.mjs +2 -1
  17. package/components/bubble-list/src/index.vue.d.ts +27 -161
  18. package/components/bubble-templates/src/index.vue.d.ts +27 -161
  19. package/components/bubble-templates/src/types.d.ts +6 -0
  20. package/components/chat-independent/index.mjs +3 -0
  21. package/components/chat-independent/src/index.vue.d.ts +27 -161
  22. package/components/colorToUniform.mjs +266 -0
  23. package/components/index2.mjs +21220 -0
  24. package/components/init.mjs +3779 -0
  25. package/components/pixi-frame/index.css +4 -0
  26. package/components/pixi-frame/index.d.ts +8 -0
  27. package/components/pixi-frame/index.mjs +6 -0
  28. package/components/pixi-frame/src/core.vue.d.ts +122 -0
  29. package/components/pixi-frame/src/ctx.d.ts +40 -0
  30. package/components/pixi-frame/src/index.vue.d.ts +215 -0
  31. package/components/pixi-frame/src/provider.vue.d.ts +2 -0
  32. package/components/pixi-frame/src/types.d.ts +1 -0
  33. package/components/pixi-frame/src/use.d.ts +3 -0
  34. package/components/pixi-frame/src/view.vue.d.ts +25 -0
  35. package/components/tables-v1/src/ctx.d.ts +1 -1
  36. package/components/tables-v1/src/el-ctx.d.ts +1 -1
  37. package/components/tables-v1-checkbox/src/ctx.d.ts +1 -1
  38. package/components/tables-v1-checkbox/src/index.vue.d.ts +1 -1
  39. package/components/webworkerAll.mjs +8 -0
  40. package/index.css +5 -4
  41. package/package.json +8 -4
  42. package/components/broadcasting-markdown/index.css +0 -3
  43. package/components/broadcasting-markdown/src/custom-speech.vue.d.ts +0 -117
  44. package/components/broadcasting-markdown/src/web-speech.vue.d.ts +0 -110
@@ -0,0 +1,2103 @@
1
+ import { g as getTextureBatchBindGroup, E as ExtensionType, f as fastCopy, D as DOMAdapter, S as STENCIL_MODES, B as BufferUsage, b as Buffer, c as BindGroup, d as createIdFromString, w as warn, h as CLEAR, i as CanvasSource, j as TextureSource, k as UniformGroup, l as CanvasPool, M as Matrix, m as compileHighShaderGpuProgram, n as colorBit, o as generateTextureBatchBit, p as roundPixelsBit, q as getMaxTexturesPerBatch, s as Shader, t as Texture, A as AbstractRenderer, R as RendererType, e as extensions } from './index2.mjs';
2
+ import { S as State, l as localUniformBitGroup2, a as localUniformBit } from './colorToUniform.mjs';
3
+ import { c as createUboSyncFunction, u as uboSyncFunctionsWGSL, U as UboSystem, B as BufferResource, G as GpuStencilModesToPixi, e as ensureAttributes, R as RenderTargetSystem, t as textureBit, S as SharedSystems, a as SharedRenderPipes } from './SharedSystems.mjs';
4
+ import 'vue';
5
+ import '@vunk/shared/enum';
6
+ import './browser.mjs';
7
+ import './_commonjsHelpers.mjs';
8
+ import './_plugin-vue_export-helper.mjs';
9
+
10
+ const tempState = State.for2d();
11
+ class GpuBatchAdaptor {
12
+ start(batchPipe, geometry, shader) {
13
+ const renderer = batchPipe.renderer;
14
+ const encoder = renderer.encoder;
15
+ const program = shader.gpuProgram;
16
+ this._shader = shader;
17
+ this._geometry = geometry;
18
+ encoder.setGeometry(geometry, program);
19
+ tempState.blendMode = "normal";
20
+ renderer.pipeline.getPipeline(
21
+ geometry,
22
+ program,
23
+ tempState
24
+ );
25
+ const globalUniformsBindGroup = renderer.globalUniforms.bindGroup;
26
+ encoder.resetBindGroup(1);
27
+ encoder.setBindGroup(0, globalUniformsBindGroup, program);
28
+ }
29
+ execute(batchPipe, batch) {
30
+ const program = this._shader.gpuProgram;
31
+ const renderer = batchPipe.renderer;
32
+ const encoder = renderer.encoder;
33
+ if (!batch.bindGroup) {
34
+ const textureBatch = batch.textures;
35
+ batch.bindGroup = getTextureBatchBindGroup(textureBatch.textures, textureBatch.count);
36
+ }
37
+ tempState.blendMode = batch.blendMode;
38
+ const gpuBindGroup = renderer.bindGroup.getBindGroup(
39
+ batch.bindGroup,
40
+ program,
41
+ 1
42
+ );
43
+ const pipeline = renderer.pipeline.getPipeline(
44
+ this._geometry,
45
+ program,
46
+ tempState,
47
+ batch.topology
48
+ );
49
+ batch.bindGroup._touch(renderer.textureGC.count);
50
+ encoder.setPipeline(pipeline);
51
+ encoder.renderPassEncoder.setBindGroup(1, gpuBindGroup);
52
+ encoder.renderPassEncoder.drawIndexed(batch.size, 1, batch.start);
53
+ }
54
+ }
55
+ /** @ignore */
56
+ GpuBatchAdaptor.extension = {
57
+ type: [
58
+ ExtensionType.WebGPUPipesAdaptor
59
+ ],
60
+ name: "batch"
61
+ };
62
+
63
+ class BindGroupSystem {
64
+ constructor(renderer) {
65
+ this._hash = /* @__PURE__ */ Object.create(null);
66
+ this._renderer = renderer;
67
+ this._renderer.renderableGC.addManagedHash(this, "_hash");
68
+ }
69
+ contextChange(gpu) {
70
+ this._gpu = gpu;
71
+ }
72
+ getBindGroup(bindGroup, program, groupIndex) {
73
+ bindGroup._updateKey();
74
+ const gpuBindGroup = this._hash[bindGroup._key] || this._createBindGroup(bindGroup, program, groupIndex);
75
+ return gpuBindGroup;
76
+ }
77
+ _createBindGroup(group, program, groupIndex) {
78
+ const device = this._gpu.device;
79
+ const groupLayout = program.layout[groupIndex];
80
+ const entries = [];
81
+ const renderer = this._renderer;
82
+ for (const j in groupLayout) {
83
+ const resource = group.resources[j] ?? group.resources[groupLayout[j]];
84
+ let gpuResource;
85
+ if (resource._resourceType === "uniformGroup") {
86
+ const uniformGroup = resource;
87
+ renderer.ubo.updateUniformGroup(uniformGroup);
88
+ const buffer = uniformGroup.buffer;
89
+ gpuResource = {
90
+ buffer: renderer.buffer.getGPUBuffer(buffer),
91
+ offset: 0,
92
+ size: buffer.descriptor.size
93
+ };
94
+ } else if (resource._resourceType === "buffer") {
95
+ const buffer = resource;
96
+ gpuResource = {
97
+ buffer: renderer.buffer.getGPUBuffer(buffer),
98
+ offset: 0,
99
+ size: buffer.descriptor.size
100
+ };
101
+ } else if (resource._resourceType === "bufferResource") {
102
+ const bufferResource = resource;
103
+ gpuResource = {
104
+ buffer: renderer.buffer.getGPUBuffer(bufferResource.buffer),
105
+ offset: bufferResource.offset,
106
+ size: bufferResource.size
107
+ };
108
+ } else if (resource._resourceType === "textureSampler") {
109
+ const sampler = resource;
110
+ gpuResource = renderer.texture.getGpuSampler(sampler);
111
+ } else if (resource._resourceType === "textureSource") {
112
+ const texture = resource;
113
+ gpuResource = renderer.texture.getGpuSource(texture).createView({});
114
+ }
115
+ entries.push({
116
+ binding: groupLayout[j],
117
+ resource: gpuResource
118
+ });
119
+ }
120
+ const layout = renderer.shader.getProgramData(program).bindGroups[groupIndex];
121
+ const gpuBindGroup = device.createBindGroup({
122
+ layout,
123
+ entries
124
+ });
125
+ this._hash[group._key] = gpuBindGroup;
126
+ return gpuBindGroup;
127
+ }
128
+ destroy() {
129
+ for (const key of Object.keys(this._hash)) {
130
+ this._hash[key] = null;
131
+ }
132
+ this._hash = null;
133
+ this._renderer = null;
134
+ }
135
+ }
136
+ /** @ignore */
137
+ BindGroupSystem.extension = {
138
+ type: [
139
+ ExtensionType.WebGPUSystem
140
+ ],
141
+ name: "bindGroup"
142
+ };
143
+
144
+ class GpuBufferSystem {
145
+ constructor(renderer) {
146
+ this._gpuBuffers = /* @__PURE__ */ Object.create(null);
147
+ this._managedBuffers = [];
148
+ renderer.renderableGC.addManagedHash(this, "_gpuBuffers");
149
+ }
150
+ contextChange(gpu) {
151
+ this._gpu = gpu;
152
+ }
153
+ getGPUBuffer(buffer) {
154
+ return this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer);
155
+ }
156
+ updateBuffer(buffer) {
157
+ const gpuBuffer = this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer);
158
+ const data = buffer.data;
159
+ if (buffer._updateID && data) {
160
+ buffer._updateID = 0;
161
+ this._gpu.device.queue.writeBuffer(
162
+ gpuBuffer,
163
+ 0,
164
+ data.buffer,
165
+ 0,
166
+ // round to the nearest 4 bytes
167
+ (buffer._updateSize || data.byteLength) + 3 & -4
168
+ );
169
+ }
170
+ return gpuBuffer;
171
+ }
172
+ /** dispose all WebGL resources of all managed buffers */
173
+ destroyAll() {
174
+ for (const id in this._gpuBuffers) {
175
+ this._gpuBuffers[id].destroy();
176
+ }
177
+ this._gpuBuffers = {};
178
+ }
179
+ createGPUBuffer(buffer) {
180
+ if (!this._gpuBuffers[buffer.uid]) {
181
+ buffer.on("update", this.updateBuffer, this);
182
+ buffer.on("change", this.onBufferChange, this);
183
+ buffer.on("destroy", this.onBufferDestroy, this);
184
+ this._managedBuffers.push(buffer);
185
+ }
186
+ const gpuBuffer = this._gpu.device.createBuffer(buffer.descriptor);
187
+ buffer._updateID = 0;
188
+ if (buffer.data) {
189
+ fastCopy(buffer.data.buffer, gpuBuffer.getMappedRange());
190
+ gpuBuffer.unmap();
191
+ }
192
+ this._gpuBuffers[buffer.uid] = gpuBuffer;
193
+ return gpuBuffer;
194
+ }
195
+ onBufferChange(buffer) {
196
+ const gpuBuffer = this._gpuBuffers[buffer.uid];
197
+ gpuBuffer.destroy();
198
+ buffer._updateID = 0;
199
+ this._gpuBuffers[buffer.uid] = this.createGPUBuffer(buffer);
200
+ }
201
+ /**
202
+ * Disposes buffer
203
+ * @param buffer - buffer with data
204
+ */
205
+ onBufferDestroy(buffer) {
206
+ this._managedBuffers.splice(this._managedBuffers.indexOf(buffer), 1);
207
+ this._destroyBuffer(buffer);
208
+ }
209
+ destroy() {
210
+ this._managedBuffers.forEach((buffer) => this._destroyBuffer(buffer));
211
+ this._managedBuffers = null;
212
+ this._gpuBuffers = null;
213
+ }
214
+ _destroyBuffer(buffer) {
215
+ const gpuBuffer = this._gpuBuffers[buffer.uid];
216
+ gpuBuffer.destroy();
217
+ buffer.off("update", this.updateBuffer, this);
218
+ buffer.off("change", this.onBufferChange, this);
219
+ buffer.off("destroy", this.onBufferDestroy, this);
220
+ this._gpuBuffers[buffer.uid] = null;
221
+ }
222
+ }
223
+ /** @ignore */
224
+ GpuBufferSystem.extension = {
225
+ type: [
226
+ ExtensionType.WebGPUSystem
227
+ ],
228
+ name: "buffer"
229
+ };
230
+
231
+ class UboBatch {
232
+ constructor({ minUniformOffsetAlignment }) {
233
+ this._minUniformOffsetAlignment = 256;
234
+ this.byteIndex = 0;
235
+ this._minUniformOffsetAlignment = minUniformOffsetAlignment;
236
+ this.data = new Float32Array(65535);
237
+ }
238
+ clear() {
239
+ this.byteIndex = 0;
240
+ }
241
+ addEmptyGroup(size) {
242
+ if (size > this._minUniformOffsetAlignment / 4) {
243
+ throw new Error(`UniformBufferBatch: array is too large: ${size * 4}`);
244
+ }
245
+ const start = this.byteIndex;
246
+ let newSize = start + size * 4;
247
+ newSize = Math.ceil(newSize / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment;
248
+ if (newSize > this.data.length * 4) {
249
+ throw new Error("UniformBufferBatch: ubo batch got too big");
250
+ }
251
+ this.byteIndex = newSize;
252
+ return start;
253
+ }
254
+ addGroup(array) {
255
+ const offset = this.addEmptyGroup(array.length);
256
+ for (let i = 0; i < array.length; i++) {
257
+ this.data[offset / 4 + i] = array[i];
258
+ }
259
+ return offset;
260
+ }
261
+ destroy() {
262
+ this.data = null;
263
+ }
264
+ }
265
+
266
+ class GpuColorMaskSystem {
267
+ constructor(renderer) {
268
+ this._colorMaskCache = 15;
269
+ this._renderer = renderer;
270
+ }
271
+ setMask(colorMask) {
272
+ if (this._colorMaskCache === colorMask)
273
+ return;
274
+ this._colorMaskCache = colorMask;
275
+ this._renderer.pipeline.setColorMask(colorMask);
276
+ }
277
+ destroy() {
278
+ this._renderer = null;
279
+ this._colorMaskCache = null;
280
+ }
281
+ }
282
+ /** @ignore */
283
+ GpuColorMaskSystem.extension = {
284
+ type: [
285
+ ExtensionType.WebGPUSystem
286
+ ],
287
+ name: "colorMask"
288
+ };
289
+
290
+ class GpuDeviceSystem {
291
+ /**
292
+ * @param {WebGPURenderer} renderer - The renderer this System works for.
293
+ */
294
+ constructor(renderer) {
295
+ this._renderer = renderer;
296
+ }
297
+ async init(options) {
298
+ if (this._initPromise)
299
+ return this._initPromise;
300
+ this._initPromise = this._createDeviceAndAdaptor(options).then((gpu) => {
301
+ this.gpu = gpu;
302
+ this._renderer.runners.contextChange.emit(this.gpu);
303
+ });
304
+ return this._initPromise;
305
+ }
306
+ /**
307
+ * Handle the context change event
308
+ * @param gpu
309
+ */
310
+ contextChange(gpu) {
311
+ this._renderer.gpu = gpu;
312
+ }
313
+ /**
314
+ * Helper class to create a WebGL Context
315
+ * @param {object} options - An options object that gets passed in to the canvas element containing the
316
+ * context attributes
317
+ * @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext
318
+ * @returns {WebGLRenderingContext} the WebGL context
319
+ */
320
+ async _createDeviceAndAdaptor(options) {
321
+ const adapter = await DOMAdapter.get().getNavigator().gpu.requestAdapter({
322
+ powerPreference: options.powerPreference,
323
+ forceFallbackAdapter: options.forceFallbackAdapter
324
+ });
325
+ const requiredFeatures = [
326
+ "texture-compression-bc",
327
+ "texture-compression-astc",
328
+ "texture-compression-etc2"
329
+ ].filter((feature) => adapter.features.has(feature));
330
+ const device = await adapter.requestDevice({
331
+ requiredFeatures
332
+ });
333
+ return { adapter, device };
334
+ }
335
+ destroy() {
336
+ this.gpu = null;
337
+ this._renderer = null;
338
+ }
339
+ }
340
+ /** @ignore */
341
+ GpuDeviceSystem.extension = {
342
+ type: [
343
+ ExtensionType.WebGPUSystem
344
+ ],
345
+ name: "device"
346
+ };
347
+ /** The default options for the GpuDeviceSystem. */
348
+ GpuDeviceSystem.defaultOptions = {
349
+ /**
350
+ * {@link WebGPUOptions.powerPreference}
351
+ * @default default
352
+ */
353
+ powerPreference: void 0,
354
+ /**
355
+ * Force the use of the fallback adapter
356
+ * @default false
357
+ */
358
+ forceFallbackAdapter: false
359
+ };
360
+
361
+ class GpuEncoderSystem {
362
+ constructor(renderer) {
363
+ this._boundBindGroup = /* @__PURE__ */ Object.create(null);
364
+ this._boundVertexBuffer = /* @__PURE__ */ Object.create(null);
365
+ this._renderer = renderer;
366
+ }
367
+ renderStart() {
368
+ this.commandFinished = new Promise((resolve) => {
369
+ this._resolveCommandFinished = resolve;
370
+ });
371
+ this.commandEncoder = this._renderer.gpu.device.createCommandEncoder();
372
+ }
373
+ beginRenderPass(gpuRenderTarget) {
374
+ this.endRenderPass();
375
+ this._clearCache();
376
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(gpuRenderTarget.descriptor);
377
+ }
378
+ endRenderPass() {
379
+ if (this.renderPassEncoder) {
380
+ this.renderPassEncoder.end();
381
+ }
382
+ this.renderPassEncoder = null;
383
+ }
384
+ setViewport(viewport) {
385
+ this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
386
+ }
387
+ setPipelineFromGeometryProgramAndState(geometry, program, state, topology) {
388
+ const pipeline = this._renderer.pipeline.getPipeline(geometry, program, state, topology);
389
+ this.setPipeline(pipeline);
390
+ }
391
+ setPipeline(pipeline) {
392
+ if (this._boundPipeline === pipeline)
393
+ return;
394
+ this._boundPipeline = pipeline;
395
+ this.renderPassEncoder.setPipeline(pipeline);
396
+ }
397
+ _setVertexBuffer(index, buffer) {
398
+ if (this._boundVertexBuffer[index] === buffer)
399
+ return;
400
+ this._boundVertexBuffer[index] = buffer;
401
+ this.renderPassEncoder.setVertexBuffer(index, this._renderer.buffer.updateBuffer(buffer));
402
+ }
403
+ _setIndexBuffer(buffer) {
404
+ if (this._boundIndexBuffer === buffer)
405
+ return;
406
+ this._boundIndexBuffer = buffer;
407
+ const indexFormat = buffer.data.BYTES_PER_ELEMENT === 2 ? "uint16" : "uint32";
408
+ this.renderPassEncoder.setIndexBuffer(this._renderer.buffer.updateBuffer(buffer), indexFormat);
409
+ }
410
+ resetBindGroup(index) {
411
+ this._boundBindGroup[index] = null;
412
+ }
413
+ setBindGroup(index, bindGroup, program) {
414
+ if (this._boundBindGroup[index] === bindGroup)
415
+ return;
416
+ this._boundBindGroup[index] = bindGroup;
417
+ bindGroup._touch(this._renderer.textureGC.count);
418
+ const gpuBindGroup = this._renderer.bindGroup.getBindGroup(bindGroup, program, index);
419
+ this.renderPassEncoder.setBindGroup(index, gpuBindGroup);
420
+ }
421
+ setGeometry(geometry, program) {
422
+ const buffersToBind = this._renderer.pipeline.getBufferNamesToBind(geometry, program);
423
+ for (const i in buffersToBind) {
424
+ this._setVertexBuffer(i, geometry.attributes[buffersToBind[i]].buffer);
425
+ }
426
+ if (geometry.indexBuffer) {
427
+ this._setIndexBuffer(geometry.indexBuffer);
428
+ }
429
+ }
430
+ _setShaderBindGroups(shader, skipSync) {
431
+ for (const i in shader.groups) {
432
+ const bindGroup = shader.groups[i];
433
+ if (!skipSync) {
434
+ this._syncBindGroup(bindGroup);
435
+ }
436
+ this.setBindGroup(i, bindGroup, shader.gpuProgram);
437
+ }
438
+ }
439
+ _syncBindGroup(bindGroup) {
440
+ for (const j in bindGroup.resources) {
441
+ const resource = bindGroup.resources[j];
442
+ if (resource.isUniformGroup) {
443
+ this._renderer.ubo.updateUniformGroup(resource);
444
+ }
445
+ }
446
+ }
447
+ draw(options) {
448
+ const { geometry, shader, state, topology, size, start, instanceCount, skipSync } = options;
449
+ this.setPipelineFromGeometryProgramAndState(geometry, shader.gpuProgram, state, topology);
450
+ this.setGeometry(geometry, shader.gpuProgram);
451
+ this._setShaderBindGroups(shader, skipSync);
452
+ if (geometry.indexBuffer) {
453
+ this.renderPassEncoder.drawIndexed(
454
+ size || geometry.indexBuffer.data.length,
455
+ instanceCount ?? geometry.instanceCount,
456
+ start || 0
457
+ );
458
+ } else {
459
+ this.renderPassEncoder.draw(size || geometry.getSize(), instanceCount ?? geometry.instanceCount, start || 0);
460
+ }
461
+ }
462
+ finishRenderPass() {
463
+ if (this.renderPassEncoder) {
464
+ this.renderPassEncoder.end();
465
+ this.renderPassEncoder = null;
466
+ }
467
+ }
468
+ postrender() {
469
+ this.finishRenderPass();
470
+ this._gpu.device.queue.submit([this.commandEncoder.finish()]);
471
+ this._resolveCommandFinished();
472
+ this.commandEncoder = null;
473
+ }
474
+ // restores a render pass if finishRenderPass was called
475
+ // not optimised as really used for debugging!
476
+ // used when we want to stop drawing and log a texture..
477
+ restoreRenderPass() {
478
+ const descriptor = this._renderer.renderTarget.adaptor.getDescriptor(
479
+ this._renderer.renderTarget.renderTarget,
480
+ false,
481
+ [0, 0, 0, 1]
482
+ );
483
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(descriptor);
484
+ const boundPipeline = this._boundPipeline;
485
+ const boundVertexBuffer = { ...this._boundVertexBuffer };
486
+ const boundIndexBuffer = this._boundIndexBuffer;
487
+ const boundBindGroup = { ...this._boundBindGroup };
488
+ this._clearCache();
489
+ const viewport = this._renderer.renderTarget.viewport;
490
+ this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
491
+ this.setPipeline(boundPipeline);
492
+ for (const i in boundVertexBuffer) {
493
+ this._setVertexBuffer(i, boundVertexBuffer[i]);
494
+ }
495
+ for (const i in boundBindGroup) {
496
+ this.setBindGroup(i, boundBindGroup[i], null);
497
+ }
498
+ this._setIndexBuffer(boundIndexBuffer);
499
+ }
500
+ _clearCache() {
501
+ for (let i = 0; i < 16; i++) {
502
+ this._boundBindGroup[i] = null;
503
+ this._boundVertexBuffer[i] = null;
504
+ }
505
+ this._boundIndexBuffer = null;
506
+ this._boundPipeline = null;
507
+ }
508
+ destroy() {
509
+ this._renderer = null;
510
+ this._gpu = null;
511
+ this._boundBindGroup = null;
512
+ this._boundVertexBuffer = null;
513
+ this._boundIndexBuffer = null;
514
+ this._boundPipeline = null;
515
+ }
516
+ contextChange(gpu) {
517
+ this._gpu = gpu;
518
+ }
519
+ }
520
+ /** @ignore */
521
+ GpuEncoderSystem.extension = {
522
+ type: [ExtensionType.WebGPUSystem],
523
+ name: "encoder",
524
+ priority: 1
525
+ };
526
+
527
+ class GpuStencilSystem {
528
+ constructor(renderer) {
529
+ this._renderTargetStencilState = /* @__PURE__ */ Object.create(null);
530
+ this._renderer = renderer;
531
+ renderer.renderTarget.onRenderTargetChange.add(this);
532
+ }
533
+ onRenderTargetChange(renderTarget) {
534
+ let stencilState = this._renderTargetStencilState[renderTarget.uid];
535
+ if (!stencilState) {
536
+ stencilState = this._renderTargetStencilState[renderTarget.uid] = {
537
+ stencilMode: STENCIL_MODES.DISABLED,
538
+ stencilReference: 0
539
+ };
540
+ }
541
+ this._activeRenderTarget = renderTarget;
542
+ this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference);
543
+ }
544
+ setStencilMode(stencilMode, stencilReference) {
545
+ const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid];
546
+ stencilState.stencilMode = stencilMode;
547
+ stencilState.stencilReference = stencilReference;
548
+ const renderer = this._renderer;
549
+ renderer.pipeline.setStencilMode(stencilMode);
550
+ renderer.encoder.renderPassEncoder.setStencilReference(stencilReference);
551
+ }
552
+ destroy() {
553
+ this._renderer.renderTarget.onRenderTargetChange.remove(this);
554
+ this._renderer = null;
555
+ this._activeRenderTarget = null;
556
+ this._renderTargetStencilState = null;
557
+ }
558
+ }
559
+ /** @ignore */
560
+ GpuStencilSystem.extension = {
561
+ type: [
562
+ ExtensionType.WebGPUSystem
563
+ ],
564
+ name: "stencil"
565
+ };
566
+
567
+ const WGSL_ALIGN_SIZE_DATA = {
568
+ i32: { align: 4, size: 4 },
569
+ u32: { align: 4, size: 4 },
570
+ f32: { align: 4, size: 4 },
571
+ f16: { align: 2, size: 2 },
572
+ "vec2<i32>": { align: 8, size: 8 },
573
+ "vec2<u32>": { align: 8, size: 8 },
574
+ "vec2<f32>": { align: 8, size: 8 },
575
+ "vec2<f16>": { align: 4, size: 4 },
576
+ "vec3<i32>": { align: 16, size: 12 },
577
+ "vec3<u32>": { align: 16, size: 12 },
578
+ "vec3<f32>": { align: 16, size: 12 },
579
+ "vec3<f16>": { align: 8, size: 6 },
580
+ "vec4<i32>": { align: 16, size: 16 },
581
+ "vec4<u32>": { align: 16, size: 16 },
582
+ "vec4<f32>": { align: 16, size: 16 },
583
+ "vec4<f16>": { align: 8, size: 8 },
584
+ "mat2x2<f32>": { align: 8, size: 16 },
585
+ "mat2x2<f16>": { align: 4, size: 8 },
586
+ "mat3x2<f32>": { align: 8, size: 24 },
587
+ "mat3x2<f16>": { align: 4, size: 12 },
588
+ "mat4x2<f32>": { align: 8, size: 32 },
589
+ "mat4x2<f16>": { align: 4, size: 16 },
590
+ "mat2x3<f32>": { align: 16, size: 32 },
591
+ "mat2x3<f16>": { align: 8, size: 16 },
592
+ "mat3x3<f32>": { align: 16, size: 48 },
593
+ "mat3x3<f16>": { align: 8, size: 24 },
594
+ "mat4x3<f32>": { align: 16, size: 64 },
595
+ "mat4x3<f16>": { align: 8, size: 32 },
596
+ "mat2x4<f32>": { align: 16, size: 32 },
597
+ "mat2x4<f16>": { align: 8, size: 16 },
598
+ "mat3x4<f32>": { align: 16, size: 48 },
599
+ "mat3x4<f16>": { align: 8, size: 24 },
600
+ "mat4x4<f32>": { align: 16, size: 64 },
601
+ "mat4x4<f16>": { align: 8, size: 32 }
602
+ };
603
+ function createUboElementsWGSL(uniformData) {
604
+ const uboElements = uniformData.map((data) => ({
605
+ data,
606
+ offset: 0,
607
+ size: 0
608
+ }));
609
+ let offset = 0;
610
+ for (let i = 0; i < uboElements.length; i++) {
611
+ const uboElement = uboElements[i];
612
+ let size = WGSL_ALIGN_SIZE_DATA[uboElement.data.type].size;
613
+ const align = WGSL_ALIGN_SIZE_DATA[uboElement.data.type].align;
614
+ if (!WGSL_ALIGN_SIZE_DATA[uboElement.data.type]) {
615
+ throw new Error(`[Pixi.js] WebGPU UniformBuffer: Unknown type ${uboElement.data.type}`);
616
+ }
617
+ if (uboElement.data.size > 1) {
618
+ size = Math.max(size, align) * uboElement.data.size;
619
+ }
620
+ offset = Math.ceil(offset / align) * align;
621
+ uboElement.size = size;
622
+ uboElement.offset = offset;
623
+ offset += size;
624
+ }
625
+ offset = Math.ceil(offset / 16) * 16;
626
+ return { uboElements, size: offset };
627
+ }
628
+
629
+ function generateArraySyncWGSL(uboElement, offsetToAdd) {
630
+ const { size, align } = WGSL_ALIGN_SIZE_DATA[uboElement.data.type];
631
+ const remainder = (align - size) / 4;
632
+ const data = uboElement.data.type.indexOf("i32") >= 0 ? "dataInt32" : "data";
633
+ return `
634
+ v = uv.${uboElement.data.name};
635
+ ${offsetToAdd !== 0 ? `offset += ${offsetToAdd};` : ""}
636
+
637
+ arrayOffset = offset;
638
+
639
+ t = 0;
640
+
641
+ for(var i=0; i < ${uboElement.data.size * (size / 4)}; i++)
642
+ {
643
+ for(var j = 0; j < ${size / 4}; j++)
644
+ {
645
+ ${data}[arrayOffset++] = v[t++];
646
+ }
647
+ ${remainder !== 0 ? `arrayOffset += ${remainder};` : ""}
648
+ }
649
+ `;
650
+ }
651
+
652
+ function createUboSyncFunctionWGSL(uboElements) {
653
+ return createUboSyncFunction(
654
+ uboElements,
655
+ "uboWgsl",
656
+ generateArraySyncWGSL,
657
+ uboSyncFunctionsWGSL
658
+ );
659
+ }
660
+
661
+ class GpuUboSystem extends UboSystem {
662
+ constructor() {
663
+ super({
664
+ createUboElements: createUboElementsWGSL,
665
+ generateUboSync: createUboSyncFunctionWGSL
666
+ });
667
+ }
668
+ }
669
+ /** @ignore */
670
+ GpuUboSystem.extension = {
671
+ type: [ExtensionType.WebGPUSystem],
672
+ name: "ubo"
673
+ };
674
+
675
+ const minUniformOffsetAlignment = 128;
676
+ class GpuUniformBatchPipe {
677
+ constructor(renderer) {
678
+ this._bindGroupHash = /* @__PURE__ */ Object.create(null);
679
+ // number of buffers..
680
+ this._buffers = [];
681
+ this._bindGroups = [];
682
+ this._bufferResources = [];
683
+ this._renderer = renderer;
684
+ this._renderer.renderableGC.addManagedHash(this, "_bindGroupHash");
685
+ this._batchBuffer = new UboBatch({ minUniformOffsetAlignment });
686
+ const totalBuffers = 256 / minUniformOffsetAlignment;
687
+ for (let i = 0; i < totalBuffers; i++) {
688
+ let usage = BufferUsage.UNIFORM | BufferUsage.COPY_DST;
689
+ if (i === 0)
690
+ usage |= BufferUsage.COPY_SRC;
691
+ this._buffers.push(new Buffer({
692
+ data: this._batchBuffer.data,
693
+ usage
694
+ }));
695
+ }
696
+ }
697
+ renderEnd() {
698
+ this._uploadBindGroups();
699
+ this._resetBindGroups();
700
+ }
701
+ _resetBindGroups() {
702
+ for (const i in this._bindGroupHash) {
703
+ this._bindGroupHash[i] = null;
704
+ }
705
+ this._batchBuffer.clear();
706
+ }
707
+ // just works for single bind groups for now
708
+ getUniformBindGroup(group, duplicate) {
709
+ if (!duplicate && this._bindGroupHash[group.uid]) {
710
+ return this._bindGroupHash[group.uid];
711
+ }
712
+ this._renderer.ubo.ensureUniformGroup(group);
713
+ const data = group.buffer.data;
714
+ const offset = this._batchBuffer.addEmptyGroup(data.length);
715
+ this._renderer.ubo.syncUniformGroup(group, this._batchBuffer.data, offset / 4);
716
+ this._bindGroupHash[group.uid] = this._getBindGroup(offset / minUniformOffsetAlignment);
717
+ return this._bindGroupHash[group.uid];
718
+ }
719
+ getUboResource(group) {
720
+ this._renderer.ubo.updateUniformGroup(group);
721
+ const data = group.buffer.data;
722
+ const offset = this._batchBuffer.addGroup(data);
723
+ return this._getBufferResource(offset / minUniformOffsetAlignment);
724
+ }
725
+ getArrayBindGroup(data) {
726
+ const offset = this._batchBuffer.addGroup(data);
727
+ return this._getBindGroup(offset / minUniformOffsetAlignment);
728
+ }
729
+ getArrayBufferResource(data) {
730
+ const offset = this._batchBuffer.addGroup(data);
731
+ const index = offset / minUniformOffsetAlignment;
732
+ return this._getBufferResource(index);
733
+ }
734
+ _getBufferResource(index) {
735
+ if (!this._bufferResources[index]) {
736
+ const buffer = this._buffers[index % 2];
737
+ this._bufferResources[index] = new BufferResource({
738
+ buffer,
739
+ offset: (index / 2 | 0) * 256,
740
+ size: minUniformOffsetAlignment
741
+ });
742
+ }
743
+ return this._bufferResources[index];
744
+ }
745
+ _getBindGroup(index) {
746
+ if (!this._bindGroups[index]) {
747
+ const bindGroup = new BindGroup({
748
+ 0: this._getBufferResource(index)
749
+ });
750
+ this._bindGroups[index] = bindGroup;
751
+ }
752
+ return this._bindGroups[index];
753
+ }
754
+ _uploadBindGroups() {
755
+ const bufferSystem = this._renderer.buffer;
756
+ const firstBuffer = this._buffers[0];
757
+ firstBuffer.update(this._batchBuffer.byteIndex);
758
+ bufferSystem.updateBuffer(firstBuffer);
759
+ const commandEncoder = this._renderer.gpu.device.createCommandEncoder();
760
+ for (let i = 1; i < this._buffers.length; i++) {
761
+ const buffer = this._buffers[i];
762
+ commandEncoder.copyBufferToBuffer(
763
+ bufferSystem.getGPUBuffer(firstBuffer),
764
+ minUniformOffsetAlignment,
765
+ bufferSystem.getGPUBuffer(buffer),
766
+ 0,
767
+ this._batchBuffer.byteIndex
768
+ );
769
+ }
770
+ this._renderer.gpu.device.queue.submit([commandEncoder.finish()]);
771
+ }
772
+ destroy() {
773
+ for (let i = 0; i < this._bindGroups.length; i++) {
774
+ this._bindGroups[i].destroy();
775
+ }
776
+ this._bindGroups = null;
777
+ this._bindGroupHash = null;
778
+ for (let i = 0; i < this._buffers.length; i++) {
779
+ this._buffers[i].destroy();
780
+ }
781
+ this._buffers = null;
782
+ for (let i = 0; i < this._bufferResources.length; i++) {
783
+ this._bufferResources[i].destroy();
784
+ }
785
+ this._bufferResources = null;
786
+ this._batchBuffer.destroy();
787
+ this._bindGroupHash = null;
788
+ this._renderer = null;
789
+ }
790
+ }
791
+ /** @ignore */
792
+ GpuUniformBatchPipe.extension = {
793
+ type: [
794
+ ExtensionType.WebGPUPipes
795
+ ],
796
+ name: "uniformBatch"
797
+ };
798
+
799
+ const topologyStringToId = {
800
+ "point-list": 0,
801
+ "line-list": 1,
802
+ "line-strip": 2,
803
+ "triangle-list": 3,
804
+ "triangle-strip": 4
805
+ };
806
+ function getGraphicsStateKey(geometryLayout, shaderKey, state, blendMode, topology) {
807
+ return geometryLayout << 24 | shaderKey << 16 | state << 10 | blendMode << 5 | topology;
808
+ }
809
+ function getGlobalStateKey(stencilStateId, multiSampleCount, colorMask, renderTarget) {
810
+ return colorMask << 6 | stencilStateId << 3 | renderTarget << 1 | multiSampleCount;
811
+ }
812
+ class PipelineSystem {
813
+ constructor(renderer) {
814
+ this._moduleCache = /* @__PURE__ */ Object.create(null);
815
+ this._bufferLayoutsCache = /* @__PURE__ */ Object.create(null);
816
+ this._bindingNamesCache = /* @__PURE__ */ Object.create(null);
817
+ this._pipeCache = /* @__PURE__ */ Object.create(null);
818
+ this._pipeStateCaches = /* @__PURE__ */ Object.create(null);
819
+ this._colorMask = 15;
820
+ this._multisampleCount = 1;
821
+ this._renderer = renderer;
822
+ }
823
+ contextChange(gpu) {
824
+ this._gpu = gpu;
825
+ this.setStencilMode(STENCIL_MODES.DISABLED);
826
+ this._updatePipeHash();
827
+ }
828
+ setMultisampleCount(multisampleCount) {
829
+ if (this._multisampleCount === multisampleCount)
830
+ return;
831
+ this._multisampleCount = multisampleCount;
832
+ this._updatePipeHash();
833
+ }
834
+ setRenderTarget(renderTarget) {
835
+ this._multisampleCount = renderTarget.msaaSamples;
836
+ this._depthStencilAttachment = renderTarget.descriptor.depthStencilAttachment ? 1 : 0;
837
+ this._updatePipeHash();
838
+ }
839
+ setColorMask(colorMask) {
840
+ if (this._colorMask === colorMask)
841
+ return;
842
+ this._colorMask = colorMask;
843
+ this._updatePipeHash();
844
+ }
845
+ setStencilMode(stencilMode) {
846
+ if (this._stencilMode === stencilMode)
847
+ return;
848
+ this._stencilMode = stencilMode;
849
+ this._stencilState = GpuStencilModesToPixi[stencilMode];
850
+ this._updatePipeHash();
851
+ }
852
+ setPipeline(geometry, program, state, passEncoder) {
853
+ const pipeline = this.getPipeline(geometry, program, state);
854
+ passEncoder.setPipeline(pipeline);
855
+ }
856
+ getPipeline(geometry, program, state, topology) {
857
+ if (!geometry._layoutKey) {
858
+ ensureAttributes(geometry, program.attributeData);
859
+ this._generateBufferKey(geometry);
860
+ }
861
+ topology || (topology = geometry.topology);
862
+ const key = getGraphicsStateKey(
863
+ geometry._layoutKey,
864
+ program._layoutKey,
865
+ state.data,
866
+ state._blendModeId,
867
+ topologyStringToId[topology]
868
+ );
869
+ if (this._pipeCache[key])
870
+ return this._pipeCache[key];
871
+ this._pipeCache[key] = this._createPipeline(geometry, program, state, topology);
872
+ return this._pipeCache[key];
873
+ }
874
+ _createPipeline(geometry, program, state, topology) {
875
+ const device = this._gpu.device;
876
+ const buffers = this._createVertexBufferLayouts(geometry, program);
877
+ const blendModes = this._renderer.state.getColorTargets(state);
878
+ blendModes[0].writeMask = this._stencilMode === STENCIL_MODES.RENDERING_MASK_ADD ? 0 : this._colorMask;
879
+ const layout = this._renderer.shader.getProgramData(program).pipeline;
880
+ const descriptor = {
881
+ // TODO later check if its helpful to create..
882
+ // layout,
883
+ vertex: {
884
+ module: this._getModule(program.vertex.source),
885
+ entryPoint: program.vertex.entryPoint,
886
+ // geometry..
887
+ buffers
888
+ },
889
+ fragment: {
890
+ module: this._getModule(program.fragment.source),
891
+ entryPoint: program.fragment.entryPoint,
892
+ targets: blendModes
893
+ },
894
+ primitive: {
895
+ topology,
896
+ cullMode: state.cullMode
897
+ },
898
+ layout,
899
+ multisample: {
900
+ count: this._multisampleCount
901
+ },
902
+ // depthStencil,
903
+ label: `PIXI Pipeline`
904
+ };
905
+ if (this._depthStencilAttachment) {
906
+ descriptor.depthStencil = {
907
+ ...this._stencilState,
908
+ format: "depth24plus-stencil8",
909
+ depthWriteEnabled: state.depthTest,
910
+ depthCompare: state.depthTest ? "less" : "always"
911
+ };
912
+ }
913
+ const pipeline = device.createRenderPipeline(descriptor);
914
+ return pipeline;
915
+ }
916
+ _getModule(code) {
917
+ return this._moduleCache[code] || this._createModule(code);
918
+ }
919
+ _createModule(code) {
920
+ const device = this._gpu.device;
921
+ this._moduleCache[code] = device.createShaderModule({
922
+ code
923
+ });
924
+ return this._moduleCache[code];
925
+ }
926
+ _generateBufferKey(geometry) {
927
+ const keyGen = [];
928
+ let index = 0;
929
+ const attributeKeys = Object.keys(geometry.attributes).sort();
930
+ for (let i = 0; i < attributeKeys.length; i++) {
931
+ const attribute = geometry.attributes[attributeKeys[i]];
932
+ keyGen[index++] = attribute.offset;
933
+ keyGen[index++] = attribute.format;
934
+ keyGen[index++] = attribute.stride;
935
+ keyGen[index++] = attribute.instance;
936
+ }
937
+ const stringKey = keyGen.join("|");
938
+ geometry._layoutKey = createIdFromString(stringKey, "geometry");
939
+ return geometry._layoutKey;
940
+ }
941
+ _generateAttributeLocationsKey(program) {
942
+ const keyGen = [];
943
+ let index = 0;
944
+ const attributeKeys = Object.keys(program.attributeData).sort();
945
+ for (let i = 0; i < attributeKeys.length; i++) {
946
+ const attribute = program.attributeData[attributeKeys[i]];
947
+ keyGen[index++] = attribute.location;
948
+ }
949
+ const stringKey = keyGen.join("|");
950
+ program._attributeLocationsKey = createIdFromString(stringKey, "programAttributes");
951
+ return program._attributeLocationsKey;
952
+ }
953
+ /**
954
+ * Returns a hash of buffer names mapped to bind locations.
955
+ * This is used to bind the correct buffer to the correct location in the shader.
956
+ * @param geometry - The geometry where to get the buffer names
957
+ * @param program - The program where to get the buffer names
958
+ * @returns An object of buffer names mapped to the bind location.
959
+ */
960
+ getBufferNamesToBind(geometry, program) {
961
+ const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
962
+ if (this._bindingNamesCache[key])
963
+ return this._bindingNamesCache[key];
964
+ const data = this._createVertexBufferLayouts(geometry, program);
965
+ const bufferNamesToBind = /* @__PURE__ */ Object.create(null);
966
+ const attributeData = program.attributeData;
967
+ for (let i = 0; i < data.length; i++) {
968
+ const attributes = Object.values(data[i].attributes);
969
+ const shaderLocation = attributes[0].shaderLocation;
970
+ for (const j in attributeData) {
971
+ if (attributeData[j].location === shaderLocation) {
972
+ bufferNamesToBind[i] = j;
973
+ break;
974
+ }
975
+ }
976
+ }
977
+ this._bindingNamesCache[key] = bufferNamesToBind;
978
+ return bufferNamesToBind;
979
+ }
980
+ _createVertexBufferLayouts(geometry, program) {
981
+ if (!program._attributeLocationsKey)
982
+ this._generateAttributeLocationsKey(program);
983
+ const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
984
+ if (this._bufferLayoutsCache[key]) {
985
+ return this._bufferLayoutsCache[key];
986
+ }
987
+ const vertexBuffersLayout = [];
988
+ geometry.buffers.forEach((buffer) => {
989
+ const bufferEntry = {
990
+ arrayStride: 0,
991
+ stepMode: "vertex",
992
+ attributes: []
993
+ };
994
+ const bufferEntryAttributes = bufferEntry.attributes;
995
+ for (const i in program.attributeData) {
996
+ const attribute = geometry.attributes[i];
997
+ if ((attribute.divisor ?? 1) !== 1) {
998
+ warn(`Attribute ${i} has an invalid divisor value of '${attribute.divisor}'. WebGPU only supports a divisor value of 1`);
999
+ }
1000
+ if (attribute.buffer === buffer) {
1001
+ bufferEntry.arrayStride = attribute.stride;
1002
+ bufferEntry.stepMode = attribute.instance ? "instance" : "vertex";
1003
+ bufferEntryAttributes.push({
1004
+ shaderLocation: program.attributeData[i].location,
1005
+ offset: attribute.offset,
1006
+ format: attribute.format
1007
+ });
1008
+ }
1009
+ }
1010
+ if (bufferEntryAttributes.length) {
1011
+ vertexBuffersLayout.push(bufferEntry);
1012
+ }
1013
+ });
1014
+ this._bufferLayoutsCache[key] = vertexBuffersLayout;
1015
+ return vertexBuffersLayout;
1016
+ }
1017
+ _updatePipeHash() {
1018
+ const key = getGlobalStateKey(
1019
+ this._stencilMode,
1020
+ this._multisampleCount,
1021
+ this._colorMask,
1022
+ this._depthStencilAttachment
1023
+ );
1024
+ if (!this._pipeStateCaches[key]) {
1025
+ this._pipeStateCaches[key] = /* @__PURE__ */ Object.create(null);
1026
+ }
1027
+ this._pipeCache = this._pipeStateCaches[key];
1028
+ }
1029
+ destroy() {
1030
+ this._renderer = null;
1031
+ this._bufferLayoutsCache = null;
1032
+ }
1033
+ }
1034
+ /** @ignore */
1035
+ PipelineSystem.extension = {
1036
+ type: [ExtensionType.WebGPUSystem],
1037
+ name: "pipeline"
1038
+ };
1039
+
1040
+ class GpuRenderTarget {
1041
+ constructor() {
1042
+ this.contexts = [];
1043
+ this.msaaTextures = [];
1044
+ this.msaaSamples = 1;
1045
+ }
1046
+ }
1047
+
1048
+ class GpuRenderTargetAdaptor {
1049
+ init(renderer, renderTargetSystem) {
1050
+ this._renderer = renderer;
1051
+ this._renderTargetSystem = renderTargetSystem;
1052
+ }
1053
+ copyToTexture(sourceRenderSurfaceTexture, destinationTexture, originSrc, size, originDest) {
1054
+ const renderer = this._renderer;
1055
+ const baseGpuTexture = this._getGpuColorTexture(
1056
+ sourceRenderSurfaceTexture
1057
+ );
1058
+ const backGpuTexture = renderer.texture.getGpuSource(
1059
+ destinationTexture.source
1060
+ );
1061
+ renderer.encoder.commandEncoder.copyTextureToTexture(
1062
+ {
1063
+ texture: baseGpuTexture,
1064
+ origin: originSrc
1065
+ },
1066
+ {
1067
+ texture: backGpuTexture,
1068
+ origin: originDest
1069
+ },
1070
+ size
1071
+ );
1072
+ return destinationTexture;
1073
+ }
1074
+ startRenderPass(renderTarget, clear = true, clearColor, viewport) {
1075
+ const renderTargetSystem = this._renderTargetSystem;
1076
+ const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget);
1077
+ const descriptor = this.getDescriptor(renderTarget, clear, clearColor);
1078
+ gpuRenderTarget.descriptor = descriptor;
1079
+ this._renderer.pipeline.setRenderTarget(gpuRenderTarget);
1080
+ this._renderer.encoder.beginRenderPass(gpuRenderTarget);
1081
+ this._renderer.encoder.setViewport(viewport);
1082
+ }
1083
+ finishRenderPass() {
1084
+ this._renderer.encoder.endRenderPass();
1085
+ }
1086
+ /**
1087
+ * returns the gpu texture for the first color texture in the render target
1088
+ * mainly used by the filter manager to get copy the texture for blending
1089
+ * @param renderTarget
1090
+ * @returns a gpu texture
1091
+ */
1092
+ _getGpuColorTexture(renderTarget) {
1093
+ const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
1094
+ if (gpuRenderTarget.contexts[0]) {
1095
+ return gpuRenderTarget.contexts[0].getCurrentTexture();
1096
+ }
1097
+ return this._renderer.texture.getGpuSource(
1098
+ renderTarget.colorTextures[0].source
1099
+ );
1100
+ }
1101
+ getDescriptor(renderTarget, clear, clearValue) {
1102
+ if (typeof clear === "boolean") {
1103
+ clear = clear ? CLEAR.ALL : CLEAR.NONE;
1104
+ }
1105
+ const renderTargetSystem = this._renderTargetSystem;
1106
+ const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget);
1107
+ const colorAttachments = renderTarget.colorTextures.map(
1108
+ (texture, i) => {
1109
+ const context = gpuRenderTarget.contexts[i];
1110
+ let view;
1111
+ let resolveTarget;
1112
+ if (context) {
1113
+ const currentTexture = context.getCurrentTexture();
1114
+ const canvasTextureView = currentTexture.createView();
1115
+ view = canvasTextureView;
1116
+ } else {
1117
+ view = this._renderer.texture.getGpuSource(texture).createView({
1118
+ mipLevelCount: 1
1119
+ });
1120
+ }
1121
+ if (gpuRenderTarget.msaaTextures[i]) {
1122
+ resolveTarget = view;
1123
+ view = this._renderer.texture.getTextureView(
1124
+ gpuRenderTarget.msaaTextures[i]
1125
+ );
1126
+ }
1127
+ const loadOp = clear & CLEAR.COLOR ? "clear" : "load";
1128
+ clearValue ?? (clearValue = renderTargetSystem.defaultClearColor);
1129
+ return {
1130
+ view,
1131
+ resolveTarget,
1132
+ clearValue,
1133
+ storeOp: "store",
1134
+ loadOp
1135
+ };
1136
+ }
1137
+ );
1138
+ let depthStencilAttachment;
1139
+ if ((renderTarget.stencil || renderTarget.depth) && !renderTarget.depthStencilTexture) {
1140
+ renderTarget.ensureDepthStencilTexture();
1141
+ renderTarget.depthStencilTexture.source.sampleCount = gpuRenderTarget.msaa ? 4 : 1;
1142
+ }
1143
+ if (renderTarget.depthStencilTexture) {
1144
+ const stencilLoadOp = clear & CLEAR.STENCIL ? "clear" : "load";
1145
+ const depthLoadOp = clear & CLEAR.DEPTH ? "clear" : "load";
1146
+ depthStencilAttachment = {
1147
+ view: this._renderer.texture.getGpuSource(renderTarget.depthStencilTexture.source).createView(),
1148
+ stencilStoreOp: "store",
1149
+ stencilLoadOp,
1150
+ depthClearValue: 1,
1151
+ depthLoadOp,
1152
+ depthStoreOp: "store"
1153
+ };
1154
+ }
1155
+ const descriptor = {
1156
+ colorAttachments,
1157
+ depthStencilAttachment
1158
+ };
1159
+ return descriptor;
1160
+ }
1161
+ clear(renderTarget, clear = true, clearColor, viewport) {
1162
+ if (!clear)
1163
+ return;
1164
+ const { gpu, encoder } = this._renderer;
1165
+ const device = gpu.device;
1166
+ const standAlone = encoder.commandEncoder === null;
1167
+ if (standAlone) {
1168
+ const commandEncoder = device.createCommandEncoder();
1169
+ const renderPassDescriptor = this.getDescriptor(renderTarget, clear, clearColor);
1170
+ const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
1171
+ passEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
1172
+ passEncoder.end();
1173
+ const gpuCommands = commandEncoder.finish();
1174
+ device.queue.submit([gpuCommands]);
1175
+ } else {
1176
+ this.startRenderPass(renderTarget, clear, clearColor, viewport);
1177
+ }
1178
+ }
1179
+ initGpuRenderTarget(renderTarget) {
1180
+ renderTarget.isRoot = true;
1181
+ const gpuRenderTarget = new GpuRenderTarget();
1182
+ renderTarget.colorTextures.forEach((colorTexture, i) => {
1183
+ if (CanvasSource.test(colorTexture.resource)) {
1184
+ const context = colorTexture.resource.getContext(
1185
+ "webgpu"
1186
+ );
1187
+ const alphaMode = colorTexture.transparent ? "premultiplied" : "opaque";
1188
+ try {
1189
+ context.configure({
1190
+ device: this._renderer.gpu.device,
1191
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
1192
+ format: "bgra8unorm",
1193
+ alphaMode
1194
+ });
1195
+ } catch (e) {
1196
+ console.error(e);
1197
+ }
1198
+ gpuRenderTarget.contexts[i] = context;
1199
+ }
1200
+ gpuRenderTarget.msaa = colorTexture.source.antialias;
1201
+ if (colorTexture.source.antialias) {
1202
+ const msaaTexture = new TextureSource({
1203
+ width: 0,
1204
+ height: 0,
1205
+ sampleCount: 4
1206
+ });
1207
+ gpuRenderTarget.msaaTextures[i] = msaaTexture;
1208
+ }
1209
+ });
1210
+ if (gpuRenderTarget.msaa) {
1211
+ gpuRenderTarget.msaaSamples = 4;
1212
+ if (renderTarget.depthStencilTexture) {
1213
+ renderTarget.depthStencilTexture.source.sampleCount = 4;
1214
+ }
1215
+ }
1216
+ return gpuRenderTarget;
1217
+ }
1218
+ destroyGpuRenderTarget(gpuRenderTarget) {
1219
+ gpuRenderTarget.contexts.forEach((context) => {
1220
+ context.unconfigure();
1221
+ });
1222
+ gpuRenderTarget.msaaTextures.forEach((texture) => {
1223
+ texture.destroy();
1224
+ });
1225
+ gpuRenderTarget.msaaTextures.length = 0;
1226
+ gpuRenderTarget.contexts.length = 0;
1227
+ }
1228
+ ensureDepthStencilTexture(renderTarget) {
1229
+ const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
1230
+ if (renderTarget.depthStencilTexture && gpuRenderTarget.msaa) {
1231
+ renderTarget.depthStencilTexture.source.sampleCount = 4;
1232
+ }
1233
+ }
1234
+ resizeGpuRenderTarget(renderTarget) {
1235
+ const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
1236
+ gpuRenderTarget.width = renderTarget.width;
1237
+ gpuRenderTarget.height = renderTarget.height;
1238
+ if (gpuRenderTarget.msaa) {
1239
+ renderTarget.colorTextures.forEach((colorTexture, i) => {
1240
+ const msaaTexture = gpuRenderTarget.msaaTextures[i];
1241
+ msaaTexture?.resize(
1242
+ colorTexture.source.width,
1243
+ colorTexture.source.height,
1244
+ colorTexture.source._resolution
1245
+ );
1246
+ });
1247
+ }
1248
+ }
1249
+ }
1250
+
1251
+ class GpuRenderTargetSystem extends RenderTargetSystem {
1252
+ constructor(renderer) {
1253
+ super(renderer);
1254
+ this.adaptor = new GpuRenderTargetAdaptor();
1255
+ this.adaptor.init(renderer, this);
1256
+ }
1257
+ }
1258
+ /** @ignore */
1259
+ GpuRenderTargetSystem.extension = {
1260
+ type: [ExtensionType.WebGPUSystem],
1261
+ name: "renderTarget"
1262
+ };
1263
+
1264
+ class GpuShaderSystem {
1265
+ constructor() {
1266
+ this._gpuProgramData = /* @__PURE__ */ Object.create(null);
1267
+ }
1268
+ contextChange(gpu) {
1269
+ this._gpu = gpu;
1270
+ this.maxTextures = gpu.device.limits.maxSampledTexturesPerShaderStage;
1271
+ }
1272
+ getProgramData(program) {
1273
+ return this._gpuProgramData[program._layoutKey] || this._createGPUProgramData(program);
1274
+ }
1275
+ _createGPUProgramData(program) {
1276
+ const device = this._gpu.device;
1277
+ const bindGroups = program.gpuLayout.map((group) => device.createBindGroupLayout({ entries: group }));
1278
+ const pipelineLayoutDesc = { bindGroupLayouts: bindGroups };
1279
+ this._gpuProgramData[program._layoutKey] = {
1280
+ bindGroups,
1281
+ pipeline: device.createPipelineLayout(pipelineLayoutDesc)
1282
+ };
1283
+ return this._gpuProgramData[program._layoutKey];
1284
+ }
1285
+ destroy() {
1286
+ this._gpu = null;
1287
+ this._gpuProgramData = null;
1288
+ }
1289
+ }
1290
+ /** @ignore */
1291
+ GpuShaderSystem.extension = {
1292
+ type: [
1293
+ ExtensionType.WebGPUSystem
1294
+ ],
1295
+ name: "shader"
1296
+ };
1297
+
1298
+ const GpuBlendModesToPixi = {};
1299
+ GpuBlendModesToPixi.normal = {
1300
+ alpha: {
1301
+ srcFactor: "one",
1302
+ dstFactor: "one-minus-src-alpha",
1303
+ operation: "add"
1304
+ },
1305
+ color: {
1306
+ srcFactor: "one",
1307
+ dstFactor: "one-minus-src-alpha",
1308
+ operation: "add"
1309
+ }
1310
+ };
1311
+ GpuBlendModesToPixi.add = {
1312
+ alpha: {
1313
+ srcFactor: "src-alpha",
1314
+ dstFactor: "one-minus-src-alpha",
1315
+ operation: "add"
1316
+ },
1317
+ color: {
1318
+ srcFactor: "one",
1319
+ dstFactor: "one",
1320
+ operation: "add"
1321
+ }
1322
+ };
1323
+ GpuBlendModesToPixi.multiply = {
1324
+ alpha: {
1325
+ srcFactor: "one",
1326
+ dstFactor: "one-minus-src-alpha",
1327
+ operation: "add"
1328
+ },
1329
+ color: {
1330
+ srcFactor: "dst",
1331
+ dstFactor: "one-minus-src-alpha",
1332
+ operation: "add"
1333
+ }
1334
+ };
1335
+ GpuBlendModesToPixi.screen = {
1336
+ alpha: {
1337
+ srcFactor: "one",
1338
+ dstFactor: "one-minus-src-alpha",
1339
+ operation: "add"
1340
+ },
1341
+ color: {
1342
+ srcFactor: "one",
1343
+ dstFactor: "one-minus-src",
1344
+ operation: "add"
1345
+ }
1346
+ };
1347
+ GpuBlendModesToPixi.overlay = {
1348
+ alpha: {
1349
+ srcFactor: "one",
1350
+ dstFactor: "one-minus-src-alpha",
1351
+ operation: "add"
1352
+ },
1353
+ color: {
1354
+ srcFactor: "one",
1355
+ dstFactor: "one-minus-src",
1356
+ operation: "add"
1357
+ }
1358
+ };
1359
+ GpuBlendModesToPixi.none = {
1360
+ alpha: {
1361
+ srcFactor: "one",
1362
+ dstFactor: "one-minus-src-alpha",
1363
+ operation: "add"
1364
+ },
1365
+ color: {
1366
+ srcFactor: "zero",
1367
+ dstFactor: "zero",
1368
+ operation: "add"
1369
+ }
1370
+ };
1371
+ GpuBlendModesToPixi["normal-npm"] = {
1372
+ alpha: {
1373
+ srcFactor: "one",
1374
+ dstFactor: "one-minus-src-alpha",
1375
+ operation: "add"
1376
+ },
1377
+ color: {
1378
+ srcFactor: "src-alpha",
1379
+ dstFactor: "one-minus-src-alpha",
1380
+ operation: "add"
1381
+ }
1382
+ };
1383
+ GpuBlendModesToPixi["add-npm"] = {
1384
+ alpha: {
1385
+ srcFactor: "one",
1386
+ dstFactor: "one",
1387
+ operation: "add"
1388
+ },
1389
+ color: {
1390
+ srcFactor: "src-alpha",
1391
+ dstFactor: "one",
1392
+ operation: "add"
1393
+ }
1394
+ };
1395
+ GpuBlendModesToPixi["screen-npm"] = {
1396
+ alpha: {
1397
+ srcFactor: "one",
1398
+ dstFactor: "one-minus-src-alpha",
1399
+ operation: "add"
1400
+ },
1401
+ color: {
1402
+ srcFactor: "src-alpha",
1403
+ dstFactor: "one-minus-src",
1404
+ operation: "add"
1405
+ }
1406
+ };
1407
+ GpuBlendModesToPixi.erase = {
1408
+ alpha: {
1409
+ srcFactor: "zero",
1410
+ dstFactor: "one-minus-src-alpha",
1411
+ operation: "add"
1412
+ },
1413
+ color: {
1414
+ srcFactor: "zero",
1415
+ dstFactor: "one-minus-src",
1416
+ operation: "add"
1417
+ }
1418
+ };
1419
+ GpuBlendModesToPixi.min = {
1420
+ alpha: {
1421
+ srcFactor: "one",
1422
+ dstFactor: "one",
1423
+ operation: "min"
1424
+ },
1425
+ color: {
1426
+ srcFactor: "one",
1427
+ dstFactor: "one",
1428
+ operation: "min"
1429
+ }
1430
+ };
1431
+ GpuBlendModesToPixi.max = {
1432
+ alpha: {
1433
+ srcFactor: "one",
1434
+ dstFactor: "one",
1435
+ operation: "max"
1436
+ },
1437
+ color: {
1438
+ srcFactor: "one",
1439
+ dstFactor: "one",
1440
+ operation: "max"
1441
+ }
1442
+ };
1443
+
1444
+ class GpuStateSystem {
1445
+ constructor() {
1446
+ this.defaultState = new State();
1447
+ this.defaultState.blend = true;
1448
+ }
1449
+ contextChange(gpu) {
1450
+ this.gpu = gpu;
1451
+ }
1452
+ /**
1453
+ * Gets the blend mode data for the current state
1454
+ * @param state - The state to get the blend mode from
1455
+ */
1456
+ getColorTargets(state) {
1457
+ const blend = GpuBlendModesToPixi[state.blendMode] || GpuBlendModesToPixi.normal;
1458
+ return [
1459
+ {
1460
+ format: "bgra8unorm",
1461
+ writeMask: 0,
1462
+ blend
1463
+ }
1464
+ ];
1465
+ }
1466
+ destroy() {
1467
+ this.gpu = null;
1468
+ }
1469
+ }
1470
+ /** @ignore */
1471
+ GpuStateSystem.extension = {
1472
+ type: [
1473
+ ExtensionType.WebGPUSystem
1474
+ ],
1475
+ name: "state"
1476
+ };
1477
+
1478
+ const gpuUploadBufferImageResource = {
1479
+ type: "image",
1480
+ upload(source, gpuTexture, gpu) {
1481
+ const resource = source.resource;
1482
+ const total = (source.pixelWidth | 0) * (source.pixelHeight | 0);
1483
+ const bytesPerPixel = resource.byteLength / total;
1484
+ gpu.device.queue.writeTexture(
1485
+ { texture: gpuTexture },
1486
+ resource,
1487
+ {
1488
+ offset: 0,
1489
+ rowsPerImage: source.pixelHeight,
1490
+ bytesPerRow: source.pixelHeight * bytesPerPixel
1491
+ },
1492
+ {
1493
+ width: source.pixelWidth,
1494
+ height: source.pixelHeight,
1495
+ depthOrArrayLayers: 1
1496
+ }
1497
+ );
1498
+ }
1499
+ };
1500
+
1501
+ const blockDataMap = {
1502
+ "bc1-rgba-unorm": { blockBytes: 8, blockWidth: 4, blockHeight: 4 },
1503
+ "bc2-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1504
+ "bc3-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1505
+ "bc7-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1506
+ "etc1-rgb-unorm": { blockBytes: 8, blockWidth: 4, blockHeight: 4 },
1507
+ "etc2-rgba8unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1508
+ "astc-4x4-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 }
1509
+ };
1510
+ const defaultBlockData = { blockBytes: 4, blockWidth: 1, blockHeight: 1 };
1511
+ const gpuUploadCompressedTextureResource = {
1512
+ type: "compressed",
1513
+ upload(source, gpuTexture, gpu) {
1514
+ let mipWidth = source.pixelWidth;
1515
+ let mipHeight = source.pixelHeight;
1516
+ const blockData = blockDataMap[source.format] || defaultBlockData;
1517
+ for (let i = 0; i < source.resource.length; i++) {
1518
+ const levelBuffer = source.resource[i];
1519
+ const bytesPerRow = Math.ceil(mipWidth / blockData.blockWidth) * blockData.blockBytes;
1520
+ gpu.device.queue.writeTexture(
1521
+ {
1522
+ texture: gpuTexture,
1523
+ mipLevel: i
1524
+ },
1525
+ levelBuffer,
1526
+ {
1527
+ offset: 0,
1528
+ bytesPerRow
1529
+ },
1530
+ {
1531
+ width: Math.ceil(mipWidth / blockData.blockWidth) * blockData.blockWidth,
1532
+ height: Math.ceil(mipHeight / blockData.blockHeight) * blockData.blockHeight,
1533
+ depthOrArrayLayers: 1
1534
+ }
1535
+ );
1536
+ mipWidth = Math.max(mipWidth >> 1, 1);
1537
+ mipHeight = Math.max(mipHeight >> 1, 1);
1538
+ }
1539
+ }
1540
+ };
1541
+
1542
+ const gpuUploadImageResource = {
1543
+ type: "image",
1544
+ upload(source, gpuTexture, gpu) {
1545
+ const resource = source.resource;
1546
+ if (!resource)
1547
+ return;
1548
+ const width = Math.min(gpuTexture.width, source.resourceWidth || source.pixelWidth);
1549
+ const height = Math.min(gpuTexture.height, source.resourceHeight || source.pixelHeight);
1550
+ const premultipliedAlpha = source.alphaMode === "premultiply-alpha-on-upload";
1551
+ gpu.device.queue.copyExternalImageToTexture(
1552
+ { source: resource },
1553
+ { texture: gpuTexture, premultipliedAlpha },
1554
+ {
1555
+ width,
1556
+ height
1557
+ }
1558
+ );
1559
+ }
1560
+ };
1561
+
1562
+ const gpuUploadVideoResource = {
1563
+ type: "video",
1564
+ upload(source, gpuTexture, gpu) {
1565
+ gpuUploadImageResource.upload(source, gpuTexture, gpu);
1566
+ }
1567
+ };
1568
+
1569
+ class GpuMipmapGenerator {
1570
+ constructor(device) {
1571
+ this.device = device;
1572
+ this.sampler = device.createSampler({ minFilter: "linear" });
1573
+ this.pipelines = {};
1574
+ }
1575
+ _getMipmapPipeline(format) {
1576
+ let pipeline = this.pipelines[format];
1577
+ if (!pipeline) {
1578
+ if (!this.mipmapShaderModule) {
1579
+ this.mipmapShaderModule = this.device.createShaderModule({
1580
+ code: (
1581
+ /* wgsl */
1582
+ `
1583
+ var<private> pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
1584
+ vec2<f32>(-1.0, -1.0), vec2<f32>(-1.0, 3.0), vec2<f32>(3.0, -1.0));
1585
+
1586
+ struct VertexOutput {
1587
+ @builtin(position) position : vec4<f32>,
1588
+ @location(0) texCoord : vec2<f32>,
1589
+ };
1590
+
1591
+ @vertex
1592
+ fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput {
1593
+ var output : VertexOutput;
1594
+ output.texCoord = pos[vertexIndex] * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5);
1595
+ output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
1596
+ return output;
1597
+ }
1598
+
1599
+ @group(0) @binding(0) var imgSampler : sampler;
1600
+ @group(0) @binding(1) var img : texture_2d<f32>;
1601
+
1602
+ @fragment
1603
+ fn fragmentMain(@location(0) texCoord : vec2<f32>) -> @location(0) vec4<f32> {
1604
+ return textureSample(img, imgSampler, texCoord);
1605
+ }
1606
+ `
1607
+ )
1608
+ });
1609
+ }
1610
+ pipeline = this.device.createRenderPipeline({
1611
+ layout: "auto",
1612
+ vertex: {
1613
+ module: this.mipmapShaderModule,
1614
+ entryPoint: "vertexMain"
1615
+ },
1616
+ fragment: {
1617
+ module: this.mipmapShaderModule,
1618
+ entryPoint: "fragmentMain",
1619
+ targets: [{ format }]
1620
+ }
1621
+ });
1622
+ this.pipelines[format] = pipeline;
1623
+ }
1624
+ return pipeline;
1625
+ }
1626
+ /**
1627
+ * Generates mipmaps for the given GPUTexture from the data in level 0.
1628
+ * @param {module:External.GPUTexture} texture - Texture to generate mipmaps for.
1629
+ * @returns {module:External.GPUTexture} - The originally passed texture
1630
+ */
1631
+ generateMipmap(texture) {
1632
+ const pipeline = this._getMipmapPipeline(texture.format);
1633
+ if (texture.dimension === "3d" || texture.dimension === "1d") {
1634
+ throw new Error("Generating mipmaps for non-2d textures is currently unsupported!");
1635
+ }
1636
+ let mipTexture = texture;
1637
+ const arrayLayerCount = texture.depthOrArrayLayers || 1;
1638
+ const renderToSource = texture.usage & GPUTextureUsage.RENDER_ATTACHMENT;
1639
+ if (!renderToSource) {
1640
+ const mipTextureDescriptor = {
1641
+ size: {
1642
+ width: Math.ceil(texture.width / 2),
1643
+ height: Math.ceil(texture.height / 2),
1644
+ depthOrArrayLayers: arrayLayerCount
1645
+ },
1646
+ format: texture.format,
1647
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
1648
+ mipLevelCount: texture.mipLevelCount - 1
1649
+ };
1650
+ mipTexture = this.device.createTexture(mipTextureDescriptor);
1651
+ }
1652
+ const commandEncoder = this.device.createCommandEncoder({});
1653
+ const bindGroupLayout = pipeline.getBindGroupLayout(0);
1654
+ for (let arrayLayer = 0; arrayLayer < arrayLayerCount; ++arrayLayer) {
1655
+ let srcView = texture.createView({
1656
+ baseMipLevel: 0,
1657
+ mipLevelCount: 1,
1658
+ dimension: "2d",
1659
+ baseArrayLayer: arrayLayer,
1660
+ arrayLayerCount: 1
1661
+ });
1662
+ let dstMipLevel = renderToSource ? 1 : 0;
1663
+ for (let i = 1; i < texture.mipLevelCount; ++i) {
1664
+ const dstView = mipTexture.createView({
1665
+ baseMipLevel: dstMipLevel++,
1666
+ mipLevelCount: 1,
1667
+ dimension: "2d",
1668
+ baseArrayLayer: arrayLayer,
1669
+ arrayLayerCount: 1
1670
+ });
1671
+ const passEncoder = commandEncoder.beginRenderPass({
1672
+ colorAttachments: [{
1673
+ view: dstView,
1674
+ storeOp: "store",
1675
+ loadOp: "clear",
1676
+ clearValue: { r: 0, g: 0, b: 0, a: 0 }
1677
+ }]
1678
+ });
1679
+ const bindGroup = this.device.createBindGroup({
1680
+ layout: bindGroupLayout,
1681
+ entries: [{
1682
+ binding: 0,
1683
+ resource: this.sampler
1684
+ }, {
1685
+ binding: 1,
1686
+ resource: srcView
1687
+ }]
1688
+ });
1689
+ passEncoder.setPipeline(pipeline);
1690
+ passEncoder.setBindGroup(0, bindGroup);
1691
+ passEncoder.draw(3, 1, 0, 0);
1692
+ passEncoder.end();
1693
+ srcView = dstView;
1694
+ }
1695
+ }
1696
+ if (!renderToSource) {
1697
+ const mipLevelSize = {
1698
+ width: Math.ceil(texture.width / 2),
1699
+ height: Math.ceil(texture.height / 2),
1700
+ depthOrArrayLayers: arrayLayerCount
1701
+ };
1702
+ for (let i = 1; i < texture.mipLevelCount; ++i) {
1703
+ commandEncoder.copyTextureToTexture({
1704
+ texture: mipTexture,
1705
+ mipLevel: i - 1
1706
+ }, {
1707
+ texture,
1708
+ mipLevel: i
1709
+ }, mipLevelSize);
1710
+ mipLevelSize.width = Math.ceil(mipLevelSize.width / 2);
1711
+ mipLevelSize.height = Math.ceil(mipLevelSize.height / 2);
1712
+ }
1713
+ }
1714
+ this.device.queue.submit([commandEncoder.finish()]);
1715
+ if (!renderToSource) {
1716
+ mipTexture.destroy();
1717
+ }
1718
+ return texture;
1719
+ }
1720
+ }
1721
+
1722
+ class GpuTextureSystem {
1723
+ constructor(renderer) {
1724
+ this.managedTextures = [];
1725
+ this._gpuSources = /* @__PURE__ */ Object.create(null);
1726
+ this._gpuSamplers = /* @__PURE__ */ Object.create(null);
1727
+ this._bindGroupHash = /* @__PURE__ */ Object.create(null);
1728
+ this._textureViewHash = /* @__PURE__ */ Object.create(null);
1729
+ this._uploads = {
1730
+ image: gpuUploadImageResource,
1731
+ buffer: gpuUploadBufferImageResource,
1732
+ video: gpuUploadVideoResource,
1733
+ compressed: gpuUploadCompressedTextureResource
1734
+ };
1735
+ this._renderer = renderer;
1736
+ renderer.renderableGC.addManagedHash(this, "_gpuSources");
1737
+ renderer.renderableGC.addManagedHash(this, "_gpuSamplers");
1738
+ renderer.renderableGC.addManagedHash(this, "_bindGroupHash");
1739
+ renderer.renderableGC.addManagedHash(this, "_textureViewHash");
1740
+ }
1741
+ contextChange(gpu) {
1742
+ this._gpu = gpu;
1743
+ }
1744
+ initSource(source) {
1745
+ if (source.autoGenerateMipmaps) {
1746
+ const biggestDimension = Math.max(source.pixelWidth, source.pixelHeight);
1747
+ source.mipLevelCount = Math.floor(Math.log2(biggestDimension)) + 1;
1748
+ }
1749
+ let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
1750
+ if (source.uploadMethodId !== "compressed") {
1751
+ usage |= GPUTextureUsage.RENDER_ATTACHMENT;
1752
+ usage |= GPUTextureUsage.COPY_SRC;
1753
+ }
1754
+ const blockData = blockDataMap[source.format] || { blockWidth: 1, blockHeight: 1 };
1755
+ const width = Math.ceil(source.pixelWidth / blockData.blockWidth) * blockData.blockWidth;
1756
+ const height = Math.ceil(source.pixelHeight / blockData.blockHeight) * blockData.blockHeight;
1757
+ const textureDescriptor = {
1758
+ label: source.label,
1759
+ size: { width, height },
1760
+ format: source.format,
1761
+ sampleCount: source.sampleCount,
1762
+ mipLevelCount: source.mipLevelCount,
1763
+ dimension: source.dimension,
1764
+ usage
1765
+ };
1766
+ const gpuTexture = this._gpu.device.createTexture(textureDescriptor);
1767
+ this._gpuSources[source.uid] = gpuTexture;
1768
+ if (!this.managedTextures.includes(source)) {
1769
+ source.on("update", this.onSourceUpdate, this);
1770
+ source.on("resize", this.onSourceResize, this);
1771
+ source.on("destroy", this.onSourceDestroy, this);
1772
+ source.on("unload", this.onSourceUnload, this);
1773
+ source.on("updateMipmaps", this.onUpdateMipmaps, this);
1774
+ this.managedTextures.push(source);
1775
+ }
1776
+ this.onSourceUpdate(source);
1777
+ return gpuTexture;
1778
+ }
1779
+ onSourceUpdate(source) {
1780
+ const gpuTexture = this.getGpuSource(source);
1781
+ if (!gpuTexture)
1782
+ return;
1783
+ if (this._uploads[source.uploadMethodId]) {
1784
+ this._uploads[source.uploadMethodId].upload(source, gpuTexture, this._gpu);
1785
+ }
1786
+ if (source.autoGenerateMipmaps && source.mipLevelCount > 1) {
1787
+ this.onUpdateMipmaps(source);
1788
+ }
1789
+ }
1790
+ onSourceUnload(source) {
1791
+ const gpuTexture = this._gpuSources[source.uid];
1792
+ if (gpuTexture) {
1793
+ this._gpuSources[source.uid] = null;
1794
+ gpuTexture.destroy();
1795
+ }
1796
+ }
1797
+ onUpdateMipmaps(source) {
1798
+ if (!this._mipmapGenerator) {
1799
+ this._mipmapGenerator = new GpuMipmapGenerator(this._gpu.device);
1800
+ }
1801
+ const gpuTexture = this.getGpuSource(source);
1802
+ this._mipmapGenerator.generateMipmap(gpuTexture);
1803
+ }
1804
+ onSourceDestroy(source) {
1805
+ source.off("update", this.onSourceUpdate, this);
1806
+ source.off("unload", this.onSourceUnload, this);
1807
+ source.off("destroy", this.onSourceDestroy, this);
1808
+ source.off("resize", this.onSourceResize, this);
1809
+ source.off("updateMipmaps", this.onUpdateMipmaps, this);
1810
+ this.managedTextures.splice(this.managedTextures.indexOf(source), 1);
1811
+ this.onSourceUnload(source);
1812
+ }
1813
+ onSourceResize(source) {
1814
+ const gpuTexture = this._gpuSources[source.uid];
1815
+ if (!gpuTexture) {
1816
+ this.initSource(source);
1817
+ } else if (gpuTexture.width !== source.pixelWidth || gpuTexture.height !== source.pixelHeight) {
1818
+ this._textureViewHash[source.uid] = null;
1819
+ this._bindGroupHash[source.uid] = null;
1820
+ this.onSourceUnload(source);
1821
+ this.initSource(source);
1822
+ }
1823
+ }
1824
+ _initSampler(sampler) {
1825
+ this._gpuSamplers[sampler._resourceId] = this._gpu.device.createSampler(sampler);
1826
+ return this._gpuSamplers[sampler._resourceId];
1827
+ }
1828
+ getGpuSampler(sampler) {
1829
+ return this._gpuSamplers[sampler._resourceId] || this._initSampler(sampler);
1830
+ }
1831
+ getGpuSource(source) {
1832
+ return this._gpuSources[source.uid] || this.initSource(source);
1833
+ }
1834
+ /**
1835
+ * this returns s bind group for a specific texture, the bind group contains
1836
+ * - the texture source
1837
+ * - the texture style
1838
+ * - the texture matrix
1839
+ * This is cached so the bind group should only be created once per texture
1840
+ * @param texture - the texture you want the bindgroup for
1841
+ * @returns the bind group for the texture
1842
+ */
1843
+ getTextureBindGroup(texture) {
1844
+ return this._bindGroupHash[texture.uid] ?? this._createTextureBindGroup(texture);
1845
+ }
1846
+ _createTextureBindGroup(texture) {
1847
+ const source = texture.source;
1848
+ this._bindGroupHash[texture.uid] = new BindGroup({
1849
+ 0: source,
1850
+ 1: source.style,
1851
+ 2: new UniformGroup({
1852
+ uTextureMatrix: { type: "mat3x3<f32>", value: texture.textureMatrix.mapCoord }
1853
+ })
1854
+ });
1855
+ return this._bindGroupHash[texture.uid];
1856
+ }
1857
+ getTextureView(texture) {
1858
+ const source = texture.source;
1859
+ return this._textureViewHash[source.uid] ?? this._createTextureView(source);
1860
+ }
1861
+ _createTextureView(texture) {
1862
+ this._textureViewHash[texture.uid] = this.getGpuSource(texture).createView();
1863
+ return this._textureViewHash[texture.uid];
1864
+ }
1865
+ generateCanvas(texture) {
1866
+ const renderer = this._renderer;
1867
+ const commandEncoder = renderer.gpu.device.createCommandEncoder();
1868
+ const canvas = DOMAdapter.get().createCanvas();
1869
+ canvas.width = texture.source.pixelWidth;
1870
+ canvas.height = texture.source.pixelHeight;
1871
+ const context = canvas.getContext("webgpu");
1872
+ context.configure({
1873
+ device: renderer.gpu.device,
1874
+ usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC,
1875
+ format: DOMAdapter.get().getNavigator().gpu.getPreferredCanvasFormat(),
1876
+ alphaMode: "premultiplied"
1877
+ });
1878
+ commandEncoder.copyTextureToTexture({
1879
+ texture: renderer.texture.getGpuSource(texture.source),
1880
+ origin: {
1881
+ x: 0,
1882
+ y: 0
1883
+ }
1884
+ }, {
1885
+ texture: context.getCurrentTexture()
1886
+ }, {
1887
+ width: canvas.width,
1888
+ height: canvas.height
1889
+ });
1890
+ renderer.gpu.device.queue.submit([commandEncoder.finish()]);
1891
+ return canvas;
1892
+ }
1893
+ getPixels(texture) {
1894
+ const webGPUCanvas = this.generateCanvas(texture);
1895
+ const canvasAndContext = CanvasPool.getOptimalCanvasAndContext(webGPUCanvas.width, webGPUCanvas.height);
1896
+ const context = canvasAndContext.context;
1897
+ context.drawImage(webGPUCanvas, 0, 0);
1898
+ const { width, height } = webGPUCanvas;
1899
+ const imageData = context.getImageData(0, 0, width, height);
1900
+ const pixels = new Uint8ClampedArray(imageData.data.buffer);
1901
+ CanvasPool.returnCanvasAndContext(canvasAndContext);
1902
+ return { pixels, width, height };
1903
+ }
1904
+ destroy() {
1905
+ this.managedTextures.slice().forEach((source) => this.onSourceDestroy(source));
1906
+ this.managedTextures = null;
1907
+ for (const k of Object.keys(this._bindGroupHash)) {
1908
+ const key = Number(k);
1909
+ const bindGroup = this._bindGroupHash[key];
1910
+ bindGroup?.destroy();
1911
+ this._bindGroupHash[key] = null;
1912
+ }
1913
+ this._gpu = null;
1914
+ this._mipmapGenerator = null;
1915
+ this._gpuSources = null;
1916
+ this._bindGroupHash = null;
1917
+ this._textureViewHash = null;
1918
+ this._gpuSamplers = null;
1919
+ }
1920
+ }
1921
+ /** @ignore */
1922
+ GpuTextureSystem.extension = {
1923
+ type: [
1924
+ ExtensionType.WebGPUSystem
1925
+ ],
1926
+ name: "texture"
1927
+ };
1928
+
1929
+ class GpuGraphicsAdaptor {
1930
+ init() {
1931
+ const localUniforms = new UniformGroup({
1932
+ uTransformMatrix: { value: new Matrix(), type: "mat3x3<f32>" },
1933
+ uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
1934
+ uRound: { value: 0, type: "f32" }
1935
+ });
1936
+ const gpuProgram = compileHighShaderGpuProgram({
1937
+ name: "graphics",
1938
+ bits: [
1939
+ colorBit,
1940
+ generateTextureBatchBit(getMaxTexturesPerBatch()),
1941
+ localUniformBitGroup2,
1942
+ roundPixelsBit
1943
+ ]
1944
+ });
1945
+ this.shader = new Shader({
1946
+ gpuProgram,
1947
+ resources: {
1948
+ // added on the fly!
1949
+ localUniforms
1950
+ }
1951
+ });
1952
+ }
1953
+ execute(graphicsPipe, renderable) {
1954
+ const context = renderable.context;
1955
+ const shader = context.customShader || this.shader;
1956
+ const renderer = graphicsPipe.renderer;
1957
+ const contextSystem = renderer.graphicsContext;
1958
+ const {
1959
+ batcher,
1960
+ instructions
1961
+ } = contextSystem.getContextRenderData(context);
1962
+ const encoder = renderer.encoder;
1963
+ encoder.setGeometry(batcher.geometry, shader.gpuProgram);
1964
+ const globalUniformsBindGroup = renderer.globalUniforms.bindGroup;
1965
+ encoder.setBindGroup(0, globalUniformsBindGroup, shader.gpuProgram);
1966
+ const localBindGroup = renderer.renderPipes.uniformBatch.getUniformBindGroup(shader.resources.localUniforms, true);
1967
+ encoder.setBindGroup(2, localBindGroup, shader.gpuProgram);
1968
+ const batches = instructions.instructions;
1969
+ let topology = null;
1970
+ for (let i = 0; i < instructions.instructionSize; i++) {
1971
+ const batch = batches[i];
1972
+ if (batch.topology !== topology) {
1973
+ topology = batch.topology;
1974
+ encoder.setPipelineFromGeometryProgramAndState(
1975
+ batcher.geometry,
1976
+ shader.gpuProgram,
1977
+ graphicsPipe.state,
1978
+ batch.topology
1979
+ );
1980
+ }
1981
+ shader.groups[1] = batch.bindGroup;
1982
+ if (!batch.gpuBindGroup) {
1983
+ const textureBatch = batch.textures;
1984
+ batch.bindGroup = getTextureBatchBindGroup(textureBatch.textures, textureBatch.count);
1985
+ batch.gpuBindGroup = renderer.bindGroup.getBindGroup(
1986
+ batch.bindGroup,
1987
+ shader.gpuProgram,
1988
+ 1
1989
+ );
1990
+ }
1991
+ encoder.setBindGroup(1, batch.bindGroup, shader.gpuProgram);
1992
+ encoder.renderPassEncoder.drawIndexed(batch.size, 1, batch.start);
1993
+ }
1994
+ }
1995
+ destroy() {
1996
+ this.shader.destroy(true);
1997
+ this.shader = null;
1998
+ }
1999
+ }
2000
+ /** @ignore */
2001
+ GpuGraphicsAdaptor.extension = {
2002
+ type: [
2003
+ ExtensionType.WebGPUPipesAdaptor
2004
+ ],
2005
+ name: "graphics"
2006
+ };
2007
+
2008
+ class GpuMeshAdapter {
2009
+ init() {
2010
+ const gpuProgram = compileHighShaderGpuProgram({
2011
+ name: "mesh",
2012
+ bits: [
2013
+ localUniformBit,
2014
+ textureBit,
2015
+ roundPixelsBit
2016
+ ]
2017
+ });
2018
+ this._shader = new Shader({
2019
+ gpuProgram,
2020
+ resources: {
2021
+ uTexture: Texture.EMPTY._source,
2022
+ uSampler: Texture.EMPTY._source.style,
2023
+ textureUniforms: {
2024
+ uTextureMatrix: { type: "mat3x3<f32>", value: new Matrix() }
2025
+ }
2026
+ }
2027
+ });
2028
+ }
2029
+ execute(meshPipe, mesh) {
2030
+ const renderer = meshPipe.renderer;
2031
+ let shader = mesh._shader;
2032
+ if (!shader) {
2033
+ shader = this._shader;
2034
+ shader.groups[2] = renderer.texture.getTextureBindGroup(mesh.texture);
2035
+ } else if (!shader.gpuProgram) {
2036
+ warn("Mesh shader has no gpuProgram", mesh.shader);
2037
+ return;
2038
+ }
2039
+ const gpuProgram = shader.gpuProgram;
2040
+ if (gpuProgram.autoAssignGlobalUniforms) {
2041
+ shader.groups[0] = renderer.globalUniforms.bindGroup;
2042
+ }
2043
+ if (gpuProgram.autoAssignLocalUniforms) {
2044
+ const localUniforms = meshPipe.localUniforms;
2045
+ shader.groups[1] = renderer.renderPipes.uniformBatch.getUniformBindGroup(localUniforms, true);
2046
+ }
2047
+ renderer.encoder.draw({
2048
+ geometry: mesh._geometry,
2049
+ shader,
2050
+ state: mesh.state
2051
+ });
2052
+ }
2053
+ destroy() {
2054
+ this._shader.destroy(true);
2055
+ this._shader = null;
2056
+ }
2057
+ }
2058
+ /** @ignore */
2059
+ GpuMeshAdapter.extension = {
2060
+ type: [
2061
+ ExtensionType.WebGPUPipesAdaptor
2062
+ ],
2063
+ name: "mesh"
2064
+ };
2065
+
2066
+ const DefaultWebGPUSystems = [
2067
+ ...SharedSystems,
2068
+ GpuUboSystem,
2069
+ GpuEncoderSystem,
2070
+ GpuDeviceSystem,
2071
+ GpuBufferSystem,
2072
+ GpuTextureSystem,
2073
+ GpuRenderTargetSystem,
2074
+ GpuShaderSystem,
2075
+ GpuStateSystem,
2076
+ PipelineSystem,
2077
+ GpuColorMaskSystem,
2078
+ GpuStencilSystem,
2079
+ BindGroupSystem
2080
+ ];
2081
+ const DefaultWebGPUPipes = [...SharedRenderPipes, GpuUniformBatchPipe];
2082
+ const DefaultWebGPUAdapters = [GpuBatchAdaptor, GpuMeshAdapter, GpuGraphicsAdaptor];
2083
+ const systems = [];
2084
+ const renderPipes = [];
2085
+ const renderPipeAdaptors = [];
2086
+ extensions.handleByNamedList(ExtensionType.WebGPUSystem, systems);
2087
+ extensions.handleByNamedList(ExtensionType.WebGPUPipes, renderPipes);
2088
+ extensions.handleByNamedList(ExtensionType.WebGPUPipesAdaptor, renderPipeAdaptors);
2089
+ extensions.add(...DefaultWebGPUSystems, ...DefaultWebGPUPipes, ...DefaultWebGPUAdapters);
2090
+ class WebGPURenderer extends AbstractRenderer {
2091
+ constructor() {
2092
+ const systemConfig = {
2093
+ name: "webgpu",
2094
+ type: RendererType.WEBGPU,
2095
+ systems,
2096
+ renderPipes,
2097
+ renderPipeAdaptors
2098
+ };
2099
+ super(systemConfig);
2100
+ }
2101
+ }
2102
+
2103
+ export { WebGPURenderer };