![]() ![]() |
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 0Bittitasoille 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,viewportYllä 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 rtsJä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:lleJa 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 rtsEnää 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 rtsOtetaan 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,$fffeTä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! :)
|
![]() ![]() ![]() |