GP2X Hardware Blitter?


Oscaruzzo

Member
Joined
Sep 26, 2005
Messages
227
Age
50
Location
Italy
Website
Visit site
Has anyone managed to do something at all with the hardware blitter (or 2d accelerator, as the doc calls it)?

I tried in many ways to do some basic rectangle-filling or area copy, but nothing happens. I just set a lot of registers, but i don't know how to "trigger" the real operation.

Any suggestion will be appreciated :)
 
I'm in the same boat. I've tried a few things, but haven't managed to get it to do anything yet. I think there may be a trigger in the MESGDSTCTRL or MESGSRCCTRL, but the MMSP2 databook is about as helpful as my grandmother trying to teach me nuclear physics.

Rlyeh has said he will have accelerated blitting routines out this week. I'm waiting for those since I cannot work it out myself.
 
I've not tried anything myself as I've only just got my GP2X but I have been looking at the docs.

I think that bit 8 of MESGSRCCTRL determines whether or not the blitter fetches it's own data or relies on the CPU to pump data to MESGFIFO maybe setting this bit will start a transfer?
Otherwise you could try setting bit 10 of MESGCTRL to clear the FIFO.

Hopefully I'll get a chance to mess around with it when I figured out the toolchain, set up the compiler etc. etc.

I'll let you know if I figure anything out.
 
If someone wants to check it, here's my (UGLY) test code
Code:
#include <errno.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

FILE *out;

void *trymmap (void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
    char *p;
    int aa;

    fprintf (out, "mmap(%X, %X, %X, %X, %X, %X) ... ", (unsigned int)start, length, prot, flags, fd, (unsigned int)offset);
    p = mmap (start, length, prot, flags, fd, offset);
    if (p == (char *)0xFFFFFFFF)
    {
        aa = errno;
        fprintf (out, "failed. errno = %d\n", aa);
    }
    else
    {
        fprintf (out, "OK! (%X)\n", (unsigned int)p);
    }

    return p;
}

int main(int argc, char *argv[]) {
    //open fb0 and mem
    out = stdout;
    int fb0 = open("/dev/fb0", O_RDWR);
    int mem = open("/dev/mem", O_RDWR);
    
    //find physical address of fb
    struct fb_fix_screeninfo fixed_info;
    ioctl(fb0, FBIOGET_FSCREENINFO, &fixed_info); 

    //mmap fb to screen
    unsigned short *screen = trymmap(0, 320*240*2, PROT_WRITE, MAP_SHARED, mem, fixed_info.smem_start);

    //mmap regs
    unsigned long *reg1l = trymmap(0, 0x10000,   PROT_READ|PROT_WRITE, MAP_SHARED, mem, 0xc0000000);
    unsigned short *reg1s = (unsigned short *)reg1l;

    unsigned long *reg2l = trymmap(0, 0x10000,   PROT_READ|PROT_WRITE, MAP_SHARED, mem, 0xE0020000);
    unsigned short *reg2s = (unsigned short *)reg2l;

    reg1s[0x28DA>>1]=0x04AB; // 16bpp
    reg1s[0x290C>>1]=320*2;  // line width in bytes

    // draw something in (0,0)-(31, 31)
    int i, j; 
    for (i=0; i<32; i++) {
        for (j=0; j<32; j++) {
            screen[i*320 + j] = i<<11 | j<<6 | (i+j)>>1;
        }
    }

    sleep(3);

    reg1l[0x090a>>2] = 0xFFFFFFFF;
 
    // copy (0,0)-(31, 31) in (32,32)-(63,63)

    // Dest control
    reg2l[0x0000 >> 2] = 0 << 6 |
                        1 << 5 |
                        0 << 0;

    // Dest base
    reg2l[0x0004 >> 2] = fixed_info.smem_start + (32*2)*320 + (32*2);

    // Dest stride
    reg2l[0x0008 >> 2] = 320 * 2;

    // Source control
    reg2l[0x000C >> 2] = 1 << 8 |
                        1 << 7 |
                        1 << 5 |
                        0 << 0;
                        
    // Source base
    reg2l[0x0010 >> 2] = fixed_info.smem_start;

    // Source stride
    reg2l[0x0014 >> 2] = 320 * 2;
    
    // Source FG
    reg2l[0x0018 >> 2] = 0x0000FFFF;

    // Source BG
    reg2l[0x001C >> 2] = 0x00000000;

    // Pattern control
    reg2l[0x0020 >> 2] = 0x01 >> 6 |
                        0x01 >> 5 |
                        0x02 >> 3 |
                        0x00 >> 0;

    // Pattern reg
    reg2l[0x0080 >> 2] = 0xFFFFFFFF;

    // Pattern FG
    reg2l[0x0024 >> 2] = 0x0000FFFF;
     
    // Pattern BG
    reg2l[0x0028 >> 2] = 0x0000FFFF;

    // Size 
    reg2l[0x002C >> 2] = 32 << 16 | 32 << 0;

    // Control reg
    reg2l[0x0030 >> 2] = 0x00 << 16 |
                        0x00 << 11 |
                        0x01 << 10 |
                        0x01 << 9 |
                        0x01 << 8 |
                        0xFF << 0;

    sleep(3);

    munmap(reg1l, 0x10000);
    munmap(reg2l, 0x10000);
    munmap(screen, 320*240*2);
    close(mem);
    close(fb0);

    chdir("/usr/gp2x");                                          //go to menu
    execl("gp2xmenu","gp2xmenu",NULL);
}
Should draw a rainbow square, sleep 3 seconds, copy it, sleep 3 seconds, and quit.

Currently, it just draws, sleeps 3 seconds, does nothing at all :( , sleeps 3 seconds and quits.
 
Oscaruzzo posted on Dec 14 2005 at 08:41 PM said:
If someone wants to check it, here's my (UGLY) test code
Code:
<code was here>
Should draw a rainbow square, sleep 3 seconds, copy it, sleep 3 seconds, and quit.

Currently, it just draws, sleeps 3 seconds, does nothing at all :( , sleeps 3 seconds and quits.


The only thing I noticed is that you seem to be shifting the wrong way when you write to the pattern control register.
You could try clearing the screen to a weird colour (like pink) first so you can see if any data is written to the frame buffer.
 
Last edited by a moderator:
I've had a chance to hack around with your code now and no sucess I'm afraid.

I put in a loop to check the busy bit of the blitter and it seems to get stuck there.

This is what I wrote:

// wait for the blitter to be free
while(reg2l[0x0034 >> 2] & 1) // check busy bit
{
sleep(1);
}

this was before any of the registers were set and it seems to get stuck here.

The only thing I can think of is that the blitter needs to get enabled or something somewhere else. I'll do a scan of the docs and see what I can find.
 
ok, I looked at the code.

The only think that stuck out was...

sleep(3);

I think this is sleep for 3 ms. If you want 3 seconds, you have to do sleep(3000)

So maybe you program quits to quickly to realise if it worked or not.
 
I can remember, hardware blitter, used to be a huge thing from a developers viewpoint when looking at the original amiga :)
 
Epsilon posted on Dec 15 2005 at 05:20 AM said:
I can remember, hardware blitter, used to be a huge thing from a developers viewpoint when looking at the original amiga :)

Still is. What do you think a graphics card is? ;)
 
Last edited by a moderator:
icurafu posted on Dec 15 2005 at 05:35 AM said:
ok, I looked at the code.

The only think that stuck out was...

sleep(3);

I think this is sleep for 3 ms. If you want 3 seconds, you have to do sleep(3000)

So maybe you program quits to quickly to realise if it worked or not.

Errr man page says
Code:
unsigned int sleep(unsigned int seconds);
;)
 
Last edited by a moderator:
TheDoktor posted on Dec 14 2005 at 10:56 PM said:
You could try clearing the screen to a weird colour (like pink) first so you can see if any data is written to the frame buffer.
Good idea. I'll try it this evening... But the "busy bit" you mention really bothers me, i guess there must be some way to enable the blitter...

I tried to activate a bunch of random clock with

reg1l[0x090a>>2] = 0xFFFFFFFF;

but doesn't seem to help.
 
Last edited by a moderator:
Oscaruzzo posted on Dec 15 2005 at 08:39 AM said:
TheDoktor posted on Dec 14 2005 at 10:56 PM said:
You could try clearing the screen to a weird colour (like pink) first so you can see if any data is written to the frame buffer.
Good idea. I'll try it this evening... But the "busy bit" you mention really bothers me, i guess there must be some way to enable the blitter...

I tried to activate a bunch of random clock with

reg1l[0x090a>>2] = 0xFFFFFFFF;

but doesn't seem to help.

I tried clearing the screen to blue but no data is being written.
Another thing I was thinking was how does writing to these registers work with the CPU data cache? I remember when I was getting started on the PS2 & DC I had problems writing to hardware registers because I was writing to cached memory and the data was staying in the CPU cache and not going to the hardware.
I also noticed that your ROP code should probably be 0xCC for a straight src copy but that didn't make it work either!
I'll hack around a bit more today is I have time and if I find anything I'll post it straight away.
 
Last edited by a moderator:
TheDoktor posted on Dec 15 2005 at 08:48 PM said:
I also noticed that your ROP code should probably be 0xCC for a straight src copy but that didn't make it work either!
Where are the ROP codes described? I couldn't find information on them anywhere.
 
Last edited by a moderator:
Galleon posted on Dec 15 2005 at 06:20 AM said:
Epsilon posted on Dec 15 2005 at 05:20 AM said:
I can remember, hardware blitter, used to be a huge thing from a developers viewpoint when looking at the original amiga :)

Still is. What do you think a graphics card is? ;)

Indeed, 3d graphics are 2D triangles with a depth buffer. If you are lucky you get the matrix multiplication thrown in, but its not necessary, as processors can do 4x4 matrix math quick enough. Luckily the Blue Book nicely prints its matrix operations for OpenGL so a straight poirt is easy.
 
Last edited by a moderator:
TheDoktor posted on Dec 15 2005 at 12:48 PM said:
Another thing I was thinking was how does writing to these registers work with the CPU data cache? I remember when I was getting started on the PS2 & DC I had problems writing to hardware registers because I was writing to cached memory and the data was staying in the CPU cache and not going to the hardware.
msync() could be the answer.
Code:
NAME
       msync - synchronize a file with a memory map

SYNOPSIS
       #include <sys/mman.h>

       int msync(void *start, size_t length, int flags);

DESCRIPTION
       msync  flushes  changes  made  to  the  in-core copy of a file that was
       mapped into memory using mmap(2) back to disk.   Without  use  of  this
       call  there  is  no guarantee that changes are written back before mun‐
       map(2) is called.
I can't try it right now, though, but will definitively try asap.
 
Last edited by a moderator:
slygamer posted on Dec 15 2005 at 01:25 PM said:
Where are the ROP codes described? I couldn't find information on them anywhere.

I googled around a bit and I found that you have 3 basic bit patterns:

#define ROP_PATTERN 0xF0
#define ROP_SOURCE 0xCC
#define ROP_DEST 0xAA

It seems as though you perform logical operations on them to indicate what you want:
eg.

If you just want a source transfer then use 0xCC.
If you want source & pattern you do 0xCC & 0xF0.

etc.

There is a bit of guesswork in that but it seems to make sense.
 
Last edited by a moderator:
LOL, thats one hell of an assumption, even their compliant C++ isn`t 100% compliant, must be hell when you want to do things your way cos your the boss and some dumbass organisation like ANSI keeps telling you you can`t do it that way :rolleyes:

:D
 
That actually looks about right, considering that the MMSP2 was also made to run WindowsCE and the 2D graphic accelerator is made to enhance Windows GDI performance.
 
Back
Top