English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 29 May 2012, 11:21   #1
phx
Natteravn
 
phx's Avatar
 
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?
phx is offline  
Old 29 May 2012, 12:29   #2
Asman
68k
 
Asman's Avatar
 
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)
Asman is offline  
Old 29 May 2012, 12:54   #3
Codetapper
2 contact me: email only!
 
Codetapper's Avatar
 
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.
Codetapper is offline  
Old 29 May 2012, 14:54   #4
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Asman View Post
I guess that you using AGA machine and FMODE is set to 0, right ?
Tested on both OCS and AGA. But I make sure to disable AGA completely, which includes FMODE=0.

Quote:
Originally Posted by Asman View Post
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.
Exactly.
phx is offline  
Old 29 May 2012, 15:09   #5
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Codetapper View Post
When the shift (scroll) value is set to 0, the Amiga will only fetch 20 words of data not 21.
Really? That's something which I don't remember from the good old times. And I didn't expect that from reading the HRM either.

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:
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.
$38-$d0 would only fetch 19 words. Are you sure?
But it would explain the additional two bytes in the modulo.

Quote:
When there is a shift value, you set DDFSTRT to $30, DDFSTOP remains at $d0, and modulo would be (4 planes * 42 bytes) = 168.
Hmm.
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:
I suspect your DDFSTOP value is too high.
Possible.

Quote:
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.
You're right. That makes sense for the faster scrolling algorithm. Currently I'm blitting the full screen in every frame, so it doesn't matter.
phx is offline  
Old 29 May 2012, 20:46   #6
Codetapper
2 contact me: email only!
 
Codetapper's Avatar
 
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
And then with a shift value:

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
I assume this is the normal way, otherwise you are wasting CPU time fetching an extra word on every single line which will never be displayed, and have to remember that when you're at 0, you can't actually see that far left block of tiles. And yes I change BPL1MOD, DDFSTRT and BPLCON1 when required directly in the copperlist.
Codetapper is offline  
Old 30 May 2012, 10:09   #7
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Indeed, you're right! The HRM says:
Code:
DDFSTRT = DDFSTOP-(8*(word count-1))
So the hardware fetches one word more than the difference DDFSTOP-DDFSTART makes you assume. Seems I forgot that over the years.

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.
phx is offline  
Old 30 May 2012, 12:23   #8
Codetapper
2 contact me: email only!
 
Codetapper's Avatar
 
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.
Codetapper is offline  
Old 31 May 2012, 20:51   #9
Photon
Moderator
 
Photon's Avatar
 
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
gives

Code:
w=336
h=256
bpls=5
bpl=w/8+xtra
bwid=bpl*bpls

Buff0:
   ds.b bwid*hgt
and then, simply adding xtra to modulos for blitter and copper helps keep things sane and easy to read.

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.
Photon is offline  
Old 31 May 2012, 23:40   #10
Codetapper
2 contact me: email only!
 
Codetapper's Avatar
 
Join Date: May 2001
Location: Auckland / New Zealand
Posts: 3,182
Quote:
Originally Posted by Photon View Post
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).
That's not completely true. I have a scrolling game that goes both left and right, and because of memory restrictions I am only using a single buffer AND the blitter is not used to draw new tiles (as they are in fast memory if found).

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!
Codetapper is offline  
Old 02 June 2012, 02:04   #11
Photon
Moderator
 
Photon's Avatar
 
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.
Photon is offline  
Old 02 June 2012, 02:58   #12
Codetapper
2 contact me: email only!
 
Codetapper's Avatar
 
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.
Codetapper is offline  
Old 02 June 2012, 22:47   #13
Photon
Moderator
 
Photon's Avatar
 
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.
Photon is offline  
 


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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 14:15.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.13125 seconds with 13 queries