informatica, videogame

Come Crash Bandicoot ha hackerato la PlayStation

Crash Bandicoot è stato il primo gioco PlayStation ad offrire una grafica incredibile perché poteva usare molta più memoria rispetto agli altri. Sapete come mai?

Andrea Scianò Andrea Scianò 10 Mag 2020 · lettura da 5 min
Come Crash Bandicoot ha hackerato la PlayStation

Giorni fa, ho visto una bellissima video-intervista ad Andy Gavin, creatore di Crash Bandicoot e della sua casa di sviluppo originaria, Naugthy Dog, famosa anche per altri numerosi successi.

In questo racconto, Andy contestualizza il periodo in cui lui ed il suo team hanno creato la famosissima mascotte, riprendendo e spiegando da vari punti di vista tutto il processo che li ha portati a creare un capolavoro entrato di diritto nella storia dei videogame.

A mio avviso, una delle parti più interessanti è la problematica tecnica legata alla memoria della PlayStation e cosa dovettero inventarsi per far raggiungere al gioco prestazioni allora impensabili: per me quest'uomo è un fucking genius.

La RAM era allora di 2 MB mentre i livelli in media occupavano più di 10 MB di dati, questo fu possibile perchè Gavin, come racconta nell'intervista, scrisse un incredibile sistema di paging che avrebbe scambiato pagine di dati da 64KB l'una mentre Crash attraversava il livello!

Dave Baggett, uno dei programmatori del team di allora che scrisse un compressore per i dati, racconta che per mettere in piedi tale sistema di paging, si prese in considerazione tutto: dalla gestione della memoria di alto livello alla codifica DMA a livello di opcode. Andy controllò persino il layout fisico dei byte sul CD-ROM in modo che, anche a 300 Kb/sec, la PlayStation 1 avrebbe potuto caricare i dati necessari per ogni pezzo di un determinato livello, prima che Crash finisse fisicamente lì.

Per far stare livelli da 10MB in 2MB, Dave scrisse il packer tool: un sistema che comprimeva e divideva i dati in modo da essere pronti a stare su una pagina da 64KB. Si prendevano tutte le risorse quali suoni, arte, codice, ecc, e le si impacchettavano in 64K pagine per il sistema di Andy.

Una dimostrazione del fatto che sia un problema molto complesso è che produrre il contenuto ideale per pagine di dimensioni fisse di una serie di oggetti di dimensioni arbitrarie è NP-completo, probabilmente impossibile da risolvere in modo ottimale in un polinomio (ovvero in un tempo ragionevole) e si riconduce al classico problema dello zaino, detto anche Knapsack problem, un problema di ottimizzazione combinatoria posto nel modo seguente.

Sia dato uno zaino che possa sopportare un determinato peso e siano dati N oggetti, ognuno dei quali caratterizzato da un peso e un valore. Il problema si pone come obbiettivo quello di scegliere quali oggetti mettere nello zaino per ottenere il maggiore valore senza eccedere il peso sostenibile dallo zaino stesso.

Per questo motivo il packer utilizzava una varietà di algoritmi come best fit, first-fit e altri, proprio per cercare di trovare il miglior imballaggio. Fondamentalmente, si provavano diverse strategie per poi utilizzare il risultato migliore.

Il problema con l'utilizzo di una ricerca come quella, tuttavia, è che non si sa mai se si otterrà sempre lo stesso risultato.
Avere un sistema così fragile significava che, una volta impacchettato il livello, poteva succedere che modificando il codice di una banale tartaruga, non si riuscisse più a trovare un imballaggio corretto.
Dave racconta che in alcuni momenti, degli artisti avrebbero voluto cambiare qualcosa ma ciò era impossibile perchè avrebbe fatto saltare il conteggio delle pagine, e i programmatori avrebbero dovuto cambiare altre cose in modo semi-casuale fino a quando il packer non avrebbe trovato di nuovo un imballaggio che potesse andar bene!

Un'altra parte delicata era far sì che il codice C/assembly potesse starci in termini di dimensioni. Anche in questo caso si esplorarono tutte le possibilità per fare in modo che il compilatore producesse codice di 200, 125, 50, quindi 8 byte più piccolo.
Per far capire quanto fosse importante il dettaglio, i dev si trovarono a convertire cicli come for (i = 0; i < x; i ++) in cicli while per poter riutilizzare qualche variabile creata in precedenza per risparmiare il contatore.
Oppure memorizzare dati nei due bit meno significativi degli indirizzi dei puntatori (che funzionava solo perché tutti gli indirizzi erano allineati a 4 byte).

Alla fine, tutto questo grande sforzo permise di far stare Crash nella memoria della prima PlayStation con soli 4 byte di disavanzo!
Sì, avete letto bene, 4 byte su 2097152!
Per questo motivo, e per altri che potete trovare nel video, l'intervista mi ha colpito molto, a tal punto che mi sono permesso di prenderla, tradurla ed applicarle i sottotitoli in italiano per poi postarla qui.
L'intervista originale è stata effettuata da ARS technica, una magazine che spesso offre spunti molto interessanti.
L'intervista integrale dura poco più di 2 ore ed è disponibile (in inglese) su questo canale Youtube.

Sperando di aver fatto cosa gradita, vi auguro buona visione. 🙂