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...
GPU optimization
Introduzione
L'esigenza di nuove funzionalità grafiche e il continuo progresso tecnologico inevitabilmente garantiscono di riscontrare colli di bottiglia grafici. Alcuni di questi possono avvenire dal lato della CPU, ad esempio nei calcoli interni al motore Godot per preparare gli oggetti per il rendering. I colli di bottiglia possono anche avvenire sulla CPU nel driver grafico, il quale ordina le istruzioni da passare alla GPU, e nel trasferimento di queste istruzioni. Infine, i colli di bottiglia possono avvenire anche dal lato della GPU stessa.
I colli di bottiglia nel rendering dipendono fortemente dall'hardware. Le GPU per i dispositivi mobili, in particolare, possono avere difficoltà con scene che vengono eseguite senza problemi sui computer desktop.
Comprendere e investigare i colli di bottiglia sulla GPU è leggermente diverso rispetto alla situazione sulla CPU. Questo perché, spesso, è possibile alterare le prestazioni solo indirettamente, cambiando le istruzioni fornite alla GPU. Inoltre, potrebbe essere più difficile prendere misure. In molti casi, l'unico modo per misurare le prestazioni è esaminare le variazioni del tempo impiegato per il rendering di ciascun frame.
Chiamate di disegno, cambi di stato e API
Nota
La sezione seguente non importa agli utenti finali, ma è utile per fornire informazioni generali che saranno importanti nelle sezioni più avanti.
Godot invia istruzioni alla GPU tramite un'API grafica (Vulkan, OpenGL, OpenGL ES o WebGL). La comunicazione e l'attività del driver coinvolte possono essere piuttosto costose, soprattutto in OpenGL, OpenGL ES e WebGL. Se riusciamo a fornire queste istruzioni in un modo che sia preferito dal driver e dalla GPU, possiamo aumentare notevolmente le prestazioni.
Quasi ogni comando dell'API in OpenGL richiede una certa quantità di validazione per garantire che la GPU sia nello stato corretto. Anche comandi apparentemente semplici possono portare a un'ondata di operazioni dietro le quinte. Pertanto, l'obiettivo è ridurre al minimo queste istruzioni e raggruppare oggetti simili il più possibile in modo che si possano renderizzare insieme, o con il minor numero possibile di questi costosi cambiamenti di stato.
Batching 2D
In 2D, i costi di trattare ogni elemento singolarmente possono essere proibitivi: possono essercene facilmente migliaia sullo schermo. Per questo motivo si utilizza il batching 2D. Più elementi simili sono raggruppati e renderizzati in batch, tramite una singola chiamata di disegno, anziché effettuare una chiamata di disegno separata per ogni elemento. Inoltre, questo significa che i cambiamenti di stato, di materiale e di texture possono rimanere al minimo.
Batching 3D
In 3D, l'obiettivo rimane comunque quello di ridurre al minimo le chiamate di disegno e i cambiamenti di stato. Tuttavia, può risultare più complesso raggruppare più oggetti in un'unica chiamata di disegno. Le mesh 3D tendono a essere composte da centinaia o migliaia di triangoli, e combinare mesh grandi in tempo reale è proibitivamente costoso. Il costo di unirle assieme supera rapidamente ogni vantaggio man mano che aumenta il numero di triangoli per ogni mesh. Un'alternativa molto migliore è quella di unire le mesh in anticipo (mesh statiche in relazione tra loro). Lo si può fare dagli artisti o programmaticamente all'interno di Godot attraverso un componente aggiuntivo.
There is also a cost to batching together objects in 3D. Several objects rendered as one cannot be individually culled. An entire city that is off-screen will still be rendered if it is joined to a single blade of grass that is on screen. Thus, you should always take objects' locations and culling into account when attempting to batch 3D objects together. Despite this, the benefits of joining static objects often outweigh other considerations, especially for large numbers of distant or low-poly objects.
Per più informazioni su ottimizzazioni specifiche al 3D, consultare Ottimizzazione delle prestazioni 3D.
Riutilizza gli shader e i materiali
Il renderer di Godot è leggermente diverso da quelli in circolazione. È progettato per ridurre al minimo i cambiamenti di stato della GPU. StandardMaterial3D fa un buon lavoro nel riutilizzare i materiali che necessitano di shader simili. Se si usano shader personalizzati, assicurarsi di riutilizzarli il più possibile. Le priorità di Godot sono:
Reusing Materials: The fewer different materials in the scene, the faster the rendering will be. If a scene has a huge amount of objects (in the hundreds or thousands), try reusing the materials. In the worst case, use atlases to decrease the amount of texture changes.
Riutilizzo degli shader: se non è possibile riutilizzare i materiali, prova almeno a riutilizzare gli shader. Nota: gli shader sono riutilizzati automaticamente tra StandardMaterial3D che condividono la stessa configurazione (funzionalità abilitate o disabilitate tramite una casella di spunta) anche se hanno parametri diversi.
Se una scena contiene, ad esempio, 20.000 oggetti, ognuno con 20.000 materiali diversi, il rendering sarà lento. Se la stessa scena contiene 20.000 oggetti, ma utilizza solo 100 materiali, il rendering sarà molto più veloce.
Costo dei pixel contro il costo dei vertici
You may have heard that the lower the number of polygons in a model, the faster it will be rendered. This is really relative and depends on many factors.
Su PC e console moderni, il costo dei vertici è basso. Le GPU originariamente renderizzavano solo triangoli. Ciò significava che ogni frame:
Tutti i vertici si dovevano trasformare dalla CPU (incluso il ritaglio).
Tutti i vertici si dovevano inviare dalla RAM principale alla memoria della GPU.
Oggi, tutto questo è gestito internamente dalla GPU, aumentando notevolmente le prestazioni. Gli artisti 3D spesso hanno un'idea sbagliata delle prestazioni base sul numero dei poligoni perché i software di modellazione 3D (come Blender, 3ds Max, ecc.) devono mantenere la geometria nella memoria della CPU per poterla modificare, riducendo le prestazioni effettive. I motori grafici per videogiochi si affidano di più alla GPU, quindi possono renderizzare molti triangoli molto più efficientemente.
Sui dispositivi mobili, la storia è diversa. Le GPU di PC e console sono mostri di potenza bruta in grado di assorbire tutta l'energia di cui hanno bisogno dalla rete elettrica. Le GPU dei dispositivi mobili, invece, sono limitate da una piccola batteria, quindi devono essere molto più efficienti energicamente.
Per essere più efficienti, le GPU mobili cercano di evitare l'overdraw. L'overdraw avviene quando lo stesso pixel sullo schermo viene renderizzato più di una volta. Immagina una città con molti edifici. Le GPU non sanno cosa è visibile e cosa è nascosto finché non lo disegnano. Ad esempio, potrebbe essere disegnata una casa e poi un'altra casa di fronte ad essa (il che significa che il rendering è avvenuto due volte per lo stesso pixel). Per le GPU sui PC in genere non importa molto e aggiungono più processori di pixel all'hardware per aumentare le prestazioni (il che aumenta anche il consumo energetico).
Usare più energia non è un'opzione sui dispositivi mobili, pertanto ricorrono a una tecnica chiamata tile-based rendering, che divide lo schermo in una griglia. Ogni cella mantiene l'elenco dei triangoli disegnati e li ordina per profondità al fine di ridurre al minimo l'overdraw. Questa tecnica migliora le prestazioni e riduce il consumo energetico, ma ha un impatto sulle prestazioni dei vertici. Di conseguenza, si possono elaborare meno vertici e triangoli per il disegno.
Inoltre, il tile-based rendering ha difficoltà quando ci sono piccoli oggetti con molta geometria in una piccola porzione dello schermo. Questo costringe le GPU mobili a concentrare gran parte dei loro sforzi su una singola cella dello schermo, il che riduce considerevolmente le prestazioni poiché tutte le altre celle devono attendere il suo completamento prima di visualizzare il frame.
In sintesi, non preoccuparti del numero di vertici sui dispositivi mobili, ma evita di concentrare i vertici in piccole parti dello schermo. Se un personaggio, un PNG, un veicolo, ecc. è lontano (e quindi appare minuscolo), utilizza un modello con un livello di dettaglio (LOD) inferiore. Anche sulle GPU sui desktop, è preferibile evitare di avere triangoli più piccoli di un pixel sullo schermo.
Pay attention to the additional vertex processing required when using:
Skinning (animazioni scheletriche)
Morph (chiavi di forma)
Oggetti illuminati per vertice (comuni sui dispositivi mobili)
Pixel/fragment shaders and fill rate
In contrast to vertex processing, the costs of fragment (per-pixel) shading have increased dramatically over the years. Screen resolutions have increased: the area of a 4K screen is 8,294,400 pixels, versus 307,200 for an old 640×480 VGA screen. That is 27 times the area! Also, the complexity of fragment shaders has exploded. Physically-based rendering requires complex calculations for each fragment.
You can test whether a project is fill rate-limited quite easily. Turn off V-Sync to prevent capping the frames per second, then compare the frames per second when running with a large window, to running with a very small window. You may also benefit from similarly reducing your shadow map size if using shadows. Usually, you will find the FPS increases quite a bit using a small window, which indicates you are to some extent fill rate-limited. On the other hand, if there is little to no increase in FPS, then your bottleneck lies elsewhere.
È possibile aumentare le prestazioni in un progetto limitato dal fill rate riducendo il carico di lavoro della GPU. Questo si può fare semplificando lo shader (magari disattivando le opzioni costose se si utilizza uno StandardMaterial3D) o riducendo il numero e le dimensioni delle texture utilizzate. Inoltre, quando si utilizzano particelle con ombreggiatura, è consigliabile forzare l'ombreggiatura per vertice nel materiale corrispondente per diminuire l'impatto dello shading.
Vedi anche
Su hardware supportato, è possibile usare Variable rate shading per ridurre i costi di elaborazione dell'ombreggiatura senza compromettere la nitidezza dei bordi nell'immagine finale.
Quando scegli come destinazione i dispositivi mobili, pensa a utilizzare gli shader più semplici possibili che puoi ragionevolmente permetterti di utilizzare.
Lettura delle texture
L'altro fattore negli shader di frammento è il costo di lettura delle texture. La lettura delle texture è un'operazione costosa, soprattutto quando si leggono diverse texture in un singolo shader di frammento. Inoltre, bisogna considerare che il filtraggio può rallentarla ulteriormente (filtraggio trilineare tra mipmap e calcolo della media). La lettura delle texture è anche costosa in termini di consumo energetico, il che è bel un problema sui dispositivi mobili.
If you use third-party shaders or write your own shaders, try to use algorithms that require as few texture reads as possible.
Compressione delle texture
Per impostazione predefinita, Godot comprime le texture dei modelli 3D all'importazione attraverso la compressione VRAM (Video RAM). La compressione VRAM non è efficiente in dimensioni come PNG o JPG quando sono memorizzate, ma aumenta enormemente le prestazioni quando si disegnano texture abbastanza grandi.
Questo perché l'obiettivo principale della compressione delle texture è la riduzione della larghezza di banda tra la memoria e la GPU.
In 3D, la forma degli oggetti dipende più dalla geometria che dalla texture, quindi la compressione generalmente non si nota. In 2D, la compressione dipende più dalle forme dentro le texture, pertanto gli artefatti risultanti dalla compressione 2D si notano di più.
Da avvertimento, la maggior parte dei dispositivi Android non supporta la compressione delle texture con trasparenza (solo opache), quindi è importante ricordarlo.
Nota
Even in 3D, "pixel art" textures should have VRAM compression disabled as it will negatively affect their appearance, without improving performance significantly due to their low resolution.
Post-elaborazione e ombre
Anche gli effetti di post-elaborazione e le ombre possono essere costosi in termini di attività di fragment shading. È sempre consigliabile testare l'impatto di entrambi su hardware diversi.
Ridurre le dimensioni delle mappe delle ombre può aumentare le prestazioni, sia di scrittura sia di lettura delle mappe. Oltretutto, il modo migliore per migliorare le prestazioni delle ombre è disattivarle per quante più luci e oggetti sia possibile. Le OmniLight/SpotLight più piccole o distanti possono spesso avere le loro ombre disattivate con un impatto visivo minimo.
Trasparenza e fusione
Gli oggetti trasparenti presentano particolari problemi per l'efficienza del rendering. Gli oggetti opachi (soprattutto in 3D) si possono renderizzare praticamente in qualsiasi ordine e lo Z-buffer garantirà che solo gli oggetti più vicini siano elaborati da uno shader. Gli oggetti trasparenti o fusi sono diversi. In gran parte dei casi, non possono affidarsi allo Z-buffer e si devono renderizzare nell'"ordine del pittore" (ovvero dal retro al davanti) per apparire correttamente.
Gli oggetti trasparenti sono anche particolarmente problematici per il fill rate, perché ogni elemento deve essere disegnato anche se in seguito saranno disegnati altri oggetti trasparenti sopra di esso.
Gli oggetti opachi non devono fare così per forza. Di solito possono sfruttare il Z-buffer scrivendo prima solo nel Z-buffer, eseguendo poi lo shader dei frammenti solo sul frammento "vincente", ovvero l'oggetto che si trova più davanti a tutti in un determinato pixel.
Transparency is particularly expensive where multiple transparent objects overlap. It is usually better to use transparent areas as small as possible to minimize these fill rate requirements, especially on mobile, where fill rate is very expensive. Indeed, in many situations, rendering more complex opaque geometry can end up being faster than using transparency to "cheat".
Consiglio multi-piattaforma
Se si intende pubblicare un gioco su più piattaforme, è bene testarlo presto e spesso su tutte le piattaforme, soprattutto su quelle mobili. Sviluppare un gioco su desktop e poi tentare di adattarlo per i dispositivi mobili all'ultimo minuto è la ricetta per un disastro.
In generale, è consigliabile progettare il gioco per il minimo comune denominatore, per poi aggiungere miglioramenti opzionali per le piattaforme più potenti. Ad esempio, si potrebbe voler usare il metodo di rendering Compatibilità sia per le piattaforme desktop sia per quelle mobili quando si punta a entrambe.
Mobile/tiled renderers
As described above, GPUs on mobile devices work in dramatically different ways from GPUs on desktop. Most mobile devices use tile renderers. Tile renderers split up the screen into regular-sized tiles that fit into super fast cache memory, which reduces the number of read/write operations to the main memory.
There are some downsides though. Tiled rendering can make certain techniques much more complicated and expensive to perform. Tiles that rely on the results of rendering in different tiles or on the results of earlier operations being preserved can be very slow. Be very careful to test the performance of shaders, viewport textures and post processing.