[zxspectrum] Strategie antiflickering


Il giorno 15/ago/07, alle ore 15:28, Stefano Bodrato ha scritto:

>Zurillion wrote:
>> La discussione col mitico EMG, mi ha fatto ricordare del capostipite >> di tutti i programmi di scacchi sui computer Sinclair: il *mitico* 1K
>> ZX Chess per lo ZX81.
>>
>Anche se non mi nutro esattamente di Assembler, credo che ci troviamo di
>fronte a qualcosa di storicamente incredibile.
>
>A mio personalissimo giudizio, rappresenta un'espressione di genialità
>che ha indubbiamente nobilitato lo zx81.

Concordo.
Ho scoperto un capolavoro altrettanto incredibile per lo ZX80: esiste un gioco di "Space Invaders" estremamente fluido e veloce, oltre che compatto. La sua caratteristica più interessante in questo caso è che non ha flickering.. in pratica il codice si occupa anche di tenere lo schermo in sincronia.


A proposito dell'eliminazione del flickering e dell'arte della programmazione assembler, ricordo come rimasi affascinato quando compresi finalmente, verso il 1986, le tecniche geniali che i programmatori avevano ideato per evitare il flickering sullo Spectrum.

[ Quello che segue sarà arcinoto a molti di voi, lo scrivo per gli altri ;-) ].

Il flickering avviene soprattutto perché il pennello elettronico traccia lo schermo dall'alto verso il basso, e la ULA si premunisce di fornire le informazioni per il pennello leggendole dalla memoria video a mano a mano che servono (rubando cicli di clock al processore).

Ora, ridisegnare uno sprite che si sposta, significa cancellarne la vecchia immagine (o parte di essa) e scrivere in memoria video l'immagine nuova. Se ciò avviene mentre l'ULA sta leggendo quella porzione di memoria video, si ha il flickering, in quanto una parte dello sprite verrà tracciata nella nuova forma, mentre un'altra parte aderirà al vecchio disegno (oppure sarà "sbiancata" in quanto l'ULA ha letto mentre noi stavamo cancellando il vecchio sprite).

La tecnica principale per evitare ciò consiste nel temporizzare le routine di tracciamento. Essendo il PAL un sistema interlacciato, il cannone video traccia un primo semiquadro (le linee dispari, ad esempio), poi traccia il secondo semiquadro, completando l'immagine (quadro), e infine ripete tutto, 25 volte al secondo ( per cui ci sono 50 semiquadri al secondo). Poiché il cannone, completato un semiquadro, non si può spostare istantaneamente in alto per ricominciare c'è un tempo morto: il segnale PAL trasmette periodicamente 625 linee, di cui solo 576 linee sono effettivamente mostrate a video. In questo modo il cannone ha modo di risalire, e le "linee" aggiuntive sono utilizzate per mandare vari segnali di controllo (il televideo utilizza parte di queste "linee fantasma" per inviare le proprie pagine).

Insomma, il trucco principale per evitare il flickering, è di eseguire tutte le routine di ritracciamento degli sprite nel tempo morto in cui il pennello elettronico non sta tracciando a video.

Dunque, ogni 1/50 di secondo, esiste un periodo di tempo (lungo circa 768 microsecondi) che può essere sfruttato per scrivere "impunemente" in memoria video.

Ma come si fa in un programma ad individuare tale tempo morto? Semplice: il segnale di interrupt è sincronizzato con il quadro video, per cui è possibile (ma non semplicissimo) scrivere una routine a interruzione di programma che tracci gli sprite nel momento giusto.

Naturalmente, come si scoprì più avanti nella storia dello Spectrum, il fatto che la ULA legga i valori da mandare a video "just in time" può essere sfruttato creativamente, per cambiare le carte in tavola alla ULA MENTRE sta scandendo la memoria video. Nascono da qui tutti gli effetti coloristici incredibili delle demo che si sono viste nel secondo periodo di vita dello Spectrum (un programma che anticipò sorprendentemente questa tecnica fu Aquaplane, che tracciava un orizzone colorato a tutto schermo, modificando il valore del Border "al volo" quando il pennello elettronico era arrivato al punto desiderato).

In ogni caso, effettuare tutti i ritracciamenti grafici nell'angusta finestra di 768 microsecondi era spesso impossibile, e così venne inventata una tecnica secondo me del tutto GENIALE (non ricordo se i primi a utilizzarla furono quelli della Ultimate o The Edge):

Visto che il pennello elettronico va dall'alto verso il basso, può capitare che il ritracciamento dello sprite proceda con velocità simile a quella di lettura della ULA. In questo caso i due processi si possono "superare" a vicenda più e più volte, ottenendo l'effetto di uno sprite "frankenstein", contenente pezzi della versione da ritracciare e pezzi ritracciati --> flickering!

Ed ecco l'idea GENIALE: effettuare tutto il ritracciamento ALLA ROVESCIA!!!!

Mi spiego meglio: scrivendo una porzione di codice assembler per copiare uno sprite in memoria video è intuitivo copiare prima i byte "bassi" e poi quelli "alti", ovvero procedere per indirizzi di memoria crescente. Ma questo può creare proprio quella situazione di cui si diceva sopra.

Se invece copiamo lo sprite in memoria video secondo indirizzi DECRESCENTI, allora IL PENNELLO ELETTRONICO (meglio: l'ULA) PUO' INCROCIARE IL RITRACCIAMENTO DELLO SPRITE AL MASSIMO UNA SOLA VOLTA !!!!! Dal punto di vista del quadro video, è come se tracciassimo Willy il minatore partendo dai piedi e finendo con il cappello.

Con questo semplice accorgimento si riduce al minimo il flickering!!!

In definitiva:

1. si temporizznoa le routine di ritracciamento con l'ingresso nella "zona morta"

2. si traccia tutto dal basso verso l'alto (nel senso del video), così se la routine "sfora" il danno sarà molto contenuto


Non so se qualcuno di voi è arrivato qui in fondo, se sì vi prego di osservare con me 768 microsecondi di silenzio in onore di quei geni che hanno pensato queste cose negli anni '80.

Ciao,
   Giovanni

Other related posts: