third_party/tinyexr/tools/texpipe/README.md
texpipe ties together the two standalone libraries in this repo — tir
(content-aware image resize) and texcomp (BC/ETC/ASTC block compression) —
to build content-aware mip chains and serialize them into multi-mip GPU texture
containers (DDS, KTX2). It is pure C11; only texpipe_cli.c does file I/O.
tir can resize with content awareness (premultiplied alpha, normal/height
modes) but has no mip-chain generator. texcomp has every block encoder but only
writes single-surface, single-mip files. Neither knows about the other. texpipe
is the missing layer: resize → per-mip content passes → compress → container.
Implemented:
--mip-source previous for the classic
half-step chain).tir premultiplied alpha feeding
BC7/BC3/ASTC alpha-capable encoders (capability #4).--content alpha, capability #2).DDSCAPS2_CUBEMAP / faceCount = 6). See the caveat below.--content normal filters
and renormalizes normals per mip (stays unit-length across LODs, verified to
~1e-7), --content height is mean-preserving. --bake-roughness captures the
pre-renormalize |N| and maps it to a Toksvig roughness (Toksvig 2005),
written as a companion EAC_R11 KTX2 mip chain so specular highlights don't
alias into shimmer at distance.--octa): fold-seam-aware mips for a 2D octahedral
map (the square's outer border folds onto itself), so an HDR octahedral
environment stays coherent across LODs under BC6H/ASTC-HDR. Pairs with the
envmap tool's convert --to octa.--srgb-resize): decode sRGB→linear, filter,
re-encode, so albedo mips preserve linear-light energy (a black/white checker
averages to linear 0.5, not the darkened 0.21 of naive sRGB-space filtering).--channel-ops l,l,m,l): per-channel downsample
rules so a single ORM/mask texture minifies correctly — m (majority)
thresholds a binary metallic/mask channel (stays crisp), r (roughness)
replaces the channel with its RMS sqrt(E[c²]) so minified roughness rises to
reduce specular aliasing, and l (default) stays linear.tp_write_ktx2_array): pack N compressed chains into one
KTX2 with layerCount = N.--minmax, tp_build_minmax_pyramid): a 2-channel
(min,max) conservative height pyramid for parallax-occlusion / relief /
cone-step mapping, stored as BC5. Bounds nest across levels and the coarsest
level bounds the whole field.--dilate N, tp_dilate): flood valid texels into the
alpha<0.5 gutter so mips/bilinear don't bleed background across atlas or
lightmap chart borders (alpha preserved).tp_build_cone_map): per-texel conservative cone
ratio for cone-step/relief mapping (O(n⁴) — modest resolutions only).tp_build_ripmap): anisotropic grid of resizes (w>>ix, h>>jy) for
grazing-angle sampling without runtime anisotropy.--filter kaiser): Kaiser-windowed sinc (radius 3, β=8) —
sharp with lower ringing than Lanczos3 (added to tir).--ycocg, tp_rgb_to_ycocg): store colour as YCoCg
before compression (shader inverts). Helps low-bit-depth codecs (BC1); roughly
neutral for BC7, which already rotates colour internally.--bc7-weights R,G,B,A, tc_bc7_options.channel_weights):
per-channel weights in the BC7 encode error metric — byte-identical to
unweighted when uniform, so no regression. (ASTC error-weighting is available
via the astcenc backend: texcomp --encoder arm --channel-weights R,G,B,A.)The edge/corner fixup makes adjacent-face borders bit-identical before
compression (the unit test measures max border deviation ≈ 0.006 on a
direction field, and the fixup is idempotent). Block codecs (BC/ETC/ASTC)
compress each face independently, so a residual seam of up to one quantization
step can reappear after encoding even with identical float borders. Nothing in
a standard independent-block codec removes this fully; rely on hardware seamless
cube filtering at runtime, or prefer higher-bit-depth codecs (BC7/ASTC) on cube
borders. --no-seam-fixup disables the pass.
make texpipe # build/libtexpipe.a + build/texpipe/texpipe CLI
make texpipe-c11-gate # strict pure-C11 gate (no <stdio.h> outside the CLI)
make texpipe-test # unit tests (per-mip PSNR, alpha coverage, containers)
texpipe -i in.{exr,png} -o out.{ktx2,dds} --format bc7 [opts]
Key options: --format, --content color|alpha|normal|height,
--container dds|ktx2, --filter, --edge clamp|wrap|reflect, --levels N,
--mip-source base|previous, --srgb, --alpha, --alpha-threshold,
--astc-block WxH, --threads, --part (see texpipe --help).
HDR codecs (bc6h, astc_hdr) require an EXR input; LDR codecs take EXR or PNG.
Cubemaps — give all six faces (order +x -x +y -y +z -z) or split one packed
image:
# 6 separate square faces
texpipe --cube-face +x px.png --cube-face -x nx.png ... -o cube.ktx2 --format bc7
# one cross/strip image
texpipe -i strip.png --cube-layout strip_h -o cube.ktx2 --format astc --astc-block 6x6
Normal maps with a baked Toksvig roughness companion:
texpipe -i normal.png -o normal.ktx2 --format bc5 --content normal \
--normal-enc unorm --bake-roughness --base-roughness 0.15
# also writes normal.ktx2.rough.ktx2 (EAC_R11 roughness mip chain)
texpipe -i height.png -o height.ktx2 --format bc7 --content height # mean-preserving
The staged C API (see include/texpipe.h) is:
tp_build_mips() base image -> content-aware float mip chain
tp_compress_chain() float chain -> compressed block payloads
tp_write_container() blocks -> DDS / KTX2 bytes
tp_process() one-shot of the three above
plus leaf helpers: tp_alpha_coverage() / tp_alpha_scale_to_coverage()
(coverage), tp_cube_seam_fixup() / tp_cube_split() (cubemap),
tp_toksvig_roughness() / tp_build_roughness_chain() (normal roughness).
Apache-2.0 (matches texcomp). Depends on tir (BSD-3-Clause) and texcomp
(Apache-2.0); both permissive and compatible for combined works.
texpipe's library (libtexpipe) is original work with no third-party runtime
dependencies. The pieces below are either bundled code used by the CLI only, or
published techniques whose provenance is credited here and in the file headers.
examples/common/stb_image.h and compiled into texpipe_cli.c (LDR PNG
loading). Not used by the library.src/texpipe_cube.c follows the edge/corner averaging technique popularized by
AMD CubeMapGen (technique, independently implemented from the standard cube
face convention; no code copied).src/texpipe_normal.c implements Toksvig, "Mipmapping Normal Maps", Journal
of Graphics Tools, 2005.src/texpipe_octa.c uses the
standard octahedral unit-vector parameterization (see the envmap notices for
the survey reference).tir (BSD-3-Clause), texcomp (Apache-2.0, see its
NOTICE.md for BC/ETC/ASTC third-party credits), TinyEXR core (BSD-3-Clause).