| Tuplapuskurointi |
| Markus Ketola |
| Tuplapuskurointi (tai kaksoispuskurointi, tässä käytetään nimitystä tuplapuskurointi (engl. double buffering)) on tekniikka, missä käytetään kahta bittikarttaa; toista näytetään, toiseen piirretään. Bittikarttojen funktion vaihto tehdään, kun näyttöruutua piirtävä elektronisuihku on kuvaruudun ala- tai ylälaidasssa. Näin saadaan aikaiseksi välkkymätön liike. Huomautettakoon vielä, että tämä juttu käsittelee tuplapuskuroinnin tekoa Classic Amigalla; tosin yhtä kaikki AmigaOnella tuplapuskuroinnin idea lienee sama. |
|
|
|
| Olen ottanut tähän artikkeliin mukaan kolme toteutusta: C-kielinen käyttöjärjestelmärutiineja käyttävä esimerkki, konekielinen käyttöjärjestelmärutiineja käyttävä esimerkki ja konekielinen suoraan erikoispiirejä käyttävä esimerkki eli ns. "hardiskoodausesimerkki". Jokaisessa näissä on tuplapuskuroinnin ohessa toteutettuna 3D-tähdet. 3D-tähtien toteutus ei ole mitenkään optimaalisen hyvin optimoitua koodia C-kielen puolella, mutta konekielipuolella koodi on 3D-tähtien osalta kohtuullisesti optimoitua. Tosin tuplapuskurointihan tässä pääasiana kuitenkin on.
C-kielisestä samoin kuin konekielisestä käyttöjärjestelmärutiineja käyttävästä ohjelmasta poistutaan painamalla ESC:iä. Jälkimmäisen 3D-tähtirutiinit on otettu suoraan hardiskoodatusta ja hieman mukailtu tarkoitusta vastaaviksi. Hardiskoodatusta versiosta poistutaan painamalla hiiren vasempaa nappia. 3D-tähtirutiini on monta vuotta sitten tekemäni, jossa on käytetty hieman apuna taannoisessa C-lehdessä julkaistua listausta. Molemmat konekieliset ohjelmat on käännetty 68040:lle. Assemblerina on käytetty Aminetista löytyvää PhxAss-assemblerin versiota 4.39, mutta kääntämisen pitäisi onnistua helposti muillakin assemblereilla. Ohessa olevassa paketissa ovat ohjelmat kokonaisuudessaan sekä lähdekoodin lisäksi vielä ajettavat. |
|
|
|
|
Tässä käytetään LibCall-nimistä makroa, jonka määrittely selviää täydellisestä listauksesta. Aloitetaan määrittelemällä BitMap-struktuurit:
myBitMap0 dc.w 40,256 ; Leveys tavuina, korkeus pikseleinä
dc.b 0,3 ; Liput, Syvyys
dc.w 0 ; Pad
dc.l BitPlane1_0
dc.l BitPlane2_0
dc.l BitPlane3_0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
myBitMap1 dc.w 40,256 ; Leveys tavuina, korkeus pikseleinä
dc.b 0,3 ; Liput, Syvyys
dc.w 0 ; Pad
dc.l BitPlane1_1
dc.l BitPlane2_1
dc.l BitPlane3_1
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
Bittitasoille voi varata muistia AllocMem-rutiinilla, mutta sen voi tehdä myös varaamalla Chip-muistista puskurin, ns. bss chunkin. Tehdään niin:
section Puskurit,bss,chip BitPlane1_0 ds.b 10240 BitPlane2_0 ds.b 10240 BitPlane3_0 ds.b 10240 BitPlane1_1 ds.b 10240 BitPlane2_1 ds.b 10240 BitPlane3_1 ds.b 10240NewScreen-struktuurissa täytyy näytön tyypiksi asettaa CUSTOMSCREEN!CUSTOMBITMAP (huutomerkki tarkoittaa or-operaatiota) sekä laittaa kenttään, joka viittaa käyttäjän määrittelemään BitMap-struktuuriin oman BitMap-struktuurin osoite. Otetaan tässä välissä talteen rastport- ja viewport-struktuurien osoitteet: move.l MinunIkkuna,a0 ; Otetaan ikkunan
move.l wd_RPort(a0),rastport ; rastport
move.l MinunNaytto,a0 ; Otetaan näyton
lea sc_ViewPort(a0),a0 ; viewport
move.l a0,viewport
Yllä oletetaan, että OpenScreen-rutiinin tulos on talletettu
MinunNaytto-nimiseen "muuttujaan" sekä vastaavasti oletetaan,
että OpenWindow-rutiinin tulos on talletettu MinunIkkuna-nimiseen
"muuttujaan". Jälleen kutsutaan WaitTOF- tai WaitBOVP-rutiinia ennen
bittikarttojen funktion vaihtoa. Ja seuraavaksi
tehdäänkin taas rutiini, joka asettaa toisen bittikartan
näytettäväksi ja toisen piirrettäväksi:
DoubleBuffering
tst.b Kumpi
beq.s zero
move.b #0,Kumpi
move.l viewport,a0
move.l vp_RasInfo(a0),a0
lea ri_BitMap(a0),a0
move.l #myBitMap1,(a0)
move.l rastport,a0
lea rp_BitMap(a0),a0
move.l #myBitMap0,(a0)
move.l viewport,a0
LibCall GFX,ScrollVPort
rts
zero move.b #1,Kumpi
move.l viewport,a0
move.l vp_RasInfo(a0),a0
lea ri_BitMap(a0),a0
move.l #myBitMap0,(a0)
move.l rastport,a0
lea rp_BitMap(a0),a0
move.l #myBitMap1,(a0)
move.l viewport,a0
LibCall GFX,ScrollVPort
rts
Jälleen ScrollVPort-rutiinia kutsutaan, jotta viewporttiin
tehdyt muutokset tulevat voimaan.
|
|
|
|
|
Tämä on siis ns. "hardiskoodausesimerkki". Aluksi on varattava muistia bittikarttoja varten. Tehdään se nyt AllocMem-rutiinia käyttäen:
move.l 4,a6 ; Execbase
move.l #30720,d0 ; Muistin määrä tavuina
move.l #65538,d1 ; MEMF_CHIP ja MEMF_CLEAR
jsr -$00c6(a6) ; AllocMem
move.l d0,BitMap0 ; Muisti BitMap0:lle
Ja vastaava BitMap1:lle.
Seuraavaksi tehdään rutiini, joka odottaa, että elektronisuihku on
kuvaruudun alalaidassa:
WaitForBeam move.w $dff004,d0 ; onko beam kuvaruudun alaosassa?
btst.l #0,d0
beq.s WaitForBeam
cmp.b #$2c,$dff006
bne.s WaitForBeam
rts
Enää ei oikeastaan tarvitsekaan muuta kuin vaihtaa bittikarttojen funktio
ja kirjoittaa bittikarttojen tiedot copperlistaan. Tehdään se nyt:
DoubleBuffering
cmp.b #1,Kumpi
beq.s YksKehiin
move.l BitMap0,ShowScreen
move.l BitMap1,DrawScreen
move.b #1,Kumpi
bra.s CopperListaan
YksKehiin
move.l BitMap1,ShowScreen
move.l BitMap0,DrawScreen
move.b #0,Kumpi
CopperListaan
move.l ShowScreen,d3 ; Tässä oletetaan, että
move.w d3,low1 ; yhden bittitason koko
swap d3 ; on 320 * 256 pikseliä eli
move.w d3,high1 ; 10240 tavua.
swap d3
add.l #10240,d3
move.w d3,low2
swap d3
move.w d3,high2
swap d3
add.l #10240,d3
move.w d3,low3
swap d3
move.w d3,high3
rts
Otetaan vielä palanen copperlistaa näkyviin:
CopperLista
dc.w $00e0 ; BPL1PTH
high1 dc.w $0000
dc.w $00e2 ; BPL1PTL
low1 dc.w $0000
dc.w $00e4 ; BPL2PTH
high2 dc.w $0000
dc.w $00e6 ; BPL2PTL
low2 dc.w $0000
dc.w $00e8 ; BPL3PTH
high3 dc.w $0000
dc.w $00ea ; BPL3PTL
low3 dc.w $0000
dc.w $0100,$3200 ; BPLCON0
dc.w $0102,$0000 ; BPLCON1
dc.w $0108,$0000 ; BPL1MOD
dc.w $010a,$0000 ; BPL2MOD
dc.w $0092,$0038 ; DDFSTRT
dc.w $0094,$00d0 ; DDFSTOP
dc.w $008e,$2c81 ; DIWSTRT
dc.w $0090,$2cc1 ; DIWSTOP
dc.w $ffff,$fffe
Tässä olikin kaikki, mitä tarvitsee tuplapuskuroinnin tekemisestä
tietää hardistasolla. Toki toimivan ohjelman aikaansaamiseksi
tulee vielä tietää mm. miten copperlista ylipäätään laitetaan päälle,
mutta se on käsitelty täydellisessä listauksessa. Tarkempi teoria
bittitasojen näyttämisestä hardistasolla sivuutetaan, mutta mainittakoon
DMACON-rekisteristä ($DFF096) kuitenkin, että sillä täytyy sallia DMA:n,
bittitasojen DMA:n ja copperin DMA:n käyttö biteillä 9, 8 ja 7 (1. bitti on 0).Copperlistassa on kommentteina rekistereiden nimet, joita käytetään, mutta merkitys jätetään lukijan oman tutkimisen varaan; developer CD 2.1:llä on AmigaGuide-muodossa Hardware Reference Manual, josta asiaa voi tutkia tarkemmin. |
|
|
|
|
Toivottavasti tästä artikkelista oli hyötyä sekä toivottavasti tämä innosti ohjelmoimaan; vaikka omista hardiskoodauksistani on kulunut pitkä aika, niin tätä artikkelia tehdessäni huomasin, kuinka hauskaa se on! Ja tuplapuskurointihan on perustekniikoita esim. pelien teossa. Ohjelmoikaamme ja pitäkäämme Amiga elossa! :)
|