Using the hardware blitter

From wiki.gp2x.org

The hardware blitter in the GP2x is one nice piece of hardware. It can speed up your program alot.

The blitter can preform multiple functions like: -Drawing a pattern -Filling a rectangle with a color -Copy a rectangle from one location to another

Because the most used function is to copy a rectangle from one location to another we'll describe that on in detail here.

Contents

Requirements

The blitter works on real memory addresses, this could be a problem for you as Linux supplies you with virtual addresses when you get memory. One of the sollutions is to use the upper 32MB of memory for your image data.

Initialization

Before you can use the blitter you need to do a few things. First you need to get access to the GP2x registers, located at 0xC0000000 and 0xE0020000. The registers at 0xC0000000 are for general MMSP2 registers and the registers at 0xE0020000 for the hardware blitter. For exact descriptions of the used registers look in MMSP2 Databook at Docs_and_Papers.

You can do this by mmaping /dev/mem at those locations like this:

  int memfd;
  unsigned long* memregs32;
  unsigned short* memregs16;
  memfd = open("/dev/mem", O_RDWR);
  
  memregs32 = (unsigned long*) mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0xc0000000);
  memregs16 = (unsigned short *)memregs32;
  
  blitter32 = (unsigned long*)mmap(0, 0x100, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0xE0020000);

After this we need to do 2 vital parts before using the blitter:

  // enable all video and graphic devices
  memregs16[0x090a >> 1] = 0xFFFF;
  // enable fastio
  memregs16[0x0904 >> 1] |= (1 << 10);

If you don't do this, the blitter won't act to anything you do, as it isn't enabled.

Blitting itself

Now we can use the blitter itself. Here is a piece of example code to get you started. To find out what every register does you need to look in the databook. (I know this code works, it might not be the optimal way to use it, so feel free to experiment) This example copies the framebuffer 2nd buffer to the first

  //Wait till the blitter is ready
  while(blitter32[0x0034 >> 2] & 1) usleep(1);

  //Set the destination as 16bit and enable it for use.
  blitter32[0x0000 >> 2] = (1 << 5) | (1 << 6);
  //Set the address of destination
  blitter32[0x0004 >> 2] = 0x3101000;
  //Set the pitch of destination in bytes.
  blitter32[0x0008 >> 2] = 320*2;
  //Set a 16bit source, enable source and say the source is not controlled by CPU(?)
  blitter32[0x000C >> 2] = (1 << 8) | (1 << 7) | (1 << 5);
  //Set the source address
  blitter32[0x0010 >> 2] = 0x3101000 + 320*2*240;
  //Set the pitch of source in bytes
  blitter32[0x0014 >> 2] = 320*2;
  //Do nothing with patern
  blitter32[0x0020 >> 2] = 0;
  //Set the size 320 by 240
  blitter32[0x002C >> 2] = (240 << 16) | (320 << 0);
  //Clear the source input FIFO, positive X,Y. And do a copy ROP.
  blitter32[0x0030 >> 2] = (1 << 10) | (1 << 9) | (1 << 8) | 0xCC;
  //Make the blitter run.
  blitter32[0x0034 >> 2] = 0x0001;

Extra info

If you blit from/to an location that is not aligned to 4 bytes you need to set the fraction bits. You can OR these on registers 0x0000 and 0x000C. More about this in the databook. Example for 16 bit:

  blitter32[0x0000 >> 2] = (1 << 5) | (1 << 6) | (DestinationX % 2) * 16;
  blitter32[0x000C >> 2] = (1 << 8) | (1 << 7) | (1 << 5) | (SourceX % 2) * 16;

If you enable bit 11 in register 0x0030 then you can blit with a transparent color.

It looks like the blitter acts funny when you use a pitch that is not aligned to 4 bytes.

It could be that you try to blit something that you have just drawn with direct pixel acces. And that the pixels are not yet writen to memory. Then you can flush the cache to memory with a flushcache function:

[FILE: flush_uppermem_cache.s]
.global flush_uppermem_cache @ void *start_address, void *end_address, int flags

flush_uppermem_cache:
    swi #0x9f0002
    bx lr

[FILE: flush_uppermem_cache.h]
extern "C" void flush_uppermem_cache(void *start_address, void *end_address, int flags);

The flags parameter should generally be set to 0.

Links

Topic where people got the blitter to work for the first time: http://www.gp32x.com/board/index.php?showtopic=23182

Personal tools