From: carter@CompSci.Bristol.AC.UK (David Carter)
Newsgroups: comp.sys.amiga.programmer
Subject: Various Questions about Fast 3d Vector Graphics
Date: 15 Sep 92 15:48:34 GMT
Reply-To: carter@CompSci.Bristol.AC.UK (David Carter)
Organization: Dept of Computer Science, University of Bristol, UK.

Hi there everyone,

   Recently, I have taken to playing around with Vector Graphics a la
Elite for a little light relief. Having got the maths, clipping and polygon
filling nicely optimised (using a mixture of C and assembler), I determined
that a major overhead was the MakeVPort()/MrgCop()/LoadView() mechanism that
I was using to double-buffer. (As recommended in the RKM)
   Experimenting, I built my own copper lists, one for each 320x256x4 bitmap
allocated, and did the switching myself by strobing the `cop1lc' register.
This gave me very smooth animation indeed (it jumped from maybe 4 frames a
second to no visible stutter, a pleasant surprise for me).

   I have a number of questions, mostly related to shutting down Intuition in
a friendly manner. At least friendly enough that I can get back to my debugger,
and find out what happened...


   While all my double buffering works very nicely, I can't convince the
machine to rebuilt the sodding Intuition display for me when my program
is cleaning up to exit. I have tried the following methods, in decreasing
order of desirability:

  a) LoadView(GfxBase->ActiView).
        (in both C and Assembler)

   b) RethinkDisplay()

   c) RemakeDisplay()

   The Libraries and Devices Manual (sort of) infers that LoadView does any
required poking to get Intuitions own cprlists installed and running. The
effects that I get are as if the LoadView has been ignored - the last copper
list that I myself installed carries on running, as if nothing had happened
Do I have to dig around in GfxBase to find a copper list ptr, and install
manually?
   Other effects that I get vary between invocations (probably because of
my own hacking around, trying to get it to work):

a) On occasions, typing a command (e.g dir) will flash the hard disk, so I
   assume that the CLI, indeed the whole O/S is still functioning, even if
   I cannot see it in action

   Does anyone have tips on debugging cprLists, when you can't see the
   screen :=).

b) On other occasions, nothing happens [An invisible GURU?]

c) The third, and by far the most entertaining alternative, is on occasions
   that I succeed in running a program that opens its own screen, such as the
   debugger that I use, PowerVisor (highly recommended, apart from the lack
   of scrollbars...) In this case, the application starts up and runs quite
   happily, with the minor caveat that all the characters are weirdly
   magnified, and overlapping, in a display of (I guess) 20 by 10 characters.

   I can't even see how I pull this last trick off, it seems to involve
   hardware undocumented in my manuals [" bitplane fetch rate"?].
   (And I am running with the original, not ECS chipset!)

Extra details:

   I know that DMA and interrupts are set up correctly, if only because
I avoid playing with them at all while debugging. And DMouse carries on
working quite happily in the background afterwards...

   While debugging, I have tried stripping my program down to a minimal
single buffered copperlist, that is $FFFF, $FFFE - "WAIT ($FF,$FE), I hope.
This only gives me option (b) above - no identifiable behaviour at all.
The real copper lists that I use set up all bitplane pointers, colour
registers and display registers: DIWSTRT,DIWEND etc. I know that this is
a bit overkill for a dedicated display, but I *know* that it works, and
guarantees that a whole display appears with a single poke to `cop1lc'.
Get it working first, then optimise. And Intuitions 'View's do a lot more
work than this anyway...

   If I comment out the "move.l d0,cop1lc(a0)" instruction in my program,
if runs quite happily to termination, so I know that the copper list, or
maybe the way that I install it (as WAIT ($FF,$FE) is just a *little* minimal),
is the problem.

   I sincerely hope that someone comes up with a "don't be silly, you have to
do *this* response", as the alternative is some really nasty bug in my minimal
test code (or maybe my equally minimal understanding). Unfortunately, while
the RKMs document the copper hardware well, and the View mechanism well, the
intersection is non-existent.

Other questions, less involved:

   As the hardware itself reloads the copper `PC' from cop1ch for each frame,
what is the benifit of strobing the cop1jmp register. Surely I don't want
the list to start running until the next frame. Especially as the WAIT
copper instruction cannot be adapted to "wait until *above* such and such
a position".
   With regard to my RethinkDisplay problems above, I have tried it with and
without the cop1jmp strobe, and also tried a cop1lch/cop1jmp pair installed
into the VBLANK handler. The effects are the same in all cases.

   A question on the philosophy of double buffering. With 3d graphics, I want
to go to work on the next frame, as soon as the previous frame has been
calculated. The problem is that the new "scratch" framebuffer is still being
displayed, so if I clear it/write to it immediately, I get visible flicker.
I can think of two solutions to this problem:

1. Wait until the "new" framebuffer has been fully displayed, before switching
   displays and writing to it. The problem is that this gives me
   *significant* slowdown, even if I do all the maths while waiting. I did
   say that my routines where chugging along at a fair rate of knots...

2. *Triple* buffering:
      a) Frame currently being written to
      b) Frame currently being displayed
      c) Frame that will be displayed after next VBLANK.
           [Will be the same as (b) unless we are calculating faster than
            25(?)/50 frames a second]

   Problem: 3 lots of 320x256x4 bitmaps is an awful of of memory to
   AllocMem(...,MEMF_CHIP). Especially with only 512K chip RAM.

   Do any of you speed demons out there have any better solutions?

   On a totally different theme, I assume that mouse and keyboard input is
gathered during the VBLANK interrupt. My debugger claims that a vanilla system
has no exec-based vblank interrupts installed [apart from my own]. Question:
how does keyboard and mouse information get to `keyboard.device' and
`gameport.device' - I assume by behind the scenes interaction with the
exec VBLANK handler. Does this interaction have a low enough overhead to
justify me using these two device drivers during high speed animation? The
alternative would seem to be to trash the 68000 interrupt vector and do
everything myself, but that is *definitely* O/S unfriendly, even if I restore
all vectors.
   Which interrupts does the O/S itself need to keep running? I can happily
switch off ALL interrupts, and switch back on only the ones that I require
(currently VBLANK only), restoring the state of the world later, but it is nice
to know these things.

   Finally, a DMA related question. What *does* bit 9 of the DMACON register
do? My RKM would have me believe that is a "Master Control bit", that when
set performs the set or clear operation on all DMA channels.

Example:  (From memory, so probably wrong)

    move.w  #($0200),dmacon(a0)   ; Switch off all DMA, using "MASTER" bit
    move.w  #($81ff),dmacon(a0)   ; Switch back on through individual bits

   I think that this should have "no" effect, what actually happens is that
I lose my display [BitPlane DMA switched off ?]. If I change the second
"magic value" to $83ff, it works. Certainly, the copper example given in
the RKM uses a value of $8380 to switch on copper and bitplane DMA. Three
bits to set two up 2 DMA channels? Should I just read this as "set bit 9
to play with DMA control at all"?

Setup:

   Ancient old A500 (original chipset), A590, 3MB RAM (1/2 Meg chip)
      - Workbench 2.05

   I am using the original 1.1 RKMS (apart from a 1.3 Includes and AutoDocs),
which I am hope are backwardly compatible, at least as far as the hardware is
concerned.

   Thanks in advance for any help that you can give.

Dave
   
Newsgroups: comp.sys.amiga.programmer