Down With The Blitter


marmakoide

Still Fresh
Joined
Sep 17, 2006
Messages
15
Age
41
Location
Paris, France
Website
www.lri.fr
Hi all
I'm trying to use the blitter to fill rectangle with a single color. By reading the harware optimised SDL, I do this way :
1) Magic to enable the blitter operations
Code:
gp2x_mem_fd = open("/dev/mem", O_RDWR);
blitter_regs_32 = (unsigned int*)mmap(0, 256, 3, MAP_SHARED, gp2x_mem_fd, 0xe0020000);

... doing stuffs...

 /* init the screen to 320x240 16bpp */
  mmsp2_regs_16[0x28da >> 1]  = 0x004ab;
  mmsp2_regs_16[0x290c >> 1]  = 640;

/* enable the hardware acceleration */
mmsp2_regs_16[0x090a >> 1]  = 0xffff;
mmsp2_regs_16[0x0904 >> 1] |= (1 << 10);

2) Now blitting the rectangle
Code:
void
gp2x_blitter_areaFill(const void* offset,
					  unsigned int x, unsigned int y,
					  int width, int height,
					  unsigned short col) {
  unsigned int lOffset;
  unsigned int lDstCtrl;

  /* Compute the adress of the upper left corner */
  lOffset = ((unsigned int)offset) + (y * 640) + (x << 1);
  lDstCtrl = (1 << 5) | ((x & 0x00000001) << 4);

  /* Wait until the blitter is not busy */
  do {} while(blitter_regs_32[BLITTER_REG_RUN >> 2] & 0x01);

  /* Set the destination */
  blitter_regs_32[BLITTER_REG_DSTCTRL >> 2] = lDstCtrl;
  blitter_regs_32[BLITTER_REG_DSTADDR >> 2] = lOffset & ~3;
  blitter_regs_32[BLITTER_REG_DSTSTRIDE >> 2] = 640;
  blitter_regs_32[BLITTER_REG_SRCCTRL >> 2] = 0;

  /* Set the filling pattern */
  blitter_regs_32[BLITTER_REG_PATCTRL >> 2] = (1 << 5) | (1 << 4);
  blitter_regs_32[BLITTER_REG_PATFORCOLOR >> 2] = col;
  blitter_regs_32[BLITTER_REG_PATBACKCOLOR >> 2] = col;
  
  /* Set the size of the rectangle */
  blitter_regs_32[BLITTER_REG_SIZE >> 2] = (height << 16) | width;

  /* Set the fill directions and the raster op */
  blitter_regs_32[BLITTER_REG_CTRL >> 2] = (1 << 10) | (1 << 9) | (1 << 8) | 0xf0;
  
  /* Launch the blitter operation */
  asm volatile("":::"memory");
  blitter_regs_32[BLITTER_REG_RUN >> 2] = 0x01;
}

The 'BLITTER_REG_XXX' comes from the MMSP2 manual. My code freeze the GP2X without displaying anything when I perform that
Code:
asm volatile ("":::"memory");
blitter_regs_32[BLITTER_REG_RUN] = 0x01;

What I missed ?
 
Last edited by a moderator:

spoyser

Member
Joined
Jun 2, 2006
Messages
112
Age
52
Website
Visit site
Hi all
I'm trying to use the blitter to fill rectangle with a single color. By reading the harware optimised SDL, I do this way :
1) Magic to enable the blitter operations
Code:
gp2x_mem_fd = open("/dev/mem", O_RDWR);
blitter_regs_32 = (unsigned int*)mmap(0, 256, 3, MAP_SHARED, gp2x_mem_fd, 0xe0020000);

... doing stuffs...

 /* init the screen to 320x240 16bpp */
  mmsp2_regs_16[0x28da >> 1]  = 0x004ab;
  mmsp2_regs_16[0x290c >> 1]  = 640;

/* enable the hardware acceleration */
mmsp2_regs_16[0x090a >> 1]  = 0xffff;
mmsp2_regs_16[0x0904 >> 1] |= (1 << 10);

2) Now blitting the rectangle
Code:
void
gp2x_blitter_areaFill(const void* offset,
					  unsigned int x, unsigned int y,
					  int width, int height,
					  unsigned short col) {
  unsigned int lOffset;
  unsigned int lDstCtrl;

  /* Compute the adress of the upper left corner */
  lOffset = ((unsigned int)offset) + (y * 640) + (x << 1);
  lDstCtrl = (1 << 5) | ((x & 0x00000001) << 4);

  /* Wait until the blitter is not busy */
  do {} while(blitter_regs_32[BLITTER_REG_RUN >> 2] & 0x01);

  /* Set the destination */
  blitter_regs_32[BLITTER_REG_DSTCTRL >> 2] = lDstCtrl;
  blitter_regs_32[BLITTER_REG_DSTADDR >> 2] = lOffset & ~3;
  blitter_regs_32[BLITTER_REG_DSTSTRIDE >> 2] = 640;
  blitter_regs_32[BLITTER_REG_SRCCTRL >> 2] = 0;

  /* Set the filling pattern */
  blitter_regs_32[BLITTER_REG_PATCTRL >> 2] = (1 << 5) | (1 << 4);
  blitter_regs_32[BLITTER_REG_PATFORCOLOR >> 2] = col;
  blitter_regs_32[BLITTER_REG_PATBACKCOLOR >> 2] = col;
  
  /* Set the size of the rectangle */
  blitter_regs_32[BLITTER_REG_SIZE >> 2] = (height << 16) | width;

  /* Set the fill directions and the raster op */
  blitter_regs_32[BLITTER_REG_CTRL >> 2] = (1 << 10) | (1 << 9) | (1 << 8) | 0xf0;
  
  /* Launch the blitter operation */
  asm volatile("":::"memory");
  blitter_regs_32[BLITTER_REG_RUN >> 2] = 0x01;
}

The 'BLITTER_REG_XXX' comes from the MMSP2 manual. My code freeze the GP2X without displaying anything when I perform that
Code:
asm volatile ("":::"memory");
blitter_regs_32[BLITTER_REG_RUN] = 0x01;

What I missed ?

I came across a similar problem when using the allegro library.

I believe you are getting stuck here:

/* Wait until the blitter is not busy */
do {} while(blitter_regs_32[BLITTER_REG_RUN >> 2] & 0x01);

As the blitter doesn't set itself to be not busy until it has actually done something.

Therefore do a dummy blit during your "magic" section without the check.
 
Last edited by a moderator:

marmakoide

Still Fresh
Joined
Sep 17, 2006
Messages
15
Age
41
Location
Paris, France
Website
www.lri.fr
I believe you are getting stuck here:

/* Wait until the blitter is not busy */
do {} while(blitter_regs_32[BLITTER_REG_RUN >> 2] & 0x01);

As the blitter doesn't set itself to be not busy until it has actually done something.

Therefore do a dummy blit during your "magic" section without the check.

Excuse me, I'am not sure to understand what you mean. You said that in my init phase, I must set the register BLITTER_REG_RUN to 0 ? Or do I must perform a full dummy blit in my init phase ?
 
Last edited by a moderator:

spoyser

Member
Joined
Jun 2, 2006
Messages
112
Age
52
Website
Visit site
I believe you are getting stuck here:

/* Wait until the blitter is not busy */
do {} while(blitter_regs_32[BLITTER_REG_RUN >> 2] & 0x01);

As the blitter doesn't set itself to be not busy until it has actually done something.

Therefore do a dummy blit during your "magic" section without the check.

Excuse me, I'am not sure to understand what you mean. You said that in my init phase, I must set the register BLITTER_REG_RUN to 0 ? Or do I must perform a full dummy blit in my init phase ?

Full blit
 
Last edited by a moderator:

Squidge

Certified Guru
Joined
Nov 16, 2003
Messages
8,493
Location
UK
Website
Visit site
You seem to be enabling the hardware acceleration and blitter, so do the first blit without checking if the blitter is ready or not and see if that helps
 

marmakoide

Still Fresh
Joined
Sep 17, 2006
Messages
15
Age
41
Location
Paris, France
Website
www.lri.fr
Yeeeeeeaaaaaah, got it ! I was listening Born to be wild, I was reading the SDL code source, scratcing my head, and... voila ! Hardware accelerated rectangle blitting ! Now I'am yelling in my room, jumping around :D

The point I missed : the blitter understand only PHYSICAL adress, not the mmu handled adresses used by the Linux kernel. The trick was to convert the Linux adress to physical. So now

--> init the stuffs
Code:
#define PHYSICAL_NONCACHED  0x03000000
#define PHYSICAL_SCREEN0	0x03100000
#define PHYSICAL_SCREEN1	0x03180000



volatile int gp2x_mem_fd;
volatile unsigned char* gp2x_mem;
volatile unsigned long*  mmsp2_regs_32;
volatile unsigned short* mmsp2_regs_16;
volatile unsigned int*  blitter_regs_32;

volatile unsigned char* gp2x_screen;
volatile unsigned char* screen_page_0;
volatile unsigned char* screen_page_1;

void 
gp2x_init() {
  gp2x_mem_fd = open("/dev/mem", O_RDWR);

  /* map the MMSP2 registers */
  mmsp2_regs_32 = mmap(0, 0x10000, 3, MAP_SHARED, gp2x_mem_fd, 0xc0000000);
  mmsp2_regs_16 = (unsigned short*)mmsp2_regs_32;
  
  /* map the blitter registers */
  blitter_regs_32 = (unsigned int*)mmap(0, 0x100, 3, MAP_SHARED, gp2x_mem_fd, 0xe0020000);

  gp2x_mem = mmap(0, 0xf00000, 3, MAP_SHARED, gp2x_mem_fd, PHYSICAL_NONCACHED);
  screen_page_0 = (unsigned char*)&gp2x_mem[0x100000];
  screen_page_1 = (unsigned char*)&gp2x_mem[0x180000];
  gp2x_screen = screen_page_0; 

  /* init the screen to 320x240 16bpp */
  mmsp2_regs_16[0x28da >> 1]  = 0x004ab;
  mmsp2_regs_16[0x290c >> 1]  = 640;
  
  /* enable the hardware acceleration */
  mmsp2_regs_16[0x090a >> 1]  = 0xffff;
  mmsp2_regs_16[0x0904 >> 1] |= (1 << 10);
}

--> Fill a rect (works only for mmaped places, as screen_page_0 and screen_page_1)
Code:
void
gp2x_blitter_areaFill(const void* offset,
					  unsigned int x, unsigned int y,
					  int width, int height,
					  unsigned short col) {
  unsigned int lOffset;
  unsigned int lDstCtrl;

  /* Compute the adress of the upper left corner */
  lOffset = (unsigned int)((long)offset - (long)(gp2x_mem)+ PHYSICAL_NONCACHED);
  lOffset += (y * 640) + (x << 1);
  lDstCtrl = (1 << 5) | ((x & 0x00000001) << 4);

  /* Wait until the blitter is not busy */
  do {} while(blitter_regs_32[BLITTER_REG_RUN >> 2] & 0x01);

  /* Set the destination */
  blitter_regs_32[BLITTER_REG_DSTCTRL >> 2] = lDstCtrl;
  blitter_regs_32[BLITTER_REG_DSTADDR >> 2] = lOffset & ~3;
  blitter_regs_32[BLITTER_REG_DSTSTRIDE >> 2] = 640;
  blitter_regs_32[BLITTER_REG_SRCCTRL >> 2] = 0;

  /* Set the filling pattern */
  blitter_regs_32[BLITTER_REG_PATCTRL >> 2] = (1 << 5) | (1 << 4);
  blitter_regs_32[BLITTER_REG_PATFORCOLOR >> 2] = col;
  blitter_regs_32[BLITTER_REG_PATBACKCOLOR >> 2] = col;
  
  /* Set the size of the rectangle */
  blitter_regs_32[BLITTER_REG_SIZE >> 2] = (height << 16) | width;

  /* Set the fill directions and the raster op */
  blitter_regs_32[BLITTER_REG_CTRL >> 2] = (1 << 10) | (1 << 9) | (1 << 8) | 0xf0;
  
  /* Launch the blitter operation */
  asm volatile("":::"memory");
  blitter_regs_32[BLITTER_REG_RUN >> 2] = 0x01;
}

You seem to be enabling the hardware acceleration and blitter, so do the first blit without checking if the blitter is ready or not and see if that helps
Humm, no need to do that, as least my GP2X don"t need that. I have still some related questions about hardware stuff.
* Is there a way to have a single adress space, instead of a MMU handled world, and the other world ? Is it the aim of the famous MMU hack ?
 
Last edited by a moderator:

spoyser

Member
Joined
Jun 2, 2006
Messages
112
Age
52
Website
Visit site
I'd recommend checking that your code works from a clean boot as well, as something else could be using the blitter first (in my case it was gmenu2x), and therefore giving the impression that all is ok
 

Squidge

Certified Guru
Joined
Nov 16, 2003
Messages
8,493
Location
UK
Website
Visit site
Well, you can use the mmu hack to find the physical address of a logical page of memory (ie. translate between the two), but I wouldn't simply because the logical memory could be made up of fragmented physical memory.

Best thing to do is use the mmu hack to make the upper memory (>32mb) cachable, stick your stuff there and blit away. Try and ensure the memory is flushed before blitting however, or you may end up with strange effects (the blitter doesn't check with the cache or the mmu for performance reasons). I think the latest module version of the hack has such an option.

oh, and, have fun :)
 
Top