gputex 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ declare const TextureFormat: {
6
6
  readonly BC7_SRGB: "BC7_SRGB";
7
7
  readonly ASTC_4x4: "ASTC_4x4";
8
8
  readonly ASTC_4x4_SRGB: "ASTC_4x4_SRGB";
9
+ readonly ETC2_RGB8: "ETC2_RGB8";
10
+ readonly ETC2_RGB8_SRGB: "ETC2_RGB8_SRGB";
9
11
  };
10
12
  type TextureFormat = (typeof TextureFormat)[keyof typeof TextureFormat];
11
13
  declare const WebGPUFeature: {
@@ -33,6 +35,31 @@ interface Capabilities {
33
35
  }
34
36
  declare function detectCapabilities(adapter: FeatureProvider): Capabilities;
35
37
 
38
+ /** One level of a mip chain. 4 bytes per pixel (RGBA8). */
39
+ interface MipLevel {
40
+ data: Uint8ClampedArray;
41
+ width: number;
42
+ height: number;
43
+ }
44
+ /**
45
+ * Produce the full mip chain from a level-0 image. The chain goes down
46
+ * to a 1×1 level — the standard OpenGL / WebGPU convention — so the
47
+ * caller gets `floor(log2(max(w, h))) + 1` levels total.
48
+ *
49
+ * Levels whose logical dimensions are below the encoder's 4×4 block
50
+ * grid are still produced here at their true logical size; padding up
51
+ * to a single block is the encoder's job, not ours.
52
+ */
53
+ declare function generateMipChain(level0: MipLevel): MipLevel[];
54
+ /**
55
+ * Pad a mip level up to a multiple of 4 in each dimension using clamp-
56
+ * to-edge sampling. Used before handing sub-4×4 levels to a block-
57
+ * compression encoder, which requires at least one full block per level.
58
+ *
59
+ * If the input is already block-aligned this returns the input unchanged.
60
+ */
61
+ declare function padToBlockMultiple(level: MipLevel): MipLevel;
62
+
36
63
  /**
37
64
  * Anything `GPUQueue.copyExternalImageToTexture` accepts. Matches the
38
65
  * WebGPU spec's CopyExternalImageSource set.
@@ -54,17 +81,21 @@ interface EncodeCallOptions {
54
81
  colorSpace?: 'srgb' | 'linear';
55
82
  }
56
83
  /**
57
- * Result of a raw bytes-only encode. This is the encoder's native output: the
58
- * compressed block bytes plus dimensions, with no Three.js (or any engine)
59
- * involvement. Feed `data` into whatever renderer's compressed-texture upload
60
- * you like, or use `buildCompressedTexture()` from `gputex/three`.
84
+ * One level of encoded output: the compressed block bytes plus logical and
85
+ * block-aligned dimensions. This is the encoder's native output shape, with
86
+ * no Three.js (or any engine) involvement — feed `data` into whatever
87
+ * renderer's compressed-texture upload you like, or use
88
+ * `buildCompressedTexture()` from `gputex/three`.
61
89
  */
62
- interface EncodeBytesResult {
90
+ interface EncodedLevelBytes {
63
91
  width: number;
64
92
  height: number;
65
93
  paddedWidth: number;
66
94
  paddedHeight: number;
67
95
  data: Uint8Array;
96
+ }
97
+ /** Result of a raw bytes-only single-image encode. */
98
+ interface EncodeBytesResult extends EncodedLevelBytes {
68
99
  encodeMs: number;
69
100
  /**
70
101
  * GPU-side compute-pass time in ms, measured with timestamp queries.
@@ -75,6 +106,16 @@ interface EncodeBytesResult {
75
106
  */
76
107
  gpuMs?: number;
77
108
  }
109
+ /** Result of a whole-chain encode — see `Encoder.encodeMipChainToBytes()`. */
110
+ interface EncodeMipChainResult {
111
+ /** Encoded levels in the order given; `levels[0]` is the base level. */
112
+ levels: EncodedLevelBytes[];
113
+ /** Wall-clock time for the whole chain: uploads → dispatches → readback. */
114
+ encodeMs: number;
115
+ /** GPU compute time for the whole chain's single compute pass (see
116
+ * `EncodeBytesResult.gpuMs` for caveats). */
117
+ gpuMs?: number;
118
+ }
78
119
  interface FormatVariant {
79
120
  colorSpace: 'srgb' | 'linear';
80
121
  }
@@ -116,16 +157,34 @@ declare abstract class Encoder {
116
157
  readonly adapter?: GPUAdapter;
117
158
  readonly ownsDevice: boolean;
118
159
  readonly disableF16: boolean;
119
- protected _pipeline: GPUComputePipeline;
160
+ protected _pipelineReady: Promise<GPUComputePipeline>;
161
+ protected _prepPipelineReady: Promise<GPUComputePipeline> | null;
120
162
  private _cachedSrcTex;
121
163
  private _cachedSrcW;
122
164
  private _cachedSrcH;
165
+ private _cachedSrcSource;
166
+ private _cachedSrcFlipY;
123
167
  private _cachedDst;
124
168
  private _cachedStaging;
125
169
  private _cachedParams;
126
170
  private _lastParams;
127
171
  private _cachedBindGroup;
172
+ private _cachedPrepPlanes;
173
+ private _cachedPrepBindGroup;
128
174
  private _resourcesBusy;
175
+ /** Set when the active shader declares a @binding(3) sampler (the BC5
176
+ * kernels read texels through textureGather + clamp-to-edge). */
177
+ private _usesSampler;
178
+ private _sampler;
179
+ private _chainSig;
180
+ private _chainTextures;
181
+ private _chainPrepPlanes;
182
+ private _chainPrepBindGroups;
183
+ private _chainParams;
184
+ private _chainBindGroups;
185
+ private _chainDst;
186
+ private _chainStaging;
187
+ private _chainBusy;
129
188
  constructor({ device, adapter, ownsDevice, disableF16 }: EncoderOptions);
130
189
  protected _buildPipeline(): void;
131
190
  destroy(): void;
@@ -133,10 +192,27 @@ declare abstract class Encoder {
133
192
  abstract get label(): string;
134
193
  /** 8 for BC1/BC4, 16 for BC5/BC7/ASTC 4×4. */
135
194
  abstract get bytesPerBlock(): number;
195
+ /**
196
+ * Pipeline-creation override constants for the active shader, or
197
+ * undefined for none. Subclasses expose quality/behaviour toggles this
198
+ * way so the OFF state is dead-coded by the shader compiler instead of
199
+ * branched at runtime.
200
+ */
201
+ protected pipelineConstants(): Record<string, number> | undefined;
136
202
  /** WGSL `@workgroup_size` dimensions. Default 8×8×1. */
137
203
  get workgroupSize(): readonly [number, number, number];
138
204
  /** Whether this format has an sRGB variant. Default true. */
139
205
  get supportsSrgb(): boolean;
206
+ /**
207
+ * Format of the single-shot source texture the encode pass samples.
208
+ * Encoders that read only a channel subset can narrow it to cut DRAM
209
+ * traffic on the bandwidth-bound compute pass (BC5 reads rg8unorm — half
210
+ * the bytes of rgba8). Must be valid as a copyExternalImageToTexture
211
+ * destination and renderable. Chain encodes keep rgba8unorm regardless
212
+ * (their inputs are RGBA mip levels / texture views); the WGSL is
213
+ * format-agnostic (`texture_2d<f32>`), so mixing is byte-identical.
214
+ */
215
+ protected get srcTextureFormat(): GPUTextureFormat;
140
216
  /**
141
217
  * Optional f16 WGSL variant. Used only when the device reports the
142
218
  * `shader-f16` feature; the format's f32 `wgslSource()` is the automatic
@@ -147,6 +223,21 @@ declare abstract class Encoder {
147
223
  protected get _useF16(): boolean;
148
224
  /** WGSL compute-shader source (f32; the fallback when f16 is unavailable). */
149
225
  abstract wgslSource(): string;
226
+ /** WGSL for the preparation pass, or null when the encoder reads the
227
+ * RGBA8 source directly. */
228
+ protected wgslPrepSource(): string | null;
229
+ /** Formats and sizes of the prepared planes for a padded source size. */
230
+ protected prepPlanes(paddedWidth: number, paddedHeight: number): {
231
+ format: GPUTextureFormat;
232
+ width: number;
233
+ height: number;
234
+ }[];
235
+ /** Workgroup counts for the prep dispatch. */
236
+ protected prepDispatch(blocksX: number, blocksY: number): [number, number];
237
+ /** Create the prepared-plane textures for one padded source size. */
238
+ private _createPrepPlanes;
239
+ /** Bind group for one prep dispatch. */
240
+ private _createPrepBindGroup;
150
241
  /** e.g. 'bc1-rgba-unorm-srgb'. */
151
242
  abstract gpuTextureFormat(opts: FormatVariant): GPUTextureFormat;
152
243
  /**
@@ -166,6 +257,55 @@ declare abstract class Encoder {
166
257
  flipY?: boolean;
167
258
  withGpuTime?: boolean;
168
259
  }): Promise<EncodeBytesResult>;
260
+ /**
261
+ * Encode a whole mip chain in ONE GPU submission. A per-level
262
+ * `encodeToBytes()` loop costs a full CPU↔GPU round trip per level (a
263
+ * 1024² chain is 11 levels → 11 `mapAsync` waits with the GPU idle in
264
+ * between); this path uploads every level, records one dispatch per level
265
+ * into a single compute pass, copies all outputs into one staging buffer
266
+ * and maps it once.
267
+ *
268
+ * `levels` are raw RGBA8 pixels in base-to-tail order; sizes don't have to
269
+ * halve level-to-level (each level is padded and clamped independently,
270
+ * exactly like `encodeToBytes`). Uploads use `writeTexture` — the direct
271
+ * raw-bytes path, which also sidesteps the broken
272
+ * `copyExternalImageToTexture` devices (see workarounds.ts). There is no
273
+ * flip option: bake any vertical flip into level 0 before generating the
274
+ * chain, as `compressTexture()` does.
275
+ */
276
+ encodeMipChainToBytes(levels: readonly MipLevel[], { withGpuTime }?: {
277
+ withGpuTime?: boolean;
278
+ }): Promise<EncodeMipChainResult>;
279
+ /**
280
+ * Encode every mip level of a GPU-resident texture in one submission —
281
+ * the zero-CPU-pixels counterpart of `encodeMipChainToBytes()`. Pair it
282
+ * with `generateGpuMipChain()` (gpuMipgen.ts): upload the image once,
283
+ * box-filter the chain on the GPU, then encode straight from the
284
+ * texture's mip views. Pixels never transit the CPU between the source
285
+ * image and the compressed-bytes readback.
286
+ *
287
+ * `srcTex` must be `rgba8unorm` with TEXTURE_BINDING usage; level 0's
288
+ * dimensions are taken from the texture and lower levels follow the
289
+ * standard floor-halving chain. Encoded output is identical to feeding
290
+ * the equivalent CPU chain to `encodeMipChainToBytes()`.
291
+ */
292
+ encodeMipChainFromTexture(srcTex: GPUTexture, { withGpuTime }?: {
293
+ withGpuTime?: boolean;
294
+ }): Promise<EncodeMipChainResult>;
295
+ /** Block-grid geometry + packed output offsets for a chain of levels.
296
+ * `byteSpan` is both the dst buffer size and the readback copy size (a
297
+ * multiple of 4: byteLen is a multiple of bytesPerBlock ≥ 8, offsets are
298
+ * CHAIN_ALIGN-ed). */
299
+ private _chainGeometry;
300
+ /** Shared chain-encode tail: one compute pass with a dispatch per level,
301
+ * one submit, one staging readback sliced into per-level byte arrays. */
302
+ private _submitChainAndRead;
303
+ /** Create the query set + resolve/staging buffers for one timed
304
+ * submission, or null when the device lacks 'timestamp-query'. */
305
+ private _createTiming;
306
+ /** Read back a timed submission's pass duration (ms) and destroy the
307
+ * timing objects. Timestamps are u64 nanoseconds. */
308
+ private _readTimingMs;
169
309
  }
170
310
 
171
311
  declare class BC1Encoder extends Encoder {
@@ -185,14 +325,26 @@ declare class BC5Encoder extends Encoder {
185
325
  get label(): string;
186
326
  get bytesPerBlock(): number;
187
327
  get supportsSrgb(): boolean;
328
+ protected get srcTextureFormat(): GPUTextureFormat;
188
329
  wgslSource(): string;
189
330
  wgslSourceFastF16(): string;
190
331
  gpuTextureFormat(): GPUTextureFormat;
191
332
  }
192
333
 
334
+ interface BC7EncoderOptions extends EncoderOptions {
335
+ /**
336
+ * Emit BC7 mode 4 on decorrelated blocks (normal maps, channel-packed
337
+ * atlases): a large quality win there, at up to ~1.5× encode time on
338
+ * exactly that content. See the header note for the measurements.
339
+ */
340
+ adaptiveMode4?: boolean;
341
+ }
193
342
  declare class BC7Encoder extends Encoder {
194
343
  static readonly requiredFeature: GPUFeatureName;
195
344
  static readonly textureFormats: readonly TextureFormat[];
345
+ private readonly adaptiveMode4;
346
+ constructor(opts: BC7EncoderOptions);
347
+ protected pipelineConstants(): Record<string, number> | undefined;
196
348
  get label(): string;
197
349
  get bytesPerBlock(): number;
198
350
  get supportsSrgb(): boolean;
@@ -212,6 +364,17 @@ declare class ASTC4x4Encoder extends Encoder {
212
364
  gpuTextureFormat({ colorSpace }: FormatVariant): GPUTextureFormat;
213
365
  }
214
366
 
367
+ declare class ETC2Encoder extends Encoder {
368
+ static readonly requiredFeature: GPUFeatureName;
369
+ static readonly textureFormats: readonly TextureFormat[];
370
+ get label(): string;
371
+ get bytesPerBlock(): number;
372
+ get supportsSrgb(): boolean;
373
+ wgslSource(): string;
374
+ wgslSourceFastF16(): string;
375
+ gpuTextureFormat({ colorSpace }: FormatVariant): GPUTextureFormat;
376
+ }
377
+
215
378
  /** Raw RGBA8 pixel data (e.g. a CPU-generated mip level). */
216
379
  interface RawPixelSource {
217
380
  data: ArrayBufferView;
@@ -358,16 +521,26 @@ type TextureHint = 'color' | 'colorWithAlpha' | 'normal';
358
521
  /**
359
522
  * Optional format preference — a wish, not a demand. Applied when the
360
523
  * device supports the format and the hint is compatible; otherwise
361
- * selection proceeds normally (BC7 → ASTC → null). Currently only
524
+ * selection proceeds normally (BC7 → ASTC → ETC2 → null). Currently only
362
525
  * 'bc1': half the memory of BC7 (0.5 vs 1 byte/pixel) for opaque
363
526
  * colour, at visibly lower quality on smooth content.
364
527
  */
365
528
  type PreferredFormat = 'bc1';
529
+ /**
530
+ * Memory/fidelity trade-off for opaque colour textures. 'high' (default)
531
+ * picks the 8-bpp formats (BC7 / ASTC 4×4); 'low' picks the 4-bpp ones
532
+ * (BC1 / ETC2 RGB8) when the adapter supports one. Hints that the 4-bpp
533
+ * formats can't carry ('colorWithAlpha', 'normal') ignore this and keep
534
+ * the 'high' selection.
535
+ */
536
+ type FormatQuality = 'high' | 'low';
366
537
  interface SelectFormatOptions {
367
538
  /** Pick the sRGB variant when the format has one. Default 'srgb'. */
368
539
  colorSpace?: 'srgb' | 'linear';
369
540
  /** Prefer a specific format when supported. See `PreferredFormat`. */
370
541
  preferredFormat?: PreferredFormat;
542
+ /** Memory/fidelity trade-off. See `FormatQuality`. Default 'high'. */
543
+ quality?: FormatQuality;
371
544
  }
372
545
  interface FormatSelection {
373
546
  /** null = no compressed path on this adapter; caller should fall back. */
@@ -393,30 +566,21 @@ interface WebGLFormatSelection {
393
566
  }
394
567
  declare function selectWebGLFormat(caps: WebGLCapabilities, hint: TextureHint, options?: SelectFormatOptions): WebGLFormatSelection;
395
568
 
396
- /** One level of a mip chain. 4 bytes per pixel (RGBA8). */
397
- interface MipLevel {
398
- data: Uint8ClampedArray;
399
- width: number;
400
- height: number;
401
- }
569
+ /** Matches mipgen's chain length: floor(log2(max(w, h))) + 1 levels. */
570
+ declare function gpuMipLevelCount(width: number, height: number): number;
402
571
  /**
403
- * Produce the full mip chain from a level-0 image. The chain goes down
404
- * to a 1×1 level — the standard OpenGL / WebGPU convention — so the
405
- * caller gets `floor(log2(max(w, h))) + 1` levels total.
572
+ * Upload `source` and generate its full mip chain on the GPU. Returns an
573
+ * `rgba8unorm` texture with `gpuMipLevelCount` levels whose dimensions
574
+ * follow the standard floor-halving chain; feed it to
575
+ * `Encoder.encodeMipChainFromTexture()`. The caller owns the texture —
576
+ * destroy it after encoding.
406
577
  *
407
- * Levels whose logical dimensions are below the encoder's 4×4 block
408
- * grid are still produced here at their true logical size; padding up
409
- * to a single block is the encoder's job, not ours.
578
+ * The returned promise resolves once the work is submitted (not completed);
579
+ * queue ordering makes the levels visible to any later submission.
410
580
  */
411
- declare function generateMipChain(level0: MipLevel): MipLevel[];
412
- /**
413
- * Pad a mip level up to a multiple of 4 in each dimension using clamp-
414
- * to-edge sampling. Used before handing sub-4×4 levels to a block-
415
- * compression encoder, which requires at least one full block per level.
416
- *
417
- * If the input is already block-aligned this returns the input unchanged.
418
- */
419
- declare function padToBlockMultiple(level: MipLevel): MipLevel;
581
+ declare function generateGpuMipChain(device: GPUDevice, source: ImageBitmap | ImageData | HTMLCanvasElement | OffscreenCanvas, { flipY }?: {
582
+ flipY?: boolean;
583
+ }): Promise<GPUTexture>;
420
584
 
421
585
  /**
422
586
  * Target raster size for an SVG source. A number scales the SVG so its
@@ -441,4 +605,141 @@ interface RasterizeSvgOptions {
441
605
  */
442
606
  declare function rasterizeSvg(source: string | Blob, options?: RasterizeSvgOptions): Promise<ImageBitmap>;
443
607
 
444
- export { ASTC4x4Encoder, ASTC4x4WebGLEncoder, BC1Encoder, BC1WebGLEncoder, BC5Encoder, BC5WebGLEncoder, BC7Encoder, BC7WebGLEncoder, type Capabilities, type EncodeBytesResult, type EncodeCallOptions, Encoder, type EncoderConstructor, type EncoderImageSource, type EncoderOptions, type ExtensionProvider, type FeatureProvider, type FormatSelection, type FormatVariant, type MipLevel, type PreferredFormat, type RasterizeSvgOptions, type RawPixelSource, type SelectFormatOptions, type SvgRasterSize, TextureFormat, type TextureHint, WebGLBlockEncoder, type WebGLCapabilities, type WebGLEncodeBytesResult, type WebGLEncoderConstructor, type WebGLEncoderImageSource, type WebGLEncoderOptions, type WebGLFormatSelection, WebGPUFeature, createWebGLContext, detectCapabilities, detectWebGLCapabilities, generateMipChain, getSharedWebGLContext, isWebGLAvailable, padToBlockMultiple, rasterizeSvg, selectFormat, selectWebGLFormat };
608
+ /**
609
+ * Everything `compressTexture()` can take as an image source. A superset
610
+ * of `EncoderImageSource` (see Encoder.ts) that also accepts URL strings
611
+ * and Blob / File objects — the common cases in a web app.
612
+ *
613
+ * SVG works through all of these: a URL to an `.svg` file, a string of
614
+ * inline SVG markup (detected by a leading `<`), an SVG Blob/File, or an
615
+ * HTMLImageElement whose src is SVG. Vector sources are rasterised to RGBA
616
+ * before encoding — see the `svgSize` option.
617
+ */
618
+ type CompressTextureSource = string | Blob | File | ImageBitmap | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageData;
619
+ interface CompressOptions {
620
+ /** How the texture will be used. Drives format selection. Default 'color'. */
621
+ hint?: TextureHint;
622
+ /**
623
+ * Prefer a specific format over the default choice when the device
624
+ * supports it; falls back to the normal selection (BC7 → ASTC → ETC2 →
625
+ * RGBA8) when it doesn't. Currently only 'bc1': half the memory of BC7
626
+ * for opaque colour textures, at lower quality. Only honoured with
627
+ * `hint: 'color'` — BC1 can't carry real alpha or normal maps.
628
+ */
629
+ preferredFormat?: PreferredFormat;
630
+ /**
631
+ * Memory/fidelity trade-off for opaque colour textures. Default 'high'
632
+ * (BC7 / ASTC 4×4, 1 byte/pixel). 'low' picks the 4-bpp formats when the
633
+ * device has one — BC1 on desktop-class GPUs, ETC2 RGB8 on mobile-class
634
+ * ones — halving GPU memory at visibly lower quality on smooth content.
635
+ * Ignored for `hint: 'colorWithAlpha'` and `hint: 'normal'` (the 4-bpp
636
+ * formats can't carry them). On the WebGL fallback tier only BC1 is
637
+ * available at 'low'.
638
+ */
639
+ quality?: FormatQuality;
640
+ /** Pick the sRGB or linear variant of the chosen format. Default 'srgb'. */
641
+ colorSpace?: 'srgb' | 'linear';
642
+ /**
643
+ * Rasterisation size for SVG sources. A number scales the SVG so its
644
+ * longest side matches (aspect ratio preserved); `{ width, height }`
645
+ * rasterises at exactly that size. Default: the SVG's intrinsic size
646
+ * (absolute width/height attributes, else the viewBox dimensions).
647
+ * Ignored for non-SVG sources.
648
+ */
649
+ svgSize?: SvgRasterSize;
650
+ /** Flip the image vertically before encoding. Default true (matches Three.js convention). */
651
+ flipY?: boolean;
652
+ /** Generate a full mip chain down to 1×1 on the CPU, encode every level. */
653
+ mipmaps?: boolean;
654
+ /** Reuse an existing device (e.g. Three.js's renderer device) instead
655
+ * of creating a new one. WebGPU path only. When provided, the encoder
656
+ * never destroys it. */
657
+ device?: GPUDevice;
658
+ adapter?: GPUAdapter;
659
+ /**
660
+ * Keep the compressed bytes in a session-scoped in-memory LRU and reuse
661
+ * them on repeat calls, skipping BOTH the image decode and the encode —
662
+ * the dominant costs. Re-loading a texture later in the session (e.g.
663
+ * two worlds sharing an atlas) becomes a few ms. Keyed by source
664
+ * identity + selected format + encode options; capped at 256 MiB of
665
+ * compressed bytes by default (`setTranscodeCacheLimit()` to tune) and
666
+ * never touches persistent storage. Default false.
667
+ *
668
+ * URL and Blob/File sources get an identity automatically (URL string or
669
+ * content hash). Pixel sources (ImageBitmap, canvas, ImageData) are only
670
+ * cached when `cacheKey` is provided.
671
+ */
672
+ cache?: boolean;
673
+ /**
674
+ * Explicit cache identity for the source, overriding the derived one.
675
+ * Use when you already know a stable name (e.g. an asset path) and want
676
+ * to skip content hashing, or to make pixel sources cacheable.
677
+ */
678
+ cacheKey?: string;
679
+ }
680
+ interface CompressResult {
681
+ /**
682
+ * Encoded compressed mip levels (`levels[0]` is the base level), ready to
683
+ * upload to a compressed texture. Null on the RGBA8 fallback path — use
684
+ * `fallbackBitmap` instead.
685
+ */
686
+ levels: EncodedLevelBytes[] | null;
687
+ /**
688
+ * Decoded RGBA8 bitmap, set only when `fallbackUncompressed` (no compressed
689
+ * format was available on either backend). Upload it as a plain RGBA8
690
+ * texture; the caller applies colour space / flipY at the texture level.
691
+ */
692
+ fallbackBitmap: ImageBitmap | null;
693
+ /** The compressed format selected, or null when we fell back to RGBA8. */
694
+ format: TextureFormat | null;
695
+ /** True iff we fell back to an uncompressed RGBA8 bitmap because no encoder fit. */
696
+ fallbackUncompressed: boolean;
697
+ /**
698
+ * Which backend produced the result. 'webgpu' = compute path, 'webgl' =
699
+ * fragment-shader fallback, 'none' = uncompressed RGBA8.
700
+ */
701
+ backend: 'webgpu' | 'webgl' | 'none';
702
+ /**
703
+ * True iff the chosen format is ASTC and the hint was 'normal'. The
704
+ * caller must apply the (R, W) → (x, y) swizzle in the material — ASTC
705
+ * has no 2-channel mode, so normal maps ride the RGBA path.
706
+ */
707
+ astcNormalRemap: boolean;
708
+ width: number;
709
+ height: number;
710
+ mipLevels: number;
711
+ /** Wall-clock time of GPU encoding, summed across mip levels. */
712
+ encodeMs: number;
713
+ /**
714
+ * Wall-clock time to turn the source into decoded RGBA pixels: fetch /
715
+ * base64 decode, image decode, SVG rasterisation. Usually the dominant
716
+ * cost for large images — when a load feels slower than `encodeMs`
717
+ * suggests, this is where the time went.
718
+ */
719
+ decodeMs: number;
720
+ /** Wall-clock time of the whole `compressTexture()` call: decode + CPU
721
+ * mip generation + encode + texture assembly. */
722
+ totalMs: number;
723
+ /** True when the result came from the in-memory transcode cache (the
724
+ * `cache` option) — no decode or encode ran; decodeMs/encodeMs are 0. */
725
+ cacheHit: boolean;
726
+ }
727
+ /**
728
+ * Destroy the WebGPU device and encoders that `compressTexture()` shares
729
+ * across calls (created lazily when neither the `device` nor the `adapter`
730
+ * option is passed). Safe to call at any time — in-flight encodes on the
731
+ * shared device will fail, and the next `compressTexture()` call recreates
732
+ * everything. No-op when nothing is cached.
733
+ */
734
+ declare function releaseSharedGpuResources(): void;
735
+ declare function compressTextureToBytes(source: CompressTextureSource, options?: CompressOptions): Promise<CompressResult>;
736
+
737
+ /**
738
+ * Cap the cache's total compressed payload in bytes (default 256 MiB).
739
+ * Lower it to evict immediately; 0 disables caching entirely.
740
+ */
741
+ declare function setTranscodeCacheLimit(bytes: number): void;
742
+ /** Drop every cached transcode. Textures already built from entries are unaffected. */
743
+ declare function clearTranscodeCache(): void;
744
+
745
+ export { ASTC4x4Encoder, ASTC4x4WebGLEncoder, BC1Encoder, BC1WebGLEncoder, BC5Encoder, BC5WebGLEncoder, BC7Encoder, type BC7EncoderOptions, BC7WebGLEncoder, type Capabilities, type CompressOptions, type CompressResult, type CompressTextureSource, ETC2Encoder, type EncodeBytesResult, type EncodeCallOptions, type EncodeMipChainResult, type EncodedLevelBytes, Encoder, type EncoderConstructor, type EncoderImageSource, type EncoderOptions, type ExtensionProvider, type FeatureProvider, type FormatQuality, type FormatSelection, type FormatVariant, type MipLevel, type PreferredFormat, type RasterizeSvgOptions, type RawPixelSource, type SelectFormatOptions, type SvgRasterSize, TextureFormat, type TextureHint, WebGLBlockEncoder, type WebGLCapabilities, type WebGLEncodeBytesResult, type WebGLEncoderConstructor, type WebGLEncoderImageSource, type WebGLEncoderOptions, type WebGLFormatSelection, WebGPUFeature, clearTranscodeCache, compressTextureToBytes, createWebGLContext, detectCapabilities, detectWebGLCapabilities, generateGpuMipChain, generateMipChain, getSharedWebGLContext, gpuMipLevelCount, isWebGLAvailable, padToBlockMultiple, rasterizeSvg, releaseSharedGpuResources, selectFormat, selectWebGLFormat, setTranscodeCacheLimit };