Double buffering on the Spectrum

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Wall_Axe
Manic Miner
Posts: 491
Joined: Mon Nov 13, 2017 11:13 pm

Re: Double buffering on the Spectrum

Post by Wall_Axe »

" used the stack to copy the data and also rearranged the off screen buffer to a more sensible layout with each line following the other in memory."

this does sound like the best way for a lot of games
AndyC
Dynamite Dan
Posts: 1387
Joined: Mon Nov 13, 2017 5:12 am

Re: Double buffering on the Spectrum

Post by AndyC »

spectron wrote: Mon Apr 16, 2018 9:00 pm Being pedantic I'd like to leave the double buffering term for the 128k ability to swap memory whereas I'd always call the term of writing off screen then copying to the visible screen as back buffering. But that's a moot point.
Strictly speaking, double buffering is any technique which uses a single back buffer to draw in that is then used to update the screen (with triple buffering being the same but with two buffers and the main screen). The "proper" term for a double or triple buffer which uses a hardware switch to swap the buffers over is page flipping.
User avatar
MonkZy
Manic Miner
Posts: 278
Joined: Thu Feb 08, 2018 1:01 pm

Re: Double buffering on the Spectrum

Post by MonkZy »

Thank you all for this incredibly illuminating thread.

I have successfully coded a working sinus-scroller, although currently it flickers rather badly. My method could be described as placing 28 sprites along a pre-calculated sine wave (i used BASIC to create a lookup table which I copied into my source code). Each character/sprite memory address is calculated real time and the character is bit-shifted into position a line at a time, no lookup-tables. After a HALT I clear all the characters (by ld'ing 0's into RAM over each character position) and start over. I am starting to think I need some serious optimisation or possibly more lookup tables to achieve a true 50hz scroller. I most certainly will need to work out the floating bus method of sync'ing. Using HALT you waste the time the raster takes to fill the bottom border, and you are forced to place your scrolling text at the bottom of the screen.

I will continue, armed with more knowledge after reading this thread.
dfzx
Manic Miner
Posts: 673
Joined: Mon Nov 13, 2017 6:55 pm
Location: New Forest, UK
Contact:

Re: Double buffering on the Spectrum

Post by dfzx »

Wall_Axe wrote: Mon Apr 16, 2018 7:52 pm if you put the still stuff like score and logo in the top third of the screen
and simply used interrupt mode 2,
to use the time the raster takes to traverse the first third of the screen..
to draw the sprites on the bottom two thirds

how is that better/worse than...

putting the still stuff in the bottom third of the screen
waiting for floating bus to indicate raster is two thirds of the way down
drawing sprites in first two thirds of screen


it seems like you still get the same amount of time to draw stuff?

does the floating bus tell you when the raster is in the border? that would give more time to draw sprites
My understanding, which might stand correction :) :

using IM2 tells you when the raster is at the start of the top border, so from there you get the time it takes to draw the top border, plus the time it takes to draw your static stuff at the top of the display.

Using the floating bus, you get the time it takes to draw your static stuff at the bottom of the display, plus the lower border, plus the top border.

So floating bus gives you more time, and has the advantage that your play area is at the top of the screen, which is normally aesthetically better.
Derek Fountain, author of the ZX Spectrum C Programmer's Getting Started Guide and various open source games, hardware and other projects, including an IF1 and ZX Microdrive emulator.
giorgio.denunzio
Drutt
Posts: 1
Joined: Tue Apr 17, 2018 9:11 am

Re: Double buffering on the Spectrum

Post by giorgio.denunzio »

Hi all!
I've just registered to this interesting Forum, and I'have not read the whole thread yet, so perhaps the information I am giving you is of little interest, but in these days there has been a discussion on the floating-bus subject at https://www.facebook.com/groups/z80asm/ ... 271378839/
I am conducting some tests, at present on the ZX48k (emulated, by now). In case you are interested, please take a look. On the other hand I'll read with attention this thread, which looks really interesting.
Thanks
Giorgio
Ralf
Rick Dangerous
Posts: 2279
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Double buffering on the Spectrum

Post by Ralf »

Hi Giorgio! Welcome to the forums!

This discussion about floating bus is certainly very interesting.

I would have one advice to beginner programmers however. Don't mess with with floating bus ;) It's a rather advanced trick. Joffa games were generally a piece of quite sophisticated code.

A "normal", typical game did it this way:

1) It keeps a screen buffer somewhere in memory
2) It draws to this buffer as fast as it can but usually longer than one frame
3) When it's ready it copies the buffer to screen by series of LDI commands without any synchronisation with screen refresh

Copying buffer to screen may alone take more than one frame so some artifacts on screen may happen. And the final framerate was around 12.5 fls or so.

It all may sound very rough and crude but in practice it worked and the result was acceptable.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Double buffering on the Spectrum

Post by Nomad »

Did Joffa Smith ever talk about or write on how he wrote his games?
Ralf
Rick Dangerous
Posts: 2279
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Double buffering on the Spectrum

Post by Ralf »

Did Joffa Smith ever talk about or write on how he wrote his games?
He made some comments here and there but not very detailed.
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Double buffering on the Spectrum

Post by Nomad »

Kind of like an anti Ian Weatherburn then (personality wise). :lol:

One of the most frustrating things trying to find out about N.O.M.A.D was the main developer had left nothing behind about how he wrote the game. It was weird that for a guy that was so sure of his own genius that he didn't talk about his process more before he became An Hero after Canvas folded.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore »

Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
druellan
Dynamite Dan
Posts: 1466
Joined: Tue Apr 03, 2018 7:19 pm

Re: Double buffering on the Spectrum

Post by druellan »

Ralf wrote: Tue Apr 17, 2018 1:14 pm He made some comments here and there but not very detailed.
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
Was Steve Wetherill also able to figure out the trick for SideWize?
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: Double buffering on the Spectrum

Post by Joefish »

Joffa did give some loose notes on how he did his scrolling, but they were such that you'd only really understand it if you tried to program it yourself. I had a few private exchanges with him and here are the basics that I gleaned. I didn't actually get anything from him about the floating bus, so I don't know when or where he used it. Much of what I understood was simply down to timing of the program code.

His general approach was for a 25fps update rate, which worked as follows:

1. Wait for an interrupt.
2. Do some pre-processing of various stuff. This is a delay whilst the raster reaches the first line of the screen, so could be using the floating bus. This may involve sorting the sprites into vertical order.
3. Redraw the scrolling level scenery line-by-line from the top down, just behind the raster. Any sprites are erased by this scenery wipe. This is inevitably slower than the raster so by the time it finishes, the raster will be well into the lower scoreboard, if not the lower border or even the next TV frame.
4. Draw the sprites as fast as possible, hopefully before the raster catches up with their positions - hence the vertical sorting earlier. Fully expect the next frame interrupt to occur while this is going on, if it hasn't already.
5. Make sound effects. Rig the system so the next interrupt breaks out of the sound routine and loops back to 2.

Sprites were generally only placeable at 2-pixel positions (4 pre-shifted frames horizontally, data stored in a left-right/right-left zig-zag form with masks and drawn two rows at a time). There were enough black-attribute columns either side for the screen to mask off sprites that went outside the scenery area.

For games, specifically:

Green Beret -
Used an 8-character high buffered strip that was pixel-scrolled horizontally, filled in at the edge from scenery data, and copied to the screen. Don't know if the scroll and copy were done simultaneously or if the scroll was done, then POP+PUSH used to copy it. The top third of the screen is simply erased. The rockets are made to protrude slightly higher into the empty sky by adding sprites to their tips.

Hysteria
Like Green Beret, used an 8-character high strip pixel-scrolled horizontally and copied to the screen. But some of the extra space was filled in by parallax patterns at the bottom of the screen. These are simply 16-bit values repeatedly PUSHed across the screen. Note how the sprites that are supposed to be sat on the background judder slightly as they move in 2-pixel resolution compared to the scenery's 1-pixel movement. Note also you can grab items off the background, though you're actually running along the strip of ground in front that's moving in 2-pixel steps.

Cobra
This one is more complicated - there is no background buffer; the scenery is redrawn from scratch each frame. There are a very limited number of scenic blocks, but it's actually quicker than a scroll+copy. Note also that the scenery now scrolls in 2-pixel steps.
The pre-shifted scenery blocks are loaded into the registers AF, BC, DE and HL then the scenery is drawn by a series of PUSHes, PUSHing the relevant pattern onto the screen at that point. It's wasteful as a scrolling pattern may be half-in and half-out of a character position. So the patterns for solid platforms might be:

AF = empty space
BC = start of platform
DE = continuous platform
HL = end of platform

But before this happens, the program must first re-write the list of PUSH instructions to match the level data. The PUSH list for each row of scenery blocks is re-used to draw all 16 pixel rows. It only has to POP four registers to fetch the scenery patterns for an entire pixel row, so it's quicker that using POP+PUSH to copy a row of data (just as many PUSHes, but fewer POPs).

The scroll can also draw things one-character over, so it only needs scenery pre-shifted to 4 positions (to cover each pattern moving across 8 pixels, not 16). The blacked-off borders either side of the screen are uneven; there's an extra character on one side to hide the scenery redraw moving about, as well as any sprite overlap.

It can have a different set of patterns on each row of the screen, and because of the character-position adjustment it can have either:
- one pattern that can be repeated to any length (e.g. platforms which need 3 pre-shifted patterns to start, repeat and end)
- or 3 separate patterns of a narrow upright object (e.g. pipes up to 10 pixels wide, which always just fit within one 16 pixel wide pre-shifted block)
- or one platform that must start and end within 24 pixels and one narrow upright object.

Finally, there's a faster parallax bit at the bottom of the screen drawn by just PUSHing a 16-bit wide pattern right across the screen. This is programmed to occur twice per game cycle. The result is that this part scrolls at 50fps, making everything seem a bit smoother.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore »

Joefish wrote: Tue Apr 17, 2018 5:15 pm I didn't actually get anything from him about the floating bus, so I don't know when or where he used it.
I think he only used it in Cobra and Terra Cresta. Both use the same code:

Code: Select all

	ld bc,$3f28	;Cobra
1$	ld a,c
	in a,($ff)
	cp b
	jr nc,1$
	
	ld c,$28	;Terra Cresta
	ld b,$3f
1$	ld a,c
	in a,($ff)
	cp b
	jr nc,1$
druellan wrote: Tue Apr 17, 2018 4:48 pm
Ralf wrote: Tue Apr 17, 2018 1:14 pm He made some comments here and there but not very detailed.
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
Was Steve Wetherill also able to figure out the trick for SideWize?
Yes, he was. Sidewize was never re-released, though. So it hangs on a +2A. Steve’s code is as follows:

Code: Select all

	ld bc,$40ff
	ld e,$40	;BRIGHT BLACK INK on BLACK PAPER
sync	ld a,r		;padding instruction
	in a,(c)
	cp e
	jp nz,sync
Curiously enough, in his blog post he admits that he doesn’t remember wha the LD A,R instruction does and speculates that it’s “some self-modifying code to conditionally branch on the state of the Z80 parity flag.” :D
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: Double buffering on the Spectrum

Post by Joefish »

I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore »

Joefish wrote: Tue Apr 17, 2018 7:07 pm I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
Yes, Sidewize was pretty impressive from a technical standpoint. Incidentally, I only learned about it a couple of years ago. It'd somehow slipped under my radar back in the day.

What I miss the most in Spectrum games today are ducks. Joffa really knew how to cook ’em. :lol:
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
druellan
Dynamite Dan
Posts: 1466
Joined: Tue Apr 03, 2018 7:19 pm

Re: Double buffering on the Spectrum

Post by druellan »

Ast A. Moore wrote: Tue Apr 17, 2018 6:59 pm Curiously enough, in his blog post
Seems he was using a bright 1 black attribute as delimiter. That's clever:

Image
I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
Me either, but when I've learned about EmuZWin's real FPS indicator, I started to test games, and I loaded Sidewize because I can, and I got instantly blown again about how well it performs.

Image

I now notice the flickering, EmuZWin seems not to be doing a great job emulating this.
robpearmain
Drutt
Posts: 21
Joined: Thu Jun 13, 2019 11:52 pm
Location: York, UK
Contact:

Re: Double buffering on the Spectrum

Post by robpearmain »

Joefish wrote: Tue Apr 17, 2018 5:15 pm


Cobra
This one is more complicated - there is no background buffer; the scenery is redrawn from scratch each frame. There are a very limited number of scenic blocks, but it's actually quicker than a scroll+copy. Note also that the scenery now scrolls in 2-pixel steps.
The pre-shifted scenery blocks are loaded into the registers AF, BC, DE and HL then the scenery is drawn by a series of PUSHes, PUSHing the relevant pattern onto the screen at that point. It's wasteful as a scrolling pattern may be half-in and half-out of a character position. So the patterns for solid platforms might be:

AF = empty space
BC = start of platform
DE = continuous platform
HL = end of platform

But before this happens, the program must first re-write the list of PUSH instructions to match the level data. The PUSH list for each row of scenery blocks is re-used to draw all 16 pixel rows. It only has to POP four registers to fetch the scenery patterns for an entire pixel row, so it's quicker that using POP+PUSH to copy a row of data (just as many PUSHes, but fewer POPs).

The scroll can also draw things one-character over, so it only needs scenery pre-shifted to 4 positions (to cover each pattern moving across 8 pixels, not 16). The blacked-off borders either side of the screen are uneven; there's an extra character on one side to hide the scenery redraw moving about, as well as any sprite overlap.

It can have a different set of patterns on each row of the screen, and because of the character-position adjustment it can have either:
- one pattern that can be repeated to any length (e.g. platforms which need 3 pre-shifted patterns to start, repeat and end)
- or 3 separate patterns of a narrow upright object (e.g. pipes up to 10 pixels wide, which always just fit within one 16 pixel wide pre-shifted block)
- or one platform that must start and end within 24 pixels and one narrow upright object.

Finally, there's a faster parallax bit at the bottom of the screen drawn by just PUSHing a 16-bit wide pattern right across the screen. This is programmed to occur twice per game cycle. The result is that this part scrolls at 50fps, making everything seem a bit smoother.
This is great information, what about when a row changed graphics, how did this work (see image attached)

Image
catmeows
Manic Miner
Posts: 711
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: Double buffering on the Spectrum

Post by catmeows »

robpearmain wrote: Fri Jun 14, 2019 12:07 am

This is great information, what about when a row changed graphics, how did this work (see image attached)

Image
By loading values in the middle of line.

Code: Select all

	push bc			 ; 89d2 c5 $0bts
	push af			 ; 89d3 f5 $0bts
	push de			 ; 89d4 d5 $0bts
	push bc			 ; 89d5 c5 $0bts
	push hl			 ; 89d6 e5 $0bts
	push hl			 ; 89d7 e5 $0bts
	push hl			 ; 89d8 e5 $0bts
	ld ($8bf0), sp		 ; 89d9 ed 73 f0 8b $14ts
	ld sp, ix		 ; 89dd dd f9 $0ats
	pop bc			 ; 89df c1 $0ats
	pop de			 ; 89e0 d1 $0ats
	pop af			 ; 89e1 f1 $0ats
	ld sp, ($8bf0)		 ; 89e2 ed 7b f0 8b $14ts
	push af			 ; 89e6 f5 $0bts
	push de			 ; 89e7 d5 $0bts
	push de			 ; 89e8 d5 $0bts
	push de			 ; 89e9 d5 $0bts
	push de			 ; 89ea d5 $0bts
	push de			 ; 89eb d5 $0bts
	push de			 ; 89ec d5 $0bts
	jp $9ced		 ; 89ed c3 ed 9c $0at
	
Proud owner of Didaktik M
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: Double buffering on the Spectrum

Post by Joefish »

Could it really do that?
OK, my 50Hz scrolling demo couldn't, but then there was no 'slack time' in it. I tried to keep mine running at a constant speed, whereas with all its sprites, Cobra varies a lot in execution time. Mine used the alternate registers for an alternate set of platforms, but could only swap them between rows, not columns. I just assumed Cobra did the same.
I did develop some code that used the alternate BC/DE/HL registers (or just as easily AF'/IX/IY) for an extra platform type within a row, but it takes longer to execute.
User avatar
g0blinish
Manic Miner
Posts: 281
Joined: Sun Jun 17, 2018 2:54 pm

Re: Double buffering on the Spectrum

Post by g0blinish »

maybe not related to topic, but I used another tricks for AY Mehademo 3

http://g0blinish.ucoz.ru/forblog2/mudademo.rar
(sources inside,compile with sjasm)
User avatar
ketmar
Manic Miner
Posts: 610
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: Double buffering on the Spectrum

Post by ketmar »

sorry for necroposting, but i happened to stumble upon Joffa's name here, and simply couldn't stop myself. i reversed Firefly engine around 10 years ago (man, i'm old now!), extracted map blitting parts from it, and even made a simple editor. i intended to use that in my game, but never wrote it. it works mostly like Cobra, using low part of the screen for the status bar, and for floating bus vsyncing. the map is 32x32 tiles of 16x16 pixels, with wraparound.

if anybody's interested, i can try to reverse-engineer my code (i lost most of my notes and such, and my asm source is not really well commented ;-), and publish it here. actually, the code is quite easy to follow (i think ;-), so i may throw in more comments, and turn it into some kind of simple example/tutorial. i think Joffa would be happy to see others learning from his tricks...
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore »

ketmar wrote: Wed Jun 17, 2020 5:04 am i reversed Firefly engine . . . . it works mostly like Cobra, using low part of the screen for the status bar, and for floating bus vsyncing
Curious. I haven’t noticed any floating bus polling in Firefly. Besides, the game runs just fine on a +2A/+3. Do you think you could share the relevant part of Firefly’s code with us?
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
ketmar
Manic Miner
Posts: 610
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: Double buffering on the Spectrum

Post by ketmar »

yeah, that may be added by me to have some more time to do things, it is hard to tell now. as i said, i lost most of my notes and oridinal disassemblies, there's only the "final" extracted engine left. if i'll find my original notes, i'll double-check. the blitter itself doesn't really need that, you can simply "chase the beam", of course.

but tbh, i don't keep hight hopes here. i think i used the mix of IDA and my own tools, and i don't have neither IDA, nor those tools anymore.

yeah, judging from git history (which is very short ;-), floating bus vsync was added by me. so sorry for misinformation. still, "builder" and "blitter" code is almost unmodified (and it seems i introduced small bug there...).

when i'll find some more time, i will properly comment it, and will make a post. i think it will be interesting to see how exactly Joffa did his magic. and if i'll find any my old notes, i'll add them.

p.s.: ah, another thing i remember about Firefly is that it is using two types of compression for maps. i don't remember exact algos, but i think that one was your usual RLE, and another one was kind of LZ coding (but somewhat twisted). or maybe just RLE with another counter size.


p.p.s.: yeah, Firefly is one of my favorite Speccy games. i remember seeing its fantastic 8-way smooth scrolling for the first time and dropped my jaw. so dissecting Firefly was a natural choice. ;-)
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Double buffering on the Spectrum

Post by Ast A. Moore »

Firefly is by far my favorite Joffa’s game. Pretty brilliant concept and implementation.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
ketmar
Manic Miner
Posts: 610
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: Double buffering on the Spectrum

Post by ketmar »

Ast A. Moore wrote: Wed Jun 17, 2020 2:53 pm Firefly is by far my favorite Joffa’s game. Pretty brilliant concept and implementation.
yeah, i absolutely agree. and it aged very well: it still looks fantastic, and insanely addictive. i never really liked Cobra or Green Beret (excellent technical implementation, but the gameplay is not my cup of tea). but i must confess that i am still playing Firefly from time to time, and it is still as good as it was the first time.

randomized world map is a brilliant touch too: it always looks like there are more unexplored maps there, even if you know that there are not so many of them. and each game feels like a fresh one.

eh, i can keep praizing Firefly the whole day... ;-)
Post Reply