[comp.sys.amiga] Double Buffering Glitch

keithd@cadovax.UUCP (Keith Doyle) (08/03/87)

Hi gang,

Included in this message is an example of a 'glitch' I've been chasing
for some time, with no success.

What I am attempting to do, is while double buffering two screens of
data, to cause the switch by swapping the bitmap structure pointed to
by the rastport with a secondary bitmap structure, and then do a:

	Forbid();
	MakeView(view);
	MrgCop();
	LoadView();
	Permit();

To cause the actual switch.  I've found the LoadView() dosen't really
need to be within the Forbid/Permit but am doing it that way for now
just for good measure until the problem can be fixed.

I've also used either WaitTOF() or WaitBOVP() either just before or
just after the Forbid() with perhaps a somewhat minimization of the
problem, but not a complete cure.  I've also replaced the Forbid/Permit
with Disable/Enable, but again, the problem *may* be lessened (it's
hard to tell) but is definitely not completely cured.

What happens is, once in a while, one of the bitplanes seems to
be out of whack for an instant.  While watching the output of the
included program, you will see, periodically, a 'ghost' image of the
screen shifted HORIZONTALLY about half the screen width.  It will appear
as a quick flash.  

Sometimes, things will work fine for several minutes before the probem will
exhibit itself, do it once, and then work fine for several minutes again.

Other times, it will do it quite often, once every few seconds or so.  It
seems highly tempermental for some reason.

Sometimes I have thought it had been fixed by a particular combination
that I've tried, but sooner or later I found that it would still occur.
So be patient, it will happen sooner or later.  

This demonstration is in hi-res, because it seems to exhibit itself more
often in hi-res, and though I have seen it in lo-res overscan, I've never
seen it in normal 320x200 lo-res.  

While I was at Siggraph last week, I noticed the problem in the new
product being announced by Associated Computer Services, the 
Deluxe Production Manager (something like that, being distributed up by EA)
which is a hi-res overscan TV-station-targeted display sequencing product
roughly in the neighborhood of ProVideo CGI but allowing IFF display files
and simple animations.  I don't know if they are doing their double 
buffering in the same manner as I am, but their product does seem to 
exhibit the same 'glitch'.  They were running on an A2000, indicating
the problem is not related to early chip-rev's or something.

What this program does, is it opens a hi-res screen and window, sets
a color palette, allocates a second bitmap structure with associated
planes, draws a series of concientric circles as a test pattern, uses
the routine MapSwap() to switch to the second bitmap, redraws the 
test pattern, and then does an endless loop calling MapSwap, delaying,
and checking for mouse events (to quit the program).

I've added notes where I've tried various combinations of things to
cure the problem.

Perhaps this is the wrong way to implement double buffering in the
first place, and I should be modifying the ViewPort structure RastPort
pointer to a secondary RastPort or something, I don't know.  This 
mechanism seems to work great except for the occasional 'glitch' as I 
mentioned, which can be quite irritating at times.  If somebody knows
that I should be using a completely different mechanism for some reason,
please let me know.  I implemented the switch using this method because
it seemed to work.  Changing just the pointer to the BitMap structure
in the RastPort dosen't work (nothing happens), I had to swap the structure 
data itself.  This implies that Intuition is keeping it's own copy of 
the pointer to the BitMap structure, and so changing the RastPort's
has no effect.

This program should compile under either Manx (16 or 32 bit) or Lattice.

If anyone out there has any ideas on this one, it would sure help.

Thanks,

Keith Doyle
#  {ucbvax,ihnp4,decvax}!trwrb!cadovax!keithd
#  cadovax!keithd@ucla-locus.arpa  Contel Business Systems 213-323-8170

---------------cut here ---------------------
/*
	bugtest.c
*/

#include "stdio.h"
#include "hardware/dmabits.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "libraries/diskfont.h"
#include "fcntl.h"
#include "exec/types.h"
#include "exec/memory.h"
#include "graphics/copper.h"
#include "graphics/gfx.h"
#include "graphics/view.h"
#include "graphics/gfxmacros.h"
#include "graphics/rastport.h"
#include "hardware/blit.h"
#include "hardware/custom.h"
#include "intuition/intuition.h"

struct BitMap *map1,*map2,*tempmap;
struct RastPort *rp;
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct Window *Window;
struct Screen *Screen;
struct ViewPort *vp,*ViewPortAddress();
struct View *view,*ViewAddress();
struct IntuiMessage *GetMsg();
short mapflag;

void *OpenLibrary();
void *AllocMem();
void *OpenScreen();
void *OpenWindow();

#define INTUITION_REV 29L
#define GRAPHICS_REV 29L

struct NewWindow NewWindow = 
{
	0,	/* left edge */
	0,	/* top edge  */
	640,	/* width     */
	400,	/* heigth    */
	0,1,	/* pen's     */

	/* IDCmpFlags */
	MOUSEBUTTONS, 

	/* flags */
	RMBTRAP | BACKDROP | NOCAREREFRESH | BORDERLESS | ACTIVATE,

	0,	/* gadget list */
	0,	/* check mark */
	0,	/* title pointer */
	0,	/* screen pointer */
	0,	/* bitmap pointer */
	0,0,	/* minimum sizes */
	0,0,	/* maximum sizes */
	CUSTOMSCREEN,
};

struct NewScreen NewScreen =
{
	0,	/* left edge */
	0,	/* top edge  */
	640,	/* width     */
	400,	/* heigth    */
	4,	/* depth     */
	0,1,	/* pen's     */
	LACE | HIRES,	/* view modes */
	CUSTOMSCREEN,	/* type      */
	0,		/* font      */
	(UBYTE *)"Screen",	/* title     */
	0,		/* gagets    */
	0,		/* bitmap    */
};

USHORT cmap[32] = {
	0x000,
	0x00f,
	0x0f0,
	0x088,
	0xf00,
	0x808,
	0x880,
	0x888,
	0xff0,
	0x008,
	0x080,
	0x0ff,
	0x800,
	0xf0f,
	0xcfc,
	0xfff,
	0xcf4,
	0xc40,
	0xc44,
	0x4c8,
	0x4c4,
	0x44c,
	0x444,
	0x48c,
	0x4c8,
	0x4cc,
	0xc48,
	0xc4c,
	0xcc4,
	0xccc,
	0xcc8,
	0xc88
};

MapSwap(m1,m2)
struct BitMap *m1,*m2;
{
	short i;
	UBYTE *t;

/* swap the bitmap structures */

Disable();	/* for good measure until bug is located,
				probably not necessary */
	/* move map1 data to to tempmap */
	movmem((char *)map1,(char *)tempmap,sizeof(struct BitMap)); 
	/* move map2 data to map1 */
	movmem((char *)map2,(char *)map1,sizeof(struct BitMap));
	/* move tempmap data to map2 */
	movmem((char *)tempmap,(char *)map2,sizeof(struct BitMap));
Enable();

	view = ViewAddress();

/*	WaitTOF();	 was WaitBOVP(vp) */
/*      ^^^^^^			^^^^^^^^^
	I've tried both of these both outside and inside the following 
	Disable/Enable or Forbid/Permit pairs, *may* minimize the problem 
	somewhat, but not cure it completely */ 

Forbid();
	MakeVPort(view,vp);
	MrgCop(view);
	LoadView(view);
Permit();

/* I've replaced the above 'Forbid()' and 'Permit()' above with 
	Disable() Enable(), and while it seemed to get better, did not
	completely cure the problem */

/*	RethinkDisplay(); */
/* 	 ^^^^^^
	I've tried this instead of the LoadView, as well as a RemakeDisplay,
	again with no success */

	mapflag = 1 ^ mapflag;  /* keep track of which map is which */
}

get_message()
{
	register ULONG class;
	register USHORT code;
	register struct IntuiMessage *Message;

	while(Message = GetMsg(Window->UserPort)) {
		class = Message->Class;
		code  = Message->Code;
		ReplyMsg(Message);
		if(class == MOUSEBUTTONS) bailout();
	}
}

main()
{
	short i;
	map1 = (struct BitMap *)0;
	map2 = (struct BitMap *)0;
	tempmap = (struct BitMap *)0;
	mapflag = 0;

/* open libraries */

if (!IntuitionBase) {
	if(!(IntuitionBase=OpenLibrary("intuition.library",INTUITION_REV)))
	{
		printf("Can't open Intuition library\n");
		bailout();
	}
}

if (!GfxBase) {
	if( !(GfxBase = OpenLibrary("graphics.library",GRAPHICS_REV)) )
	{
		printf("Can't open Graphics library\n");
		bailout();
	}
}

/* allocate bitmap struct space */

	if ((map1 = 
		AllocMem((long)sizeof(struct BitMap),MEMF_CLEAR)) == 0) {
		printf("Out of memory\n");
		bailout();
	}

/* allocate temp map space */
	if ((tempmap = 
		AllocMem((long)sizeof(struct BitMap),MEMF_CLEAR)) == 0) {
		printf("Out of memory\n");
		bailout();
	}

/* setup the temp bitmap for the data */
	map1->BytesPerRow = 80;
	map1->Rows = 400;
	map1->Depth = 4;

	Screen = OpenScreen( &NewScreen);
	if(!Screen) {
		printf("Can't open Screen\n");
		bailout();
	}

	NewWindow.Screen = Screen;
	Window = OpenWindow( &NewWindow );
	if(!Window) {
		printf("Can't open Window\n");
		bailout();
	}
	
	ShowTitle(Screen,0L);		/* hide the screen title */
	vp = ViewPortAddress(Window);	/* get the windows viewport */
	rp = Window->RPort;

/* setup color map */
	LoadRGB4(vp,cmap,32L);

/* allocate a second bitmap */

	for(i=0;i<4;i++)
	{
		if( (map1->Planes[i] = AllocMem( 32000L, 
			MEMF_CHIP | MEMF_CLEAR)) == 0 ) {
			printf("Out of memory\n");
			bailout();
		}
	}

/* draw a pattern */
	SetAPen(rp,15L);
	Move(rp,316L,202L);
	Text(rp,"1",1L);
	for (i=10;i<120;i+=10) {
		DrawCircle(rp,320L,200L,(long)i);
	}

/* point map2 to original screen's bitmap */
	map2 = rp->BitMap;

/* point to other map */
	MapSwap(map1,map2);

/* draw second pattern */
	SetAPen(rp,15L);
	Move(rp,316L,202L);
	Text(rp,"2",1L);
	for (i=10;i<120;i+=10) {
		DrawCircle(rp,320L,200L,(long)i);
	}

/* endless loop/toggle maps */
	for(;;) {
		MapSwap(map1,map2);
		Delay(5L);	 /* amount of delay dosen't matter, you can 
				    remove this with no apparent effect */
		get_message();	/* used to detect mouse hit for exit */
	}
}

bailout()
{
	short i;

	if (map1) {
		/* make sure maps are straight */
		if (mapflag) MapSwap(map1,map2); 
		for (i=0;i<4;i++) FreeMem(map1->Planes[i],32000L);
		FreeMem(map1,(long)sizeof(struct BitMap));
	}
	if (tempmap) FreeMem(tempmap,(long)sizeof(struct BitMap));
	if (Window) CloseWindow(Window);
	if (Screen) CloseScreen(Screen); 
	if (GfxBase) CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
	exit(0);
}

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (08/05/87)

In article <1679@cadovax.UUCP> keithd@cadovax.UUCP (Keith Doyle) writes:
>Hi gang,
>
>Included in this message is an example of a 'glitch' I've been chasing
>for some time, with no success.
>
>What I am attempting to do, is while double buffering two screens of
>data, to cause the switch by swapping the bitmap structure pointed to
>by the rastport with a secondary bitmap structure, and then do a:
>
>	Forbid();
>	MakeView(view);
>	MrgCop();
>	LoadView();
>	Permit();
>
	Hummmm.  Did you know that you can do this, and Intuition won't
mind:

	screen -> ViewPort.RasInfo -> BitMap = pointer_to_other_BitMap;
	ScrollVPort (&screen -> ViewPort);

	All you do is stuff the pointer to the bitmap structure you want,
and call ScrollVPort() on the viewport structure.  This has the added
advantage that it massages the existing copper lists in place.  MrgCop()
computes a whole new list, which I'm sure takes much longer.  Be sure you
restore the original pointer before you call CloseScreen(); I've no idea
what will happen if you don't.

	If you'd like to see ScrollVPort()-style double buffering in action,
take a look at the source code to Ing, my windows-bouncing program.  I use
it in there.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	ihnp4!ptsfa -\
 \_ -_	 Bike shrunk by popular demand,	      dual ---> !{well,unicom}!ewhac
O----^o	 But it's still the only way to fly.  hplabs / (pronounced "AE-wack")
"Work FOR?  I don't work FOR anybody!  I'm just having fun."  -- The Doctor