\articolo{{\em Tornado 3D}: lo sviluppo di un software di grafica 3D in 
linea con i tempi}{Massimiliano Marras}

\index{Marras!articolo di}

\paragrafo{Doverosa precisazione}
State per leggere la presentazione di un nuovo prodotto commerciale per
\A: un software di modellazione, animazione e rendering\index{rendering}
chiamato {\em Tornado 3D\index{Tornado 3D}}. Poich\'e sono tanto l'autore
di questa presentazione quanto l'autore del programma, \`e perfettamente
lecito avere dei dubbi su quanto leggerete. In attesa che {\em Tornado 3D}
sia distribuito al pubblico (a dicembre) e possiate verificare di persona,
mi auguro che alcune delle ottimizzazioni e dei metodi descritti in questo
articolo tornino utili alla comunit\`a dei programmatori \A.


\paragrafo{Il software di ieri}

``Dimmi, in quale anno siamo?'' Innumerevoli film sui viaggi nel tempo
hanno sfruttato questa battuta, generando inevitabilmente un sorriso nello
spettatore. Per quanto drammatica possa essere la situazione rappresentata,
domandare ``in quale anno'' si \`e, sfocia sempre nel ridicolo,
nell'assurdo. Eppure, guardando certo software 3D per \A, magari targato
proprio '96, si ha in qualche modo la sensazione di essere vittime di una
distorsione temporale. Requester non standard, font topaz-8 non
modificabili, sedici colori anche su schermi da sedici milioni di colori,
preview wireframe in bianco e nero e naturalmente il mouse che si muove a
scatti durante i calcoli. I partecipanti ad Ipisa sanno bene che queste
mancanze non sono da imputare ad \A quanto alle software house, ma per
la maggior parte degli utenti ci\`o che conta non \`e la teoria quanto la
pratica, e confrontare lo stesso programma su un Pentium 100\unit{Mhz} e su
di un Amiga 68060\index{68060} con scheda grafica getta spesso nello sconforto. Il
programma che su PC \`e colorato e veloce, su \A appare smorto e lento.
Certo, la versione \A ``gira'' anche senza FPU, con pochi megabyte di
RAM, e funziona anche con un sistema operativo vecchio di otto anni, ma
questi sono davvero meriti? Per un gioco, un wordprocessor o un programma
di paint, prodotti che interessano un largo pubblico, certamente s\`{\i}.
Uno dei grandi meriti di \A \`e proprio l'aver contribuito
significativamente alla diffusione dei computer tra la gente, senza bisogno
di camici bianchi e continue, forzate, upgrade. Il discorso cambia, e
molto, quando pensiamo all'altra faccia di \A: non pi\`u home computer
``amichevole'' ma strumento professionale, di costo e prestazioni elevate.
Chi investe molti milioni su un sistema \A moderno, ad esempio \A
4000 con 68060 e CyberVision\index{CyberVision} 64, pu\`o legittimamente
aspettarsi di fare con esso {\em le stesse cose} che vede fare su di un
Pentium 100\unit{Mhz} {\em se non di pi\`u}. Altrimenti la tentazione di
vendere tutto e cambiare ambiente operativo \`e forte.


\paragrafo{{\em Tornado 3D}: un software per gli \A di oggi}

Lo sviluppo di {\em Tornado 3D} ha avuto inizio nel 1992, nella convinzione
che gi\`a allora si potesse fare qualcosa di pi\`u rispetto a quanto era
disponibile. La scintilla che ha dato inizio a tutto \`e stata l'arrivo
dell'allora nuovissimo Amiga 4000/040. Aperto lo scatolone e installata la
macchina non si poteva non notare l'aumento enorme di prestazioni rispetto
al vecchio Amiga 3000 al suo fianco. Ma i primi rendering effettuati con un
ben noto software 3D, raffreddarono immediatamente l'entusiasmo: il
4000/040 25\unit{Mhz} risultava appena il 20\% pi\`u veloce del 3000/030
quando si usavano tessiture matematiche! Questo test pu\`o essere fatto
anche oggi: quattro anni e tre versioni dopo, quel software continua ad
usare istruzioni non implementate sul 68040/060. Questo \`e anche il motivo
per cui un Pentium 100\unit{Mhz} risulta ``essere'' 14 volte pi\`u veloce
del 4000/040 e due volte e mezza pi\`u veloce del 68060: codice non
ottimizzato, mentre i compilatori per PC offrono moltitudini di
ottimizzazioni per Pentium. Anche la definizione di codice ``non
ottimizzato'' \`e impropria: sembra che le prestazioni non siano {\em
ottimali} quando in realt\`a bisognerebbe definirle disastrose. Vediamo di
spiegare perch\'e: come \`e noto il 68040 e il 68060 dispongono di una
versione ridotta del coprocessore matematico 68881/2, priva di molte
istruzioni (quelle presenti sono per\`o molto veloci). Un programma scritto
per l'accoppiata 68030/882 contiene al suo interno queste istruzioni non
implementate (ad esempio FCOS, che calcola il coseno) e naturalmente tenta
di eseguirle anche su 040/060; il risultato \`e una trap e l'emulazione
dell'istruzione mancante via software. Per capire quanto impatto abbia
ci\`o sulle prestazioni di un programma basta pensare che tutto il tempo
durante il quale il puntatore del mouse rimane bloccato il computer non sta
in realt\`a facendo nulla di utile: sopperisce alle mancanze di un codice
inadatto. Se vogliamo veramente spaventarci, leggiamo cosa dice la Motorola
in proposito nel ``M68040 microprocessor's user manual'': ``Quando una
istruzione floating-point non implementata viene incontrata, il processore
attende che tutte le precedenti operazioni FP siano completate [\ldots]
l'istruzione viene decodificata parzialmente per ricavare l'operando
[\ldots] l'operando viene passato alla FPU che lo converte in precisione
estesa [\ldots] il processore inizia a gestire l'eccezione facendo una
copia dello {\em status register}, entra in modo supervisore, pulisce i bit
di trace, crea uno stack frame [\ldots] l'handler delle eccezioni emula
l'istruzione in software''. Abbiamo sintetizzato in poche righe una pagina
intera di descrizione, ma dovrebbe essere sufficiente per capire che
chiamare ``non ottimizzato'' un codice che effettua tutte queste operazioni
ogni volta che incontra una istruzione non implementata (in un rendering
640$\times$480 pu\`o capitare decine di milioni di volte!) \`e come
ostinarsi a guidare un'auto sportiva con il freno a mano inserito.

Una delle priorit\`a nello sviluppo di {\em Tornado 3D} \`e stata appunto
quella di non fare ricorso alle istruzioni emulate. Purtroppo il
compilatore SAS/C C 6.5 impiegato per scrivere {\em Tornado 3D} non \`e in
grado di generare del codice assolutamente esente da istruzioni emulate
per 68040/060. La soluzione \`e stata quella di riscrivere da capo una
libreria matematica che sostituisse le istruzioni emulate, e che potesse
essere compilata come codice inline in modo da evitare anche il costo
associato ad un salto a subroutine. La libreria di funzioni accetta
inoltre gli argomenti come ``FLOAT'' presentando un ulteriore vantaggio
rispetto alle librerie standard `C', tradizionalmente legate al tipo
``double''. Questo ha permesso, per esempio, di impiegare un numero
inferiore di termini nelle serie di Taylor usate per l'approssimazione di
molte funzioni, nonch\`e di sfruttare alcuni noti trucchi legati alla
rappresentazione interna dei dati in formato IEEE singola precisione (ad
esempio per il calcolo diretto della radice quadrata inversa, usata
spessissimo nei software 3D per normalizzare i vettori). Naturalmente
scrivere una libreria di funzioni non \`e che una parte dell'opera di
ottimizzazione, specialmente se si vuole supportare il 68060. Prendiamo ad
esempio questa linea di codice:
\begin{center}
\c{return((float)( x >=a ))}
\end{center}
sembra banale, un semplice cast a float del risultato di una
comparazione. Ritorna 1 se $x$ \`e maggiore od uguale ad $a$ e zero
altrimenti. La si preferisce alla verbosa:

\begin{codestyle}
  if (x >= a)	
    return((float)1.);	
  else
   return((float)0.);
\end{codestyle}

\noindent perch\'e un buon compilatore non genera nessun salto aumentando
la coerenza della cache. E infatti se guardiamo il codice prodotto dal
SAS/C sembrerebbe che:

\begin{codestyle}
;  347:	if(x>=a) return((FLOAT)1.);
;       else return((FLOAT)0.);
              FMOVE.X        FP1,FP2
              FMOVE.X        FP0,FP3
              FMOVE.S        FP0,$18(A7)
              FMOVE.S        FP1,$1c(A7)
              FCMP.B         FP3,FP2
              FBOLT.W        ___Step__4
___Step__2:
              FMOVE.S        #$3f800000,FP0
              BRA.B          ___Step__6
___Step__3:
___Step__4:
              FMOVE.S        #$0,FP0

\end{codestyle}

\noindent sia meno efficiente di:

\begin{codestyle}
;  348:	return((float)(x>=a));
              FMOVE.X        FP1,FP2
              FMOVE.X        FP0,FP3
              FCMP.B         FP3,FP2
              FSUGE.B        D0
              NEG.B          D0
              EXTB.L         D0
              FMOVE.L        D0,FP2
              FMOVE.X        FP2,FP0
\end{codestyle}

\noindent Ebbene, su di un 68060 il codice pi\`u ottimizzato \`e
``leggermente'' pi\`u lento rispetto a quello semplice. Il motivo? \c{FSUGE},
istruzione emulata su 68060. Quanto \`e il rallentamento? Per centomila
iterazioni la comparazione esplicita richiede 0,0229 secondi, che passano
ad uno spaventoso 4,84 secondi per il codice con l'istruzione emulata.
Stiamo parlando di una riga di codice che viene eseguita {\em 211 volte
pi\`u lentamente} di un'altra! Naturalmente come tutti i test questo \`e
poco significativo, non eseguiremo mai centomila volte di fila questa
comparazione, ma nella situazione reale dove abbiamo incontrato il
problema, cambiare quella sola linea ha prodotto un incremento di
velocit\`a pari a pi\`u di tre volte. Poich\`e queste linee di codice si
trovavano all'interno di una funzione piuttosto complessa (il calcolo
delle lens flares e degli effetti atmosferici) con abbondati \code{sqrt},
\code{sin()}, \code{cos()} e \code{atan2()}, l'output del profiler non \`e
servito a molto nello scovare il problema: si dava per scontato che il
tempo impiegato fosse dovuto alla complessit\`a delle operazioni, non ad
una istruzione emulata (essendo solo una, non si notava lo scatto del
puntatore, ovviamente \code{sin()} e \code{cos()} non sono istruzioni emulate,
appartenendo alla libreria proprietaria di {\em Tornado 3D}). Solo usando
il tool della Phase5 ``CyberSnooper\index{CyberSnooper}'' \`e stato
possibile identificare questa e molte altre occasioni nelle quali un banale
cambiamento portava a miglioramenti molto significativi. La morale? Non
fidarsi del compilatore\ldots


\paragrafo{I colori, quanti colori\ldots}
La ricordate? Era una delle frasi chiave nello spot televisivo dello
sfortunato CD$^{32}$. A quattro anni dall'avvento degli Aga e delle schede
grafiche 256 colori su schermo dovrebbero essere la norma, eppure ancora
oggi i software 3D mostrano preview a sedici colori, se non a due. Se poi
si prova ad aprirli su schermi a 16 o 24 bit sotto
CyberGraphX\index{CyberGraphX}, alcuni diventano lentissimi, altri si
rifiutano di farlo lamentandosi per il modo video ``illegale''. Di certo
non sfruttano i colori in pi\`u. {\em Tornado 3D} offre --- per la prima
volta su \A --- preview interattive a colori in modi flat, Gouraud,
transparent, textured, e photorealistic. Nei modi pi\`u semplici (fino a
textured) \`e possibile muovere la telecamera e anche modellare con una
preview in tempo reale a 16 e 24\unit{bit} su schermi CyberGraphX e a 256
colori diterati anche su schermi Aga. A parit\`a di risoluzione, il
rendering FlatShade che alcuni software (su uno '060) calcolano in 10
secondi, {\em Tornado 3D} riesce a calcolarlo e disegnarlo a video pi\`u di
25 volte al secondo! Nel modo Photorealistic, e questa \`e una novit\`a
assoluta, {\em Tornado 3D} permette gi\`a adesso di manipolare
interattivamente una approssimazione del rendering definitivo, con tanto di
ombre, rifrazioni, bumpmap e lens flares! Naturalmente non \`e veloce come
le altre funzioni di preview (pur essendo gi\`a utilizzabile
produttivamente con 68060 e schede grafiche), ma con il crescere della
potenza di elaborazione (si pensi ai recenti annunci della Phase5 sulla
disponibilit\`a di schede PowerAmiga 604 a 200\unit{Mhz} sar\`a possibile
navigare fluidamente nelle proprie scene con un vero e proprio rendering in
tempo reale.

Pur non potendo entrare nei dettagli delle tecniche impiegate per ottenere
questi risultati, vogliamo dare un'idea di massima della struttura aperta
adottata per {\em Tornado 3D} che potr\`a tornare utile a quanti vogliano
sviluppare software compatibile con le schede grafiche senza compromettere
le prestazioni. All'avvio {\em Tornado 3D} analizza il modo video richiesto
dall'utente e prepara i driver a basso livello necessari, e da quel momento
in poi non viene pi\`u eseguito nessun test per sapere cosa fare. Le
funzioni di ridisegno infatti, non vengono mai chiamate direttamente ma
solo tramite puntatori a funzioni, che si riadattano dinamicamente alla
situazione. Ogni driver agisce diversamente, garantendo per\`o che il
risultato sia lo stesso. Questo principio in realt\`a \`e intrinsecamente
legato alla struttura interna di {\em Tornado 3D}. Per fare un esempio, se
l'utente muove un oggetto (in pieno double buffering anche a 16/24 bit su
CyberGraphX/CyberVision 64, occupando la stessa quantit\`a di memoria usata
per i modi Amiga!) \`e l'oggetto stesso che sa come ridisegnarsi, sia sulle
viste ortogonali sia in prospettiva. Ogni oggetto infatti possiede il
proprio pool di memoria, le proprie routine di disegno e di rendering, i
propri ``costruttori'' e ``distruttori'', e queste funzioni possono anche
essere plug-in esterne. Al momento di disegnarsi sul video, o di essere
reso in una scena, l'oggetto chiama \code{AutoRender()}, \code{AutoDraw()}
etc. che del tutto automaticamente eseguiranno le operazioni necessarie. Se
\`e un oggetto poligonale probabilmente \code{AutoDraw()} corrisponder\`a
alla \code{PolyDrawInteractive()} o, se l'oggetto \`e troppo complesso per
la macchina su cui gira {\em Tornado 3D} in quel momento, alla
\code{BoxDrawInteractive()}. Se per\`o fosse un oggetto particellare, o una
metaball, o ancora un poligono frattale o una spline, ad essere chiamate
sarebbero le funzioni apposite e l'oggetto si disegnerebbe sempre
correttamente senza che sia mai necessario gestire casi speciali. A loro
volta, anche le funzioni di disegno e di rendering si adattano
dinamicamente alla situazione. Se l'utente ha aperto il programma a
24\unit{bit}, la preview a colori appare a 24\unit{bit}, se \`e in un modo
a 256 colori l'immagine viene diterata in modo del tutto trasparente,
cos\`{\i} come viene convertita in ham6 o in toni di grigio se si usa uno
schermo Aga a 6 bitplane. Ancora, se un determinato oggetto \`e interamente
visibile la funzione \code{ClipLine()} \`e automaticamente sostituita dalla
NoClipLine, risparmiando inutili test di clipping per ogni linea disegnata.
Naturalmente \`e necessario progettare il software in questo modo sin
dall'inizio, ma i risultati in termini di prestazioni sono davvero
notevoli.


\paragrafo{Alcune caratteristiche di {\em Tornado 3D}}
\begin{itemize}
\item modellazione\index{modellazione}, animazione, rendering integrati in
     un unico editor;

\item numero illimitato di progetti aperti contemporaneamente in finestre
      ridimensionabili;

\item preview interattiva a colori e rendering interattivo, anche in
      animazione;

\item animazione estremamente semplice, interfaccia stile videoregistatore,
      morphing automatico;

\item ottimizzato per 68040/68060 e CyberVision 64/CyberGraphX;

\item GUI font-adaptive standard GadTools, pieno supporto CyberGraphX e
      grafica \A;

\item ombre soffici, rifrazione ed effetti di atmosfera senza bisogno di
      raytracing\index{raytracing};

\item particelle ``single-point'', campi di forza, animazione procedurale;

\item rendering ad alta qualit\`a e velocit\`a mediante il ``deferred shading
      accumulation buffer'';

\item mappature: color, diffuse, reflect, filter, specular, bump, bright,
      polish, refract, clip, mask\ldots

\item antialias delle texture basato sulle ``summed area tables'' senza usare
      memoria aggiuntiva;

\item cinque tipi di nebbia, lens flare realistiche, motion blur velocissimo;

\item luci distanti, puntiformi, spot e l'esclusiva ``ombrello diffusore''
      per il massimo realismo;

\item e molto altro ancora\ldots
\end{itemize}
%
Qui di seguito potete osservare una schermata di {\em Tornado 3D} all'opera:
\begin{center}
\includegraphics[width=\columnwidth]{marras/pics/tornado.eps}
\end{center}

\autore{Massimiliano Marras\\
e-mail \c{mc1606@mclink.it}}{}

\citazione{\selectlanguage{english}
We see computers everywhere but in the productivity statistics}{Robert Solow}
