@ludicon/spark.js 0.0.13 → 0.0.15

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/spark.esm.js CHANGED
@@ -1,6 +1,6 @@
1
- const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import("./spark_astc_rgb-DaSIMKXW.js"), "./spark_astc_rgba.wgsl": () => import("./spark_astc_rgba-BToA2Rcq.js"), "./spark_bc1_rgb.wgsl": () => import("./spark_bc1_rgb-DZwuM1tO.js"), "./spark_bc4_r.wgsl": () => import("./spark_bc4_r-DjThizCH.js"), "./spark_bc5_rg.wgsl": () => import("./spark_bc5_rg-6bO0Gvo9.js"), "./spark_bc7_rgb.wgsl": () => import("./spark_bc7_rgb-FXpBw9fE.js"), "./spark_bc7_rgba.wgsl": () => import("./spark_bc7_rgba-C8Hi2pUY.js"), "./spark_eac_r.wgsl": () => import("./spark_eac_r-D8HGiglc.js"), "./spark_eac_rg.wgsl": () => import("./spark_eac_rg-DvsrLP9h.js"), "./spark_etc2_rgb.wgsl": () => import("./spark_etc2_rgb-C-j5FZpn.js"), "./utils.wgsl": () => import("./utils-Dw9jXlhw.js") }), k = Object.fromEntries(
2
- Object.entries(z).map(([n, e]) => [n.replace("./", ""), async () => (await e()).default])
3
- ), s = {
1
+ const V = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import("./spark_astc_rgb-DaSIMKXW.js"), "./spark_astc_rgba.wgsl": () => import("./spark_astc_rgba-BToA2Rcq.js"), "./spark_bc1_rgb.wgsl": () => import("./spark_bc1_rgb-DZwuM1tO.js"), "./spark_bc4_r.wgsl": () => import("./spark_bc4_r-DjThizCH.js"), "./spark_bc5_rg.wgsl": () => import("./spark_bc5_rg-6bO0Gvo9.js"), "./spark_bc7_rgb.wgsl": () => import("./spark_bc7_rgb-FXpBw9fE.js"), "./spark_bc7_rgba.wgsl": () => import("./spark_bc7_rgba-C8Hi2pUY.js"), "./spark_eac_r.wgsl": () => import("./spark_eac_r-D8HGiglc.js"), "./spark_eac_rg.wgsl": () => import("./spark_eac_rg-DvsrLP9h.js"), "./spark_etc2_rgb.wgsl": () => import("./spark_etc2_rgb-C-j5FZpn.js"), "./utils.wgsl": () => import("./utils-_0JXKkpk.js") }), I = Object.fromEntries(
2
+ Object.entries(V).map(([u, e]) => [u.replace("./", ""), async () => (await e()).default])
3
+ ), i = {
4
4
  ASTC_4x4_RGB: 0,
5
5
  ASTC_4x4_RGBA: 1,
6
6
  // ASTC_4x4_RGBM: 2,
@@ -19,7 +19,7 @@ const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import(
19
19
  // BC6H_RGB: 15,
20
20
  BC7_RGB: 16,
21
21
  BC7_RGBA: 17
22
- }, B = [
22
+ }, G = [
23
23
  /* 0 */
24
24
  "astc-4x4-rgb",
25
25
  // ASTC_4x4_RGB
@@ -113,7 +113,7 @@ const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import(
113
113
  /* 17 */
114
114
  "spark_bc7_rgba.wgsl"
115
115
  // BC7_RGBA
116
- ], Y = [
116
+ ], W = [
117
117
  /* 0 */
118
118
  16,
119
119
  // ASTC_4x4_RGB
@@ -160,7 +160,7 @@ const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import(
160
160
  /* 17 */
161
161
  16
162
162
  // BC7_RGB
163
- ], W = [
163
+ ], Y = [
164
164
  /* 0 */
165
165
  4,
166
166
  // ASTC_4x4_RGB
@@ -207,34 +207,34 @@ const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import(
207
207
  /* 17 */
208
208
  4
209
209
  // BC7_RGB
210
- ], T = Object.freeze({
211
- "astc-4x4-rgb": s.ASTC_4x4_RGB,
212
- "astc-4x4-rgba": s.ASTC_4x4_RGBA,
213
- "eac-r": s.EAC_R,
214
- "eac-rg": s.EAC_RG,
215
- "etc2-rgb": s.ETC2_RGB,
216
- "bc1-rgb": s.BC1_RGB,
217
- "bc4-r": s.BC4_R,
218
- "bc5-rg": s.BC5_RG,
219
- "bc7-rgb": s.BC7_RGB,
220
- "bc7-rgba": s.BC7_RGBA,
210
+ ], P = Object.freeze({
211
+ "astc-4x4-rgb": i.ASTC_4x4_RGB,
212
+ "astc-4x4-rgba": i.ASTC_4x4_RGBA,
213
+ "eac-r": i.EAC_R,
214
+ "eac-rg": i.EAC_RG,
215
+ "etc2-rgb": i.ETC2_RGB,
216
+ "bc1-rgb": i.BC1_RGB,
217
+ "bc4-r": i.BC4_R,
218
+ "bc5-rg": i.BC5_RG,
219
+ "bc7-rgb": i.BC7_RGB,
220
+ "bc7-rgba": i.BC7_RGBA,
221
221
  // aliases:
222
- "astc-rgb": s.ASTC_4x4_RGB,
223
- "astc-rgba": s.ASTC_4x4_RGBA,
222
+ "astc-rgb": i.ASTC_4x4_RGB,
223
+ "astc-rgba": i.ASTC_4x4_RGBA,
224
224
  // webgpu aliases:
225
- "bc1-rgba-unorm": s.BC1_RGB,
226
- "bc1-rgba-unorm-srgb": s.BC1_RGB,
227
- "bc4-r-unorm": s.BC4_R,
228
- "bc5-rg-unorm": s.BC5_RG,
229
- "bc7-rgba-unorm": s.BC7_RGBA,
230
- "bc7-rgba-unorm-srgb": s.BC7_RGBA,
231
- "etc2-rgb8unorm": s.ETC2_RGB,
232
- "etc2-rgb8unorm-srgb": s.ETC2_RGB,
233
- "eac-r11unorm": s.EAC_R,
234
- "eac-rg11unorm": s.EAC_RG,
235
- "astc-4x4-unorm": s.ASTC_4x4_RGBA,
236
- "astc-4x4-unorm-srgb": s.ASTC_4x4_RGBA
237
- }), V = [
225
+ "bc1-rgba-unorm": i.BC1_RGB,
226
+ "bc1-rgba-unorm-srgb": i.BC1_RGB,
227
+ "bc4-r-unorm": i.BC4_R,
228
+ "bc5-rg-unorm": i.BC5_RG,
229
+ "bc7-rgba-unorm": i.BC7_RGBA,
230
+ "bc7-rgba-unorm-srgb": i.BC7_RGBA,
231
+ "etc2-rgb8unorm": i.ETC2_RGB,
232
+ "etc2-rgb8unorm-srgb": i.ETC2_RGB,
233
+ "eac-r11unorm": i.EAC_R,
234
+ "eac-rg11unorm": i.EAC_RG,
235
+ "astc-4x4-unorm": i.ASTC_4x4_RGBA,
236
+ "astc-4x4-unorm-srgb": i.ASTC_4x4_RGBA
237
+ }), $ = [
238
238
  /* 0 */
239
239
  "astc-4x4-unorm",
240
240
  // ASTC_4x4_RGB
@@ -281,7 +281,7 @@ const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import(
281
281
  /* 17 */
282
282
  "bc7-rgba-unorm"
283
283
  // BC7_RGB
284
- ], $ = [
284
+ ], X = [
285
285
  /* 0 */
286
286
  !0,
287
287
  // ASTC_4x4_RGB
@@ -329,63 +329,66 @@ const z = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import(
329
329
  !0
330
330
  // BC7_RGB
331
331
  ];
332
- function w(n, e) {
333
- if (!n)
332
+ function w(u, e) {
333
+ if (!u)
334
334
  throw new Error(e);
335
335
  }
336
- function X(n) {
337
- return typeof GPUDevice < "u" && n instanceof GPUDevice;
336
+ function H(u) {
337
+ return typeof GPUDevice < "u" && u instanceof GPUDevice;
338
338
  }
339
- function F() {
339
+ function j() {
340
340
  return ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"].includes(navigator.platform) || // iPad on iOS 13 detection
341
341
  navigator.userAgent.includes("Mac") && "ontouchend" in document;
342
342
  }
343
- function j() {
344
- const n = navigator.userAgent.match(/Safari\/(\d+(\.\d+)?)/);
345
- return n && parseFloat(n[1]);
343
+ function O() {
344
+ const u = navigator.userAgent;
345
+ if (u.includes("Chrome") || u.includes("Chromium"))
346
+ return null;
347
+ const e = u.match(/Safari\/(\d+(\.\d+)?)/);
348
+ return e && parseFloat(e[1]);
346
349
  }
347
- function Q() {
348
- const n = navigator.userAgent.match(/Firefox\/(\d+(\.\d+)?)/);
349
- return n && parseFloat(n[1]);
350
+ function k() {
351
+ const u = navigator.userAgent.match(/Firefox\/(\d+(\.\d+)?)/);
352
+ return u && parseFloat(u[1]);
350
353
  }
351
- function H(n) {
354
+ function Q(u) {
352
355
  const e = /* @__PURE__ */ new Set(), r = {
353
356
  "texture-compression-bc": [
354
- s.BC1_RGB,
355
- s.BC4_R,
356
- s.BC5_RG,
357
- s.BC7_RGB,
358
- s.BC7_RGBA
357
+ i.BC1_RGB,
358
+ i.BC4_R,
359
+ i.BC5_RG,
360
+ i.BC7_RGB,
361
+ i.BC7_RGBA
359
362
  ],
360
- "texture-compression-etc2": [s.ETC2_RGB, s.EAC_R, s.EAC_RG],
361
- "texture-compression-astc": [s.ASTC_4x4_RGB, s.ASTC_4x4_RGBA]
363
+ "texture-compression-etc2": [i.ETC2_RGB, i.EAC_R, i.EAC_RG],
364
+ "texture-compression-astc": [i.ASTC_4x4_RGB, i.ASTC_4x4_RGBA]
362
365
  };
363
- for (const [t, i] of Object.entries(r))
364
- if (n.features.has(t))
365
- for (const a of i)
366
- e.add(a);
366
+ for (const [t, s] of Object.entries(r))
367
+ if (u.features.has(t))
368
+ for (const n of s)
369
+ e.add(n);
367
370
  return e;
368
371
  }
369
- function Z(n) {
372
+ function Z(u) {
370
373
  const e = document.createElement("canvas");
371
- e.width = n.width, e.height = n.height;
374
+ e.width = u.width, e.height = u.height;
372
375
  const r = e.getContext("2d");
373
- r.drawImage(n, 0, 0);
374
- const t = r.getImageData(0, 0, n.width, n.height);
376
+ r.drawImage(u, 0, 0);
377
+ const t = r.getImageData(0, 0, u.width, u.height);
375
378
  return new Uint8Array(t.data.buffer);
376
379
  }
377
- function J(n) {
378
- return /\.svg(?:$|\?)/i.test(n) || /^data:image\/svg\+xml[,;]/i.test(n);
380
+ function J(u) {
381
+ return /\.svg(?:$|\?)/i.test(u) || /^data:image\/svg\+xml[,;]/i.test(u);
379
382
  }
380
- function K(n) {
383
+ function K(u) {
381
384
  return new Promise((e, r) => {
382
385
  const t = new Image();
383
- t.crossOrigin = "anonymous", t.decoding = "async", t.onload = () => e(t), t.onerror = r, t.src = n;
386
+ t.crossOrigin = "anonymous", t.decoding = "async", t.onload = () => e(t), t.onerror = r, t.src = u;
384
387
  });
385
388
  }
386
- async function ee(n, e = {}) {
387
- const r = await fetch(n, { mode: "cors" });
388
- if (!r.ok) throw new Error(`HTTP ${r.status} for ${n}`);
389
+ async function ee(u, e = {}) {
390
+ const r = await fetch(u, { mode: "cors" });
391
+ if (!r.ok) throw new Error(`HTTP ${r.status} for ${u}`);
389
392
  const t = await r.blob();
390
393
  return createImageBitmap(t, {
391
394
  imageOrientation: e.flipY ? "flipY" : "none",
@@ -393,35 +396,36 @@ async function ee(n, e = {}) {
393
396
  premultiplyAlpha: "none"
394
397
  });
395
398
  }
396
- const te = F();
397
- function v(n) {
398
- return J(n) || te ? K(n) : ee(n);
399
+ const te = O();
400
+ function N(u) {
401
+ return J(u) || te ? K(u) : ee(u);
399
402
  }
400
- const O = 256, N = 4;
401
- function re(n, e, r, t) {
402
- let i = 0, a = 0;
403
- const o = [];
403
+ const L = 256, F = 4;
404
+ function re(u, e, r, t) {
405
+ let s = 0, n = 0;
406
+ const a = [];
404
407
  do {
405
- const c = Math.ceil(n / 4), u = Math.ceil(e / 4), f = Math.ceil(c * r / O) * O, l = u * f;
406
- i++, o.push({ offset: a, alignedSize: l, w: n, h: e, bw: c, bh: u, bytesPerRow: f }), a += l, n = Math.max(1, Math.floor(n / 2)), e = Math.max(1, Math.floor(e / 2));
407
- } while (t && (n >= N || e >= N));
408
- return { mipmapCount: i, outputSize: a, bufferRanges: o };
408
+ const o = Math.ceil(u / 4), c = Math.ceil(e / 4), l = Math.ceil(o * r / L) * L, f = c * l;
409
+ s++, a.push({ offset: n, alignedSize: f, w: u, h: e, bw: o, bh: c, bytesPerRow: l }), n += f, u = Math.max(1, Math.floor(u / 2)), e = Math.max(1, Math.floor(e / 2));
410
+ } while (t && (u >= F || e >= F));
411
+ return { mipmapCount: s, outputSize: n, bufferRanges: a };
409
412
  }
410
- class L {
413
+ class D {
411
414
  #e;
412
- #o;
413
- #i = [];
414
- #l;
415
- #c;
416
- #m;
415
+ #f;
416
+ #l = [];
417
417
  #g;
418
+ #a = !1;
419
+ #s;
420
+ #o;
418
421
  #u;
419
- #a;
422
+ #m;
423
+ #i;
420
424
  #n = new Array(3);
421
425
  #r;
422
- #f;
423
- #s;
424
- #_ = 0;
426
+ #p;
427
+ #c;
428
+ #G = 0;
425
429
  /**
426
430
  * Initialize the encoder by detecting available compression formats.
427
431
  * @param {GPUDevice} device - WebGPU device.
@@ -430,7 +434,7 @@ class L {
430
434
  * @returns {Promise<void>} Resolves when initialization is complete.
431
435
  */
432
436
  static async create(e, r = {}) {
433
- const t = new L();
437
+ const t = new D();
434
438
  return await t.#B(e, r.preload ?? !1, r.useTimestampQueries ?? !1), t;
435
439
  }
436
440
  /**
@@ -461,10 +465,10 @@ class L {
461
465
  "bc7-rgba"
462
466
  ], r = [];
463
467
  for (const t of e) {
464
- const i = T[t];
465
- if (this.#t(i)) {
466
- const a = W[i];
467
- r.push({ format: t, ratio: a });
468
+ const s = P[t];
469
+ if (this.#t(s)) {
470
+ const n = Y[s];
471
+ r.push({ format: t, ratio: n });
468
472
  }
469
473
  }
470
474
  return r;
@@ -489,7 +493,7 @@ class L {
489
493
  */
490
494
  static getRequiredFeatures(e) {
491
495
  const r = [];
492
- return !F() && e.features.has("texture-compression-bc") && r.push("texture-compression-bc"), e.features.has("texture-compression-etc2") && r.push("texture-compression-etc2"), e.features.has("texture-compression-astc") && r.push("texture-compression-astc"), e.features.has("shader-f16") && r.push("shader-f16"), e.features.has("timestamp-query") && r.push("timestamp-query"), r;
496
+ return !j() && e.features.has("texture-compression-bc") && r.push("texture-compression-bc"), e.features.has("texture-compression-etc2") && r.push("texture-compression-etc2"), e.features.has("texture-compression-astc") && r.push("texture-compression-astc"), e.features.has("shader-f16") && r.push("shader-f16"), e.features.has("timestamp-query") && r.push("timestamp-query"), r;
493
497
  }
494
498
  /**
495
499
  * Try to determine the best compression options automatically. Do not use this in production, this is
@@ -501,10 +505,10 @@ class L {
501
505
  */
502
506
  async selectPreferredOptions(e, r = {}) {
503
507
  if (r.format == null || r.format == "auto") {
504
- const t = e instanceof Image || e instanceof ImageBitmap || e instanceof GPUTexture ? e : await v(e);
508
+ const t = e instanceof Image || e instanceof ImageBitmap || e instanceof GPUTexture ? e : await N(e);
505
509
  r.format = "auto";
506
- const i = await this.#b(r, t);
507
- r.format = B[i], t instanceof GPUTexture && t.format.endsWith("-srgb") && (r.srgb = !0), (i == s.EAC_RG || i == s.BC5_RG) && (r.normal = !0);
510
+ const s = await this.#d(r, t);
511
+ r.format = G[s], t instanceof GPUTexture && t.format.endsWith("-srgb") && (r.srgb = !0), (s == i.EAC_RG || s == i.BC5_RG) && (r.normal = !0);
508
512
  }
509
513
  return r;
510
514
  }
@@ -549,25 +553,26 @@ class L {
549
553
  */
550
554
  async encodeTexture(e, r = {}) {
551
555
  w(this.#e, "Spark is not initialized");
552
- const t = e instanceof Image || e instanceof ImageBitmap || e instanceof GPUTexture ? e : await v(e);
556
+ const t = e instanceof Image || e instanceof ImageBitmap || e instanceof GPUTexture ? e : await N(e);
553
557
  console.log("Loaded image", t);
554
- const i = await this.#b(r, t), a = this.#p(i), o = Math.ceil(t.width / 4) * 4, c = Math.ceil(t.height / 4) * 4, u = Y[i], f = r.generateMipmaps || r.mips, { mipmapCount: l, outputSize: d, bufferRanges: m } = re(o, c, u, f), h = (r.srgb || r.format?.endsWith("srgb")) && $[i], _ = h ? 1 : r.normal ? 2 : 0, G = V[i] + (h ? "-srgb" : ""), A = h ? ["rgba8unorm", "rgba8unorm-srgb"] : ["rgba8unorm"], x = this.#_++;
558
+ const s = await this.#d(r, t), n = this.#h(s), a = Math.ceil(t.width / 4) * 4, o = Math.ceil(t.height / 4) * 4, c = W[s], l = r.generateMipmaps || r.mips, { mipmapCount: f, outputSize: h, bufferRanges: m } = re(a, o, c, l), b = (r.srgb || r.format?.endsWith("srgb")) && X[s], _ = b ? 1 : r.normal ? 2 : 0, B = $[s] + (b ? "-srgb" : ""), A = b ? ["rgba8unorm", "rgba8unorm-srgb"] : ["rgba8unorm"], x = this.#G++;
555
559
  console.time("create input texture #" + x);
556
- let S = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.STORAGE_BINDING;
557
- const P = r.flipY || o != t.width || c != t.height;
558
- !P && !(t instanceof GPUTexture) && (S |= GPUTextureUsage.RENDER_ATTACHMENT);
559
- const g = this.#e.createCommandEncoder();
560
- g.pushDebugGroup?.("spark process texture"), this.#r && typeof g.writeTimestamp == "function" && g.writeTimestamp(this.#r, 0);
561
- let b;
562
- (P || !(t instanceof GPUTexture && !f)) && (b = this.#e.createTexture({
563
- size: [o, c, 1],
564
- mipLevelCount: l,
560
+ let C = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
561
+ this.#a ? C |= GPUTextureUsage.RENDER_ATTACHMENT : C |= GPUTextureUsage.STORAGE_BINDING;
562
+ const y = r.flipY || a != t.width || o != t.height;
563
+ !y && !(t instanceof GPUTexture) && (C |= GPUTextureUsage.RENDER_ATTACHMENT);
564
+ const p = this.#e.createCommandEncoder();
565
+ p.pushDebugGroup?.("spark process texture"), this.#r && typeof p.writeTimestamp == "function" && p.writeTimestamp(this.#r, 0);
566
+ let d;
567
+ (y || !(t instanceof GPUTexture && !l)) && (d = this.#e.createTexture({
568
+ size: [a, o, 1],
569
+ mipLevelCount: f,
565
570
  format: "rgba8unorm",
566
- usage: S,
571
+ usage: C,
567
572
  viewFormats: A
568
573
  }));
569
- let C;
570
- P ? t instanceof GPUTexture ? this.#d(g, t, b, o, c, h, r.flipY) : (C = this.#e.createTexture({
574
+ let R;
575
+ y ? t instanceof GPUTexture ? this.#_(p, t, d, a, o, b, r.flipY) : (R = this.#e.createTexture({
571
576
  size: [t.width, t.height, 1],
572
577
  mipLevelCount: 1,
573
578
  format: "rgba8unorm",
@@ -576,76 +581,76 @@ class L {
576
581
  viewFormats: A
577
582
  }), this.#e.queue.copyExternalImageToTexture(
578
583
  { source: t },
579
- { texture: C },
584
+ { texture: R },
580
585
  { width: t.width, height: t.height }
581
- ), this.#d(g, C, b, o, c, _, r.flipY)) : t instanceof GPUTexture ? f ? g.copyTextureToTexture({ texture: t }, { texture: b }, { width: o, height: c }) : b = t : this.#e.queue.copyExternalImageToTexture({ source: t }, { texture: b }, { width: o, height: c }), f && this.#T(g, b, l, o, c, _), g.popDebugGroup?.(), console.timeEnd("create input texture #" + x);
582
- const U = this.#e.createTexture({
583
- size: [o, c, 1],
584
- mipLevelCount: l,
585
- format: G,
586
+ ), this.#_(p, R, d, a, o, _, r.flipY)) : t instanceof GPUTexture ? l ? p.copyTextureToTexture({ texture: t }, { texture: d }, { width: a, height: o }) : d = t : this.#e.queue.copyExternalImageToTexture({ source: t }, { texture: d }, { width: a, height: o }), l && this.#w(p, d, f, a, o, _), p.popDebugGroup?.(), console.timeEnd("create input texture #" + x);
587
+ const E = this.#e.createTexture({
588
+ size: [a, o, 1],
589
+ mipLevelCount: f,
590
+ format: B,
586
591
  usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
587
- }), y = this.#e.createBuffer({
588
- size: d,
592
+ }), U = this.#e.createBuffer({
593
+ size: h,
589
594
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
590
- }), E = `dispatch compute shader '${B[i]}' #${x}`;
591
- console.time(E), g.pushDebugGroup?.("spark encode texture");
595
+ }), S = `dispatch compute shader '${G[s]}' #${x}`;
596
+ console.time(S), p.pushDebugGroup?.("spark encode texture");
592
597
  let M = {};
593
- this.#r && typeof g.writeTimestamp != "function" && (M = {
598
+ this.#r && typeof p.writeTimestamp != "function" && (M = {
594
599
  writeTimestamps: {
595
600
  querySet: this.#r,
596
601
  beginningOfPassWriteIndex: 0,
597
602
  endOfPassWriteIndex: 1
598
603
  }
599
604
  });
600
- const I = await a, R = g.beginComputePass(M);
601
- R.setPipeline(I);
602
- for (let p = 0; p < l; p++) {
603
- const D = this.#e.createBindGroup({
604
- layout: I.getBindGroupLayout(0),
605
+ const v = await n, T = p.beginComputePass(M);
606
+ T.setPipeline(v);
607
+ for (let g = 0; g < f; g++) {
608
+ const z = this.#e.createBindGroup({
609
+ layout: v.getBindGroupLayout(0),
605
610
  entries: [
606
611
  {
607
612
  binding: 0,
608
- resource: b.createView({
609
- baseMipLevel: p,
613
+ resource: d.createView({
614
+ baseMipLevel: g,
610
615
  mipLevelCount: 1
611
616
  })
612
617
  },
613
618
  {
614
619
  binding: 1,
615
- resource: this.#a
620
+ resource: this.#i
616
621
  },
617
622
  {
618
623
  binding: 2,
619
624
  resource: {
620
- buffer: y,
621
- offset: m[p].offset,
622
- size: m[p].size
625
+ buffer: U,
626
+ offset: m[g].offset,
627
+ size: m[g].size
623
628
  }
624
629
  }
625
630
  ]
626
631
  });
627
- R.setBindGroup(0, D), R.dispatchWorkgroups(Math.ceil(m[p].bw / 16), Math.ceil(m[p].bh / 16));
632
+ T.setBindGroup(0, z), T.dispatchWorkgroups(Math.ceil(m[g].bw / 16), Math.ceil(m[g].bh / 16));
628
633
  }
629
- R.end();
630
- for (let p = 0; p < l; p++)
631
- g.copyBufferToTexture(
634
+ T.end();
635
+ for (let g = 0; g < f; g++)
636
+ p.copyBufferToTexture(
632
637
  {
633
- buffer: y,
634
- offset: m[p].offset,
635
- bytesPerRow: m[p].bytesPerRow,
636
- rowsPerImage: m[p].bh
638
+ buffer: U,
639
+ offset: m[g].offset,
640
+ bytesPerRow: m[g].bytesPerRow,
641
+ rowsPerImage: m[g].bh
637
642
  },
638
643
  {
639
- texture: U,
640
- mipLevel: p
644
+ texture: E,
645
+ mipLevel: g
641
646
  },
642
647
  {
643
- width: m[p].bw * 4,
644
- height: m[p].bh * 4,
648
+ width: m[g].bw * 4,
649
+ height: m[g].bh * 4,
645
650
  depthOrArrayLayers: 1
646
651
  }
647
652
  );
648
- return this.#r && typeof g.writeTimestamp == "function" && g.writeTimestamp(this.#r, 1), g.popDebugGroup?.(), this.#e.queue.submit([g.finish()]), console.timeEnd(E), C?.destroy(), b != t && b?.destroy(), y?.destroy(), U;
653
+ return this.#r && typeof p.writeTimestamp == "function" && p.writeTimestamp(this.#r, 1), p.popDebugGroup?.(), this.#e.queue.submit([p.finish()]), console.timeEnd(S), R?.destroy(), d != t && d?.destroy(), U?.destroy(), E;
649
654
  }
650
655
  /**
651
656
  * Returns the time (in milliseconds) it took to perform the most recent `encodeTexture()` call.
@@ -670,77 +675,132 @@ class L {
670
675
  if (!this.#r)
671
676
  return 0;
672
677
  const e = this.#e.createCommandEncoder();
673
- e.resolveQuerySet(this.#r, 0, 2, this.#f, 0), e.copyBufferToBuffer(this.#f, 0, this.#s, 0, 16), this.#e.queue.submit([e.finish()]), await this.#e.queue.onSubmittedWorkDone(), await this.#s.mapAsync(GPUMapMode.READ);
674
- const r = this.#s.getMappedRange(), t = new BigUint64Array(r), i = t[0], a = t[1];
675
- return this.#s.unmap(), Number(a - i) / 1e6;
678
+ e.resolveQuerySet(this.#r, 0, 2, this.#p, 0), e.copyBufferToBuffer(this.#p, 0, this.#c, 0, 16), this.#e.queue.submit([e.finish()]), await this.#e.queue.onSubmittedWorkDone(), await this.#c.mapAsync(GPUMapMode.READ);
679
+ const r = this.#c.getMappedRange(), t = new BigUint64Array(r), s = t[0], n = t[1];
680
+ return this.#c.unmap(), Number(n - s) / 1e6;
676
681
  }
677
682
  async #B(e, r, t) {
678
- w(e, "device is required"), w(X(e), "device is not a WebGPU device"), this.#e = e, this.#o = H(this.#e), this.#a = this.#e.createSampler({
683
+ w(e, "device is required"), w(H(e), "device is not a WebGPU device"), this.#e = e, this.#f = Q(this.#e), this.#i = this.#e.createSampler({
679
684
  magFilter: "linear",
680
685
  minFilter: "linear"
681
686
  });
682
- for (let i = 0; i < 3; i++)
683
- this.#n[i] = this.#e.createBuffer({
687
+ for (let s = 0; s < 3; s++)
688
+ this.#n[s] = this.#e.createBuffer({
684
689
  size: 4,
685
690
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
686
- }), this.#e.queue.writeBuffer(this.#n[i], 0, new Uint32Array([i]));
691
+ }), this.#e.queue.writeBuffer(this.#n[s], 0, new Uint32Array([s]));
687
692
  if (t && this.#e.features.has("timestamp-query")) {
688
- const i = j(), a = Q();
689
- (!i || i >= 26) && !a && (this.#r = this.#e.createQuerySet({
693
+ const s = O(), n = k();
694
+ (!s || s >= 26) && !n && (this.#r = this.#e.createQuerySet({
690
695
  type: "timestamp",
691
696
  count: 2
692
- }), this.#f = this.#e.createBuffer({
697
+ }), this.#p = this.#e.createBuffer({
693
698
  size: 16,
694
699
  // 2 timestamps × 8 bytes each
695
700
  usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.QUERY_RESOLVE
696
- }), this.#s = this.#e.createBuffer({
701
+ }), this.#c = this.#e.createBuffer({
697
702
  size: 16,
698
703
  // 2 timestamps × 8 bytes each
699
704
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
700
705
  }));
701
706
  }
702
- if (this.#l = this.#e.features.has("shader-f16"), await this.#G(), r) {
703
- let i;
704
- Array.isArray(r) ? i = r.map((a) => this.#h(a, !1)) : i = this.#o;
705
- for (const a of i)
706
- a !== void 0 && !this.#i[a] && this.#p(a).catch((o) => {
707
- console.error(`Failed to preload pipeline for format ${a}:`, o);
707
+ if (this.#g = this.#e.features.has("shader-f16"), await this.#C(), r) {
708
+ let s;
709
+ Array.isArray(r) ? s = r.map((n) => this.#b(n, !1)) : s = this.#f;
710
+ for (const n of s)
711
+ n !== void 0 && !this.#l[n] && this.#h(n).catch((a) => {
712
+ console.error(`Failed to preload pipeline for format ${n}:`, a);
708
713
  });
709
714
  }
710
715
  }
711
- async #G() {
716
+ async #C() {
712
717
  const e = this.#e.createShaderModule({
713
- code: await k["utils.wgsl"](),
718
+ code: await I["utils.wgsl"](),
714
719
  label: "utils"
715
720
  });
716
721
  if (typeof e.compilationInfo == "function") {
717
- const r = await e.compilationInfo();
718
- if (r.messages.some((t) => t.type == "error")) {
722
+ const t = await e.compilationInfo();
723
+ if (t.messages.some((s) => s.type == "error")) {
719
724
  console.error("WGSL compilation errors:");
720
- for (const t of r.messages)
721
- console.error(t);
725
+ for (const s of t.messages)
726
+ console.error(s);
722
727
  throw new Error("Shader compilation failed");
723
728
  }
724
729
  }
725
- this.#c = await this.#e.createComputePipelineAsync({
726
- layout: "auto",
727
- compute: {
728
- module: e,
729
- entryPoint: "mipmap"
730
- }
731
- }), this.#m = await this.#e.createComputePipelineAsync({
732
- layout: "auto",
733
- compute: {
734
- module: e,
735
- entryPoint: "resize"
736
- }
737
- }), this.#g = await this.#e.createComputePipelineAsync({
738
- layout: "auto",
739
- compute: {
740
- module: e,
741
- entryPoint: "flipy"
742
- }
743
- }), this.#u = await this.#e.createComputePipelineAsync({
730
+ if (k() && (this.#a = !0), this.#a) {
731
+ this.#s = {}, this.#o = {}, this.#u = {};
732
+ const t = ["rgba8unorm-srgb", "rgba8unorm"];
733
+ for (const s of t)
734
+ this.#s[s] = this.#e.createRenderPipeline({
735
+ label: `mipmap-pipeline-${s}`,
736
+ layout: "auto",
737
+ vertex: {
738
+ module: e,
739
+ entryPoint: "fullscreen_vs"
740
+ },
741
+ fragment: {
742
+ module: e,
743
+ entryPoint: "mipmap_fs",
744
+ targets: [{ format: s }]
745
+ },
746
+ primitive: {
747
+ topology: "triangle-strip",
748
+ stripIndexFormat: "uint32"
749
+ }
750
+ }), this.#o[s] = this.#e.createRenderPipeline({
751
+ label: `resize-pipeline-${s}`,
752
+ layout: "auto",
753
+ vertex: {
754
+ module: e,
755
+ entryPoint: "fullscreen_vs"
756
+ },
757
+ fragment: {
758
+ module: e,
759
+ entryPoint: "resize_fs",
760
+ targets: [{ format: s }]
761
+ },
762
+ primitive: {
763
+ topology: "triangle-strip",
764
+ stripIndexFormat: "uint32"
765
+ }
766
+ }), this.#u[s] = this.#e.createRenderPipeline({
767
+ label: `flip-y-pipeline-${s}`,
768
+ layout: "auto",
769
+ vertex: {
770
+ module: e,
771
+ entryPoint: "fullscreen_vs"
772
+ },
773
+ fragment: {
774
+ module: e,
775
+ entryPoint: "flipy_fs",
776
+ targets: [{ format: s }]
777
+ },
778
+ primitive: {
779
+ topology: "triangle-strip",
780
+ stripIndexFormat: "uint32"
781
+ }
782
+ });
783
+ } else
784
+ this.#s = this.#e.createComputePipeline({
785
+ layout: "auto",
786
+ compute: {
787
+ module: e,
788
+ entryPoint: "mipmap"
789
+ }
790
+ }), this.#o = this.#e.createComputePipeline({
791
+ layout: "auto",
792
+ compute: {
793
+ module: e,
794
+ entryPoint: "resize"
795
+ }
796
+ }), this.#u = this.#e.createComputePipeline({
797
+ layout: "auto",
798
+ compute: {
799
+ module: e,
800
+ entryPoint: "flipy"
801
+ }
802
+ });
803
+ this.#m = await this.#e.createComputePipelineAsync({
744
804
  layout: "auto",
745
805
  compute: {
746
806
  module: e,
@@ -748,47 +808,47 @@ class L {
748
808
  }
749
809
  });
750
810
  }
751
- async #p(e) {
752
- if (this.#i[e])
753
- return this.#i[e];
811
+ async #h(e) {
812
+ if (this.#l[e])
813
+ return this.#l[e];
754
814
  const r = (async () => {
755
- console.time("loadPipeline " + B[e]);
815
+ console.time("loadPipeline " + G[e]);
756
816
  const t = q[e];
757
- w(t, `No shader available for format ${B[e]}`);
758
- let i = await k[t]();
759
- this.#l || (i = i.replace(/^enable f16;\s*/m, "").replace(/\bf16\b/g, "f32").replace(/\bvec([234])h\b/g, "vec$1f").replace(/\bmat([234]x[234])h/g, "mat$1f").replace(/\b(\d*\.\d+|\d+\.)h\b/g, "$1"));
760
- const a = this.#e.createShaderModule({
761
- code: i,
762
- label: B[e]
817
+ w(t, `No shader available for format ${G[e]}`);
818
+ let s = await I[t]();
819
+ this.#g || (s = s.replace(/^enable f16;\s*/m, "").replace(/\bf16\b/g, "f32").replace(/\bvec([234])h\b/g, "vec$1f").replace(/\bmat([234]x[234])h/g, "mat$1f").replace(/\b(\d*\.\d+|\d+\.)h\b/g, "$1"));
820
+ const n = this.#e.createShaderModule({
821
+ code: s,
822
+ label: G[e]
763
823
  });
764
- if (typeof a.getCompilationInfo == "function") {
765
- const c = await a.getCompilationInfo();
766
- if (c.messages.some((u) => u.type == "error")) {
824
+ if (typeof n.getCompilationInfo == "function") {
825
+ const o = await n.getCompilationInfo();
826
+ if (o.messages.some((c) => c.type == "error")) {
767
827
  console.error("WGSL compilation errors:");
768
- for (const u of c.messages)
769
- console.error(u);
828
+ for (const c of o.messages)
829
+ console.error(c);
770
830
  throw new Error("Shader compilation failed");
771
831
  }
772
832
  }
773
- const o = await this.#e.createComputePipelineAsync({
833
+ const a = await this.#e.createComputePipelineAsync({
774
834
  layout: "auto",
775
835
  compute: {
776
- module: a,
836
+ module: n,
777
837
  entryPoint: "main"
778
838
  }
779
839
  });
780
- return console.timeEnd("loadPipeline " + B[e]), o;
840
+ return console.timeEnd("loadPipeline " + G[e]), a;
781
841
  })();
782
- return this.#i[e] = r, r;
842
+ return this.#l[e] = r, r;
783
843
  }
784
844
  #t(e) {
785
- return this.#o.has(e);
845
+ return this.#f.has(e);
786
846
  }
787
- #h(e, r) {
788
- const t = T[e];
847
+ #b(e, r) {
848
+ const t = P[e];
789
849
  if (t != null && this.#t(t))
790
850
  return t;
791
- const i = r ? [
851
+ const s = r ? [
792
852
  "bc4-r",
793
853
  "eac-r",
794
854
  "bc5-rg",
@@ -815,100 +875,104 @@ class L {
815
875
  "astc-rgba",
816
876
  "astc-4x4-rgba"
817
877
  ];
818
- for (const a of i)
819
- if (a.includes(e) && this.#t(T[a]))
820
- return T[a];
878
+ for (const n of s)
879
+ if (n.includes(e) && this.#t(P[n]))
880
+ return P[n];
821
881
  }
822
- async #b(e, r) {
882
+ async #d(e, r) {
823
883
  if (e.format == null)
824
884
  e.format = "rgb";
825
885
  else if (e.format == "auto") {
826
886
  if (e.alpha) {
827
- if (this.#t(s.BC7_RGBA)) return s.BC7_RGBA;
828
- if (this.#t(s.ASTC_4x4_RGBA)) return s.ASTC_4x4_RGBA;
887
+ if (this.#t(i.BC7_RGBA)) return i.BC7_RGBA;
888
+ if (this.#t(i.ASTC_4x4_RGBA)) return i.ASTC_4x4_RGBA;
829
889
  } else if (e.srgb) {
830
- if (this.#t(s.BC7_RGB)) return s.BC7_RGB;
831
- if (this.#t(s.ASTC_4x4_RGB)) return s.ASTC_4x4_RGB;
832
- if (this.#t(s.BC1_RGB)) return s.BC1_RGB;
833
- if (this.#t(s.ETC2_RGB)) return s.ETC2_RGB;
890
+ if (this.#t(i.BC7_RGB)) return i.BC7_RGB;
891
+ if (this.#t(i.ASTC_4x4_RGB)) return i.ASTC_4x4_RGB;
892
+ if (this.#t(i.BC1_RGB)) return i.BC1_RGB;
893
+ if (this.#t(i.ETC2_RGB)) return i.ETC2_RGB;
834
894
  } else if (e.normal) {
835
- if (this.#t(s.BC5_RG)) return s.BC5_RG;
836
- if (this.#t(s.EAC_RG)) return s.EAC_RG;
895
+ if (this.#t(i.BC5_RG)) return i.BC5_RG;
896
+ if (this.#t(i.EAC_RG)) return i.EAC_RG;
837
897
  } else {
838
- let i;
898
+ let s;
839
899
  if (r instanceof GPUTexture)
840
- r.format == "r8unorm" || r.format == "r16unorm" ? i = 1 : r.format == "rg8unorm" || r.format == "rg16unorm" ? i = 2 : i = await this.#R(r);
900
+ r.format == "r8unorm" || r.format == "r16unorm" ? s = 1 : r.format == "rg8unorm" || r.format == "rg16unorm" ? s = 2 : s = await this.#T(r);
841
901
  else {
842
- const a = Z(r);
843
- i = this.#C(a);
902
+ const n = Z(r);
903
+ s = this.#R(n);
844
904
  }
845
- if (i == 4) {
846
- if (this.#t(s.BC7_RGBA)) return s.BC7_RGBA;
847
- if (this.#t(s.ASTC_4x4_RGBA)) return s.ASTC_4x4_RGBA;
848
- } else if (i == 3) {
849
- if (this.#t(s.BC7_RGB)) return s.BC7_RGB;
850
- if (this.#t(s.ASTC_4x4_RGB)) return s.ASTC_4x4_RGB;
851
- if (this.#t(s.BC1_RGB)) return s.BC1_RGB;
852
- if (this.#t(s.ETC2_RGB)) return s.ETC2_RGB;
853
- } else if (i == 2) {
854
- if (this.#t(s.BC5_RG)) return s.BC5_RG;
855
- if (this.#t(s.EAC_RG)) return s.EAC_RG;
856
- } else if (i == 1) {
857
- if (this.#t(s.BC4_R)) return s.BC4_R;
858
- if (this.#t(s.EAC_R)) return s.EAC_R;
905
+ if (s == 4) {
906
+ if (this.#t(i.BC7_RGBA)) return i.BC7_RGBA;
907
+ if (this.#t(i.ASTC_4x4_RGBA)) return i.ASTC_4x4_RGBA;
908
+ } else if (s == 3) {
909
+ if (this.#t(i.BC7_RGB)) return i.BC7_RGB;
910
+ if (this.#t(i.ASTC_4x4_RGB)) return i.ASTC_4x4_RGB;
911
+ if (this.#t(i.BC1_RGB)) return i.BC1_RGB;
912
+ if (this.#t(i.ETC2_RGB)) return i.ETC2_RGB;
913
+ } else if (s == 2) {
914
+ if (this.#t(i.BC5_RG)) return i.BC5_RG;
915
+ if (this.#t(i.EAC_RG)) return i.EAC_RG;
916
+ } else if (s == 1) {
917
+ if (this.#t(i.BC4_R)) return i.BC4_R;
918
+ if (this.#t(i.EAC_R)) return i.EAC_R;
859
919
  }
860
920
  }
861
921
  throw new Error("No supported format found.");
862
922
  }
863
- const t = this.#h(e.format, e.preferLowQuality);
923
+ const t = this.#b(e.format, e.preferLowQuality);
864
924
  if (t === void 0)
865
925
  throw new Error(`Unsupported format: ${e.format}`);
866
926
  return t;
867
927
  }
868
- #C(e) {
869
- let r = !0, t = !0, i = 0;
870
- const a = Math.min(1024 * 128, e.length);
871
- for (let o = 0; o < a; o += 4) {
872
- const c = e[o] / 255, u = e[o + 1] / 255, f = e[o + 2] / 255;
873
- e[o + 3] < 255 && (r = !1), (c != u || u != f) && (t = !1);
874
- const d = 2 * c - 1, m = 2 * u - 1, h = 2 * f - 1, _ = d * d + m * m + h * h, G = Math.sqrt(_);
875
- (Math.abs(G - 1) > 0.2 || h < -0.1) && (i += 1);
928
+ #R(e) {
929
+ let r = !0, t = !0, s = 0;
930
+ const n = Math.min(1024 * 128, e.length);
931
+ for (let a = 0; a < n; a += 4) {
932
+ const o = e[a] / 255, c = e[a + 1] / 255, l = e[a + 2] / 255;
933
+ e[a + 3] < 255 && (r = !1), (o != c || c != l) && (t = !1);
934
+ const h = 2 * o - 1, m = 2 * c - 1, b = 2 * l - 1, _ = h * h + m * m + b * b, B = Math.sqrt(_);
935
+ (Math.abs(B - 1) > 0.2 || b < -0.1) && (s += 1);
876
936
  }
877
- return r ? t ? 1 : 16 * i < a ? 2 : 3 : 4;
937
+ return r ? t ? 1 : 16 * s < n ? 2 : 3 : 4;
878
938
  }
879
- async #R(e) {
939
+ async #T(e) {
880
940
  const t = this.#e.createBuffer({
881
941
  size: 12,
882
942
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
883
- }), i = this.#e.createBuffer({
943
+ }), s = this.#e.createBuffer({
884
944
  size: 12,
885
945
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
886
- }), a = this.#e.createBindGroup({
887
- layout: this.#u.getBindGroupLayout(0),
946
+ }), n = this.#e.createBindGroup({
947
+ layout: this.#m.getBindGroupLayout(0),
888
948
  entries: [
889
949
  { binding: 0, resource: e.createView() },
890
950
  { binding: 1, resource: { buffer: t } }
891
951
  ]
892
- }), o = this.#e.createCommandEncoder(), c = o.beginComputePass();
893
- c.setPipeline(this.#u), c.setBindGroup(0, a);
894
- const { width: u, height: f } = e, l = Math.ceil(u / 8), d = Math.ceil(f / 8);
895
- c.dispatchWorkgroups(l, d), c.end(), o.copyBufferToBuffer(t, 0, i, 0, 12), this.#e.queue.submit([o.finish()]), await this.#e.queue.onSubmittedWorkDone(), await i.mapAsync(GPUMapMode.READ);
896
- const m = new Uint32Array(i.getMappedRange()), h = m[0] == 0, _ = m[1] == 0, G = m[2];
897
- return i.unmap(), i.destroy(), t.destroy(), h ? _ ? 1 : 4 * G < u * f ? 2 : 3 : 4;
952
+ }), a = this.#e.createCommandEncoder(), o = a.beginComputePass();
953
+ o.setPipeline(this.#m), o.setBindGroup(0, n);
954
+ const { width: c, height: l } = e, f = Math.ceil(c / 8), h = Math.ceil(l / 8);
955
+ o.dispatchWorkgroups(f, h), o.end(), a.copyBufferToBuffer(t, 0, s, 0, 12), this.#e.queue.submit([a.finish()]), await this.#e.queue.onSubmittedWorkDone(), await s.mapAsync(GPUMapMode.READ);
956
+ const m = new Uint32Array(s.getMappedRange()), b = m[0] == 0, _ = m[1] == 0, B = m[2];
957
+ return s.unmap(), s.destroy(), t.destroy(), b ? _ ? 1 : 4 * B < c * l ? 2 : 3 : 4;
898
958
  }
899
959
  // Apply scaling and flipY transform.
900
- async #d(e, r, t, i, a, o, c) {
901
- const u = e.beginComputePass(), f = c ? this.#g : this.#m;
902
- u.setPipeline(f);
903
- const l = this.#e.createBindGroup({
904
- layout: f.getBindGroupLayout(0),
960
+ #_(e, r, t, s, n, a, o) {
961
+ if (this.#a) {
962
+ this.#P(e, r, t, s, n, a, o);
963
+ return;
964
+ }
965
+ const c = e.beginComputePass(), l = o ? this.#u : this.#o;
966
+ c.setPipeline(l);
967
+ const f = this.#e.createBindGroup({
968
+ layout: l.getBindGroupLayout(0),
905
969
  entries: [
906
970
  {
907
971
  binding: 0,
908
972
  resource: r.createView({
909
973
  baseMipLevel: 0,
910
974
  mipLevelCount: 1,
911
- format: o == 1 ? "rgba8unorm-srgb" : "rgba8unorm",
975
+ format: a == 1 ? "rgba8unorm-srgb" : "rgba8unorm",
912
976
  usage: GPUTextureUsage.TEXTURE_BINDING
913
977
  })
914
978
  },
@@ -924,41 +988,89 @@ class L {
924
988
  },
925
989
  {
926
990
  binding: 2,
927
- resource: this.#a
991
+ resource: this.#i
928
992
  },
929
993
  {
930
994
  binding: 3,
931
- resource: { buffer: this.#n[o] }
995
+ resource: { buffer: this.#n[a] }
932
996
  }
933
997
  ]
934
998
  });
935
- u.setBindGroup(0, l), u.dispatchWorkgroups(Math.ceil(i / 8), Math.ceil(a / 8)), u.end();
999
+ c.setBindGroup(0, f), c.dispatchWorkgroups(Math.ceil(s / 8), Math.ceil(n / 8)), c.end();
936
1000
  }
937
- async #T(e, r, t, i, a, o) {
938
- const c = e.beginComputePass();
939
- c.setPipeline(this.#c);
940
- let u = i, f = a;
941
- for (let l = 0; l < t - 1; l++)
942
- u = Math.max(1, Math.floor(u / 2)), f = Math.max(1, Math.floor(f / 2)), this.#w(c, r, l, l + 1, u, f, o);
943
- c.end();
1001
+ // Apply scaling and flipY transform.
1002
+ #P(e, r, t, s, n, a, o) {
1003
+ const c = a == 1 ? "rgba8unorm-srgb" : "rgba8unorm", l = t.createView({
1004
+ baseMipLevel: 0,
1005
+ mipLevelCount: 1,
1006
+ dimension: "2d",
1007
+ format: c,
1008
+ usage: GPUTextureUsage.RENDER_ATTACHMENT
1009
+ }), f = e.beginRenderPass({
1010
+ colorAttachments: [
1011
+ {
1012
+ view: l,
1013
+ loadOp: "clear",
1014
+ storeOp: "store",
1015
+ clearValue: [0, 0, 0, 0]
1016
+ }
1017
+ ]
1018
+ }), h = o ? this.#u[c] : this.#o[c];
1019
+ f.setPipeline(h);
1020
+ const m = this.#e.createBindGroup({
1021
+ layout: h.getBindGroupLayout(0),
1022
+ entries: [
1023
+ {
1024
+ binding: 0,
1025
+ resource: r.createView({
1026
+ baseMipLevel: 0,
1027
+ mipLevelCount: 1,
1028
+ format: a == 1 ? "rgba8unorm-srgb" : "rgba8unorm",
1029
+ usage: GPUTextureUsage.TEXTURE_BINDING
1030
+ })
1031
+ },
1032
+ {
1033
+ binding: 2,
1034
+ resource: this.#i
1035
+ },
1036
+ {
1037
+ binding: 3,
1038
+ resource: { buffer: this.#n[a] }
1039
+ }
1040
+ ]
1041
+ });
1042
+ f.setBindGroup(0, m), f.draw(4, 1, 0, 0), f.end();
1043
+ }
1044
+ async #w(e, r, t, s, n, a) {
1045
+ let o = s, c = n;
1046
+ if (this.#a)
1047
+ for (let l = 0; l < t - 1; l++)
1048
+ o = Math.max(1, Math.floor(o / 2)), c = Math.max(1, Math.floor(c / 2)), this.#y(e, r, l, l + 1, o, c, a);
1049
+ else {
1050
+ const l = e.beginComputePass();
1051
+ l.setPipeline(this.#s);
1052
+ for (let f = 0; f < t - 1; f++)
1053
+ o = Math.max(1, Math.floor(o / 2)), c = Math.max(1, Math.floor(c / 2)), this.#x(l, r, f, f + 1, o, c, a);
1054
+ l.end();
1055
+ }
944
1056
  }
945
- #w(e, r, t, i, a, o, c) {
946
- const u = this.#e.createBindGroup({
947
- layout: this.#c.getBindGroupLayout(0),
1057
+ #x(e, r, t, s, n, a, o) {
1058
+ const c = this.#e.createBindGroup({
1059
+ layout: this.#s.getBindGroupLayout(0),
948
1060
  entries: [
949
1061
  {
950
1062
  binding: 0,
951
1063
  resource: r.createView({
952
1064
  baseMipLevel: t,
953
1065
  mipLevelCount: 1,
954
- format: c == 1 ? "rgba8unorm-srgb" : "rgba8unorm",
1066
+ format: o == 1 ? "rgba8unorm-srgb" : "rgba8unorm",
955
1067
  usage: GPUTextureUsage.TEXTURE_BINDING
956
1068
  })
957
1069
  },
958
1070
  {
959
1071
  binding: 1,
960
1072
  resource: r.createView({
961
- baseMipLevel: i,
1073
+ baseMipLevel: s,
962
1074
  mipLevelCount: 1,
963
1075
  dimension: "2d",
964
1076
  format: "rgba8unorm",
@@ -967,17 +1079,57 @@ class L {
967
1079
  },
968
1080
  {
969
1081
  binding: 2,
970
- resource: this.#a
1082
+ resource: this.#i
971
1083
  },
972
1084
  {
973
1085
  binding: 3,
974
- resource: { buffer: this.#n[c] }
1086
+ resource: { buffer: this.#n[o] }
1087
+ }
1088
+ ]
1089
+ });
1090
+ e.setBindGroup(0, c), e.dispatchWorkgroups(Math.ceil(n / 8), Math.ceil(a / 8));
1091
+ }
1092
+ #y(e, r, t, s, n, a, o) {
1093
+ const c = o == 1 ? "rgba8unorm-srgb" : "rgba8unorm", l = r.createView({
1094
+ baseMipLevel: s,
1095
+ mipLevelCount: 1,
1096
+ dimension: "2d",
1097
+ format: c,
1098
+ usage: GPUTextureUsage.RENDER_ATTACHMENT
1099
+ }), f = e.beginRenderPass({
1100
+ colorAttachments: [
1101
+ {
1102
+ view: l,
1103
+ loadOp: "clear",
1104
+ storeOp: "store",
1105
+ clearValue: [0, 0, 0, 0]
1106
+ }
1107
+ ]
1108
+ }), h = this.#e.createBindGroup({
1109
+ layout: this.#s[c].getBindGroupLayout(0),
1110
+ entries: [
1111
+ {
1112
+ binding: 0,
1113
+ resource: r.createView({
1114
+ baseMipLevel: t,
1115
+ mipLevelCount: 1,
1116
+ format: c,
1117
+ usage: GPUTextureUsage.TEXTURE_BINDING
1118
+ })
1119
+ },
1120
+ {
1121
+ binding: 2,
1122
+ resource: this.#i
1123
+ },
1124
+ {
1125
+ binding: 3,
1126
+ resource: { buffer: this.#n[o] }
975
1127
  }
976
1128
  ]
977
1129
  });
978
- e.setBindGroup(0, u), e.dispatchWorkgroups(Math.ceil(a / 8), Math.ceil(o / 8));
1130
+ f.setPipeline(this.#s[c]), f.setBindGroup(0, h), f.draw(4, 1, 0, 0), f.end();
979
1131
  }
980
1132
  }
981
1133
  export {
982
- L as Spark
1134
+ D as Spark
983
1135
  };
@@ -2,6 +2,10 @@ const n = `struct Params {
2
2
  colorMode: u32,
3
3
  };
4
4
 
5
+ const COLOR_LINEAR : u32 = 0u;
6
+ const COLOR_SRGB : u32 = 1u;
7
+ const COLOR_NORMAL : u32 = 2u;
8
+
5
9
  @group(0) @binding(0) var src : texture_2d<f32>;
6
10
  @group(0) @binding(1) var dst : texture_storage_2d<rgba8unorm, write>;
7
11
  @group(0) @binding(2) var smp: sampler;
@@ -38,25 +42,53 @@ fn mipmap(@builtin(global_invocation_id) id : vec3<u32>) {
38
42
 
39
43
  let size_rcp = vec2f(1.0) / vec2f(dstSize);
40
44
 
41
- // We are not doing this yet, but in some cases we want to take 4 samples in order to apply alpha weighting,
42
- // or to support non multiple of two textures.
45
+ // We take 4 samples explicitly in order to support alpha weighting and for slightly more correct
46
+ // results when using non multiple of two textures.
43
47
  let uv0 = (vec2f(id.xy) + vec2f(0.25)) * size_rcp;
44
48
  let uv1 = uv0 + 0.5 * size_rcp;
45
49
 
46
50
  var color = vec4f(0.0);
47
- color += textureSampleLevel(src, smp, vec2f(uv0.x, uv0.y), 0);
48
- color += textureSampleLevel(src, smp, vec2f(uv1.x, uv0.y), 0);
49
- color += textureSampleLevel(src, smp, vec2f(uv0.x, uv1.y), 0);
50
- color += textureSampleLevel(src, smp, vec2f(uv1.x, uv1.y), 0);
51
- color *= 0.25;
51
+
52
+ if (params.colorMode == COLOR_SRGB) {
53
+ let c00 = textureSampleLevel(src, smp, vec2f(uv0.x, uv0.y), 0);
54
+ let c10 = textureSampleLevel(src, smp, vec2f(uv1.x, uv0.y), 0);
55
+ let c01 = textureSampleLevel(src, smp, vec2f(uv0.x, uv1.y), 0);
56
+ let c11 = textureSampleLevel(src, smp, vec2f(uv1.x, uv1.y), 0);
57
+
58
+ let a00 = c00.a;
59
+ let a10 = c10.a;
60
+ let a01 = c01.a;
61
+ let a11 = c11.a;
62
+ let a_sum = a00 + a10 + a01 + a11;
63
+
64
+ color.a = 0.25 * a_sum;
65
+ if (a_sum > 1.0 / 256.0) {
66
+ color.r = (c00.r * a00 + c10.r * a10 + c01.r * a01 + c11.r * a11) / a_sum;
67
+ color.g = (c00.g * a00 + c10.g * a10 + c01.g * a01 + c11.g * a11) / a_sum;
68
+ color.b = (c00.b * a00 + c10.b * a10 + c01.b * a01 + c11.b * a11) / a_sum;
69
+ } else {
70
+ color.r = 0.25 * (c00.r + c10.r + c01.r + c11.r);
71
+ color.g = 0.25 * (c00.g + c10.g + c01.g + c11.g);
72
+ color.b = 0.25 * (c00.b + c10.b + c01.b + c11.b);
73
+ }
74
+ }
75
+ else {
76
+ // For linear colors, we assume no alpha.
77
+ // @@ We could normalize/reconstruct normals before averaging.
78
+ color += textureSampleLevel(src, smp, vec2f(uv0.x, uv0.y), 0);
79
+ color += textureSampleLevel(src, smp, vec2f(uv1.x, uv0.y), 0);
80
+ color += textureSampleLevel(src, smp, vec2f(uv0.x, uv1.y), 0);
81
+ color += textureSampleLevel(src, smp, vec2f(uv1.x, uv1.y), 0);
82
+ color *= 0.25;
83
+ }
52
84
 
53
85
  // This would be the single sample implementation:
54
86
  // let uv = (vec2f(id.xy) + vec2f(0.5)) * size_rcp;
55
87
  // var color = textureSampleLevel(src, smp, vec2f(uv.x, uv.y), 0);
56
88
 
57
- if (params.colorMode == 1) {
89
+ if (params.colorMode == COLOR_SRGB) {
58
90
  color = linear_to_srgb_vec4(color);
59
- } else if (params.colorMode == 2) {
91
+ } else if (params.colorMode == COLOR_NORMAL) {
60
92
  color = normalize_vec4(color);
61
93
  }
62
94
 
@@ -73,9 +105,9 @@ fn resize(@builtin(global_invocation_id) id : vec3<u32>) {
73
105
  let uv = (vec2f(id.xy) + vec2f(0.5)) / vec2f(dstSize);
74
106
  var color = textureSampleLevel(src, smp, uv, 0);
75
107
 
76
- if (params.colorMode == 1) {
108
+ if (params.colorMode == COLOR_SRGB) {
77
109
  color = linear_to_srgb_vec4(color);
78
- } else if (params.colorMode == 2) {
110
+ } else if (params.colorMode == COLOR_NORMAL) {
79
111
  color = normalize_vec4(color);
80
112
  }
81
113
 
@@ -92,15 +124,80 @@ fn flipy(@builtin(global_invocation_id) id : vec3<u32>) {
92
124
  let uv = (vec2f(f32(id.x), f32(dstSize.y - 1u - id.y)) + vec2f(0.5)) / vec2f(dstSize);
93
125
  var color = textureSampleLevel(src, smp, uv, 0);
94
126
 
95
- if (params.colorMode == 1) {
127
+ if (params.colorMode == COLOR_SRGB) {
96
128
  color = linear_to_srgb_vec4(color);
97
- } else if (params.colorMode == 2) {
129
+ } else if (params.colorMode == COLOR_NORMAL) {
98
130
  color = normalize_vec4(color);
99
131
  }
100
132
 
101
133
  textureStore(dst, id.xy, color);
102
134
  }
103
135
 
136
+ // Fullscreen vertex shader
137
+ struct VSOutput {
138
+ @builtin(position) pos: vec4<f32>,
139
+ @location(0) tex : vec2<f32>
140
+ };
141
+
142
+ @vertex
143
+ fn fullscreen_vs(@builtin(vertex_index) vertexIndex : u32) -> VSOutput {
144
+
145
+ var pos = array<vec2<f32>, 4>(
146
+ vec2<f32>(-1.0, 1.0),
147
+ vec2<f32>( 1.0, 1.0),
148
+ vec2<f32>(-1.0, -1.0),
149
+ vec2<f32>( 1.0, -1.0)
150
+ );
151
+
152
+ var tex = array<vec2<f32>, 4>(
153
+ vec2<f32>(0.0, 0.0),
154
+ vec2<f32>(1.0, 0.0),
155
+ vec2<f32>(0.0, 1.0),
156
+ vec2<f32>(1.0, 1.0)
157
+ );
158
+
159
+ var vs_output : VSOutput;
160
+ vs_output.tex = tex[vertexIndex];
161
+ vs_output.pos = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
162
+ return vs_output;
163
+ }
164
+
165
+ @fragment
166
+ fn mipmap_fs(@location(0) uv : vec2<f32>) -> @location(0) vec4<f32> {
167
+
168
+ var color = textureSample(src, smp, uv);
169
+
170
+ if (params.colorMode == 2) {
171
+ color = normalize_vec4(color);
172
+ }
173
+
174
+ return color;
175
+ }
176
+
177
+ @fragment
178
+ fn resize_fs(@location(0) uv : vec2<f32>) -> @location(0) vec4<f32> {
179
+
180
+ var color = textureSample(src, smp, uv);
181
+
182
+ if (params.colorMode == 2) {
183
+ color = normalize_vec4(color);
184
+ }
185
+
186
+ return color;
187
+ }
188
+
189
+ @fragment
190
+ fn flipy_fs(@location(0) uv : vec2<f32>) -> @location(0) vec4<f32> {
191
+
192
+ var color = textureSample(src, smp, vec2(uv.x, 1 - uv.y));
193
+
194
+ if (params.colorMode == 2) {
195
+ color = normalize_vec4(color);
196
+ }
197
+
198
+ return color;
199
+ }
200
+
104
201
 
105
202
  @group(0) @binding(1) var<storage, read_write> global_counters: array<atomic<u32>, 3>;
106
203
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ludicon/spark.js",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "Real-Time GPU Texture Codecs for the Web",
5
5
  "main": "dist/spark.esm.js",
6
6
  "module": "dist/spark.esm.js",