Compressed Textures (BC / ASTC / ETC2)¶
SimVX loads GPU block-compressed textures from .ktx2 (KTX 2.0) and .dds
containers, transcoding the universal UASTC interchange format to whatever block
family the current GPU prefers. Block-compressed textures use a fraction of the
VRAM of RGBA8 and stay compressed on the GPU, so they are the right choice for
shipped game assets.
A runnable example is at
examples/features/3d/compressed_texture.py (uv run python examples/features/3d/compressed_texture.py).
Loading¶
There is no special API. .ktx2 / .dds are accepted transparently anywhere a
texture source is accepted; the texture manager dispatches on the file suffix
(or the magic bytes for in-memory sources):
mat = Material(albedo_map="hero.ktx2") # UASTC or explicit-BC KTX2
spr = Sprite2D(texture="tiles.dds") # explicit-BC DDS
Fallback chain¶
Loading never crashes; it degrades step by step:
Native transcode. A UASTC
.ktx2is transcoded to the device’s chosen block target via the nativebasis_universaltranscoder. The target is picked by a device probe in this order, each gated by BOTH the coarse compression-family feature AND a per-format SAMPLED check: BC7 -> ASTC-4x4 -> ETC2. Explicit-BC files skip the probe (they carry their own VkFormat).CPU decode. If the GPU exposes no usable block family (or the native transcoder is not built), mip 0 is decoded to RGBA8 on the CPU via the optional
texture2ddecoderpackage and uploaded asR8G8B8A8_UNORM.Skip. If even the CPU decoder/dependency is absent, a one-time WARNING is logged and the texture resolves to the
-1“couldn’t resolve” sentinel.
Mip sampling¶
When a .ktx2 / .dds carries a mip chain, the whole chain is uploaded and the
bound sampler’s maxLod is set to mip_count - 1, so minified surfaces sample
the smaller levels (no aliasing). Single-mip textures keep maxLod = 0
unchanged. Generate the chain at authoring time with --genmipmap.
Optional dependency + build¶
The native transcoder is an opt-in C++ extension built once after install:
simvx build-textures # requires a C++ compiler (g++ / clang / MSVC)
texture2ddecoder is the pip-installable CPU-decode fallback (uv pip install texture2ddecoder). Both are optional: with neither present, compressed textures
degrade gracefully (see the fallback chain). See Installation for the
dependency matrix.
Re-enabling the ASTC and ETC2 transcode targets grows the built .so and adds
the ASTC table-generation cost at compile time (acceptable for the full
platform matrix). Changing the transcoder’s define-set requires a forced
rebuild: delete the cached _simvx_basis_transcoder*.so (or re-run
simvx build-textures), because uv reuses the cached/installed binary
otherwise.
Per-platform target matrix¶
Platform |
Block family |
Notes |
|---|---|---|
Desktop (PC) |
BC7 |
Near-universal; the desktop probe picks it first. |
Mobile / tablet |
ASTC-4x4 |
Modern GPUs (Adreno, Mali, Apple). |
Older mobile / WebGL-class |
ETC2 |
Widely supported baseline. |
Web runtime |
UASTC (in-browser) |
The web export ships raw UASTC and the browser/WebGPU transcodes per-device via the |
The desktop probe order is BC7 -> ASTC-4x4 -> ETC2 -> CPU-decode. ASTC sizes other than 4x4 are out of scope (their larger texel footprint would break the 4-texel block-row math).