[comp.sys.amiga] Double Buffering - Ex. Copper Interrupt

haitex@pnet01.cts.com (Wade Bickel) (11/10/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-installsthem (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
> 

      Jim G.,

	I agree with Jim M. that the copper interrupt is probably your
      best solution.  Here is some sample code that should help you. I
      have found this to be a difficult type of code to work with.  I
      recommend that you read the Hardware manule in detail.


(****************************************************************************
 *			        CopInt.MOD
 *---------------------------------------------------------------------------
 *	     COPYRIGHT 1987 by Wade W. Bickel and Haitex Resources.
 *	           SOURCE RELEASED TO PUBLIC DOMAIN 11-9-87
 ****************************************************************************
 *  MODULE: CopInt.MOD  				CREATED: 10-16-87
 *  AUTHOR: Wade W. Bickel 4231 Acacia Ave. Bonita, Ca. 92002, (619) 421-5602
 *  FUNCTION:  This module contains routines for generating a copper
 *		 interrupt and handler system.
 *  NOTES:     Thanks to Leon D. Frenkel for his invaluable assistance
 *		 in creating this module.
 *	       Written and tested using Benchmark Modula-2, A1000, 2.5M
 *	       Note:  this version (distributed on UseNet, for public
 *			reference/comments) derived from more complex
 *			library routines, and not tested as shown.
 ***************************************************************************)
(* IMPLEMENTATION *)  MODULE CopInt;

(* Some Extra Imports have not been sifted from Public Source file *)
FROM SYSTEM 		IMPORT BYTE, ADR, INLINE, ADDRESS;
FROM Blit 		IMPORT WaitTOF;
FROM CustomHardware 	IMPORT custom;
FROM Copper 		IMPORT UCopListPtr, UCopList, CBump, CMove,
				 CWait, UCopperListInit, FreeCopList;
FROM CopperUtil 	IMPORT CEND, CINIT, CMOVE, CWAIT;
FROM INTHardware 	IMPORT INTSetClr, INTCoper;
FROM Interrupts		IMPORT Interrupt, AddIntServer, RemIntServer;
FROM Nodes 		IMPORT NTInterrupt;
FROM Rasters 		IMPORT RastPortPtr;
FROM SimpleScreens 	IMPORT CreateScreen;
FROM Views 		IMPORT ViewPtr, ViewPortPtr, MrgCop, LoadView,
				 LoadRGB4, MakeVPort;
VAR
  uc				: UCopList;
  ucp				: UCopListPtr;
  int				: Interrupt;

 (************************************************************************
  *  CopperServer:        Copper interrupt server routine.
  *
  ************************************************************************)
  PROCEDURE CopperServer(): LONGCARD;   (* Interrupt Server *)
    BEGIN
      INLINE(48E7H, 03F3EH); (* MOVEM.L D2-D7/A2-A6,-(SP)  Push Registers *)
(*
    		==== PUT YOUR SWITCHING CONTROL HERE ====
      	MakeVPort(V^,VP^);     (* just point V and VP at the View and *)
    	LoadView(V^);	       (*  ViewPort you want to use *) 
*) 
      INLINE(4CDFH, 07CFCH); (* MOVEM.L (SP)+,D2-D7/A2-A6  Pop Registers *)
      RETURN (0D);	     (* Return D0 = 0 Continue Server Chain *)
    END CopperServer;
 
 (************************************************************************
  *  InitSwitching:    Initalize and impliment copper interrupt server.
  *
  *		       v, v2   :  View Pointers to two already initialized
  *				 views (with there own viewports).
  *		       VIntPos :  vertical screen position of desired
  *				 interrupt.
  *		       Note:      the Hardware Manule indicates that the
  *				 visable screen starts at line 20, but
  *				 my experience says that the visable 
  *				 screen starts at line 0. 
  ************************************************************************)
  PROCEDURE InitSwitching(VAR v, v2 : ViewPtr; VIntPos : INTEGER):BOOLEAN;
     BEGIN
        WITH int DO
         isNode.lnType := NTInterrupt;
         isNode.lnPri  := BYTE(0);
         isNode.lnName := NIL;
         isCode        := ADR(CopperServer); 
         isData        := NIL;
       END;
       AddIntServer(INTCoper, int);
       ucp := CINIT(uc, 10);                     (* Create USER Copper List *)
       						 (*   only need 4 wds but   *)
						 (*   I've not yet fixed it.*)
       CWAIT(uc, VIntPos, 0);			 (* Generate Interrupt at   *)
       						 (*   X = 0, Y = VIntPos.   *)
       CMOVE(uc, ADR(custom^.intreq), {INTSetClr, INTCoper});  (* cause int *)
       CEND(uc);
       (* Install New Copper List *)
       WaitTOF();				 (* Probably not needed *)
       v^.ViewPort^.UCopIns := ADR(uc);
       v2^.ViewPort^.UCopIns := ADR(uc);
   
     END InitSwitching;

 (************************************************************************
  *  TerminateSwitching:     Terminates copper interrupt server and de-
  *			  allocates allocations made in InitSwitching.
  ************************************************************************)
   PROCEDURE TerminateSwitching(VAR v, v2 : ViewPtr);
     BEGIN
      (* Cleanup *)
      RemIntServer(INTCoper, int);
      v^.ViewPort^.UCopIns := NIL;
      MrgCop(v^);				(* IMPLEMENT VIEW *)
      v2^.ViewPort^.UCopIns := NIL;
      MrgCop(v2^);				(* IMPLEMENT VIEW *)
      FreeCopList(uc.FirstCopList^);
     END TerminateSwitching;

END CopInt.

	   =======================================================
	  
     	  Now ALL you need to do is control the switching between the
	the views.  I recommend, after initialization, that you	draw
	into the available bitmap until it is complete, do as much
	of the screen creation as possible (ie MakeView), then signal
	this to the interrupt routine and wait for a return signal
	telling you that it is ok to resume drawing.  In the interrupt
        routine wait for the described signal from your renderer and
	then reset the RasterPortPtr you're useing to point at the
	bitmap you were displaying, and do a LoadView on the View just
	finished. (I do the MakeView in the interrupt routine without
        problems).

	  		A FEW NOTES: 

           Merging the copper lists takes a significant amount of time,
        therefor it would be benificial to you to avoid having to re-
        merge the lists any more often than necessary.  If you are working
        under Intuition good luck, as a rats-nest of problems will now
        arise for you.  Note that for not intuition displays the copper
        interrupt chain is usually empty, and that multi-taskablity is
	threatened by your server so be carefull.
	  A short wait and I should be making a more complex screen 
        buffering system available (though how and in what form I
        don't know).
	            
					Hopes this helps you,

						Wade.
						(619) 421-5602


UUCP: {cbosgd, hplabs!hp-sdd, sdcsvax, nosc}!crash!pnet01!haitex
ARPA: crash!pnet01!haitex@nosc.mil
INET: haitex@pnet01.CTS.COM