Any3DAny3D
·Any3D Team

Le texture, l'ingordo che divora la tua VRAM

3d-compressiontexture-compressionwebglwebgpu

La volta scorsa abbiamo dimezzato i vertici e il modello è un po' ristretto, ma non è diventato un fulmine — perché il vero mangiatore di dimensioni era ancora lì: le texture. In un modello PBR, le texture di solito occupano oltre l'80% della dimensione, ed è la parte che si gonfia di più nella VRAM.

Questo articolo è la cura per il problema dell'«ingordo di VRAM» delle texture. Tre cose: perché PNG/JPG sono colpevoli agli occhi della GPU; come sono fatti i formati di texture nativi della GPU e perché non si possono usare direttamente; e come Basis Universal + KTX2 collegano i tre.

Ripasso: perché il JPG fa esplodere la VRAM

Nell'articolo precedente abbiamo dato una formula:

Uso VRAM = larghezza * altezza * 4 byte (RGBA) * 1.333 (con mipmap)

Una texture 4096×4096, sia che sia un JPG da 1,5 MB o un PNG da 8 MB su disco, diventa ~87 MB nella VRAM. Un solo motivo: la GPU non capisce JPG/PNG.

L'unità di campionamento texture della GPU capisce una cosa sola: date delle coordinate UV, leggere un colore da un blocco di pixel di dimensione fissa. Richiede che la texture sia nella VRAM come «pixel grezzi stesi». Quindi prima di caricare un JPG sulla GPU, il browser deve prima decomprimerlo completamente in pixel RGBA sulla CPU, poi spingere l'intero blocco nella VRAM.

Questo processo ha tre problemi:

  1. Esplosione della VRAM: i pixel grezzi decompressi sono enormi. 87 MB non è un'esagerazione, è ciò che calcola la formula.
  2. Blocco dell'upload: spostare un grande blocco di pixel dalla memoria della CPU alla VRAM della GPU è un'operazione lenta che blocca il primo frame.
  3. Costo di decodifica della CPU: decodificare un'immagine grande costa tempo di per sé, soprattutto su mobile.

Estendendo la metafora della «spugna compressa» della volta scorsa: PNG/JPG è una spugna premuta piatta per un trasporto facile; una volta sulla GPU, la spugna assorbe acqua e torna alla dimensione piena. Il download è diventato più veloce; la VRAM non ha risparmiato nulla.

I formati di texture della GPU: compressi nella VRAM per natura

Visto che la GPU non accetta un PNG precompresso, possiamo mantenere la texture compressa anche dentro la VRAM? La GPU decodifica un singolo blocco di pixel al volo durante il campionamento, quasi senza costo.

È proprio ciò che fanno i formati di texture nativi GPU. Famiglie rappresentative:

Famiglia di formatoNome completoPiattaforme principaliNote
BC1-7Block CompressionDesktop (PC, Mac)Veterano, compressione a blocchi 4×4 per generazione
ETC1/2Ericsson Texture CompressionMobile (Android/iOS più vecchi)Vecchio standard mobile
ASTCAdaptive Scalable Texture CompressionMobile/VR (dispositivi nuovi)Flessibile, qualità migliore, regolabile per blocco
PVRTCPowerVRiOS più vecchiIn fase di sostituzione con ASTC

Questi formati condividono un tratto: le texture sono memorizzate compresse in piccoli blocchi di 4×4 pixel (block), e la GPU decodifica un piccolo blocco a richiesta durante il campionamento — ciò che esce non è un singolo pixel ma un intero blocco. Il vantaggio è che l'uso della VRAM si riduce di un rapporto fisso indipendentemente dal contenuto.

Confronto:

PNG/JPG (tradizionale)Formati nativi GPU
Dimensione su discoPiccola (JPG soprattutto)Media (compressione a blocchi, bitrate fisso)
Uso VRAMGrande (decompresso a pixel grezzi)Piccolo (compressione a blocchi, residente)
Upload alla GPULento (decodifica CPU + grosso trasferimento)Veloce (sposta e basta, nessuna decodifica)
Velocità di campionamentoVeloce (già pixel grezzi)Veloce (decodifica hardware in tempo reale)

I formati GPU sembrano la soluzione perfetta. Allora perché non usarli direttamente?

Il problema: dispositivi diversi riconoscono formati diversi

Questa è la più grande trappola dei formati di texture GPU — frammentazione.

  • I PC desktop riconoscono BC1-7, non ASTC
  • I telefoni Android riconoscono ETC2/ASTC, per lo più non BC
  • iOS (A7+) riconosce ASTC, i più vecchi PVRTC
  • WebGPU/WebGL si appoggiano sulle stesse capacità hardware dietro al dispositivo

Se vuoi che una texture «esista come formato nativo GPU su tutti i dispositivi», devi preparare una copia separata per ogni piattaforma. Un prodotto per desktop + Android + iOS ha bisogno di BC + ETC2/ASTC per la stessa texture — tre versioni. Il pacchetto triplica, lo sforzo anche.

Peggio: sul web non sai quale dispositivo apre la pagina l'utente. Pre-generare tutti i formati non è realistico, e il rilevamento a runtime arriva tardi.

Basis Universal: codifica una volta, transcodifica ovunque

Basis Universal (Basis in breve) è nato per risolvere questa frammentazione. La sua idea in una frase:

Prima codifica la texture in un «formato intermedio», poi a runtime transcodificala nel formato nativo corrispondente in base alle capacità GPU del dispositivo attuale.

Flusso di transcodifica (schemativo):

Texture sorgente (PNG/JPG)
      │  codifica offline una tantum (lenta, una volta)
      ▼
Formato intermedio Basis (ETC1S o UASTC)
      │  impacchettato in un contenitore KTX2
      ▼
Pubblica sul web ──┬── GPU desktop ──→ transcodifica runtime → BC1/3/7
                   ├── Android ────→ transcodifica runtime → ETC2
                   └── iOS/VR ─────→ transcodifica runtime → ASTC

Punti chiave:

  • La codifica offline avviene una volta e produce una rappresentazione intermedia compatta
  • La transcodifica a runtime è molto veloce (calcolo puro, pochi millisecondi), e transcodifica formati a blocchi — non serve decompressione per pixel
  • Ciò che entra nella VRAM dopo la transcodifica è un vero formato nativo GPU, quindi l'uso della VRAM si calcola con i tassi di compressione a blocchi, identico ai formati nativi GPU

Basis offre due modalità di codifica intermedia; il prossimo articolo le sviluppa, ma ricordate i nomi:

  • ETC1S: rapporto di compressione estremamente alto, adatto a diffuse/albedo e altre color map
  • UASTC: qualità superiore, adatto a normali e altre mappe sensibili alla precisione

KTX2: il contenitore standard per le texture GPU

Rimane una questione ingegneristica: dove mettere i dati Basis codificati, come marcarli e come relazionarli a glTF? La risposta è KTX2.

KTX2 (Khronos Texture 2) non è un altro formato di immagine — è un formato contenitore. Come uno .zip non si cura se contiene documenti o immagini, KTX2 si limita a impacchettare i dati di texture GPU (inclusi quelli codificati Basis) in una struttura standard con metadati (formato, livelli mipmap, spazio colore, ecc.).

In glTF, KTX2 si collega tramite l'estensione KHR_texture_basisu: la texture non è più un file PNG ma un file KTX2 che contiene la codifica Basis. Al caricamento, il motore rileva le capacità del dispositivo e transcodifica nel BC/ETC/ASTC corrispondente.

Districchiamo i tre ruoli — non confondeteli:

NomeRuoloAnalogia
Basis UniversalSchema di codifica (come comprimere una texture nel formato intermedio)Una sorta di «algoritmo di compressione»
KTX2Formato contenitore (come impacchettare i dati codificati)Una «scatola»
KHR_texture_basisuEstensione glTF (dice al motore che è una texture Basis)Un'«etichetta»

Un file KTX2 può contenere codifica Basis (multipiattaforma) o un formato nativo (es. BC7 grezzo). Sul web, al 99% contiene Basis, perché ciò che vogliamo è «codifica una volta, transcodifica ovunque».

Esempio VRAM: una texture 4096 confrontata

Sovrapponendo formula e formati GPU, ecco l'impronta reale di una texture 4096×4096 RGBA sotto diverse opzioni:

OpzioneDim. su discoUso VRAM (con mipmap)Velocità uploadMultipiattaforma
PNG~8 MB~87 MBLenta (serve decodifica)
JPG~1.5 MB~87 MBLenta (serve decodifica)
WebP~2 MB~87 MBLenta (serve decodifica)
KTX2 (ETC1S)~2-3 MB~11-14 MBVeloce✅ (transcode)
KTX2 (UASTC)~6-8 MB~22 MBVeloce✅ (transcode)

Da dove vengono i numeri VRAM: la compressione a blocchi della GPU di solito si conta a 4bpp (4 bit per pixel) o 8bpp. 4096×4096 a 4bpp è circa 8 MB, ×1.333 con mipmap ≈ 11 MB. UASTC è per lo parte transcodificato a 8bpp, quindi circa 22 MB.

L'importante non è il numero esatto di una riga, ma questi due punti:

  1. I formati tradizionali (PNG/JPG/WebP) hanno un uso VRAM quasi identico — tutti pixel grezzi decompressi, 87 MB. Per quanto piccoli su disco, la VRAM non si risparmia.
  2. KTX2 abbassa la VRAM a 1/4 o 1/8, e la dimensione su disco è altrettanto competitiva.

Ecco perché VR e web mobile vanno quasi sempre con KTX2 — quante texture da 87 MB stanno nella VRAM da 2 GB di un telefono? A 11 MB ne stanno sette.

Matrice di supporto delle piattaforme: quali GPU riconoscono quali formati

Basis ci scherma dai dettagli, ma capire il mapping sottostante aiuta nella risoluzione dei problemi. Ecco il supporto attuale dei dispositivi principali per i formati nativi:

Piattaforma / dispositivoBC1-7ETC2ASTCPVRTC
PC desktop (D3D11/12, Vulkan, WebGPU)Parziale (GPU nuove)
macOS (Metal)✅ (macchine nuove)
Android (mainstream)
iOS (A8+)✅ (dispositivi più vecchi)
WebGL 2In base all'estensioneParziale
WebGPU✅ (desktop)✅ (a seconda del dispositivo)

Basis rileva queste capacità a runtime e transcodifica la stessa codifica intermedia nella migliore corrispondenza. Ecco perché questo strato Basis sul web è quasi insostituibile — non puoi prevedere il dispositivo dell'utente prima della pubblicazione.

Flusso di upload a confronto: tradizionale vs formati GPU

Per finire, fissiamo la differenza in un diagramma di flusso.

PNG/JPG tradizionale:

File PNG ──download──> memoria CPU ──decodifica CPU (lenta)──> blocco pixel RGBA ──upload (grande, lento)──> VRAM (87 MB)

KTX2 + Basis:

File KTX2 ──download──> memoria CPU ──transcodifica runtime (veloce)──> formato a blocchi GPU ──upload (piccolo, veloce)──> VRAM (11 MB)

Quest'ultimo omette il grande passo di «decodifica CPU per pixel», e i dati caricati sono di un ordine di grandezza inferiori. Primo frame più veloce, meno VRAM — questo è il valore centrale dell'approccio.

Prossimo passo

La teoria è fatta; il prossimo articolo è pratica. Comprimeremo le texture in KTX2 con toktx e gltf-transform, le caricheremo in Three.js / Babylon.js e tratteremo come scegliere ETC1S vs UASTC e come regolare i parametri di compressione.

Supportaci