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