GP2X Hw Accelerated Sdl


Simon Parzer said:
How do I do a vsync? I think the WaitForBlitter is just for the blitter to finish its work.
And I definitely need the wait to keep the game at 50 fps.
Yes the WaitForBlitter just waits for the blitter to be free.
I've just checked, the v-sync isn't directly available - sorry I thought I had, I'll expose the v-sync call as SDL_GP2X_VSync() in a few minutes as after looking at a few other video drivers there are no v-sync calls in single-buffer mode.
 
Last edited by a moderator:
QUOTE
I've just checked, the v-sync isn't directly available - sorry I thought I had, I'll expose the v-sync call as SDL_GP2X_VSync() in a few minutes as after looking at a few other video drivers there are no v-sync calls in single-buffer mode.


So, how do I get to use Vsync? Is it in SVN already?
 
Simon Parzer said:
So, how do I get to use Vsync? Is it in SVN already?

It should be. You need to include the gp2x specific header (SDL_gp2x.h) that is required to access all the extensions I added.
Just call SDL_GP2X_VSync(); It takes no parameters and returns void.
 
Last edited by a moderator:
Thanks for your work on HW SDL paeryn. It's top notch and I use it with psx4gp2x. :)
 
Thanks, paeryn. SDL_GP2X_VSync() works now, but my self-compiled SDL reduces performance by 50%, so I don't use it. Don't know what I did wrong, but I'll wait for a pre-compiled build.

I looked a bit around the source code and stumbled over ARM_Blit1to2.s, an asm-optimized version of the Blit1to2 function. What I would need, though is an optimized version of Blit1to2Key, as I'm mostly working with bitmaps where 1 color is transparent. Would that be possible? (I can't do it myself because I know little about asm and nothing about ARM asm).
In the C code there is very little difference. The Blit1to2Key just checks if a pixel matches the transparent color.

Blit1to2
CODE
int width, height;
Uint8 *src, *dst;
Uint16 *map;
int srcskip, dstskip;

/* Set up some basic variables */
width = info->d_width;
height = info->d_height;
src = info->s_pixels;
srcskip = info->s_skip;
dst = info->d_pixels;
dstskip = info->d_skip;
map = (Uint16 *)info->table;

while ( height-- ) {
DUFFS_LOOP(
{
*(Uint16 *)dst = map[*src++];
dst += 2;
},
width);
src += srcskip;
dst += dstskip;
}


Blit1to2Key
CODE

int width = info->d_width;
int height = info->d_height;
Uint8 *src = info->s_pixels;
int srcskip = info->s_skip;
Uint16 *dstp = (Uint16 *)info->d_pixels;
int dstskip = info->d_skip;
Uint16 *palmap = (Uint16 *)info->table;
Uint32 ckey = info->src->colorkey;

/* Set up some basic variables */
dstskip /= 2;

while ( height-- ) {
DUFFS_LOOP(
{
if ( *src != ckey ) {
*dstp=palmap[*src];
}
src++;
dstp++;
},
width);
src += srcskip;
dstp += dstskip;
}
 
Simon Parzer said:
I looked a bit around the source code and stumbled over ARM_Blit1to2.s, an asm-optimized version of the Blit1to2 function. What I would need, though is an optimized version of Blit1to2Key, as I'm mostly working with bitmaps where 1 color is transparent. Would that be possible? (I can't do it myself because I know little about asm and nothing about ARM asm).
If you post the code for the ARM_Blit1to2.s, it probably wouldn't be hard to modify.
 
Last edited by a moderator:
ARM_blit1to2.S
CODE
@ ARM code version of Blit1to2.
@
@ @author Robin Watts (robin@wss.co.uk)

.text

.global Blit1to2ARM

@ Reads a width x height block of 8 bpp pixels from srcPtr, looks
@ them up in the palette at map, and stores them as 16bpp pixels
@ at dstPtr. srcPitch and dstPitch give information about how to
@ find the next lines.
Blit1to2ARM:
@ r0 = srcPtr
@ r1 = srcPitch
@ r2 = dstPtr
@ r3 = dstPitch
MOV r12,r13
STMFD r13!,{r4-r11,r14}
LDMIA r12,{r4-r6}
@ r4 = width
@ r5 = height
@ r6 = map

CMP r7,#0
BLE end
SUBS r5,r5,#1 @ while (--height)
BLT end
height_loop:
SUBS r7,r4,#5 @ r7= width_minus_5
BLE thin
width_loop:
@ Have to do at least 6 here
LDRB r8, [r0],#1 @ r8 = *src++
LDRB r9, [r0],#1 @ r9 = *src++
LDRB r10,[r0],#1 @ r10= *src++
LDRB r11,[r0],#1 @ r11= *src++
LDRB r12,[r0],#1 @ r12= *src++
LDRB r14,[r0],#1 @ r14= *src++
ADD r8, r8, r8 @ r8 = 2*r8
ADD r9, r9, r9 @ r9 = 2*r9
ADD r10,r10,r10 @ r10= 2*r10
ADD r11,r11,r11 @ r11= 2*r11
ADD r12,r12,r12 @ r12= 2*r12
ADD r14,r14,r14 @ r14= 2*r14
LDRH r8, [r6,r8] @ r8 = map[r8]
LDRH r9, [r6,r9] @ r9 = map[r9]
LDRH r10,[r6,r10] @ r10= map[r10]
LDRH r11,[r6,r11] @ r11= map[r11]
LDRH r12,[r6,r12] @ r12= map[r12]
LDRH r14,[r6,r14] @ r14= map[r14]
SUBS r7,r7,#6 @ r7 = width_minus_5 -= 6
STRH r8, [r2],#2 @ *dstPtr++ = r8
STRH r9, [r2],#2 @ *dstPtr++ = r9
STRH r10,[r2],#2 @ *dstPtr++ = r10
STRH r11,[r2],#2 @ *dstPtr++ = r11
STRH r12,[r2],#2 @ *dstPtr++ = r12
STRH r14,[r2],#2 @ *dstPtr++ = r14
BGT width_loop @ width_minus_5>0 => 6+ left to do
thin:
ADDS r7,r7,#5 @ r7 = width (width <= 5)
BEQ end_thin
thin_lp:
LDRB r8,[r0],#1 @ r8 = *src++
SUBS r7,r7,#1 @ r7 = width--
@ Stall
ADD r8,r8,r8 @ r8 = 2*r8
LDRH r8,[r6,r8] @ r8 = map[r8]
@ Stall
@ Stall
STRH r8,[r2],#2 @ *dstPtr++ = r8
BGT thin_lp
end_thin:

ADD r2,r2,r3 @ dstPtr += dstPitch
ADD r0,r0,r1 @ srcPtr += srcPitch

SUBS r5,r5,#1
BGE height_loop

end:
LDMFD r13!,{r4-r11,PC}
 
Something like the code below should work. I am not sure how it would be plugged into SDL (I don't use SDL), in this code I assume the transparent color made it magically into r14 somehow.

I would think, though, that the hardware blitter on the gp2x should be able to handle this sort of thing... this code will add about 4 or so cycles per pixel on average which is a bit painful.

CODE

@ r14 = transparent color


CMP r7,#0
BLE end
SUBS r5,r5,#1 @ while (--height)
BLT end
height_loop:
SUBS r7,r4,#4 @ r7= width_minus_4
BLE thin
width_loop:
@ Have to do at least 5 here
LDRB r8, [r0],#1 @ r8 = *src++
LDRB r9, [r0],#1 @ r9 = *src++
LDRB r10,[r0],#1 @ r10= *src++
LDRB r11,[r0],#1 @ r11= *src++
LDRB r12,[r0],#1 @ r12= *src++
ADD r8, r8, r8 @ r8 = 2*r8
ADD r9, r9, r9 @ r9 = 2*r9
ADD r10,r10,r10 @ r10= 2*r10
ADD r11,r11,r11 @ r11= 2*r11
ADD r12,r12,r12 @ r12= 2*r12
LDRH r8, [r6,r8] @ r8 = map[r8]
LDRH r9, [r6,r9] @ r9 = map[r9]
LDRH r10,[r6,r10] @ r10= map[r10]
LDRH r11,[r6,r11] @ r11= map[r11]
LDRH r12,[r6,r12] @ r12= map[r12]
SUBS r7,r7,#5 @ r7 = width_minus_4 -= 5

CMP r8, r14 @ skip the store if color is transparent
BEQ increment1
STRH r8, [r2] @ *dstPtr = r8
increment1:
ADD r2, r2, #2 @ dstPtr++

CMP r9, r14 @ skip the store if color is transparent
BEQ increment2
STRH r9, [r2] @ *dstPtr = r9
increment2:
ADD r2, r2, #2 @ dstPtr++

CMP r10, r14 @ skip the store if color is transparent
BEQ increment3
STRH r10, [r2] @ *dstPtr = r10
increment3:
ADD r2, r2, #2 @ dstPtr++

CMP r11, r14 @ skip the store if color is transparent
BEQ increment4
STRH r11, [r2] @ *dstPtr = r11
increment4:
ADD r2, r2, #2 @ dstPtr++

CMP r12, r14 @ skip the store if color is transparent
BEQ increment5
STRH r12, [r2] @ *dstPtr = r12
increment5:
ADD r2, r2, #2 @ dstPtr++

BGT width_loop @ width_minus_4>0 => 5+ left to do
thin:
ADDS r7,r7,#4 @ r7 = width (width <= 4)
BEQ end_thin
thin_lp:
LDRB r8,[r0],#1 @ r8 = *src++
SUBS r7,r7,#1 @ r7 = width--
@ Stall
ADD r8,r8,r8 @ r8 = 2*r8
LDRH r8,[r6,r8] @ r8 = map[r8]
@ Stall
@ Stall
STRH r8,[r2],#2 @ *dstPtr++ = r8
BGT thin_lp
end_thin:

ADD r2,r2,r3 @ dstPtr += dstPitch
ADD r0,r0,r1 @ srcPtr += srcPitch

SUBS r5,r5,#1
BGE height_loop

end:
LDMFD r13!,{r4-r11,PC}
 
The issue isnt the blitter, the reduced performance is most likely because waiting for a VSync to occur involves...you guessed it...waiting! Those milliseconds add up and can reduce performance.

EDIT: I should add that waiting for vsync is usually used to reduce screen tearing, as waiting for a vsync makes sure what you blit is what you see displayed. It's smoother as there's no flicker, etc. But performance goes down. Thats why when you benchmark graphics cards on the PC you disable VSync, otherwise you won't get anymore FPS above the refresh rate. :)
 
My arm assembly has gotten rusty... I forgot about conditional execution!

This version is only two cycles per pixel slower than the nontransparent blit. Note, this isn't tested.

CODE

@ r14 = transparent color
CMP r7,#0
BLE end
SUBS r5,r5,#1 @ while (--height)
BLT end
height_loop:
SUBS r7,r4,#4 @ r7= width_minus_4
BLE thin
width_loop:
@ Have to do at least 5 here
LDRB r8, [r0],#1 @ r8 = *src++
LDRB r9, [r0],#1 @ r9 = *src++
LDRB r10,[r0],#1 @ r10= *src++
LDRB r11,[r0],#1 @ r11= *src++
LDRB r12,[r0],#1 @ r12= *src++
ADD r8, r8, r8 @ r8 = 2*r8
ADD r9, r9, r9 @ r9 = 2*r9
ADD r10,r10,r10 @ r10= 2*r10
ADD r11,r11,r11 @ r11= 2*r11
ADD r12,r12,r12 @ r12= 2*r12
LDRH r8, [r6,r8] @ r8 = map[r8]
LDRH r9, [r6,r9] @ r9 = map[r9]
LDRH r10,[r6,r10] @ r10= map[r10]
LDRH r11,[r6,r11] @ r11= map[r11]
LDRH r12,[r6,r12] @ r12= map[r12]
CMP r8, r14 @ r8 transparent color?
STRNEH r8, [r2] @ if not, *dstPtr = r8
ADD r2, r2, #2 @ dstPtr++
CMP r9, r14 @ r9 transparent color?
STRNEH r9, [r2] @ if not, *dstPtr = r9
ADD r2, r2, #2 @ dstPtr++
CMP r10, r14 @ r10 transparent color?
STRNEH r10, [r2] @ if not, *dstPtr = r10
ADD r2, r2, #2 @ dstPtr++
CMP r11, r14 @ r11 transparent color?
STRNEH r11, [r2] @ if not, *dstPtr = r11
ADD r2, r2, #2 @ dstPtr++
CMP r12, r14 @ r12 transparent color?
STRNEH r12, [r2] @ if not, *dstPtr = r12
ADD r2, r2, #2 @ dstPtr++
SUBS r7,r7,#5 @ r7 = width_minus_4 -= 5
BGT width_loop @ width_minus_4>0 => 5+ left to do
thin:
ADDS r7,r7,#4 @ r7 = width (width <= 4)
BEQ end_thin
thin_lp:
LDRB r8,[r0],#1 @ r8 = *src++
SUBS r7,r7,#1 @ r7 = width--
@ Stall
ADD r8,r8,r8 @ r8 = 2*r8
LDRH r8,[r6,r8] @ r8 = map[r8]
@ Stall
@ Stall
STRH r8,[r2],#2 @ *dstPtr++ = r8
BGT thin_lp
end_thin:

ADD r2,r2,r3 @ dstPtr += dstPitch
ADD r0,r0,r1 @ srcPtr += srcPitch

SUBS r5,r5,#1
BGE height_loop

end:
LDMFD r13!,{r4-r11,PC}
 
QUOTE
The issue isnt the blitter, the reduced performance is most likely because waiting for a VSync to occur involves...you guessed it...waiting! Those milliseconds add up and can reduce performance.


Yeah, I know that. But if I use SDL-1.2.11 the performance is about 50% from what I get from SDL-1.2.9, VSync or not. And I'm not able to build 1.2.9 myself as I have some problems with the build scripts (configure/make).
So, until I get a recent build of 1.2.9 (VSync included) I can't really test it.

@dzz:
Your code really should go to SVN after it's been tested.
 
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<320-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.
 
I'll look into that tomorrow. And you say it only happens every few frames, not every time? It may be to do with the blitter not being flushed properly. It'd be nice if we had more complete specs of the MMSP2 and it's bugs.

I don't know why 1.2.11 would be slower, djwillis merged the core 1.2.11 with my additions to 1.2.9 (and some of his own). I've not tested 11 other than to check it compiled, I'll see if he missed something. In the meantime I'll update the pre-compiled 1.2.9 libs on my site to include the vsync later tonight.
 
QUOTE
I'll look into that tomorrow. And you say it only happens every few frames, not every time?

Only every few frames and then not for all blits.
And only if the tile that overlaps with the right screen edge is at a position where (x%16==1), basically a blit that ends with pixel 15 on the right edge (pos. 319) of the screen. As soon as I find time I draw you a concept sketch or something.

I found out how to avoid the bug: Check if the blit fulfills the conditions, and if so, split it into two seperate blits. That way I could avoid the problem in my test cases without sacrificing the rightmost pixel column.
 
synkro said:
What happens when you flush the data cache before blitting?
Assuming you're using mmuhack to gain fast access to upper memory (where all HW_SURFACES reside), if you don't flush the cache and you've just written to the source surface then some of the new data will (could) only be in the 920's cache and not in the physical memory. The blitter (indeed all of the hardware blocks) can only see what is in physical memory and not what is in the 920's cache.

If you' have just written new data directly into a surface's bitmap and then blit from that surface, if you've not flushed the cache then the blitter may be copying the previous contents the the bitmap as the blitter cannot see any new data that is held in the processor's cache.

Flushing just makes sure that the processor's idea of what the memory contents are get propagated back the the real memory which all the other hardware sees.

Where I've put 920 it also applies to the 940 - I keep forgetting which is the main one but they both be told to cache upper memory so it applies to them both.
Hope that covered what your were asking ;-)
 
Last edited by a moderator:
paeryn said:
synkro said:
What happens when you flush the data cache before blitting?
Assuming you're using mmuhack to gain fast access to upper memory (where all HW_SURFACES reside), if you don't flush the cache and you've just written to the source surface then some of the new data will (could) only be in the 920's cache and not in the physical memory. The blitter (indeed all of the hardware blocks) can only see what is in physical memory and not what is in the 920's cache.

If you' have just written new data directly into a surface's bitmap and then blit from that surface, if you've not flushed the cache then the blitter may be copying the previous contents the the bitmap as the blitter cannot see any new data that is held in the processor's cache.

Flushing just makes sure that the processor's idea of what the memory contents are get propagated back the the real memory which all the other hardware sees.

Where I've put 920 it also applies to the 940 - I keep forgetting which is the main one but they both be told to cache upper memory so it applies to them both.
Hope that covered what your were asking ;-)



Ugh.. That's not I wanted to aks but thank you! I meant if flushing would reduce Simon's graphic :) As I had problem with DMA copy onto the screen and unflushed cache Nonetheless, keep up the good work!
 
Last edited by a moderator:
Hi,

I've tried last precompiled version of Accelerated SDL, but I have a problem.

All seems to work fine, but when I select TV-Out from GP2X menu, the GP2X's menu is showed correctly but my game screen is cutted a bit from the lower part and a lot from the right part.

As my English is not quite good I have two examples:


Do you know if there is any solution?

Thanks a lot :)
 
That's the old 'HW surface with double buffers on tvout' bug. The only fix I've found is to turn off double buffering and create your own instead (blit everything to a surface, then blit that to the actual screen at the end).
 
The tv-out stuff is very much a hack, there are problems with overscan and everything. I'm re-writing it for 1.2.12

There is a new function added to the 1.2.9 and 1.2.11 code that was requested by Trenki to allow getting the physical address of HWSURFACE bitmaps so you can pass them to code on the 940, it's
CODE
void *SDL_GP2X_PhysAddress(SDL_Surface *surface);

Read the README.GP2X for full instructions on using it, but basically the surface must be HWSURFACE and you must have already called SDL_LockSurface(surface); otherwise it returns NULL.
 
Back
Top