Double buffering screen bitmap

Basic and Machine Language

Moderator: Moderators

User avatar
thegg
Vic 20 Amateur
Posts: 69
Joined: Mon Aug 30, 2021 4:49 am
Location: England
Occupation: retired

Re: Double buffering screen bitmap

Post by thegg »

Not sure about the 'cleverly' bit, but if you don't mind an extra few cycles in the point plotting code you might like to consider:
Allocate a ZP address as a variable.
Load the ZP with $00 when starting to write to bit-map 1.
Load the ZP with $08 when starting to write to bit-map 2.
In the point plotting code load the highb,x value into the accumulator and OR it with the ZP: effectively adding 8 to the high bit value.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Double buffering screen bitmap

Post by Mike »

thegg wrote:[...] if you don't mind an extra few cycles in the point plotting code [...]
Your suggestion just adds another 3 extra cycles to the loop core of a line drawing routine that runs at 51 cycles/pixel.
fleischgemuese
Vic 20 Newbie
Posts: 12
Joined: Fri Dec 29, 2023 11:47 pm
Website: https://fleischgemuese.itch.io
Location: Germany

Re: Double buffering screen bitmap

Post by fleischgemuese »

Hi,
I'm not really using Assembler but I can show you how I did double buffering using TurboRascal (TRSE). Maybe it helps:

(A) Memory setup
I used $1000 and $1e00 as screen addr1/2 to switch between. The colour address is $9400 and $9600
The charset location is at $1800, and 192 chars are sufficient for me
(B) Variables:
currentBank 0=screen1, 1=screen2
time: Timer for counting the frames
framestatus: indicate if the update of tiles are finished
raster: rasterline (different for PAL/NTSC)

(C) VBL Raster interrupt

Explanation: The interrupt is separated into 4 parts depending on frameStatus and time

frameStatus := 1 -> start cycle set by GameLoop
frameStatus := 0 -> cycle is finished

time in cycle
time = 0: Switch bank depending on current bank
time = 1: Copy all data from bank to another
time = 2: cycle is finished and frameStatus = 0

Code: Select all

interrupt vbl();
begin
	StartIRQ(0);
	UpdateSound();
	if(frameStatus = 1) then begin
		if(time = 0) then begin
			SwitchBank();
		end
		else if(time = 1 and currentBank = 0) then begin 
			copyHalfScreen(^@SCREEN_ADDR1, ^@SCREEN_ADDR2, 10,0,0);
			copyHalfScreen(^@COLOR_ADDR1, ^@COLOR_ADDR2, 10,0,0);
		end
		else if(time = 1 and currentBank = 1) then begin
			copyHalfScreen(^@SCREEN_ADDR2, ^@SCREEN_ADDR1, 10,0,0);
			copyHalfScreen(^@COLOR_ADDR2, ^@COLOR_ADDR1, 10,0,0);
		end;
	end;
	if(time = 2) then begin
      	frameStatus := 0;
    end;
    if(time < 4) then inc(time)
	else if(frameStatus = 1) then begin 
		time:=0;
	end;
    closeIRQ();
end;

(D) Game loop example
Only Update the game objects that are hidden after the interrupt cycle is done. If finished set framestatus =1 to start new cycle

Code: Select all

				while(state = @STATE_PLAY) do begin
					ReadJoy1();
					waitnoraster(0);
					if(frameStatus = 0)	then begin
						Update();
						Animate();
						CycleWater();
						frameStatus := 1;
					end;					
				end;

(E) Update Example

While doing an update use the correct screenmemory

Code: Select all


	if(currentBank = 1) then	screenmemory := scr1[y+1] else screenmemory := scr2[y+1];
	
	screenmemory[x]:=c;
Note scr1 is a pointer to the screen location, same need to be done for the color ram

(F) Switch Bank function

Code: Select all

procedure SwitchBank();
begin
	if (currentBank = 0) then 
	begin
		VICCR5 := $fe;
		VICCR2 := VICCR2 | $80;		
		currentBank := 1;
	end
	else 
	begin
		VICCR5 := $ce;
		VICCR2 := VICCR2 & $7F;		
		currentBank := 0;
	end;
end;

(G) Start VBL interrupt

Code: Select all

	// PAL=121, NTSC=107
	if (HSCROLL_REGISTER = 12) then raster := 121 else raster := 107;

	VIARasterIRQ(vbl(), raster, 0);

Hope this helps...
heaven6502
Vic 20 Drifter
Posts: 29
Joined: Sat Jan 26, 2013 3:30 pm

Re: Double buffering screen bitmap

Post by heaven6502 »

after 2018 I am back into VIC coding...

i am struggling in my 3d routines and same double buffering a 16x16 char matrix.

so... 16x16 = 256 chars = $0800 similar to C64 --> $1000 charset 1 and $1800 charset 2

leaves no room for screen ram... (I am on an expanded VIC) --> $0200

now my setup of VIC regs:

Code: Select all

	lda	#16+$80	;collums+$0200 shift
	sta	$9002
	lda	#16+1	;lines + 8x16 chars
	sta	$9003
	lda	#%10001100  ;$0200 screenram $1000 font
	sta	$9005
while my main loop will look like this

Code: Select all

loop	
	lda #154
	jsr vsync
	lda $9005
	eor #%00000010
	sta $9005 ;here $1800
	jsr clr_speedcode ;$1000
	jsr render_scene

	lda #154
	jsr vsync
	lda $9005
	eor #%00000010
	sta $9005 ;here $1000
	jsr clr_speedcode2 ;clear $1800
	jsr render_scene
continue2
	jmp loop


now does that looks ok?

but Vice shows half of the matrix in rom charset...
heaven6502
Vic 20 Drifter
Posts: 29
Joined: Sat Jan 26, 2013 3:30 pm

Re: Double buffering screen bitmap

Post by heaven6502 »

ok... the rom chars are there because I setup the matrix like on C64 with *16 collums... but i need *8... :D (so just chars 00-7f and 80-ff showed rom chars)
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: Double buffering screen bitmap

Post by MrSterlingBS »

Thanks a lot for the answers.

I have one "trick" to save six bytes and eight cycles!

Code: Select all

	lda value1				; for $1800
	; eor #%00000010
	sta $9005 				;here $1800
	jsr clr_speedcode 		;$1000
	jsr render_scene

	lda #154
	jsr vsync
	lda value2				; for $1000
	; eor #%00000010
	sta $9005 				;here $1000
aeb
Vic 20 Amateur
Posts: 68
Joined: Sat Jun 19, 2004 2:06 pm

Re: Double buffering screen bitmap

Post by aeb »

Clearing an entire bitmap is slow... In "Back in the Good Old Days" demo from 2004 I allocated chars dynamically (like a ring buffer) when drawing and eor-filling the frame. Char 0 was used for empty screen, so I only needed to clear ~200-256 bytes to wipe a screen buffer.

Dynamic char allocation also allows displaying much bigger objects than what's possible with a fixed bitmap. When eor-filling, I had 3 more "preset" chars for quickly filling 4x16 pix areas of solid colors (bit patterns $55, $aa, and $ff).

Demo part with filled vectors & glenz, unexpanded VIC (attempts to load the next part "cae" after exit):
cad.zip
(2.37 KiB) Downloaded 13 times
https://www.youtube.com/watch?v=StlAe7kzsZg

(Only 2 axis of rotation, sorry, I didn't have a proper 3D matrix rotation formula at hand, but just adapted something from high school trigonometry :D )
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Double buffering screen bitmap

Post by Mike »

aeb wrote:In "Back in the Good Old Days" demo from 2004 I allocated chars dynamically (like a ring buffer) when drawing and eor-filling the frame [...] Char 0 was used for empty screen [...] I had 3 more "preset" chars for quickly filling 4x16 pix areas of solid colors (bit patterns $55, $aa, and $ff)
That method may well be feasible if there is only one object on screen with large uniform coloured areas, but in any case we are not anymore talking about a bitmap then. In a bitmap, single pixel access can be extremely streamlined (see the other thread about line drawing here), with dynamically allocated chars, the overhead per pixel will be much higher.

BTW, the original HYPER-GRAPHICS did such a scheme for a overscan 208x256 graphics screen, providing a 'sparse' bitmap already in 1986 (published in Markt & Technik 64'er Sonderheft 3), the characters 0..25 not usable because they overlapped the text screen, character 26 was the empty tile and characters 27..255 were available to hold non-empty tile definitions. Only roughly 50% of the graphics screen could be filled, which restricted the use of the graphics package to line graphics, function plots or the like.

Exactly this program then was the motivation for tokra and me to create MAXIGRAFIK, which then did the same resolution of 208x256 as true display bitmap, in 2010. :mrgreen:
Post Reply