[comp.sys.amiga] Double Buffering

guilford@sunbird.steinmetz (james d guilford) (11/05/87)

I am planning to write some animation-type software, and so  I looked
up double buffering in the RKM. It suggested that I create two screens
and two sets of copper lists, and then to flip screens, I just replace
the copper list pointers.

My question is whether I still have to sync with the vertical retrace.
It seems to me that even after updating the copper-list pointers, they
will not be used until the next scan begins. Thus it would not be safe
to start rendering into the other screen until after at least one
vertical blanking period. Is this right?

I am thinking of creating an interrupt handler on the vertical
blanking list which would have a private message port. When I change
the copper list points, I would send it a message. When the vertical
retrace occurs, it would reply to the message. When I see the reply, I
know it is safe to start rendering the next screen. Is this the best
way to go?


--JimG (guilford@csv.rpi.edu)

jimm@mitsumi.UUCP (Jim Mackraz) (11/06/87)

In article <7768@steinmetz.steinmetz.UUCP> guilford@csv.rpi.edu (james d guilford) writes:
)
)I am planning to write some animation-type software, and so  I looked
)up double buffering in the RKM. It suggested that I create two screens
)and two sets of copper lists, and then to flip screens, I just replace
)the copper list pointers.

Note that the copper list pointers you replace are in graphics base, unless
you also want to replace the vblank interrupt routine which re-installs
them (and handles interlace).  One way to do this is use LoadView().

)
)My question is whether I still have to sync with the vertical retrace.
)It seems to me that even after updating the copper-list pointers, they
)will not be used until the next scan begins. Thus it would not be safe
)to start rendering into the other screen until after at least one
)vertical blanking period. Is this right?

I don't exactly know what protection you need to replace the actual pointers.
If you use LoadView() you probably are safe.  But your concern about
rendering in the newly offscreen buffer is exactly correct.

)I am thinking of creating an interrupt handler on the vertical
)blanking list which would have a private message port. When I change
)the copper list points, I would send it a message. When the vertical
)retrace occurs, it would reply to the message. When I see the reply, I
)know it is safe to start rendering the next screen. Is this the best
)way to go?

Not best, but workable.  You can tell your interrupt handler that you
made the change by setting a global, perhaps within Disable/Enable.
Your handler need only send a Signal to your main task (which signal/task
values it can read from globals shared with your program's main task).

The big problem is that you will find yourself waiting until TOP
of frame to start rendering, which needlessly prevents you from
rendering during that valuable vertical retrace time.  I think (might
not be correct) that the blitter can run much faster when no
display DMA is occuring (during vertical blank).

So the optimal solution uses as bottom of frame interrupt generated
by the Copper.  This requires a custom copper list, and this opens
a can of a few worms.

)--JimG (guilford@csv.rpi.edu)

	jimm

-- 
	Jim Mackraz
	Mitsumi Technology, Inc.		408/980-5422
	{amiga,pyramid}!mitsumi!jimm

bilbo@pnet02.cts.com (Bill Daggett) (11/07/87)

I almost hate to do this but would someone please make a simple statement
concerning what the Amiga term "copper" means?  What did the name derive from
and what is it?  And now, back to Double Buffering...
 
*Bilbo*  Recombinant Hobbit
* Sometimes The Dragon Wins! *

dillon@CORY.BERKELEY.EDU (Matt Dillon) (11/08/87)

>I almost hate to do this but would someone please make a simple statement
>concerning what the Amiga term "copper" means?  What did the name derive from
>and what is it?  And now, back to Double Buffering...

	Copper.  Co-Processor.  The amiga has a simple three-instruction
co-processor which handles changing between screens in the middle of a 
display refresh.  Each screen has a copper list which is executed at the place
the screen physically starts on the screen, loading the plane pointers and
colormap for that screen into the video chip.

	The graphics.library handles the copper.  You really have to get
into the guts of the Amiga to use it (beyond the Screen structure and into
the View structure).

					-Matt
 

peter@sugar.UUCP (Peter da Silva) (11/09/87)

In article <7768@steinmetz.steinmetz.UUCP>, guilford@sunbird.steinmetz (james d guilford) writes:
> I am planning to write some animation-type software, and so  I looked
> up double buffering in the RKM. It suggested that I create two screens
> and two sets of copper lists, and then to flip screens, I just replace
> the copper list pointers.

Why don't you just set up two screens and use ScreenToFront and ScreenToBack
to flip them? These routines are (as far as I have been able to tell) as near
instantanious as you can get. Let intuition worry about the copper lists.
That's what it's for, after all.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (11/10/87)

In article <7768@steinmetz.steinmetz.UUCP> guilford@csv.rpi.edu (james d guilford) writes:
:My question is whether I still have to sync with the vertical retrace.
:It seems to me that even after updating the copper-list pointers, they
:will not be used until the next scan begins. Thus it would not be safe
:to start rendering into the other screen until after at least one
:vertical blanking period. Is this right?
:
	Yup.  After finishing rendering into the off-screen bitmap, you'd
LoadView() it (or ScrrenToFront() it), then call WaitTOF().  When WaitTOF()
comes back, the system will be displaying your other view.

:I am thinking of creating an interrupt handler on the vertical
:blanking list which would have a private message port. When I change
:the copper list points, I would send it a message. When the vertical
:retrace occurs, it would reply to the message. When I see the reply, I
:know it is safe to start rendering the next screen. Is this the best
:way to go?
:
	Seems needlessly complicated to me.  WaitTOF()ing is much easier.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	ihnp4!ptsfa -\
 \_ -_		Recumbent Bikes:	      dual ---> !{well,unicom}!ewhac
O----^o	      The Only Way To Fly.	      hplabs / (pronounced "AE-wack")
"Work FOR?  I don't work FOR anybody!  I'm just having fun."  -- The Doctor

dillon@CORY.BERKELEY.EDU (Matt Dillon) (11/10/87)

>Why don't you just set up two screens and use ScreenToFront and ScreenToBack
>to flip them? These routines are (as far as I have been able to tell) as near
>instantanious as you can get. Let intuition worry about the copper lists.
>That's what it's for, after all.

	Nah... too clugy... very inefficient considering that Intuition must
redo the copper list everytime you do the flip.

					-Matt

keithd@cadovax.UUCP (Keith Doyle) (11/11/87)

In article <4414@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
>	Yup.  After finishing rendering into the off-screen bitmap, you'd
>LoadView() it (or ScrrenToFront() it), then call WaitTOF().  When WaitTOF()
>comes back, the system will be displaying your other view.

Um, wouldn't this be a case where WaitBOVP() would be a teensy bit better?
You get to render through the vertical interval, instead of starting at
the top of the next screen after the vertical interval.  Or has everyone 
just given up on WaitBOVP()?

Keith Doyle
#  {ucbvax,decvax}!trwrb!cadovax!keithd  Contel Business Systems 213-323-8170

keithd@cadovax.UUCP (Keith Doyle) (11/11/87)

In article <1038@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes:
>Why don't you just set up two screens and use ScreenToFront and ScreenToBack
>to flip them? These routines are (as far as I have been able to tell) as near
>instantanious as you can get. Let intuition worry about the copper lists.
>That's what it's for, after all.

I suppose that would work, but if you're waiting for IDCMP messages, it
could be a problem.

Keith Doyle
#  {ucbvax,decvax}!trwrb!cadovax!keithd  Contel Business Systems 213-323-8170

bart@amiga.UUCP (Barry A. Whitebook) (11/12/87)

[ eat this line -- please! ]

this is amiga!bart:

regarding double buffering of animation... here is what "robo" does

----------------- begin fragment -------------------------

while( ... )
{
	Animate(&animKey, rp);
	SortGList(rp);
	DrawGList(rp,vp); 
	vp->RasInfo->BitMap = &bitmap[dispIndex]; 
	WaitTOF();
	MakeScreen(screen);	
	RethinkDisplay();
	dispIndex ^= 1;
	rp->BitMap = &bitmap[dispIndex];
}

----------------- end   fragment -------------------------

note that for a non-dualpf screen the RasInfo->Bitmap is used to remake
the copper list for this screen which has a non-layered vp. 
also note that the rp->BitMap change allows for the current DrawGlist()
call to take place in the "not-currently-displayed" bitmap. also
remember to tell gels that DBUFFER is in effect so that save/restore
works properly between bitmaps.

another way to double buffer is found in the amiga3d demo which
DOES NOT USE gels code to render into its rp->bitmaps, so it incurs less
overhead on the double buffering itself by making these calls:

----------------- begin fragment -------------------------

while( ... )
{
	Forbid();
	WaitTOF();
	WaitBlit();
	Disable();
	(&screen->ViewPort)->RasInfo = rip[frametoggle];
	ScrollVPort(&screen->ViewPort);
	Enable();
	Permit();
	frametoggle ^= 1;
}
----------------- end   fragment -------------------------

this stuffs alternate rasinfo pointers into the viewport and
lets ScrollVPort handle the pokes directly into the copper list.
NOTE CAREFULLY: the elaborate Forbid; WaitTOF; Disable; Enable; Permit;
nesting are to protect the "currently displayed" copper list from being
modified while the copper is fetching instructions from that list.

happy hacking. 

-- 
     //----------------------------------------------------- ----------\\
    //|  Bart Whitebook                                     | {|V|)))  |\\
      |                                                     | ()^()-)))|
      |  16795 Lark Avenue, Suite #106, Los Gatos, CA 95030 |  /_   ?))|
      |  UUCP: pyramid!oliveb!amiga!bart                    | { _ } )\ |
      |  BIX:  amiga_bart                                   | \   //   | 
    \\|_____________________________________________________|__\//____ |//
     \\                                                                //

bryce@hoser.berkeley.edu (Bryce Nesbitt) (11/12/87)

In article <1038@> peter@sugar.UUCP (Peter da Silva) writes:
>In article <7768@>, guilford@sunbird.steinmetz (james d guilford) writes:
>
>> I looked up double buffering in the RKM.  It suggested...
>
>Why don't you just set up two screens and use ScreenToFront and ScreenToBack
>to flip them? 

Peter da Silva, multitasking terrorist.  This is quick, easy and  probably
will be compatible in the future.  But it is also a dirty, ugly
kludge that gives users headaches.  Try C= N or C= M on such a program.
Try dragging the screen.  YUCK!


*At least* put some protection in if you go this route.  Someone else
probably has a better suggestion, but how about:

	key=LockIBase(0L);
		check IntuitionBase->FirstScreen; if the same
		as yours, contine.  Else quit animating.
	UnLockIBase(key);

In the second case, post a "start animating" requester in *your*
screen.  Or maybe one in each, come to think of it.  Still a 
kludge.


It could be that many of the "better" Dbuffering techniques may
break Hedley's Highres Monitor.  (That 1000*800 monochrome monitor
shown at Comdex)  This is pure speculation, however.


This is another one that works:

Set the ViewPort->RasInfo->BitMap plane pointers to the
"other" data then MakeScreen(Screen), RethinkDisplay().
The problem with this is that it rebuilds the copperlists
and that takes a while.  (Reference: WaveBench-1 in interlace :-)

I've seen ScrollVPort() used.  This is fast but seems to have some
display trashing problems and has crashed.  Perhaphs a Forbid()?

A unique solution was used by Matt Dillon.  He had a two bitplane
display for Wiredemo.  He draws into one plane at a time, setting
the color registers to make that plane invisible at the time.
Flopping the color registers is fast.  The problem here is that two
bitplanes of data are fetched by the custom chips, I think (but am 
ot positive) that droping one bitplane will leave more cycles for
the blitter. (issue: can the blitter take advantage of free
"odd" cycles)
Other than that, it works great in practice!

|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce
 (")
  U	"We want to fashon puppets that pull their own strings."
	-Ann Marion

carolyn@cbmvax.UUCP (11/12/87)

>
>Um, wouldn't this be a case where WaitBOVP() would be a teensy bit better?
>You get to render through the vertical interval, instead of starting at
>the top of the next screen after the vertical interval.  Or has everyone 
>just given up on WaitBOVP()?

   WaitBOVP(vp) busywaits, WaitTOF() does not.  This has to be taken in
consideration.  For non-multitasking type applications, WaitBOVP(vp) should
be ok.
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CATS   >>Commodore Amiga Technical Support<<
                     UUCP  ...{allegra,ihnp4,rutgers}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

eric@cbmvax.UUCP (Eric Cotton) (11/12/87)

In article <2740@cbmvax.UUCP> carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) writes:
>>
>>Um, wouldn't this be a case where WaitBOVP() would be a teensy bit better?
>>You get to render through the vertical interval, instead of starting at
>>the top of the next screen after the vertical interval.  Or has everyone 
>>just given up on WaitBOVP()?
>
>   WaitBOVP(vp) busywaits, WaitTOF() does not.  This has to be taken in
>consideration.  For non-multitasking type applications, WaitBOVP(vp) should
>be ok.

Which isn't to say that non-multitasking type applications are encouraged!
-- 
	Eric Cotton
	Commodore-Amiga

  *======================================================================*
 *=====     UUCP: {rutgers|ihnp4|allegra}!cbmvax!eric                =====*
*=====      FONE: (215) 431-9100                                      =====*
*=====      MAIL: 1200 Wilson Drive / West Chester, PA 19380          =====*
 *=====     PAUL: "I don't find this stuff amusing anymore."         =====*
  *======================================================================*

peter@sugar.UUCP (Peter da Silva) (11/14/87)

In article <8711102005.AA06675@cory.Berkeley.EDU>, dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
> >Why don't you just set up two screens and use ScreenToFront and ScreenToBack
> >to flip them? These routines are (as far as I have been able to tell) as near
> >instantanious as you can get. Let intuition worry about the copper lists.
> >That's what it's for, after all.
> 	Nah... too clugy... very inefficient considering that Intuition must
> redo the copper list everytime you do the flip.

Yes, but the question is: "is it fast enough". I do NOT like playing games
that close to the hardware. Too likely to do something that won't survive
1.3 or 1.4 or maybe 2.0.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

peter@sugar.UUCP (Peter da Silva) (11/15/87)

In article <1863@cadovax.UUCP>, keithd@cadovax.UUCP (Keith Doyle) writes:
> In article <1038@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes:
> >Why don't you just set up two screens and use ScreenToFront and ScreenToBack
> >to flip them?
> I suppose that would work, but if you're waiting for IDCMP messages, it
> could be a problem.

Well, I'm using this technique. Could you please explain just what sort of
problems you can expect from IDCMP messages? I'm Wait()ing on the OR of all
my mp_SigBits, though if I wanted to go for the gold I could share one
IDCMP for all the windows on both screens. Or is there some bug in the system
you've discovered...?
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

hobie@sq.UUCP (11/15/87)

Keith Doyle (keithd@cadovax.UUCP) writes:
<In article <1038@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes:
<>Why don't you just set up two screens and use ScreenToFront and ScreenToBack
<>to flip them? These routines are (as far as I have been able to tell) as near
<>instantanious as you can get. Let intuition worry about the copper lists.
<>That's what it's for, after all.
<
<I suppose that would work, but if you're waiting for IDCMP messages, it
<could be a problem.
<
<Keith Doyle

Not if you have a backdrop  window in each screen and you call ActivateWindow()
after the ScreenToFront().  I've done this and it works well.  Of course, you 
have to do the "clone the IDCMP port" using ModifyIDCMP() so messages always go
to the sames place.

 Hobie Orris			 	| 	
 guest of SoftQuad Inc., Toronto, Ont.	|"There'll be no more giant leeches
 {ihnp4 | decvax | ? }!utzoo!sq!hobie	| When you find the good Lord Jesus"

peter@sugar.UUCP (Peter da Silva) (11/22/87)

In article <21733@ucbvax.BERKELEY.EDU>, bryce@hoser.berkeley.edu (Bryce Nesbitt) writes:
> In article <1038@> peter@sugar.UUCP (Peter da Silva) writes:
> >Why don't you just set up two screens and use ScreenToFront and ScreenToBack
> >to flip them? 
> Peter da Silva, multitasking terrorist.

Yow! borrowing Stallman's terminology? Have a look at my Gauge program to see
some TRUE terror-tactics!

> This is quick, easy and  probably
> will be compatible in the future.

My main point.

> But it is also a dirty, ugly
> kludge that gives users headaches.  Try C= N or C= M on such a program.

Good point.

> Try dragging the screen.  YUCK!

Flip()
{
	MoveScreen(scr[!mine], 0, scr[mine]->TopEdge - scr[!mine]->TopEdge);
	ScreenToFront(scr[!mine]);
	mine = !mine;
}

> In the second case, post a "start animating" requester in *your*
> screen.  Or maybe one in each, come to think of it.  Still a 
> kludge.

Better than whatever Scult/Animate-3d does, though. And did you try dragging
Halfbright Hill, ever? Whetever you do should be attached to screens or
you'll see some REAL terror tactics!

(Still have no idea why Halfbright Hill did the stuff it did. An overscan
screen would have done the job fine.)

> Set the ViewPort->RasInfo->BitMap plane pointers to the
> "other" data then MakeScreen(Screen), RethinkDisplay().
> The problem with this is that it rebuilds the copperlists
> and that takes a while.  (Reference: WaveBench-1 in interlace :-)

Looks like it's not too bad an idea.

> A unique solution was used by Matt Dillon.  He had a two bitplane
> display for Wiredemo.  He draws into one plane at a time, setting
> the color registers to make that plane invisible at the time.
> Flopping the color registers is fast.

This is an all-time classic technique.

By the way, how do you get OUT of wiredemo?
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

kkaempf@rmi.UUCP (Klaus Kaempf) (12/02/87)

This message is being forwarded by me for a friend who has
no access to the UseNet (yet!).
Feel free to send replies to me.

Klaus Kaempf
kkaempf@rmi.UUCP

- - - - - - - - -

In article <782@mitsumi.UUCP> jimm@mitsumi.UUCP (Jim
Mackraz) writes:
> In article <7768@steinmetz.steinmetz.UUCP>
> guilford@csv.rpi.edu (james d guilford) writes:
>> I am planning to write some animation-type software, and
>> so I looked up double buffering in the RKM. It suggested
>> that I create two screens and two sets of copper lists,
>> and then to flip screens, I just replace the copper list
>> pointers.

If you do so, you will certainly run into the same troubles,
almost all other programs that use double-buffering have.
No-one knows, if there isn't anyone else doing the same
thing to the copperlists, you are doing right now. This will
result in the same crash the JUGGLER etc. will end up with,
if you just try to drag the screen or use Amiga-M/Amiga-N.
Intuition will remove and deallocate the copperlist YOU
installed and next time YOU need it ...

Of course you cannot use MakeVPort()/RethinkDisplay() each
and every frame (you might as well display the "zz" cloud
then), but I used two approaches to solve this problem in my
programs:

Scan the copperlists (AND the intermediate copperlists!!!)
for the MOVE instructions, that will install your bitplanes,
and replace the arguments to these directly (Disable(), of
course). You will also have to set up the "struct BitMap" in
your ViewPort to reflect these new circumstances, because
someone else might call "RemakeDisplay()". DO NOT assume a
fixed layout of the copperlists! This one should be written
in assembler.

The second approach will only "MrgCop()", if the pointers to
the copperlists within the View have been changed by someone
else since the last time, your program exchanged them. I
wrote an example to demonstrate this some time ago and if
anyone is interested, I will post the source for it ( <10 KB
highly readable C source for both Lattice and Aztec).

This method might sometimes miss a change (resulting in
flickering) and is certainly VERY SLOW, IF TWO programs
behave this way, but at least it won't crash!

How about a public semaphore in 1.3? Or something like a
"ChangeCount" to check out, if the copperlists have been
changed recently.

Hey Leo! Don't _you_ have a better idea 'bout this?

> Note that the copper list pointers you replace are in
> graphics base, unless you also want to replace the vblank
> interrupt routine which re-installs them (and handles
> interlace). One way to do this is use LoadView().

This was true for 1.1. If you were running at a higher
interrupt priority level than the vblank interrupt or simply
disabled it, only every second line of an interlace screen
was being displayed (this looked rather funny, try it
yourself). Under Kickstart 1.2 the copperlists will exchange
each other themselves after they did their job for the
single frame - so no need for vblank and processor any
longer (except for synchronization).

!ralph

       Ralph Babel | sys64824
       Falkenweg 3 | (!#X3F0001)()
D-6204 Taunusstein | (**((void (**)(void))0xfc0004))();

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (12/16/87)

In article <812@rmi.UUCP> kkaempf@rmi.UUCP (Klaus Kaempf) writes:
:In article <782@mitsumi.UUCP> jimm@mitsumi.UUCP (Jim
:Mackraz) writes:
:: In article <7768@steinmetz.steinmetz.UUCP>
:: guilford@csv.rpi.edu (james d guilford) writes:
::: I am planning to write some animation-type software, and
::: so I looked up double buffering in the RKM. It suggested
::: that I create two screens and two sets of copper lists,
::: and then to flip screens, I just replace the copper list
::: pointers.
:
:Scan the copperlists (AND the intermediate copperlists!!!)
:for the MOVE instructions, that will install your bitplanes,
:and replace the arguments to these directly (Disable(), of
:course). You will also have to set up the "struct BitMap" in
:your ViewPort to reflect these new circumstances, because
:someone else might call "RemakeDisplay()". DO NOT assume a
:fixed layout of the copperlists! This one should be written
:in assembler.
:
:Hey Leo! Don't _you_ have a better idea 'bout this?
:
	Well, the procedure you just described (scanning Copper lists) is
precisely what ScrollVPort() does.

	For example code, look at my old display hack, "Ing".  It double-
buffers using ScrollVPort().  You can drag the screen, depth arrange it and
everything.  It does glitch a tiny bit, but that is largely dependent on the
Phase of The Moon.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	ihnp4!ptsfa -\
 \_ -_		Recumbent Bikes:	      dual ---> !{well,unicom}!ewhac
O----^o	      The Only Way To Fly.	      hplabs / (pronounced "AE-wack")
"Work FOR?  I don't work FOR anybody!  I'm just having fun."  -- The Doctor