Questo documento mostra come ottimizzare le prestazioni del gioco utilizzando strumenti per identificare e risolvere i colli di bottiglia della CPU e della GPU.
Ottimizzazione della CPU
Se l'analisi mostra che il gioco è CPU-bound, sono necessari ulteriori accertamenti. Ciò richiede l'identificazione dei thread o delle API specifici che causano colli di bottiglia e riducono gli FPS.
Per l'ottimizzazione della CPU, una soluzione universale in genere non è efficace. Devi invece identificare il carico di lavoro più impegnativo in base al gioco o alla scena e ottimizzare la logica e le funzioni pertinenti.
Strumenti di tracciamento della sincronizzazione del motore grafico
I seguenti strumenti possono aiutarti in questa analisi:
Approfondimenti irreali
All'interno dei progetti Unreal Engine, lo strumento Unreal Insight facilita l'analisi delle informazioni di traccia di temporizzazione per i singoli thread che compongono un frame.
Ad esempio, GameThread utilizza in genere la percentuale più elevata di tempo della CPU, principalmente attribuibile a Tick Time. Inoltre, una parte
considerevole del tempo di utilizzo viene consumata dalle attività associate a
FActorComponentTickFunction.
Per ottimizzare FActorComponentTick, è fondamentale escludere i calcoli e
implementare l'eliminazione per i personaggi e gli oggetti posizionati al di fuori del
campo visivo della videocamera. Inoltre, l'utilizzo di animazioni basate sul livello di dettaglio
può portare a ulteriori miglioramenti del rendimento.
Unity Profiler (Unity)
L'analisi tramite Unity Profiler rivela che il thread principale consuma oltre 45 ms, con PostLateUpdate.FinishFrameRendering che occupa 16,23 ms, il che lo rende l'operazione più dispendiosa in termini di tempo. All'interno di questo, vengono osservate più invocazioni di Inl_RenderCameraStack. È consigliabile verificare la necessità delle videocamere attive e ottimizzarle di conseguenza.
Strumenti di profilazione a livello di sistema
Utilizza i seguenti strumenti di profilazione:
Perfetto
Utilizzando la traccia Perfetto, puoi determinare le assegnazioni dei core della CPU e i dettagli di esecuzione di ogni thread su un dispositivo Android. Ciò consente di identificare i colli di bottiglia delle prestazioni analizzando i dati di esecuzione dei thread.
Scenario di overhead della CPU
La traccia indica che il carico di lavoro su GameThread e RenderThread sta causando ritardi in QueuePresent di RHI Thread, il che porta a uno scenario CPU-bound, basato su VSync.
Scenario di overhead della GPU
La traccia indica che il completamento della GPU supera i 25 ms, il che indica uno scenario vincolato alla GPU.
Simpleperf
Per identificare le funzioni con l'utilizzo attuale più elevato della CPU, è possibile utilizzare simpleperf. Per risultati ottimali, ti consigliamo di ordinare queste funzioni in modo da dare la priorità a quelle con il maggior utilizzo.
Simpleperf ti aiuta a esaminare i dati sulle funzioni che utilizzano più tempo CPU. Per
ottimizzare l'utilizzo della CPU, inizia con le funzioni che utilizzano più CPU. In questo
esempio, USkeletalMeshComponent, associato all'animazione in
ActorComponentTickFunctions, utilizza la maggior parte della CPU.
Ottimizzazione della GPU
Se l'analisi mostra che il gioco è vincolato alla GPU, è essenziale un'ulteriore indagine. Ciò richiede l'utilizzo di vari strumenti e tecniche per l'ottimizzazione e l'analisi della GPU.
Per ottimizzare la GPU, utilizza un debugger di frame per analizzare la pipeline di rendering e le chiamate di disegno per ogni scena. Inoltre, devi comprendere a fondo l'architettura della GPU e il comportamento della pipeline per identificare operazioni non necessarie o aree da ottimizzare.
Le sezioni seguenti descrivono metodi e strumenti per l'ottimizzazione della GPU.
Elimina i RenderPass non necessari
Per migliorare le prestazioni di rendering e ridurre il carico di lavoro della GPU, elimina i passaggi di rendering non necessari. Sono inclusi tutti i pass di rendering che non hanno chiamate di disegno o il cui output non viene utilizzato nel frame finale.
Utilizza un debugger GPU, ad esempio RenderDoc, per analizzare la pipeline di rendering e
identificare le opportunità di ottimizzazione.
Nessuna chiamata di disegno: controlla se la pass di rendering include chiamate di disegno. Se non ha chiamate di estrazione, rimuovi la tessera.
Output inutilizzato:verifica se le passate successive accedono o visualizzano gli output delle passate di rendering, ad esempio colore o profondità. In caso contrario, rimuovi la tessera.
Tessere unificabili:identifica le tessere che puoi unire:
- Stesso framebuffer o allegati
- Operazioni di caricamento o archiviazione compatibili
- Nessuna barriera di dipendenza nel mezzo
Ridurre al minimo le operazioni di caricamento o archiviazione
Le operazioni di caricamento o archiviazione richiedono molte risorse perché utilizzano molta memoria.
Ridurre al minimo le operazioni di caricamento e archiviazione non necessarie. Esegui queste azioni solo quando
sono necessari allegati all'interno di un RenderPass. In caso contrario, sostituiscili con operazioni Clear o Don't care per ridurre l'overhead.
Come ottimizzare
Utilizza un debugger GPU, ad esempio RenderDoc, per analizzare la pipeline di rendering e
identificare le seguenti opportunità di ottimizzazione:
Caricamento:se un allegato di pass di rendering non utilizza i dati di un pass o di un allegato precedente, un'operazione di caricamento non è necessaria. In questi casi, l'utilizzo di
Don't careoClearpuò ridurre il sovraccarico.Store:se un allegato di passaggio di rendering non viene utilizzato dopo il passaggio di rendering corrente, l'operazione di archiviazione non è necessaria. In questi casi, utilizza
Don't careoClear.Sostituisci:determina se le impostazioni di caricamento o memorizzazione correnti possono essere sostituite da
ClearoDon't Caresenza influire sul frame finale.
Evita l'eliminazione per attivare Early-Z
Early-Z migliora le prestazioni sulle piattaforme mobile. Tuttavia, un'istruzione discard
all'interno di uno shader disattiva automaticamente Early-Z. Se l'istruzione discard
non è essenziale, rimuovila.
Accelerazione Early-Z
Questa ottimizzazione riduce notevolmente le operazioni dello shader di framenti e migliora le prestazioni della GPU.
Early-Z Test di profondità e stencil
Come ottimizzare
Utilizza un debugger GPU, ad esempio RenderDoc, per analizzare la pipeline di rendering e
identificare le seguenti opportunità di ottimizzazione:
Utilizzo di
discardnegli shader di frammenti: la parola chiavediscardimpedisce alla GPU di eseguire test di profondità anticipati perché la visibilità del frammento non è nota in anticipo.Modifica di
gl_FragDepth: la modifica dinamica digl_FragDepthcambia la profondità di un frammento, il che disattiva l'ottimizzazione Early-Z perché la profondità finale è sconosciuta prima dell'elaborazione del frammento.Alpha-to-coverage attivato:quando alpha-to-coverage è attivato (spesso utilizzato nel rendering MSAA), la copertura dei frammenti dipende dai valori alfa. Ciò può ritardare il test della profondità e disattivare Early-Z.
Ottimizzare il formato della texture
La selezione ottimale del formato della texture riduce il consumo di memoria, migliora l'efficienza della larghezza di banda e le prestazioni di rendering. L'utilizzo di formati con precisione eccessivamente elevata può sprecare risorse GPU senza fornire vantaggi visivi.
Come ottimizzare
Utilizza un debugger GPU, ad esempio RenderDoc, per analizzare la pipeline di rendering e
identificare le seguenti opportunità di ottimizzazione:
- Utilizza
D24S8anzichéD32S8per i buffer di stencil di profondità:l'utilizzo diD24S8per i buffer di stencil di profondità riduce il consumo di memoria del 20% rispetto aD32S8, con una differenza minima o nulla nella qualità visiva nella maggior parte delle applicazioni. - Utilizza la compressione
ASTCper le texture a colori:la compressioneASTCriduce significativamente l'utilizzo della memoria delle texture, fino a 8 volte rispetto ai formati non compressi, preservando al contempo un'elevata qualità visiva. - Utilizza formati a metà precisione anziché a precisione singola: utilizza
R16FoRG16Fper ridurre la larghezza di banda della memoria e il consumo di spazio di archiviazione. Questi formati sono adatti ai buffer di post-elaborazione.
Ottimizzare la complessità della geometria
Ridurre al minimo la complessità geometrica migliora le prestazioni di rendering, in particolare sui dispositivi mobili con funzionalità GPU limitate. Ciò comporta l'utilizzo di un numero ridotto di vertici e triangoli, il consolidamento degli oggetti per ridurre le chiamate di disegno e l'eliminazione di geometrie non sottoposte a rendering o non necessarie. Tecniche come la semplificazione della mesh, il livello di dettaglio (LOD) e l'eliminazione del frustum o dell'occlusione possono ridurre significativamente il carico di lavoro della GPU e aumentare i frame rate.
Come ottimizzare
Utilizza strumenti di profilazione e debugger GPU, come RenderDoc, Android GPU Inspector o altri analizzatori delle prestazioni, per identificare i colli di bottiglia delle prestazioni correlati alla geometria.
Riduci il conteggio dei triangoli:riduci al minimo l'utilizzo di poligoni, in particolare per gli oggetti piccoli o distanti.
Utilizza il livello di dettaglio (LOD): in base alla distanza della videocamera, vengono utilizzate automaticamente mesh più semplici.
Unisci mesh piccoli:consolida gli oggetti statici per ridurre le chiamate di disegno e il sovraccarico della CPU.
Tronco di piramide e eliminazione dell'occlusione: evita di eseguire il rendering di oggetti che si trovano al di fuori della visuale o che sono oscurati da altri elementi.
Rimuovere gli allegati non necessari
Gli allegati dei pass di rendering (ad esempio colore, profondità, stencil) consumano larghezza di banda della memoria e risorse GPU, anche se non vengono utilizzati. La rimozione di allegati inutili o ridondanti migliora le prestazioni e riduce il consumo energetico, in particolare sulle piattaforme mobile.
Come ottimizzare
Utilizza strumenti di profilazione e debugger GPU, come RenderDoc,
Android GPU Inspector o altri analizzatori delle prestazioni, per identificare
i colli di bottiglia delle prestazioni correlati alla geometria.
- Controlla l'utilizzo effettivo:ci sono chiamate di disegno o shader che scrivono o leggono dall'allegato?
- Analizza l'output dei frame:utilizza
RenderDoco utilità simili per determinare se l'allegato contribuisce all'immagine finale. - Prendi in considerazione allegati temporanei o fittizi:gli allegati temporanei o un'operazione di negozio "Non mi interessa" devono essere utilizzati per i dati temporanei che non richiedono un'archiviazione permanente.
Ottimizza la precisione degli shader
L'utilizzo di una precisione eccessivamente elevata (ad esempio highp anziché mediump o lowp) all'interno degli shader aumenta il carico di lavoro della GPU, il consumo energetico e la pressione dei registri, in particolare sulle GPU mobile. Utilizzando la precisione adeguata più bassa per le variabili (ad esempio posizioni, colori, UV), puoi migliorare le prestazioni senza un impatto visivo percepibile.
Come ottimizzare
Utilizza strumenti di profilazione e debugger GPU come RenderDoc, Android GPU Inspector o altri analizzatori delle prestazioni per identificare i colli di bottiglia delle prestazioni correlati alla geometria.
Esamina il codice dello shader:valuta le variabili dello shader e verifica che l'alta precisione venga utilizzata solo quando necessario, ad esempio per i calcoli di profondità o spazio schermo. Utilizza una precisione media o bassa per colori, coordinate UV o valori che non richiedono un'elevata precisione.
Utilizza debugger GPU:le utilità di diagnostica, come RenderDoc o i profiler GPU per dispositivi mobili (ad esempio AGI, Mali/GPU Inspector), identificano l'utilizzo elevato dei registri o gli stalli degli shader associati a problemi di precisione.
Attivare il back-face culling
Il rendering dei triangoli rivolti verso l'esterno della videocamera (facce posteriori) spesso non è necessario per gli oggetti solidi.
Come ottimizzare
L'utilizzo di VK_CULL_MODE_NONE può influire negativamente sulle prestazioni perché costringe la GPU a eseguire il rendering delle facce anteriore e posteriore, il che aumenta il carico di lavoro di rendering.
Ridurre al minimo l'overdraw nelle scene dell'interfaccia utente
Elimina le chiamate di disegno e i passaggi di rendering non necessari, in particolare nelle scene dell'interfaccia utente, per migliorare le prestazioni di rendering e ridurre il carico di lavoro della GPU. Ad esempio, in una scena dell'interfaccia utente in cui viene eseguito il rendering del mondo intero prima di sovrapporre l'interfaccia utente sullo schermo, il rendering del mondo diventa ridondante.
Come ottimizzare
Utilizza un debugger GPU, ad esempio RenderDoc, per analizzare la pipeline di rendering e
identificare le seguenti opportunità di ottimizzazione:
- Verifica l'assenza di scoperti superflui. Nei contesti dell'interfaccia utente, dove potrebbe essere visualizzata l'intera schermata, verifica che i passaggi di rendering precedenti non siano inutilmente sovradisegnati.
- Abilita il test di profondità e l'eliminazione per ottimizzare le prestazioni.
- Valuta la possibilità di eseguire il rendering in ordine dalla parte anteriore a quella posteriore.