Using the Blitter

  • OwnBlitter()/DisownBlitter()
  • Blitter Timing Problems
  • Blitter Speed Optimisation
  • Calculating LF Bytes
  • Clearing with the blitter

    OwnBlitter()/DisownBlitter()

    If you are using the blitter in your code and you are leaving the system intact (as you should) always use the graphics.library functions OwnBlitter() and DisownBlitter() to take control of the blitter. Remember to free it for system use, many system functions (including floppy disk data decoding) use the blitter.

    OwnBlitter() does not trash any registers. I guess DisownBlitter() doesn't either, although Chris may well correct me on this, and they are fast enough to use around your blitter code, so don't just OwnBlitter() at the beginning of your code and DisownBlitter() at the end, only @{" OwnBlitter() " link ownblitter} when you need to.

    graphics.library/OwnBlitter()

    OwnBlitter -- get the blitter for private usage
    
    OwnBlitter()
       -456
    
    void OwnBlitter( void );
    
    If blitter is available return immediately with the blitter
    locked for your exclusive use. If the blitter is not available
    put task to sleep. It will be awakened as soon as the blitter
    is available. When the task first owns the blitter the blitter
    may still be finishing up a blit for the previous owner. You
    must do a WaitBlit before actually using the blitter registers.
    
    Calls to OwnBlitter() do not nest. If a task that owns the
    blitter calls OwnBlitter() again, a lockup will result.
    (Same situation if the task calls a system function
    that tries to own the blitter).
    

    graphics.library/DisownBlitter()

    DisownBlitter - return blitter to free state.
    
    DisownBlitter()
        -462
    
    void DisownBlitter( void );
    
    Free blitter up for use by other blitter users.
    

    graphics.library/QBlit()

    QBlit -- Queue up a request for blitter usage
    
    QBlit( bp )
    -276   a1
    
    void QBlit( struct bltnode * );
    
    Link a request for the use of the blitter to the end of the
    current blitter queue.  The pointer bp points to a blit structure
    containing, among other things, the link information, and the
    address of your routine which is to be called when the blitter
    queue finally gets around to this specific request.  When your
    routine is called, you are in control of the blitter ... it is
    not busy with anyone else's requests.  This means that you can
    directly specify the register contents and start the blitter.
    Your code must be written to run either in supervisor or user
    mode on the 68000.
    
    IN:
          bp - pointer to a blit structure
    
    Your routine is called when the blitter is ready for you.
    In general requests for blitter usage through this channel are
    put in front of those who use the blitter via OwnBlitter and
    DisownBlitter. However for small blits there is more overhead
    using the queuer than Own/Disown Blitter.
    

    graphics.library/QBSBlit

    QBSBlit -- Synchronize the blitter request with the video beam.
    
    QBSBlit( bsp )
     -294    a1
    
    void QBSBlit( struct bltnode * );
    
    Call a user routine for use of the blitter, enqueued separately from
    the @{" QBlit ",link qblit} queue.  Calls the user routine contained in the blit
    structure when the video beam is located at a specified position
    onscreen.   Useful when you are trying to blit into a visible part
    of the screen and wish to perform the data move while the beam is
    not trying to display that same area.  (prevents showing part of
    an old display and part of a new display simultaneously).  Blitter
    requests on the QBSBlit queue take precedence over those on the
    regular blitter queue. The beam position is specified the blitnode.
    
    IN:
       bsp - pointer to a blit structure.
    
    

    graphics.library/WaitBlit()

    WaitBlit -- Wait for the blitter to finish.
    
    WaitBlit()
     -228
    

    Blitter Timing

    Another common cause for demo crashes is blitter timing.

    Assuming that a particular routine will be slow enough that a blitter wait is not needed is silly. Always check for blitter finished, and wait if you need to.

    Don't assume the blitter will always run at the same speed too. Think about how your code would run if the processor or blitter were running at 100 times the current speed. As long as you keep this in mind, you'll be in a better frame of mind for writing code that works on different Amigas.

    Another big source of blitter problems is using the blitter in interrupts.

    Many demos do all processing in the interrupt, with only a
    .wt   btst     #6,$bfe001  ; is left mouse button clicked?
          bne.s    .wt
    
    loop outside of the interrupt. However, some demos do stuff outside the interrupt too. Warning. If you use blitter in both your interrupt and your main code, (or for that matter if you use the blitter via the copper and also in your main code), you may have big problems....

    Take this for example:
       lea      $dff000,a5
       move.l   GfxBase,a6
       jsr      _LVOWaitBlit(a6)
       move.l   #-1,BLTAFWM(a5)                 ; set FWM and LWM in one go
       move.l   #source,BLTAPT(a5)
       move.l   #dest,BLTDPT(a5)
       move.w   #%100111110000,BLTCON0(a5)
       move.w   #0,BLTCON1(a5)
       move.w   #64*height+width/2,BLTSIZE(a5)  ; trigger blitter
    
    There is *nothing* stopping an interrupt, or copper, triggering a blitter operation between the WaitBlit() call and your final BLTSIZE blitter trigger. This can lead to total system blowup.

    Code that may, by luck, work on standard speed machines may die horribly on faster processors due to timing differences causing this type of problem to occurr.

    You can prevent this by using OwnBlitter()

    The safest way to avoid this is to keep all your blitter calls together, use the copper exclusively, or write a blitter-interrupt routine to do your blits for you, which is very good because you avoid getting stuck in a waitblit-loop.

    Always use the graphics.library WaitBlit() routine for your end of blitter code. It does not change any registers, it takes into account any revision of blitter chip and any unusual circumstances, and on an Amiga 1200 will execute faster (because in 32-bit ROM) than any code that you could write in chipram.

    Calculating LF Bytes

    Instead of calculating your LF-bytes all the time you can do this
    A  EQU   %11110000
    B  EQU   %11001100
    C  EQU   %10101010
    
    So when you need an lf-byte you can just type:
       move.w   #(A!B)&C,d0
    

    Blitter clears

    If you use the blitter to clear large areas, you can generally improve speed on higher processors (68020+) by replacing it by a cache-loop that clears with movem.l instead:
            moveq  #0,d0
            moveq  #0,d1
            moveq  #0,d2
            moveq  #0,d3
            moveq  #0,d4
            moveq  #0,d5
            moveq  #0,d6
            sub.l  a0,a0
            sub.l  a1,a1
            sub.l  a2,a2
            sub.l  a3,a3
            sub.l  a4,a4
            sub.l  a5,a5
    
            lea    EndofBitplane,a6
            move.w #(bytes in plane/156)-1,d7
    .Clear
            movem.l d0-d6/a0-a5,-(a6)
            movem.l d0-d6/a0-a5,-(a6)
            movem.l d0-d6/a0-a5,-(a6)
            dbf d7,.Clear
    
    ; final couple of movems may be needed to clear last few bytes of screen...
    
    This loop was (on my 1200) almost three times faster than the blitter.

    With 68000-68010 you can gain some time by NOT using blitter- nasty and the movem-loop.

    BLITTER SPEEDS. (from the Hardware Reference Manual)

    Some general notes about blitter speeds. These numbers are for the blitter only, in 16-bit chip ram.
                     n * H * W
       time taken = -----------
                        7.09   (7.15 for NTSC)
    
    time is in microseconds. H=blitheight,W=blitwidth(#words),n=cycles
    
    n=4+....depends on # DMA-channels used
    
    A: +0          (this one is free!)
    B: +2
    C or D: +0     In line-mode, every pixel takes 8 cycles.
    C and D: +2
    
    
    So, use A,D,A&D for the fastest operation. Use A&C for 2-source operations (e.g. collision check or so).

    Main Menu