29 May 2012, 11:21 | #1 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
|
BPLxMOD for interleaved bitmaps
It's at least 15 years ago when I last programmed the chipset, but this confuses me:
I want to display a soft-scrolling screen of 320x240 pixels. To use the scroll-delay in BPLCON1 I have to fetch an additional word each line. So the usual DDFSTRT of $38 becomes $30, with DDFSTOP still at $d8. This means I have 42 bytes each line. For an interleaved 32 color bitmap I will point BPL1PT to the bitmap's start address, BPL2PT to bitmap+42, BPL3PT to bitmap+84 and so on. Now the BPLxMOD. I thought that when the hardware has read its 21 words for a line it has to skip 4 * 21 words (for the other 4 interleaved bitplanes) to advance to the start address of the next line. So I set BPLxMOD to 4*42 = 168. But that's wrong! It simply didn't work. With some experiments I got the expected result then setting the BPLxMOD to 166. Two bytes are missing. Why? |
29 May 2012, 12:29 | #2 |
68k
Join Date: Sep 2005
Location: Somewhere
Posts: 828
|
I guess that you using AGA machine and FMODE is set to 0, right ?
And if I understand correctly, when modulo is set to 166, then this simple block of code shows two lines ( second line is exactly under first one ) 16 pixels long with color01. Code:
SCR_DEPTH = 5 SCR_BROW = 42 SCR_NEXTLINE = SCR_DEPTH*SCR_BROW lea screen,a0 moveq #-1,d0 move.w d0,(a0) move.w d0,SCR_NEXTLINE(a0) |
29 May 2012, 12:54 | #3 |
2 contact me: email only!
Join Date: May 2001
Location: Auckland / New Zealand
Posts: 3,182
|
When the shift (scroll) value is set to 0, the Amiga will only fetch 20 words of data not 21.
The usual method is when there is no shift value (assuming 1 pixel/frame then it'd be every 16 frames) you set DDFSTRT to $38, DDFSTOP to $d0 and the modulo would be (4 planes * 42 bytes) + 2 bytes = 170. When there is a shift value, you set DDFSTRT to $30, DDFSTOP remains at $d0, and modulo would be (4 planes * 42 bytes) = 168. I suspect your DDFSTOP value is too high. Incidentally with this method, when you reach the edge you will have to plot an entire column of tiles down the side in one frame. Usually it's better to make the screen an extra word wide, always have a complete column of tiles ready to scroll on, and plot into the next column, thus make it at least 44 bytes wide per line. |
29 May 2012, 14:54 | #4 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
|
Tested on both OCS and AGA. But I make sure to disable AGA completely, which includes FMODE=0.
Exactly. |
29 May 2012, 15:09 | #5 | |||||
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
|
Quote:
This would mean I have to put DDFSTRT, DDFSTOP and BPLxMOD into the copperlist and adapt them for scroll&15==0 and the other cases? Sounds strange... Quote:
But it would explain the additional two bytes in the modulo. Quote:
What I am doing ATM is to start blitting the tiles at bitmap+2, whenever the scroll-position can be divided by 16 (i.e. scroll value is 0), and to the bitmap start address otherwise. But that could be nonsense. Quote:
Quote:
|
|||||
29 May 2012, 20:46 | #6 |
2 contact me: email only!
Join Date: May 2001
Location: Auckland / New Zealand
Posts: 3,182
|
Here's part of the copperlist of an example I did with a 320 wide screen, firstly with no scroll on the screen:
Code:
000004c0: 3001 ff00 ; Wait for vpos >= 0x30, ignore horizontal. ; VP 30, VE 7f; HP 00, HE 00; BFD 1 000004c4: 0108 00c8 ; BPL1MOD := 0x00c8 000004c8: 010a 00c8 ; BPL2MOD := 0x00c8 000004cc: 0092 0038 ; DDFSTRT := 0x0038 000004d0: 0094 00d0 ; DDFSTOP := 0x00d0 000004d4: 008e 3481 ; DIWSTRT := 0x3481 000004d8: 0090 24c1 ; DIWSTOP := 0x24c1 000004dc: 0102 0000 ; BPLCON1 := 0x0000 000004e0: 0104 0000 ; BPLCON2 := 0x0000 Code:
000004c0: 3001 ff00 ; Wait for vpos >= 0x30, ignore horizontal. ; VP 30, VE 7f; HP 00, HE 00; BFD 1 000004c4: 0108 00c6 ; BPL1MOD := 0x00c6 000004c8: 010a 00c6 ; BPL2MOD := 0x00c6 000004cc: 0092 0030 ; DDFSTRT := 0x0030 000004d0: 0094 00d0 ; DDFSTOP := 0x00d0 000004d4: 008e 3481 ; DIWSTRT := 0x3481 000004d8: 0090 24c1 ; DIWSTOP := 0x24c1 000004dc: 0102 00cc ; BPLCON1 := 0x00cc 000004e0: 0104 0000 ; BPLCON2 := 0x0000 |
30 May 2012, 10:09 | #7 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
|
Indeed, you're right! The HRM says:
Code:
DDFSTRT = DDFSTOP-(8*(word count-1)) This explains my modulo problems, because I fetched one additional, useless, word with DDFSTOP=$d8. Also thanks for the trick with changing DDFSTRT and BPLxMOD during scrolling. |
30 May 2012, 12:23 | #8 |
2 contact me: email only!
Join Date: May 2001
Location: Auckland / New Zealand
Posts: 3,182
|
I just checked the copperlist of a few games and it seems my method is not at all normal (unless I picked a weird bunch of games). Most games seem happy to leave the DDFSTRT value alone, and when there is no scroll they must take 2 off the bitplane address before stuffing it into the copperlist.
Of course it wastes some extra DMA time as you're pointlessly fetching a word that will never be displayed sometimes, but I guess they do it to keep everything consistent. If the timing is so critical that fetching one less word per line means the game stays at 50Hz with no scrolling, then for all other scroll positions it would presumably drop a frame and run at 25Hz most of the time! I guess it doesn't really matter too much either way, you either detect no scroll and take 2 off the bitplane pointers or change the DDFSTRT and modulos. |
31 May 2012, 20:51 | #9 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
There's no gain in changing DDFSTRT/STOP every 16th frame, unless you have something running that takes 5 scanlines that exact frame only. And then you should aim to distribute that over frames instead, to avoid jumps in "rastertime left before stutter". It's the maximum rastertime that causes a stutter or not, not the average, so "evenness" is much more important for optimization than saving cycles.
For a scrollable standard 320x256 screen, just set to $30/$d0, DIWSTRT to $81/$c1 as usual, and you can scroll your heart out and DIWSTRT will cover the 0-15 pixels at the left edge. Organization of bitplanes is entirely unrelated to how it's displayed. To not see any 16x16 blocks or whatever being drawn as they're scrolled in, you just add a few bytes to the bitplane-width. I always use these simple constants and use them to make the program dynamic: Code:
w=336 h=256 bpls=5 bpl=w/8 bwid=bpl*bpls Buff0: ds.b bwid*hgt And then modulos become a simple dc.w $108,bwid-bpl and blits modulos become bwid-bobwid or bpl-bobwid respectively, depending on whether you blit several bitplanes at once or one at a time for some reason. With extra bytes to draw into (offscreen), adding Code:
xtra=16/8 ;16 pixels=2 bytes outside Code:
w=336 h=256 bpls=5 bpl=w/8+xtra bwid=bpl*bpls Buff0: ds.b bwid*hgt You never need to add more bytes offscreen than your widest offscreen blit, and you never have to make space on "either side", just on the right. Just reserve xtra bytes below the screen start address for the first line if scrolling right (player going left). The only reason to not use interleaved bitplanes is to save memory. F.ex. if one bitplane can be made less tall by mirroring or scaling or whatever. I.e. if it's a custom display. |
31 May 2012, 23:40 | #10 | |
2 contact me: email only!
Join Date: May 2001
Location: Auckland / New Zealand
Posts: 3,182
|
Quote:
With this (admitedly abnormal) setup you need far more "xtra" bytes because the blitter maybe blitting into an off-screen area that the tiles are being drawn into with the CPU, and if that happens when you restore the graphics some maybe corrupt. Plus you need a strip of tiles on each side of the screen as the player maybe on a 16 pixel boundary and could go either direction. With certain scroll positions and blit shift positions, I require another strip to be safe, otherwise corruption occurs. So if you are using the blitter to draw everything, I would agree with Photon but there are certainly situations where this is not a 100% rule! |
|
02 June 2012, 02:04 | #11 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
That's more of a problem of CPU fighting with the blitter over the same memory addresses, and even with that setup it just takes making a proper render loop to fix. If you don't want to blit background, THEN blit tiles or bobs you're basically trying to double-buffer the margin with just one buffer.
This doesn't affect the point of not having to "add extra bytes in both margins if it scrolls both ways". You may want to add more bytes than "xtra" for many reasons, including making bwid a power of 2 to save 6 cycles over a LUT and distributing fast-scrolling tile blits over several frames. It's very rare that you'd need to, though, and the goal was to separate the concepts involved in making any and all scrolling games or demos. If you discover you have a lot of work to do in the margin, you just increase xtra and don't have to change anything in the code. Last edited by Photon; 02 June 2012 at 02:10. |
02 June 2012, 02:58 | #12 |
2 contact me: email only!
Join Date: May 2001
Location: Auckland / New Zealand
Posts: 3,182
|
If the tiles are in fast memory, then you can't blit them. So you either do all the blitting and then use the CPU to copy the tiles (which may mean the game drops a frame) or setup a blitter queue of all drawing operations for the next frame and let the CPU do it's work copying the tiles in at the same time.
If you're blitting large objects, it's silly to have the CPU in a busy wait loop. The "add extra bytes in both margins" point is that if you have say 4 extra words then you are effectively putting 2 on either side of the screen. It's still a gap of 4 words whether you pretend to be adding them to the left, right or both sides. Either side of the screen needs a row of tiles ready to be scrolled on at all times. |
02 June 2012, 22:47 | #13 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
No, because when scrolling leftward you start blitting a tileset (partial tile-column) in the word that was previously between DIWSTRT and DDFSTRT; the xtra bytes still contains a valid, previously blitted tile-column, providing 16/maxspeed frames in which to blit tilesets.
If direction changes the frame after, you go back to blitting tilesets in the xtra-bytes, the valid column that was put between DIWSTRT and DDFSTRT again providing 16/maxspeed frames in which to blit partial tile-columns. It doesn't matter whether the tiles are 8, 16 or 32 wide - as long the largest blit in 16px wide, xtra can be 2 in each case. Only if the largest blit is wider than 2 bytes need xtra be increased. If you're forced to write a tile render routine that doesn't have a tile-column ready when the screen has scrolled a full 16px in any direction, only then do you need margins wider than the largest blit. If you can re-write it to one that couples BPLCON1 ranges with specific tilesets, you've solved it! I know it can be tricky sometimes to decide why you need wider margins in a scroll routine, and it's really no problem just adding the margin, it doesn't steal many bytes and it solves the problem instantly and you can focus on things that are more fun But it certainly isn't necessary, and I hope I've shown that. |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Raw Interleaved Graphics | Hungry Horace | Coders. General | 12 | 28 January 2023 23:30 |
Bitmaps in FASTRAM and blitting - C++ | NovaCoder | Coders. General | 22 | 01 December 2010 23:40 |
Bitmaps Brothers | Djay | request.Old Rare Games | 22 | 23 November 2003 21:18 |
KOCH to publish new Bitmaps RTS | LaundroMat | Amiga scene | 1 | 17 January 2003 17:36 |
|
|