Using the hardware blitter
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.
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.
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.
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;
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.
Topic where people got the blitter to work for the first time: http://www.gp32x.com/board/index.php?showtopic=23182