[comp.sys.mac.programmer] Synching to the VBL - CODE

chaffee@reed.UUCP (Alex Chaffee) (03/02/91)

In the UMPG, there's some code for installing a task on the VBL queue. It
sez:

	Subject:.c2.Sync Drawing (with Code)

	To do synched drawing on a Mac II, you want to use a technique
	analogous to that of watching TickCount() on the MacPlus, but you
	have to make your own VBL counter.  This should be done with
	VBLTask tied to the video slot so you really get video synching.

This is true. The author (Dave) provided some code for doing this.
Unfortunately, he used a technique which is clearly taboo - self-modifying
code. Here's code for a safer way to do the same thing. It's based on tech
note #180; MPW programmers should consult that note to convert my asm{} code
into the GetA5() macros.

Note that this doesn't deal with multiple monitors or checking for the
existence of color quickdraw (which is, I believe, required for the
GetVideoDefault call). It's not dangerous to leave the task running, as it
gets swapped out by Multifinder.

Usage:
	#include "sync.h"
	InstallSync();
	...
	WaitForSync();
	CopyBits(...);
	...
	RemoveSync();



--- File: sync.h ---
/*
	Sync.h
*/

/*	Exported Variables	*/

extern	long	vCounter;		/*	just like Ticks - incremented every refresh	*/

/*	Macros/Prototypes	*/

void InstallSync(void);
void RemoveSync(void);
void WaitForSync (void);

static long vblJunk;
#define WaitForSync()	vblJunk = vCounter; do {} while (vblJunk == vCounter);

--- File: Sync.c ---
/*
	Sync.c
	
	Implements a VBL counter (like Ticks) on any Mac.
	
	Usage:
		#include "sync.h"
		InstallSync();
		...
		WaitForSync();
		CopyBits(...);
		...
		RemoveSync();

	Author: Alex Chaffee (chaffee@reed.bitnet)
*/

#include "Sync.h"

/*	Types	*/
typedef struct {
	long	goodA5;
	VBLTask	task;
} MYVBLTASK;

/*	Globals	*/

long	vCounter;
static MYVBLTASK	mytask;
static DefVideoRec	video;

/*	Prototypes	*/
static pascal void Task(void);

/*	Task	*/
static pascal void Task(void)
{
	long	oldA5;
	MYVBLTASK	vbltask;
	asm {
		move.l	A5,oldA5	; save off the old value of A5
		move.l	-4(A0), A5	; A0 points to our VBL task record, and earlier we
					; saved CurrentA5 near it
	}
	vCounter++;
	mytask.task.vblCount = 1;	/*	we want to run again real soon	*/
	asm {
		move.l	oldA5,A5
	}
}

/*	InstallSync	*/
void InstallSync(void)
{
	GetVideoDefault(&video);

	mytask.goodA5 = (long)CurrentA5;
	vCounter = 0;

	mytask.task.qType = vType;
	mytask.task.vblAddr = (ProcPtr) Task;
	mytask.task.vblCount = 1;
	mytask.task.vblPhase = 0;
	SlotVInstall(&mytask.task, video.sdSlot);
}

void RemoveSync(void)
{
	SlotVRemove(&mytask.task, video.sdSlot);
}

/*	If you don't want to use the macro, uncomment this function	*/
/*
void WaitForSync (void)
{
	long vJunk = vCounter;
	do {} while ( vCounter == vJunk );
}
*/

---------------
Alex Chaffee
chaffee@reed.{UUCP,BITNET}
Reed College, Portland OR 97202
____________________
-- 
Alex Chaffee
chaffee@reed.{UUCP,BITNET}
Reed College, Portland OR 97202
____________________