gputex 0.3.2 → 0.3.4
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/README.md +48 -41
- package/dist/index.d.ts +12 -1
- package/dist/index.js +521 -203
- package/dist/three.js +526 -208
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ alpha or a normal map.
|
|
|
46
46
|
|
|
47
47
|
## WebGL fallback
|
|
48
48
|
|
|
49
|
-
WebGPU is the primary path. When it's unavailable (older Safari, Firefox without WebGPU, locked-down environments) `compressTexture()` automatically falls back to a **WebGL2** path that runs the same family of block encoders as fragment shaders — each 4×4 block is computed in one fragment, written to an `RGBA32UI` render target, and read back. The
|
|
49
|
+
WebGPU is the primary path. When it's unavailable (older Safari, Firefox without WebGPU, locked-down environments) `compressTexture()` automatically falls back to a **WebGL2** path that runs the same family of block encoders as fragment shaders — each 4×4 block is computed in one fragment, written to an `RGBA32UI` render target, and read back. The two backends are not byte-identical (the WebGPU fast paths use projection assignment and f16 where available), but they implement the same algorithms at the same quality level and the resulting `CompressedTexture` looks the same under either renderer.
|
|
50
50
|
|
|
51
51
|
The fallback chain is **WebGPU → WebGL2 → uncompressed RGBA8**. The `backend` field on the result (`'webgpu' | 'webgl' | 'none'`) tells you which path ran.
|
|
52
52
|
|
|
@@ -77,17 +77,24 @@ material.map = texture
|
|
|
77
77
|
|
|
78
78
|
`quality` trades encode speed against compression accuracy:
|
|
79
79
|
|
|
80
|
-
- **`'fast'` (default)** — a
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
- **`'fast'` (default)** — a principal-axis endpoint seed (per-block
|
|
81
|
+
covariance power-iteration — unlike a bbox diagonal it follows
|
|
82
|
+
anti-correlated channels, worth **+2–4 dB on normal-map-like content**)
|
|
83
|
+
plus projection-based index assignment (each pixel is projected onto the
|
|
84
|
+
colinear endpoint line in O(1) instead of searching every palette entry),
|
|
85
|
+
and the block bits packed with straight-line constant shifts. The formats
|
|
86
|
+
with coarse 4-level palettes (BC1, ASTC) and BC5 add a least-squares
|
|
87
|
+
endpoint refit accepted per block only when it lowers the error; BC7's
|
|
88
|
+
16-level mode-6 palette makes the refit redundant on a principal-axis seed
|
|
89
|
+
(≤0.05 dB), so its fast path skips it and stays the cheapest per pixel. On
|
|
90
|
+
GPUs that report the `shader-f16` feature the whole fast path (all four
|
|
91
|
+
formats, BC1 included) runs in f16 — the f32 path is the automatic
|
|
92
|
+
fallback. Net vs `'high'` on an Apple GPU: roughly **10–30× faster**
|
|
93
|
+
depending on format, for a PSNR cost of **≤0.35 dB on the test cards**
|
|
94
|
+
(BC7 within 0.1 dB of `'high'`; ASTC fast actually measures slightly above
|
|
95
|
+
it) and up to a few dB on adversarial high-frequency noise, where any
|
|
96
|
+
single-line seed trails `'high'`'s exhaustive search. See the benchmark
|
|
97
|
+
table below.
|
|
91
98
|
- **`'high'`** — exhaustive endpoint search (farthest-pair seed, full nearest
|
|
92
99
|
search, p-bit search); matches the CPU reference encoders block-for-block
|
|
93
100
|
(byte-identical on >96% of blocks; the rest are equal-error FP tie-breaks,
|
|
@@ -252,35 +259,30 @@ const tex = buildCompressedTexture([bytes], TextureFormat.BC7_SRGB)
|
|
|
252
259
|
Measured with the repo's GPU test suite (see below) on an Apple Silicon GPU
|
|
253
260
|
(`metal-3`) in Chrome, encoding a 2048×2048 image. **GPU pass** is the compute
|
|
254
261
|
shader alone (WebGPU timestamp queries, median of 20 runs); end-to-end wall
|
|
255
|
-
time adds ~
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
|
262
|
-
|
|
|
263
|
-
| BC1 | fast
|
|
264
|
-
|
|
|
265
|
-
| BC5 | fast
|
|
266
|
-
|
|
|
267
|
-
| BC7 | fast
|
|
268
|
-
|
|
|
269
|
-
| ASTC 4×4 | fast
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
|
|
|
273
|
-
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
Per-quadrant PSNR on the committed 512² test card is equal to or better than
|
|
280
|
-
the previous fast encoders everywhere (flat tiles bit-identical, gradients
|
|
281
|
-
+0.01 dB, noise −0.01 dB); the `high` paths still match the CPU reference
|
|
282
|
-
encoders. Timestamps are quantised to 100 µs by Chrome, so sub-millisecond
|
|
283
|
-
figures are ±0.05–0.1 ms.
|
|
262
|
+
time adds ~2–4 ms of image upload + result readback regardless of format.
|
|
263
|
+
Each encoder caches its GPU resources (source texture, output/staging
|
|
264
|
+
buffers, bind group) across encodes, so repeated encodes — including mip
|
|
265
|
+
chains — skip per-call allocation: in an interleaved A/B this cuts BC7
|
|
266
|
+
end-to-end wall time by ~10% at 512², ~20% at 1024–2048² and ~35% at 4096².
|
|
267
|
+
|
|
268
|
+
| Format | Quality | Shader | GPU pass |
|
|
269
|
+
| -------- | -------------- | ------ | ----------- |
|
|
270
|
+
| BC1 | fast (default) | f16 | **0.26 ms** |
|
|
271
|
+
| BC1 | fast | f32 | 0.46 ms |
|
|
272
|
+
| BC5 | fast (default) | f16 | **0.26 ms** |
|
|
273
|
+
| BC5 | fast | f32 | 0.26 ms |
|
|
274
|
+
| BC7 | fast (default) | f16 | **0.26 ms** |
|
|
275
|
+
| BC7 | fast | f32 | 0.59 ms |
|
|
276
|
+
| ASTC 4×4 | fast (default) | f16 | **0.26 ms** |
|
|
277
|
+
| ASTC 4×4 | fast | f32 | 0.56 ms |
|
|
278
|
+
| BC1 | high | f32 | 2.7 ms |
|
|
279
|
+
| BC5 | high | f32 | 1.0 ms |
|
|
280
|
+
| BC7 | high | f32 | 10.4 ms |
|
|
281
|
+
| ASTC 4×4 | high | f32 | 1.6 ms |
|
|
282
|
+
|
|
283
|
+
Timestamps are quantised to 100 µs by Chrome and Apple GPU clock states swing
|
|
284
|
+
timings by ~2×, so sub-millisecond figures are indicative (±0.1 ms); compare
|
|
285
|
+
variants only within a single session.
|
|
284
286
|
|
|
285
287
|
## Testing
|
|
286
288
|
|
|
@@ -294,6 +296,11 @@ bun run --filter gputex build # build the library the example consumes
|
|
|
294
296
|
cd example && bunx next dev # then open http://localhost:3000/test
|
|
295
297
|
```
|
|
296
298
|
|
|
299
|
+
A second page, `/bench`, measures median end-to-end `encodeToBytes()` wall
|
|
300
|
+
time per format across image sizes (256²–4096²) at fast quality — the
|
|
301
|
+
numbers that matter for runtime streaming, where host overhead dominates
|
|
302
|
+
small textures (results on `window.__GPUTEX_BENCH__`).
|
|
303
|
+
|
|
297
304
|
The page runs three groups against the live WebGPU device and renders
|
|
298
305
|
PASS/FAIL tables (machine-readable copy on `window.__GPUTEX_TESTS__`):
|
|
299
306
|
|
package/dist/index.d.ts
CHANGED
|
@@ -126,13 +126,24 @@ declare abstract class Encoder {
|
|
|
126
126
|
readonly adapter?: GPUAdapter;
|
|
127
127
|
readonly ownsDevice: boolean;
|
|
128
128
|
readonly disableF16: boolean;
|
|
129
|
-
protected _module: GPUShaderModule;
|
|
129
|
+
protected _module: GPUShaderModule | null;
|
|
130
130
|
protected _moduleF16: GPUShaderModule | null;
|
|
131
131
|
protected _pipelineF16: GPUComputePipeline | null;
|
|
132
132
|
protected _pipeline: GPUComputePipeline;
|
|
133
133
|
protected _pipelineCache: Map<EncodeQuality, GPUComputePipeline>;
|
|
134
|
+
private _cachedSrcTex;
|
|
135
|
+
private _cachedSrcW;
|
|
136
|
+
private _cachedSrcH;
|
|
137
|
+
private _cachedDst;
|
|
138
|
+
private _cachedStaging;
|
|
139
|
+
private _cachedParams;
|
|
140
|
+
private _lastParams;
|
|
141
|
+
private _bindGroupCache;
|
|
142
|
+
private _resourcesBusy;
|
|
134
143
|
constructor({ device, adapter, ownsDevice, disableF16 }: EncoderOptions);
|
|
135
144
|
protected _buildPipeline(): void;
|
|
145
|
+
/** The f32 module, parsed on first use (see `_module`). */
|
|
146
|
+
protected _ensureModule(): GPUShaderModule;
|
|
136
147
|
/**
|
|
137
148
|
* Pipeline for a given quality level. Encoders that don't declare a
|
|
138
149
|
* `QUALITY_HIGH` override (`supportsQuality === false`, e.g. BC1) ignore the
|