Page 1 of 1

disable video on vblank, better?

Posted: Sun Jun 03, 2018 12:50 am
by Miquel
Makes any difference disabling the display at the beginning of a vertical blank in terms of upload speed to vpd memory?, basically doing dma copy (68k ram->vdp ram). And then enabling it, hopefully inside the same vblank.

Another related question: why sega docs says dma flag must be set on and off at every dma operation? It's clear that lots of games don't follow this instruction... (?!?)

Re: disable video on vblank, better?

Posted: Wed Jun 06, 2018 12:05 pm
by Charles MacDonald
Unfortunately it doesn't speed anything up, the access time during V-Blank is the same as when the screen is turned off.

However you can get more time to do DMA transfers by "letterboxing" the display, where you turn off V-Blank early (say line 200) and then back on late (say line 8 of the next frame). This gives you additional scanlines to use for full-speed transfers, at the cost of reduced vertical resolution. Virtua Racing does this.

One catch is that if the screen is turned off on the last line of the previous frame, then sprite processing on the first displayed line is delayed. So the first displayed line won't show sprites correctly, but all other lines will after that.

Re: disable video on vblank, better?

Posted: Wed Jun 06, 2018 5:38 pm
by Miquel
Roger Charles. What you say seems the logical answer, but you never know how things are implemented for real, so I ask. Thanks!

It's the second the I implement the vertical exception routine and both times I have find myself thinking about this. This time I have reduced the vertical exception to basically this:

0: move.w (%a0)+, (%a1) /* main loop: where regs are set */
1: dbra.w %d0, 0b

and I think it will be very close to the mythical 7+KB of data transfered to the vdp, more than enough for me. (But hey! give more speed if it was just setting a flag).

Re: disable video on vblank, better?

Posted: Thu Jun 07, 2018 7:56 am
by Stef
I guess your small loop is to set the DMA registers right ?
In this case why not just enroll the loop as the number of register to set is fixed.

Re: disable video on vblank, better?

Posted: Thu Jun 07, 2018 11:20 am
by Miquel
Stef wrote:
Thu Jun 07, 2018 7:56 am
I guess your small loop is to set the DMA registers right ?
In this case why not just enroll the loop as the number of register to set is fixed.
Yes, while in the vert-except all it does is set vdp registers, but it's length it's not fixed, it depends completely on the frame. In regular code when I call a dma function, or any other video function, all it does is fill a buffer called 'g_videoCmdsBuffer' with prefabricated vdp register sets. Also there is another general use buffer to allocate the data.
Let me show you the full code:

Code: Select all

ROUTINE ExceptionVideoVerticalBlank
* Check if frame is ended
	btst.b	#gameStateNotReadyBit, g_gameState
	jeq		2f
	addq.w	#1, g_framesLost
	rte
2:
* Write DMA commands
	movem.l   %d0/%a0-%a1, -(%sp)
	move.l	#0x00C00004, %a1
	move.l	#g_videoCmdsBuffer, %a0
	move.l	g_pVideoCmdsBufferPos, %d0
	sub.l	%a0, %d0
	lsr.w	#1, %d0					/* bytes->words: Num regs to set */
	jra		1f

0:	move.w	(%a0)+, (%a1)			/* main loop: where regs are set */
1:	dbra.w	%d0, 0b

        movem.l	(%sp)+, %d0/%a0-%a1
* Mark the game as not ready for a frame
	bset.b	#gameStateNotReadyBit, g_gameState
	rte
It only allows dma work ram to vdp ram copy, but the other two (fill, vram copy) I have found them to be not useful at all. Also I have removed Actors/Object code (which I do in the v-except) to be a direct comparison.

Re: disable video on vblank, better?

Posted: Thu Jun 07, 2018 3:29 pm
by Sik
I think Stef meant the amount of registers per DMA is fixed, which means you could unroll the loop to iterate over every transfer instead of every word. But yeah technically that still isn't correct, it assumes all you do is normal DMA transfers and nothing else (e.g. it won't work if you do "continued" DMAs where you only set again length and destination and reuse the source from the last transfer, and of course DMA copy and fill are their own unique beasts).

If you do only that kind of DMAs though (entirely possible for most games actually!) then it's indeed a better option to unroll the loop. Maybe have separate queues for those than for the rest of the commands, since they're the most common way to use DMA. But we're getting into a different topic :v

Re: disable video on vblank, better?

Posted: Thu Jun 07, 2018 4:25 pm
by Miquel
As you say, this code not only does dma operations but also any other video operation, like setting register 0, 1, plane addresses, window position,... anything except for:
- Some operations directly related to horizontal-interrupts, which must be done on spot
- Fill and vpd copy dma operations, which I don't use (it requires an extra wait, it could be incorporated)
- Any operation using vdp data register, which is the same as a dma but slower so I don't use it.

One of big virtues of all this is that operations are not done 'now', but at the beginning of the next frame keeping everything clean and synchronized. If you have tried to do a game you know what I mean. The other obviously is that this is much faster.

One possible optimization is doing a move.l instead of a move.w (in the loop), the problem is Sega says "last operation on a dma must be a word operation" or something like this in the manual.

About separating different 'commands' into different queues I think is a bit overkill since the buffer usually is filled with less than 50 words per frame.
Even so it could be unrolled to a jump table... perhaps when the code is more solid/definitive I could try.

Re: disable video on vblank, better?

Posted: Sat Jun 16, 2018 12:20 pm
by Miquel
Sik wrote:
Thu Jun 07, 2018 3:29 pm
If you do only that kind of DMAs though (entirely possible for most games actually!) then it's indeed a better option to unroll the loop.
Loop unrolled, but no two queues thankfully:

Code: Select all

0:	addq.w	#1, g_framesLost
	rte
ROUTINE ExceptionVideoVerticalBlank
* Check if frame is ended
	btst.b	#gameStateNotReadyBit, g_gameState
	jne		0b
* Write to vdp registers
	movem.l %d0-%d1/%a0-%a1, -(%sp)
	move.l	#0x00C00004, %a1
	move.l	#g_videoCmdsBuffer, %a0
	move.l	g_pVideoCmdsBufferPos, %d0
	sub.l	%a0, %d0
	move.w	%d0, %d1
	lsr.w	#5, %d1			/* d1: number of loops */
	and.w	#0x1E, %d0
	neg.w	%d0				/* d0: backwards jump */
	jmp		(1f, %d0.w, %pc)
0:	move.w	(%a0)+, (%a1)	/* main loop: where regs are set */
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
	move.w	(%a0)+, (%a1)
1:	dbra.w	%d1, 0b
* Mark the game as not ready for a frame
	bset.b	#gameStateNotReadyBit, g_gameState
* Initialize frame dependent vars
	move.l	#g_videoCmdsBuffer, g_pVideoCmdsBufferPos
	/* among other things*/
	movem.l	(%sp)+, %d0-%d1/%a0-%a1
	rte
Hope this is good enough for you.