Re: [hatari-devel] vsync & video base address setting

[ Thread Index | Date Index | More Archives ]

Le 23/04/2023 à 10:57, Miro Kropáček a écrit :

this is more an Atari question than a Hatari one but knowing how many knowledgeable people are here... :)

Even though I'm not actively coding on ST/E machines, out of curiosity I'd like to know how a programmer is supposed to handle double buffering on ST/E.

On Falcon it is easy:

- do your code
- swap buffers
- Vsync() // wait for vbl
- VsetScreen(-1, new_buffer, -1, -1) // set physbase

This works because VsetScreen just writes to FFFF8201 & friends which gets reloaded at the line defined by VDB (btw, you can consider this as a feature request, Hatari doesn't do this yet ;-)). And since we know that the write to FFFF820x is happening during VBL, it's 100% safe to assume that this never happens:

move.b vbasehi,$ffff8201
// VDB --> Videl reloads its internal video base pointer from $ffff8201, $ffff8203 and $ffff820d
move.b vbasemi,$ffff8203 // too late guys...
move.b vbaselo,$ffff820d //

But what about the ST/E shifter? AFAIK the video base is taken into account at line 310 (end of the visible area / start of VBL). So if I do the steps above, Setscreen() will have no effect for the whole frame because when setting it during VBL, the video base has already been read.

I was considering:

- do your code
- swap buffers
- Setscreen(-1, new_buffer, -1) // set physbase
- Vsync() // wait for vbl

which does the trick but then there's the danger of reading only the partially set video base address, isn't it? (see my example above, just replace VDB with line 310...) Assuming that your code may take a variable amount of frames (i.e. you can't set the logical buffer in advance so it reloads by the end of the frame), is there a way to do a 100% safe double buffering on ST/E?

I can think of only one way, optimize the Setscreen() call into one instruction, i.e. align the screen buffer on 256 bytes (8203 = $00) and just

move.l new_buffer,d0 ; $00123400
lsr.w #8,d0 ; $00120034
move.l d0,$ffff8200.w ; not interruptible by the Shifter?


2 cases depending on STF or STE :
- on STE it's easy to solve as on Falcon : during your VBL int, just write the new video address to ff8205/07/09 ; you need to do this before the end of top border (ie line 63 on 50 Hz screen). These 3 bytes are not writable on STF but they are on STE.

- on STF, you must write the new screen address for vbl 'n' during vbl 'n-1', else if you write the new address during vbl int 'n' it will only be applied when vbl 'n+1' starts.

It's trickier if your code takes a variables number of VBL to render one frame. The only solution I can think of is to have a way to evaluate how much of a frame you rendered already to decide if this is the last VBL before switching buffer and doing the write to ff8201/03.

If you write to ff8201/03 when your frame is completely rendered, you have 2 paths : - the write happens before end of current VBL, then it's ok, it will be taken immediately when next VBL starts. - the write happens when next VBL already started (somewhere between line 0 and 63), then bad luck, your new buffer will be displayed on next vbl, not the current one.

this can be a problem because you can't write to the 2nd buffer as it will be displayed next. but you can't write to the 1st buffer either as it's possibly being displayed for 1 extra VBL. Easiest solution : use triple buffering to ensure you always have 3 buffers :
 - displayed buffer
 - next displayed buffer
 - working buffer where you can write your next frame.


Mail converted by MHonArc 2.6.19+