I found a weird bug with the MMSP2 hardware blitting in SDL. I don't know what causes it, but I can reproduce it.
If you blit a lot of small-sized bitmaps (say, a screen full of 32x32 tiles) at the screen using an x position where (x%16)==1, some of these bitmaps eventually will be moved by a few pixels during the blit. It very often happens with the first bitmap in a row.
Of cource I have an example, maybe it will make things clearer. Note that the glitch only occurs if XOFF%16 is 1 (e.g. 1,17,33,49,65,..).
CODE
#include <SDL.h>
#ifdef GP2X
 #include <SDL_gp2x.h>
 #include <unistd.h>
#endif
// 1,17,33,49,65,..
const int XOFF = 17;
int main(int argc, char** argv)
{
  SDL_Rect rect;
  int x,y;
  SDL_Surface* buffer;
  SDL_Surface* screen;
  SDL_Surface* image;
  SDL_Surface* image_hw;
  SDL_Init(SDL_INIT_VIDEO);
#ifdef GP2X
  SDL_GP2X_AllowGfxMemory(NULL,0);
  screen = SDL_SetVideoMode(320,240,16,SDL_HWSURFACE);
  buffer = SDL_CreateRGBSurface(SDL_HWSURFACE,
      screen->w,screen->h,
      screen->format->BitsPerPixel,
      screen->format->Rmask,
      screen->format->Gmask,
      screen->format->Bmask,
      screen->format->Amask);
#else
  screen = SDL_SetVideoMode(320,240,16,0);
  buffer = SDL_CreateRGBSurface(SDL_SWSURFACE,
      screen->w,screen->h,
      screen->format->BitsPerPixel,
      screen->format->Rmask,
      screen->format->Gmask,
      screen->format->Bmask,
      screen->format->Amask);
#endif
      
  image = SDL_LoadBMP("test.bmp");
  image_hw = SDL_DisplayFormat(image);
  SDL_FreeSurface(image);
  while (1)
  {
    SDL_Event event;
    SDL_PollEvent(&event);
    if (event.type == SDL_QUIT) break;
    SDL_FillRect(buffer,NULL,0);
    for (y=0;y<240-1;y+=image_hw->h)
    {
      for (x=0;x

20-1-XOFF;x+=image_hw->w)
      {
         rect.x = x+XOFF;
         rect.y = y;
         rect.w = image_hw->w;
         rect.h = image_hw->h;
         SDL_BlitSurface(image_hw,NULL,buffer,&rect);
      }
    }
    SDL_BlitSurface(buffer,NULL,screen,NULL);
    SDL_UpdateRect(screen,0,0,0,0);
    SDL_Delay(10);
  }
  SDL_FreeSurface(image_hw);
  SDL_FreeSurface(buffer);
  SDL_Quit();
#ifdef GP2X
  chdir("/usr/gp2x");
  execl("/usr/gp2x/gp2xmenu","/usr/gp2x/gp2xmenu",NULL);
#endif
}
An interesting fact is that if I blit the tiles as a part from a bigger bitmap (e.g. {64,128,32,32} from a 256x256 tilemap) it appears that the tile in reality doesn't move on the screen. It's the source rectange that is aligned wrongly. I think so because in that special case I see a few pixels from a wrong tile everytime a bitmap "moves" through the glitch. So, it seems if I blit e.g. {64,96,32,32} from src to {33,0,32,32} and the glitch occurs the src rect isn't {64,128,32,32}, but {66,128,32,32} or something like that. I can only judge from my observations as I obviously don't see into the hardware (is there even any way to debug the MMSP2?).
As I said the misalignment of the blit (or the srcrect, if that's the issue) only happens every couple frames and only for a few of the bitmaps.
EDIT:
Another thing I found out: It only happens if I blit until the right edge of the screen. For example, with 32x32 bitmaps and an x offset of 17 (normally causing the bug), stopping before the last tile (which gives a 15-pixel black border on the right edge) everything is ok.
I even did some more experiments. If I do manual clipping, leaving the last pixel blank (in the case of a 32x32 tile at x:289 the destination rect would be of width 30 instead of 32 which normally would get clipped to 31), everything is alright, too. (If I clip to 31 in the said example, which is the exact amount of pixels left on the screen---I think SDL does this, too---the bug is back again).
I hope I expressed the problem in an understandable way. If you don't get it, I can do a quick illustration.
I don't know anything about the MMSP2, but it seems that the number 16 is very important to it (maybe it processes the pixels in chunks of 16?). Otherwise I have no explanation for this weird behaviour.
What would be a possible workaround (need to try it) is to split the "border blit" into two blits to circumvent the issue with the 15th pixel on the edge.