Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Reducing stutter from shader (pipeline) compilations
Avvertimento
Questa pagina si applica solo ai renderer Forward+ e Mobile, non a Compatibilità. Gli ubershader e la precompilazione di pipeline si basano su funzionalità disponibili solo nelle moderne API grafiche di basso livello (Vulkan, Direct3D 12, Metal). Il renderer Compatibilità utilizza OpenGL 3.3, OpenGL ES 3.0 o WebGL 2.0 a seconda della piattaforma. Queste versioni non hanno le funzionalità necessarie per implementare efficacemente gli ubershader e la precompilazione di pipeline.
Per evitare scatti dovuti agli shader in modalità Compatibilità, è necessario usare il classico metodo di precaricare i materiali, gli shader e le particelle visualizzandoli per almeno un frame nel frustum di visualizzazione durante il caricamento del livello.
La compilazione della pipeline, nota anche come compilazione degli shader, è un'operazione complessa necessaria al motore grafico per poter disegnare qualsiasi tipo di contenuto attraverso la GPU.
Gli shader e i materiali in Godot passano tra diverse fasi prima di poter essere eseguiti dalla GPU.
In termini più precisi, la compilazione degli shader implica la traduzione del codice GLSL generato da Godot in un formato intermedio che può essere condiviso tra sistemi (come SPIR-V quando si usa Vulkan). Tuttavia, questo formato non può essere utilizzato direttamente dalla GPU.
La compilazione della pipeline è la fase in cui il driver della GPU converte il formato shader intermedio (il risultato della compilazione dello shader) in un formato che la GPU può effettivamente utilizzare per il rendering. I driver solitamente mantengono una cache delle pipeline memorizzata da qualche parte nel sistema per evitare di ripetere il processo ogni volta che viene avviato un gioco. Questa cache viene generalmente eliminata quando il driver viene aggiornato.
Le pipeline contengono più informazioni oltre al codice shader, il che significa che per ogni shader possono esserci decine o più pipeline! Questo rende difficile per un motore compilarle in anticipo, sia perché sarebbe molto lento, sia perché occuperebbe molta memoria. Inoltre, questo passaggio si può eseguire solo sul sistema dell'utente ed è molto difficile condividere il risultato tra utenti a meno che non abbiano esattamente lo stesso hardware e la stessa versione dei driver.
Prima di Godot 4.4, non esisteva altra soluzione per la compilazione della pipeline se non quella di generarla quando un oggetto appariva nel campo visivo della telecamera, causando il famigerato scatto di shader o i rallentamenti che avvengono solo durante la prima esecuzione. Con Godot 4.4, sono stati introdotti nuovi meccanismi per mitigare gli scatti causati dalla compilazione della pipeline.
Ubershader: Godot utilizza costanti di specializzazione, una funzionalità che consente al driver di ottimizzare il codice di una pipeline in base a una serie di parametri come illuminazione, qualità delle ombre, ecc. Le costanti di specializzazione servono per ottimizzare uno shader limitando le funzionalità non necessarie. La modifica di una costante di specializzazione richiede la ricompilazione della pipeline. Gli Ubershader sono una versione speciale dello shader in grado di modificare queste costanti durante il rendering, il che significa che Godot può precompilare una sola pipeline in anticipo e compilare le versioni più ottimizzate in background durante il gioco. Questo riduce significativamente il numero di pipeline che si devono create.
Precompilazione delle pipeline: grazie all'uso degli ubershader, il motore può precompilare le pipeline in anticipo in diversi punti, ad esempio quando le mesh vengono caricate o nodi vengono aggiunti alla scena. Essendo parte del processo di caricamento delle risorse, è possibile precompilare le pipeline anche in più thread in background, se possibile, durante le schermate di caricamento o persino durante il gioco.
A partire da Godot 4.4, Godot rileverà quali pipeline sono necessarie e le precompilerà al momento del caricamento. Questo sistema di rilevamento è per lo più automatico, ma si basa sul fatto che il RenderingServer rilevi la presenza di tutti gli shader, le mesh o le funzionalità di rendering al momento del caricamento. Ad esempio, se si carica una mesh e uno shader durante l'esecuzione del gioco, la pipeline per quella combinazione di mesh/shader non sarà compilata finché la mesh/shader non saranno caricati. Similmente, cose come abilitare l'MSAA o istanziare un nodo VoxelGI durante l'esecuzione del gioco attiveranno la ricompilazione delle pipeline.
Monitor di precompilazione delle pipeline
La compilazione in anticipo delle pipeline è il meccanismo principale che Godot utilizza per mitigare gli scatti degli shader, ma non è una soluzione perfetta. Può essere molto utile essere consapevoli delle situazioni che possono portare a scatti di pipeline e le soluzioni alternative sono piuttosto intuitive rispetto alle versioni precedenti.Queste soluzioni potrebbero diventare meno necessarie con il tempo e con le future versioni di Godot, man mano che saranno implementate più tecniche di rilevamento.
Il debugger di Godot offre dei monitor per tenere traccia del numero di pipeline create dal gioco e del passaggio che ne ha attivato la compilazione. È possibile monitorare questi valori durante l'esecuzione del gioco per identificare potenziali cause di scatti degli shader senza dover cancellare la cache dei driver ogni volta che si desidera testarlo. Improvvisi aumenti di questi valori fuori dalle schermate di caricamento possono manifestarsi come scatti durante il gioco la prima volta che un utente lo gioca sul proprio sistema. Si consiglia di dare un'occhiata a questi monitor per identificare le possibili cause di scatti per i giocatori, poiché potrebbe essere difficile riscontrarli personalmente senza cancellare la cache dei driver o testare su un sistema meno potente.
Compilazioni delle pipeline di uno dei progetti demo.
Nota
Possiamo visualizzare le pipeline compilate durante il gioco e verificare quali passaggi potrebbero causare scatti. Si noti che questi valori aumenteranno soltanto e non diminuiranno mai, poiché le pipeline eliminate non sono tracciate da questi monitor e le pipeline possono essere cancellate e ricreate durante il gioco.
Canvas: compilato durante il disegno di un nodo 2D. Il motore attualmente non supporta la precompilazione per gli elementi 2D e avverranno scatti quando il nodo 2D viene disegnato per la prima volta.
Mesh: compilato durante il caricamento di una mesh 3D e l'identificazione delle pipeline che si possono precompilare dalle sue proprietà. Questo può causare scatti se una mesh viene caricata durante il gioco, ma si possono mitigare se la mesh viene caricata tramite un thread in background. I modificatori che fanno parte dei nodi, come i materiali sostitutivi, non si possono compilare in questo passaggio.
Surface: compilato quando un frame sta per essere disegnato e gli oggetti 3D sono stati istanziati per la prima volta nell'albero di scene. Questo passaggio può includere anche la compilazione di nodi che non sono nemmeno visibili nell'albero di scene. lo scatto avverrà solo nel primo frame in cui il nodo viene aggiunto alla scena, quindi non sarà evidente se avviene subito dopo una schermata di caricamento.
Draw: compilato su richiesta quando è necessario disegnare un oggetto 3D e un ubershader non è stato precompilato in anticipo. Il motore non è in grado di precompilare questa pipeline, in quanto ha attivato un caso non ancora coperto o è stato modifico il codice del motore. Porta a scatti durante il gioco. Questo è identico alle versioni di Godot prima della 4.4. Se si riscontrano compilazioni in questo caso, è bene farlo sapere agli sviluppatori poiché questo non dovrebbe mai accadere con il sistema degli Ubershader. Assicurarsi di allegare anche un progetto di riproduzione minimo.
Specialization: compilato in background durante il gioco per ottimizzare il framerate. Non può causare scatti, ma potrebbe ridurre il framerate se ne avvengono molti per frame.
Pipeline precompilation features
Godot offre tante funzionalità di rendering che non servono necessariamente a tutti i giochi. Purtroppo, la precompilazione della pipeline non può sapere in anticipo se una particolare funzionalità è utilizzata da un progetto. Alcune di queste funzionalità si possono rilevare solo quando un utente aggiunge un nodo alla scena o cambia una particolare impostazione nel progetto o nell'ambiente. Il sistema di precompilazione della pipeline terrà traccia di queste funzionalità non appena vengono incontrate per la prima volta e ne abiliterà la precompilazione per qualsiasi mesh o superficie creata successivamente.
Se il proprio gioco utilizza queste funzionalità, assicurarsi di avere una scena che le utilizzi il prima possibile prima di caricare la maggior parte delle risorse. Questa scena può essere molto semplice e basterà purché utilizzi le funzionalità che il gioco intende avere. È possibile anche renderizzarla fuori dallo schermo per almeno un frame, se necessario, ad esempio coprendola con un nodo ColorRect o attraverso un nodo SubViewport posizionato fuori dai limiti della finestra.
È importante anche tenere presente che modificare una qualsiasi di queste impostazioni durante il gioco causerà immediatamente qualche scatto. Assicurarsi di modificare queste impostazioni solo tramite le schermate di configurazione, se necessario, e di inserire schermate di caricamento e messaggi quando le modifiche vengono applicate.
MSAA Level: abilitata quando si cambia il livello di MSAA 3D nelle impostazioni del progetto. Purtroppo, usare livelli di MSAA diversi su viewport diverse causerà scatti, poiché il motore tiene traccia di un solo livello alla volta per eseguire la precompilazione.
Reflection Probes: abilitata quando un nodo ReflectionProbe viene posizionato nella scena.
Separate Specular: abilitata quando si utilizzano effetti come il sub-surface scattering o un effetto di compositore che si basa sul campionamento della specularità direttamente dallo schermo.
Motion Vectors: abilitata quando si utilizzano effetti come TAA, FSR2 o un effetto di compositore che richiede vettori di movimento (come la sfocatura di movimento).
Normal and Roughness: abilitata quando si utilizzano SDFGI, VoxelGI, riflessi nello spazio dello schermo, SSAO, SSIL o si utilizza il
normal_roughness_bufferin uno shader personalizzato o CompositorEffect.Lightmaps: abilitata quando un nodo LightmapGI viene posizionato nella scena e un nodo utilizza una lightmap precalcolata.
VoxelGI: abilitata quando un nodo VoxelGI viene posizionato nella scena.
SDFGI: abilitata quando un nodo WorldEnvironment abilita l'SDFGI.
Multiview: abilitata per i progetti XR.
16/32-bit Shadows: abilitata quando la configurazione della precisione della profondità nelle mappe delle ombre viene modificata nelle impostazioni del progetto.
Omni Shadow Dual Paraboloid: abilitata quando una luce omnidirezionale proietta ombre e usa la modalità a doppio paraboloide (dual paraboloid).
Omni Shadow Cubemap: abiltata quando una luce omnidirezionale proietta ombre e usa la modalità cubemap (che è quella predefinita).
Se si riscontrano scatti durante il gioco e i monitor segnalano un aumento improvviso delle compilazioni durante il passaggio Surface, è molto probabile che una funzionalità non sia stata abilitata in anticipo. Assicurarsi che questo effetto sia abilitato durante il caricamento del gioco dovrebbe mitigare il problema.
Pipeline precompilation instancing
Una causa comune di scatti nei giochi è il fatto che alcuni effetti si istanziano nella scena solo a causa di interazioni che succedono durante il gioco. Ad esempio, se esiste un effetto di particelle che viene aggiunto alla scena tramite uno script solo quando un giocatore compie un'azione. Anche se la scena è precaricata, il motore potrebbe non essere in grado di precompilare le pipeline finché l'effetto non viene aggiunto alla scena almeno una volta.
Fortunatamente, Godot 4.4 e versioni successive sono in grado di precompilare queste pipeline a condizione che la scena sia istanziata almeno una volta, anche se è completamente invisibile o fuori dal campo visivo della telecamera.
Nodo proiettile nascosto aggiunto al giocatore in uno dei progetti demo. Questo aiuta il motore a precompilare in anticipo le pipeline dell'effetto.
Se si conoscono gli effetti aggiunti dinamicamente alla scena durante il gioco e si notano aumenti improvvisi sul monitor delle compilazioni quando questi effetti appaiono, una soluzione alternativa è quella di aggiungere una versione nascosta dell'effetto da qualche parte dove è garantito che appaia.
Ad esempio, se il personaggio del giocatore è in grado di creare una sorta di esplosione, è possibile aggiungere l'effetto come figlio del giocatore, come nodo invisibile. Assicurarsi di disabilitare lo script allegato al nodo nascosto o di nascondere qualsiasi altro nodo che potrebbe causare problemi, cosa che si può fare abilitando l'opzione Figli modificabili sul nodo.
Shader baker
A partire da Godot 4.5, è possibile scegliere di preparare gli shader durante l'esportazione per migliorare i tempi di avvio iniziale. Questo in genere non risolve gli scatti esistenti, ma riduce il tempo necessario per caricare il gioco per la prima volta. Questo è particolarmente il caso quando si utilizza Direct3D 12 o Metal, che hanno tempi iniziali di compilazione degli shader significativamente più lunghi rispetto a Vulkan a causa della fase di conversione richiesta. Gli shader di Godot utilizzano GLSL e SPIR-V, ma Direct3D 12 e Metal utilizzano formati diversi.
Nota
Lo shader baker può preparare il codice sorgente solo nel formato intermedio (SPIR-V per Vulkan, DXIL per Direct3D 12, MIL per Metal). Non può preparare il formato intermedio nella pipeline finale, poiché questo dipende dal driver della GPU e dall'hardware.
Lo shader baker non sostituisce la precompilazione della pipeline, ma mira a completarla.
Se abilitato, lo shader baker raggrupperà il codice shader compilato nel PCK, saltando completamente la fase di compilazione dello shader. Lo svantaggio è che l'esportazione richiederà un po' più di tempo. Il file PCK sarà più grande di qualche megabyte.
Per impostazione predefinita, Lo shader baker è disabilitato, ma è possibile abilitarlo in ogni preimpostazione di esportazione nella finestra Esporta selezionando l'opzione di esportazione Shader Baker > Enabled.
Si noti che lo shader baking sarà in grado di esportare shader solo per i driver supportati dalla piattaforma su cui è attualmente in esecuzione l'editor:
L'editor in esecuzione su Windows può esportare shader per Vulkan e Direct3D 12.
L'editor in esecuzione su macOS può esportare shader per Vulkan e Metal.
L'editor in esecuzione su Linux può esportare shader solo per Vulkan.
L'editor in esecuzione su Android può esportare shader solo per Vulkan.
Lo shader baker esporterà solo gli shader che corrispondono all'impostazione del progetto rendering/rendering_device/driver per la piattaforma di destinazione.
Nota
Lo shader baker è supportato solo per i rendering Forward+ e Mobile. Non avrà alcun effetto se il progetto utilizza il rendering Compatibilità o per gli utenti che utilizzano l'alternativa Compatibilità perché il loro hardware non supporta i rendering Forward+ o Mobile.
Ciò significa anche che lo shader baker non è supportato sulla piattaforma web, poiché la piattaforma web supporta solo il renderer Compatibilità.
Inoltre, lo shader baker non è supportato quando si esporta un progetto usando l'argomento della riga di comando --headless, poiché Godot non può accedere alla GPU se eseguito in modalità headless.