Skip to content

GPU tier: texture formats and anisotropic filtering (#2397) - #2403

Merged
paul-hammant merged 2 commits into
mainfrom
feat/2397-texture-formats
Oct 4, 2026
Merged

paul-hammant merged 2 commits into
mainfrom
feat/2397-texture-formats

Conversation

@nicolas-maman

Copy link
Copy Markdown
Collaborator

Closes #2397.

Masks, normal maps, HDR images and compressed assets can now be sampled through the shared GPU shape, in contrib.vulkan, contrib.d3d12 and contrib.metal.

  • Formats: texture_create_format(dev, w, h, format, mipmapped, linear, repeat, anisotropy) makes a 2D texture in R8, RG8, RGBA8 UNORM or sRGB, RGBA16F, RGBA32F, or BC1/BC3/BC4/BC5/BC7 (BC1, BC3 and BC7 also sRGB). texture_format_supported asks first. A block-compressed texture must be whole 4x4 blocks in every module, because Direct3D 12 requires it.
  • Mip chains: a mipmapped uncompressed texture builds its chain on upload, in its own format.
    • Vulkan blits it, and refuses a format it cannot linear-blit.
    • D3D12 builds it on the CPU: bytes as bytes, half and float as floats, sRGB as linear light.
    • Metal uses generateMipmapsForTexture:, and refuses a 32-bit float chain where the GPU cannot filter one.
  • Level uploads: texture_upload_level uploads a block format's chain, or one made offline, one level at a time. Only that level's layout or state changes. The texture binds once every level has pixels, and the refusal says which case it is.
  • Anisotropy: the last argument filters anisotropically, up to the device's limit; texture_anisotropy reports what was granted.

Tests: each module's textures spec checks the following against pixels read back from an RGBA32F target:

  • every uncompressed format, against known values, including sRGB 188 reading as linear 0.503 and half/float values outside 0..1;
  • each format's chain at its 1x1 level: a 4x4 ring reads 0.75, where byte-averaged sRGB would read 0.52;
  • known BC1, BC4 and BC7 blocks, decoded;
  • a BC1 chain uploaded level by level, refused to bind until it is complete;
  • 16:1 squeezed one-texel stripes, which blur to grey with the isotropic filter and stay sharp with the anisotropic one.

Run locally:

  • Vulkan: NVIDIA under the validation layer with sync and best practices on, and lavapipe. Only the known small-dedicated-allocation advisories remain.
  • D3D12: the GPU and WARP with the debug layer, 0 messages.
  • Metal: cross-compiled for arm64 macOS; it first runs on macOS CI.

Follow-up filed: BC6H, ASTC/ETC2, signed formats, and cubes and arrays in other formats (#2402).

texture_create_format makes a 2D texture in R8, RG8, RGBA8 UNORM or sRGB,
RGBA16F, RGBA32F, or the BC1, BC3, BC4, BC5 and BC7 block formats, in
contrib.vulkan, contrib.d3d12 and contrib.metal; texture_format_supported
asks first. A mipmapped uncompressed texture builds its chain in its own
format (D3D12 on the CPU, sRGB averaged as light); texture_upload_level
uploads a block format's chain level by level, and the texture binds once
every level has pixels. Anisotropy is granted up to the device's limit and
reported by texture_anisotropy.

Each module's textures spec samples every uncompressed format, checks each
chain's last level, decodes known BC1, BC4 and BC7 blocks, uploads a BC1
chain by level, and shows squeezed stripes staying sharp only when filtered
anisotropically.
Newer lavapipe keeps about a fifth of the stripes' contrast through its
anisotropic approximation, which the API leaves to the implementation. The
spec now asks for an isotropic sampler to blur the stripes to grey and an
anisotropic one to keep clearly more, and prints both.
@paul-hammant
paul-hammant merged commit e1556a7 into main Oct 4, 2026
48 of 49 checks passed
@paul-hammant
paul-hammant deleted the feat/2397-texture-formats branch October 4, 2026 07:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GPU tier: sampled texture formats (sRGB, R8, RG8, half and float, BC1/BC3/BC4/BC5/BC7) and anisotropic filtering

2 participants