[comp.sys.atari.st] Yet More on Animation

dmb@TIS.COM (David M. Baggett) (09/29/88)

   There was some discussion about Setscreen waiting for the vertical
blank before returning.  I tried a few things to see how Setscreen
behaves in practice, and I still believe that

   Setscreen returns immediately.

   If Setscreen waited for the vertical blank when you set the
physical screen base, the following code would take about 1 minute:

	for (i = 0; i < 3600; i++) {
		Setscreen((char *) -1L, Physbase(), -1);
	}

It doesn't.  It takes about 2 seconds.  This means that Setscreen does
_not_ wait for the vertical blank to return.
   It _is_ true that the physical screen base doesn't actually set until
the vertical blank.  This is because Setscreen simply writes a value into
a location in page 4.  The _vertical blank routine_ looks at this location
and sets the physical base.  We're talking about an interrupt here.
   So you do have to Vsync after setting the physcial screen to be sure
you won't get flicker.  To illustrate:

	C statement executed			Status of VBI

	for (;;) {
		/*
		 * Do stuff			Yet to come
		 */

		Setscreen(...)			Yet to come
		Vsync();			It happens
		
		/*
 		 * Do stuff			Just finished (now
		 */				previous Setscreen
						has taken effect)
	}

If you don't explicitly Vsync, some of your Setscreen calls won't
ever take effect (they will be "overwriten" by the next Setscreen
call).
   Unless my compiler is different from everyone else's (I'm usnig
Laser C), this is how Setscreen works.

			David Baggett
			dmb@TIS.COm (arpanet)

leo@philmds.UUCP (Leo de Wit) (10/01/88)

In article <8809282323.AA10646@TIS.COM> dmb@TIS.COM (David M. Baggett) writes:
>
>   There was some discussion about Setscreen waiting for the vertical
>blank before returning.  I tried a few things to see how Setscreen
>behaves in practice, and I still believe that
>
>   Setscreen returns immediately.
>
>   If Setscreen waited for the vertical blank when you set the
>physical screen base, the following code would take about 1 minute:
>
>	for (i = 0; i < 3600; i++) {
>		Setscreen((char *) -1L, Physbase(), -1);
>	}
>
>It doesn't.  It takes about 2 seconds.  This means that Setscreen does
>_not_ wait for the vertical blank to return.

This is correct. I did the same test. Well, I did put in onto the net also.

>   It _is_ true that the physical screen base doesn't actually set until
>the vertical blank.  This is because Setscreen simply writes a value into
>a location in page 4.  The _vertical blank routine_ looks at this location
>and sets the physical base.  We're talking about an interrupt here.

No. This is not correct. The physical screen base *IS* altered
immediately; the reason this has no effect until the next vertical
blank is that the video counter that generates addresses pointing into
the screen memory is still happily incrementing and will be reset to
the new screen start location only when it is about to rebuild the next
screen, i.e. at vbl time.  This is hardware stuff, and has nothing to
do with the code that the vbl routine consists of; you can try it for
yourself by setting the vbl semaphore ($452): decrement the vbl
semaphore making it negative; now the code inside the routine won't get
executed, but still the screen start address is updated! Note: you must
not disable the vbl itself by setting the status word, as this will
effectively disable the interrupt and hence the refill of the video
counter.

I think you're mixing up some locations in page 4.

$44e    _v_bas_ad (logical screen base)
$45e   screenpt

The first one is the logical base that is used by all routines that want
to produce output to the screen. Having logical and physical screen
different means you can prepare a picture in the first, while showing
the old picture in the other.

The second one, screenpt, is used in the vbl routine as follows:  if
screenpt is not zero, both the physical and logical screen base will be
reset to this value. Note the physical screen base has no associated
RAM location; it is set by filling in two I/O addresses, which
correspond to the shifter's counting base register.

Screenpt is *NOT* set by SETSCREEN! SETSCREEN sets either physical,
logical base or resolution or any combination of the three. Only if the
resolution is being set, SETSCREEN waits for a vbl.
Screenpt could be used for animation, were it not that setting both
logical and physical screen starts make it less usefull for that.


>   So you do have to Vsync after setting the physcial screen to be sure
>you won't get flicker.  To illustrate:
>
   [example omitted]...

    Not quite true. In fact this can slow down fast animations considerably.
If you generate new frames at a rate lower than the vbl frequency it's OK,
but if you generate at a higher rate this means you'll have to wait each
time for the vbl. You could argue you still can't display at a higher rate
than the vbl, which of course is true, but not waiting for the vbl means
in effect once and a while skipping a frame (as you indicated). 
The flicker does not result from not using Vsync but from writing in a
screen memory that's being displayed. I posted this before, but some extra
explanation won't harm:

Most people use two screens when animating. This is ok if you synchronize
by using Vsync(), but it leads to trouble when you don't. For clarity I
introduce the notion of actual screen memory, which is the memory currently
being addressed by the shifter. Having screen memories A and B:

Actual      A          A          A          B
Physical    A          B          B          B
Logical     B          A          A          A
                       ^          ^          ^
                       |          |          |
  time axis --->   SETSCREEN   write log    vbl    etc.

If the logical screen gets updated between a SETSCREEN and a vbl it
also affects the actual screen (they're both A), so there's trouble.
The solution is to use (at least one) extra screens, traversing them
cyclic and having the physical screen walk 'one behind', viz.:

Actual      A          A          A          B          B
Physical    A          B          B          B          C
Logical     B          C          C          C          A
                       ^          ^          ^          ^
                       |          |          |          |
  time axis --->   SETSCREEN   write log    vbl     SETSCREEN etc.

It can be shown that having two SETSCREEN's within a vbl period still
can lead to flicker; the solution is to use more screens, or to await
the vbl if you already had two - the wait time now being much less than
in the original case. Trial and error are good judges in these cases,
along with your criteria for what looks nice on the screen and how much
screen memory you have to waste.

>   Unless my compiler is different from everyone else's (I'm usnig
>Laser C), this is how Setscreen works.

Well, close.

>			David Baggett
>			dmb@TIS.COm (arpanet)

       Leo.