Fortnite

Fortnite sul blog tecnico di Android

6.9.2018
Da Il team di Fortnite

INTRODUZIONE

Il 9 agosto abbiamo lanciato la beta di Fortnite per Android su alcuni dispositivi del nostro partner Samsung. Qualche giorno dopo, abbiamo inviato una serie di inviti a una cerchia di proprietari di dispositivi Android prodotti da altri marchi. La beta ci ha fornito informazioni molto importanti dal punto di vista delle prestazioni, della sicurezza e della compatibilità con altri dispositivi, oltre a permetterci di migliorare l'installazione su Android tramite il programma di installazione di Fortnite. Ma scopriamo insieme i dettagli tecnici che si celano dietro al lancio, nonché i progetti su cui stiamo lavorando e quali novità abbiamo in serbo per Android nell'immediato futuro.  

STATISTICHE

Nel corso dei primi 21 giorni dal lancio di Fortnite su Android, l'interesse degli utenti ha continuato a crescere: oltre 23 milioni di giocatori si sono registrati per la beta Android, mentre 15 milioni di utenti hanno installato il nostro APK.  Anche se al momento è possibile giocare su dispositivi Android solo tramite invito, il passaggio dalla fase a invito a quella ad accesso libero sarà simile a quanto avvenuto sui dispositivi iOS. 
 

OTTIMIZZAZIONE DELL'HARDWARE 


Introduzione tecnica

Lanciare lo stesso gioco su tutte le piattaforme continuando a garantire il cross-play è stata una vera impresa. Di solito, quando si adatta un gioco per renderlo compatibile con i dispositivi mobili, si tende a semplificare i contenuti e persino il design così da rispettare i parametri prestazionali della piattaforma. Per fare un esempio, si possono eliminare le facce posteriori degli oggetti più vicini alla telecamera per ridurre le draw call. Gli utenti che avviano Fortnite su Android partecipano alla stessa partita a cui altri amici giocano su PC o console, ecco perché dobbiamo renderizzare qualsiasi elemento importante per il gioco.

Come siamo arrivati al lancio su Android

Da gennaio 2018 un'intera squadra si è dedicata anima e corpo a sviluppare la versione di Battaglia reale per Android. Anche se ci siamo concentrati soprattutto sulle prestazioni di rendering, sulla stabilità e sulla memoria, la vera sfida è stata far fronte alla grande varietà di hardware per Android e le numerose versioni di driver e sistemi operativi disponibili.

La stretta collaborazione con tutti i nostri partner si è rivelata fondamentale per lanciare Fortnite su Android. Senza le loro conoscenze, la loro esperienza e il loro impegno niente di tutto questo sarebbe stato possibile.

Abbiamo lavorato gomito a gomito con Samsung per progettare e ottimizzare una versione di Fortnite compatibile con i loro dispositivi. Samsung ha inviato ingegneri in varie sedi di Epic Games sparse in tutto il mondo e ha collaborato direttamente con la nostra squadra per ottimizzare il gioco e analizzarne le prestazioni, oltre a contribuire allo sviluppo di vari cambiamenti di codice per il renderer di Vulkan. Servendosi di cellulari dotati di speciali strumenti di diagnostica e dei loro dispositivi di progettazione aziendali, sono riusciti a scovare e a risolvere i principali colli di bottiglia delle prestazioni e della memoria. Inoltre, la collaborazione con Samsung ci ha permesso di sviluppare la procedura di installazione più sicura e fluida possibile per gli utenti che possiedono cellulari Samsung.

Anche gli ingegneri di Google sono venuti nelle nostre aziende per progettare e ottimizzare Fortnite: in particolare, ci hanno aiutato a individuare gli elementi chiave da ottimizzare e una fuoriuscita di memoria e hanno creato un ottimo sistema di perfezionamento del frame pacing per OpenGL su Android. Gli sviluppatori di Android che lavorano in Google mettono a disposizione tutto il loro talento e la loro passione per migliorare costantemente l'ecosistema Android e garantire una fantastica esperienza di gioco.

Inoltre, abbiamo avuto la possibilità di collaborare con molti altri partner come ARM Holdings, Qualcomm, Imagination Technologies, Razer e HiSilicon (solo per citarne alcuni) che ci hanno affiancato nelle fasi di test e ottimizzazione di Fortnite.
 

Frammentazione

L'ecosistema Android si compone di cellulari costruiti da più produttori. Ogni telefono è progettato su un SoC (Sistema su circuito integrato) che comprende una configurazione dei core della CPU e della GPU. Esistono diverse tipologie di SoC tra cui gli Snapdragon di Qualcomm (attualmente presenti nel 71% dei dispositivi supportati) che contengono una GPU Adreno, gli Exynos di Samsung, la serie MT di MediaTek e la serie Kirin di HiSilicon; questi ultimi contengono tutti GPU Mali sviluppate da ARM Holdings. Ogni dispositivo funziona con una versione leggermente diversa del sistema operativo Android e la maggior parte dei produttori sceglie di personalizzare le funzionalità dello scheduler e del risparmio di energia. Anche i dispositivi che hanno la stessa GPU montano versioni diverse del driver di grafica. Questo significa che due dispositivi che condividono lo stesso hardware sottostante possono offrire prestazioni molto diverse, oltre a essere soggetti a bug differenti.

Siamo piacevolmente sorpresi di constatare  che un numero di gran lunga maggiore di utenti ha scelto di installare la versione più recente di Android rispetto a quanto ci aspettavamo per i dispositivi con massimo 2 anni di vita. Per quanto riguarda la nostra beta, che esige requisiti di sistema più elevati, al momento più del 92% degli utenti di Fortnite ha installato Android 8 Oreo o versioni più recenti, circa l'8% usa Android 7 Nougat e meno dello 0,5% ha una versione anteriore al 2015. Invece per i dispositivi con 2 o più anni di vita i numeri calano sensibilmente. Per questi dispositivi infatti, i produttori devono pubblicare appositi aggiornamenti e, nella maggior parte dei casi, coordinarsi con i vari operatori di telefonia mobile di tutto il mondo per assicurare che le fasi di sviluppo e di lancio avvengano con successo.

Per gestire un sistema così complesso, ci serviamo del sistema gerarchico di profili disponibile su Unreal Engine. Prima di tutto, creiamo quattro profili in base alle prestazioni desiderate: Basso, Medio, Alto e Epico. Questi profili permettono di regolare le impostazioni di scalabilità nel motore grafico per permettere al gioco di funzionare su dispositivi che offrono prestazioni diverse. Il profilo Basso limita il più possibile la distanza di visualizzazione e disattiva tutte le funzioni grafiche accessorie. Il profilo Epico invece offre il pacchetto completo: ombre, fogliame e la massima distanza di visualizzazione disponibile sui dispositivi più recenti.

Inoltre, abbiamo messo a disposizione una serie di profili per alcune GPU tra cui Adreno 54x e Mali G72. Questi profili di GPU permettono di scegliere l'insieme di prestazioni più adatte alle potenzialità dell'hardware e ci consentono di abilitare le ottimizzazioni e i workaround specifici per l'hardware in uso. Infine, abbiamo sviluppato una serie di profili personalizzati sul singolo dispositivo, tra i quali Samsung Galaxy Note 9 (Adreno) e Google Pixel 2 XL. Quest'ultima serie di profili ci permette di abilitare ulteriori workaround e ottimizzazioni specifiche per ogni dispositivo laddove sia necessario. All'avvio, facciamo attenzione a caratteristiche come il modello del dispositivo, le versioni del sistema operativo e del driver di grafica per capire quale sia il profilo migliore da adottare.
 

Prestazioni di rendering

Per mantenere un frame rate costante, il costo in CPU per il rendering era senza dubbio il principale collo di bottiglia dal punto di vista delle prestazioni. La CPU è molto più lenta con il driver di grafica di Android rispetto a quelle di PC, console e iOS. Mentre gli ultimi dispositivi Android come la versione Adreno del Galaxy S9 arrivano a più di 1500 draw call per frame, i modelli precedenti ne supportano decisamente meno. I dispositivi di fascia media compatibili si attestano intorno alle 600 draw call, mentre i modelli più economici arrivano più o meno a 400.

Avevamo già ridotto il numero di oggetti per cui è necessario renderizzare ogni singolo frame quando a inizio anno abbiamo lanciato la versione per iOS, perciò dovevamo pensare ad altre soluzioni. Abbiamo cercato di trasformare le draw call del batching dinamico in draw call a istanza e, se da un lato abbiamo ottenuto alcuni miglioramenti, dall'altro i progressi non erano sufficienti a giustificare l'aumento di complessità del codice.

Una serie di ottimizzazioni nel renderer di OpenGL hanno dato buoni frutti, ma una delle conquiste più importanti è stata una vera sorpresa e l'abbiamo ottenuta grazie alle ottimizzazioni della memoria: i "finti" buffer uniformi. Si tratta di un percorso di codice che UE4 ha introdotto ormai da anni e che viene usato in quei dispositivi OpenGL ES 2.0 che originariamente non supportano i buffer uniformi, detti anche buffer costanti. Ecco come funziona: Al momento della compilazione dello shader, individuiamo tutte le costanti necessarie allo shader e le riuniamo in un insieme da cui lo shader attinge. Salviamo anche una tabella di mapping che comunica al motore grafico dove reperire le costanti a partire dai buffer uniformi e dove posizionarle nell'insieme delle costanti. Quando il programma viene eseguito, facciamo in modo che i buffer uniformi siano accessibili nella memoria della CPU, usiamo la tabella di mapping per copiarli in un buffer temporaneo e carichiamo tutte le costanti con una sola chiamata di funzione glUniform4fv.

Anche il processo resta un po' un mistero, il percorso di codice dei "finti" buffer uniformi fa risparmiare parecchio tempo al driver. È possibile che il driver stia facendo qualcosa di simile nei suoi processi interni, il che ci permette di alleggerire il carico di lavoro. Un'altra spiegazione potrebbe essere la seguente: poiché creiamo e assegniamo meno risorse, il driver ha semplicemente bisogno di meno tempo per registrare i buffer in modo da conservarli. In ogni caso, questa soluzione è riuscita a ridurre il costo in driver addirittura del 10-15% a volte.
 

Vulkan

Vulkan è l'API grafica per Android più all'avanguardia, progettata per offrire ottime prestazioni e un accesso a basso livello all'hardware. Nel 2016 abbiamo avviato una collaborazione con Samsung per realizzare la demo ProtoStar e mostrare quali risultati si possono ottenere usando un'API grafica di alto livello su Android. Dato che Fortnite renderizza tantissimi oggetti per ogni singolo frame, Vulkan sembrava la scelta perfetta. Purtroppo non è stato così semplice.

Il supporto per Vulkan non è ancora obbligatorio su Android, ecco perché non possiamo dare per scontato che tutti i dispositivi ce l'abbiano. Dato che ci rivolgiamo esclusivamente agli hardware più recenti, non abbiamo certo gettato la spugna; il vero problema è che i primi driver di Vulkan presentavano tutta una serie di bug e di problemi a livello di prestazioni per cui OpenGL si è rivelato più veloce e più stabile di Vulkan sulla maggior parte dei dispositivi. Non c'è da stupirsi: le aziende hanno avuto dieci anni per ottimizzare e migliorare le rispettive implementazioni di OpenGL. Vulkan è un'API molto più potente e ci vorrà ancora tempo per raggiungere gli stessi livelli di affidabilità.

Abbiamo però lanciato il supporto per Vulkan su Samsung S9+ (Adreno) e su Note 9 (Adreno). Grazie alla preziosa collaborazione degli ingegneri di Samsung, siamo riusciti a ottimizzare il supporto per Vulkan su UE4 così da renderlo più veloce di OpenGL del 20% circa. In futuro continueremo a lavorare con i nostri partner che costruiscono hardware per lanciare il supporto di alto livello per Vulkan su altri dispositivi, così da poter offrire un'esperienza di gioco migliore a tutti gli utenti di Fortnite su Android e migliorare le prestazioni dei driver di Vulkan a beneficio degli sviluppatori.
 

Memoria

La memoria è ancora una lotta continua. Non stiamo solo lanciando un gioco per console su dispositivi mobili, no! Continuiamo anche ad aggiungere nuovi contenuti. Ecco perché non smettiamo mai di trovare nuove formule per ottimizzare la memoria. Android presenta sfide davvero uniche rispetto alle altre piattaforme.

Non c'è una memoria "standard" su cui possiamo basarci. Ogni dispositivo ha una quantità di memoria diversa, così come sono diverse le applicazioni in background e i criteri che stabiliscono quando interrompere un'applicazione perché sta usando troppa memoria. Nessuna API è in grado di capire quanta memoria si ha a disposizione. Giusto per dare qualche dato, nel corso di un test abbiamo avviato una partita e cominciato ad allocare memoria finché il sistema operativo non ha interrotto il processo. Utilizzando telefoni appena accesi e senza altre applicazioni attive, su un Samsung Galaxy S8 (Mali) siamo riusciti ad allocare 3 GB dei 4 GB di memoria totali prima che il programma venisse chiuso. Su un Google Pixel 2 siamo riusciti ad allocare solo 1,8 GB dei 3,6 GB totali.

Il sistema, soprattutto il driver di grafica, distribuisce molta memoria al posto nostro. UE4 traccia qualsiasi richiesta di memoria venga fatta al sistema operativo, compresa una stima della memoria allocata dalla GPU, ma non riusciamo a capire bene cosa stia allocando il driver. Attraverso una serie di test abbiamo scoperto che, in Fortnite, gran parte della memoria allocata dal driver è destinata agli shader.

L'ottimizzazione dei "finti" buffer uniformi di cui abbiamo parlato prima è stata eseguita per risparmiare memoria. OpenGL ha bisogno che l'applicazione sia in grado di individuare la posizione di ciascun elemento di un buffer uniforme. Ad esempio, si può chiedere a OpenGL l'offset della matrice LocalToWorld all'interno del buffer uniforme delle primitive. Per compiere questa operazione, il driver deve conservare in memoria alcuni metadati, come ad esempio la tabella degli offset, che includano le stringhe del nome di ogni elemento. Il processo va ripetuto per ogni programma.

In Fortnite ci sono moltissime tipologie di shader. Durante una normale sessione di gioco, il motore grafico usa circa 2.000 programmi di shader diversi. Sembra che il driver salvi questi metadati all'interno di ogni shader, il che richiede moltissima memoria. Su Fortnite siamo riusciti a risparmiare 400 MB di memoria grazie ai "finti" buffer uniformi.

Quando abbiamo lanciato per la prima volta Fortnite su Android, dai nostri test interni risultava che stessimo rispettando i limiti di memoria dei dispositivi. Abbiamo fatto anche altre prove attivando Google maps e ascoltando musica in streaming, tutto per assicurarci che Fortnite funzionasse senza problemi. Ma quando abbiamo lanciato il gioco sul mercato, ci siamo accorti che i cellulari di numerosi giocatori si arrestavano in modo anomalo o presentavano prestazioni molto basse a causa della mancanza di memoria.

Quando un dispositivo Android è a corto di memoria, il sistema operativo cerca di ottenere nuove risorse chiudendo le applicazioni al momento non in uso. Tuttavia, abbiamo scoperto che ci sono varie applicazioni e servizi in background con bassissime prestazioni che si riavviano nel momento esatto in cui il sistema operativo le arresta. Tanto per peggiorare un po' le cose! Android chiude l'applicazione per guadagnare memoria ma poi l'app si riavvia e ricomincia a consumare memoria esattamente come prima. In realtà è addirittura peggio perché la CPU impiega molto tempo ad avviare e chiudere le applicazioni, il che significa che non solo non abbiamo liberato spazio nella memoria, ma stiamo anche sovraccaricando inutilmente la CPU.

Abbiamo aggiornato i nostri test installando e avviando tutta una serie di applicazioni molto diffuse tra gli utenti per poter individuare eventuali problemi nel minor tempo possibile, ma dobbiamo ancora trovare un modo per ridurre l'utilizzo della memoria. Siamo riusciti a ridimensionare il problema nei dispositivi impostati su Alto o Epico che montano un SoC Snapdragon e possiedono una memoria di 4 GB. Ancora una volta, è la memoria dello shader a fare la differenza. Come soluzione provvisoria, abbiamo disabilitato le ombre per migliorare un po' le cose. In questo modo, abbiamo ridotto il numero di shader necessari perché non c'è più bisogno delle varianti per cercare e filtrare le mappe delle ombre. Abbiamo anche aggiunto una cache con algoritmo LRU per gli shader. La cache ci permette di mantenere attivi solo i programmi di shader necessari per renderizzare la scena in corso. Gli altri shader vengono compressi e salvati nella memoria. Quando ne abbiamo bisogno, li decomprimiamo e li rimandiamo al driver.
 

Cosa ci attende in futuro

In questo momento stiamo lavorando per fare in modo che il gioco funzioni bene su tutti i dispositivi attualmente supportati e per recuperare abbastanza memoria in modo da migliorare sia la qualità visiva sia la stabilità. In seguito ci occuperemo dei problemi di compatibilità relativi, ad esempio, agli effetti sonori che con l'aggiornamento 5.40 sono già stati risolti su numerosi dispositivi; inoltre, stiamo lavorando per aumentare la compatibilità con altri modelli. Vogliamo anche offrire agli utenti maggiori possibilità di personalizzare i dispositivi e stiamo cercando di ottenere un buon compromesso tra qualità e prestazioni.

Continueremo a migliorare il supporto per Vulkan per renderlo compatibile con una gamma di modelli sempre più ampia. Non smetteremo quindi di collaborare  con i vari produttori di dispositivi per ottenere le migliori ottimizzazioni sia su UE4 sia sui driver. Riteniamo che, nel lungo periodo, continuare ad affinare il supporto per Vulkan e i driver ci aiuterà a offrire prestazioni di gioco migliori per tutti gli utenti e per tutti i titoli Android che usano UE4.

Ci occuperemo anche dei modelli più vecchi e più lenti, ma non avrebbe senso andare troppo indietro nel tempo. Ogni anno, i telefoni di fascia alta sono il 50% più veloci dell'anno precedente. Fortnite funziona discretamente sui cellulari con due anni di vita e molto bene sui cellulari dell'anno scorso, ma le prestazioni si fanno davvero straordinarie sui modelli di quest'anno. Di questo passo, provate a immaginare come sarà sui cellulari dell'anno prossimo!

image2.png


Infine, molte delle ottimizzazioni dei codici applicate a Unreal Engine sono già state pubblicate nella versione 4.20. Le restanti saranno disponibili nella versione 4.21, che verrà lanciata a breve. Ci impegneremo sempre a condividere le ottimizzazioni future con tutti gli sviluppatori che usano UE4.
 

LA BATTAGLIA CONTRO I MALWARE   

Ancora prima che annunciassimo il lancio di Fortnite su Android, siamo venuti a conoscenza di una serie di siti che recitavano "Fortnite per Android" assolutamente non autorizzati. Di solito sono pieni di malware o di truffe.  Non appena ce ne siamo accorti, abbiamo subito avviato le procedure di notifica e rimozione con i siti stessi, con i relativi fornitori di web hosting e con le inserzioni e i video che li pubblicizzavano.  Anche se il sito non contiene malware, qualsiasi distribuzione o presunta distribuzione di Fortnite per Android non ha assolutamente ricevuto la nostra approvazione. L'unica procedura ufficiale per ottenere Fortnite su Android è andare sul sito di Epic Games e scaricare il programma di installazione di Fortnite.
 
Finora, Epic ha avviato procedimenti contro 47 siti non autorizzati, molti dei quali sembrano essere gestiti dagli stessi malintenzionati. Continueremo a tenerli d'occhio per cercare di renderli non raggiungibili o almeno di limitare gli accessi sfruttando la rete di partner antifrode a cui Epic Games si appoggia (tra cui ISP, fornitori di browser e aziende che sviluppano antivirus) che potrebbero inviare un messaggio di avviso simile al seguente: 

Image1.png
 
Un team intero sta lavorando sodo per individuare nuovi siti di malware non appena compaiono. Inoltre, abbiamo assunto un indirizzo IP di terzi e un'agenzia che si occupa di far rispettare i regolamenti antifrode per vigilare ancora più attentamente. Grazie a queste collaborazioni, siamo in grado di individuare e monitorare i nuovi domini che vengono registrati con URL sospetti; se dovessero rivelarsi siti malevoli, Epic Games potrà quindi prendere adeguati provvedimenti, compreso adire le vie legali.

PER CONCLUDERE

L'edizione di Fortnite per Android è davvero pioniera nel settore: è il primo gioco per console e PC ad arrivare su dispositivi mobili Android continuando a garantire il cross-play e piena compatibilità ed è anche il primo gioco con diffusione di massa a non essere lanciato su Google Play. È stata davvero un'impresa titanica e sono molte le cose che abbiamo dovuto imparare, ma il fatto che 15 milioni di utenti Android abbiano già scelto di scaricare Fortnite è senza dubbio un ottimo successo. Possiamo dire di essere sulla strada giusta. E, cosa ancora più importante, tutto il lavoro tecnico necessario per lanciare Fortnite su Android verrà messo a disposizione degli sviluppatori che usano Unreal Engine con la versione 4.21; è sempre un grande piacere condividere i nostri progressi.