GP2X Quake 1 Port


coderunner

Still Fresh
Joined
Feb 18, 2006
Messages
10
For the author of the q1 port for the gp2x, is the port compiled using only the C code or did you enable the asm rendering code? The readme mentions that the software renderer is about 50% as fast using the C only code, but I'd also imagine that porting x86 asm to ARM asm(?) would be quite an undertaking(I haven't seen ARM asm before myself so I'm not sure).
 
I believe Quake2X is just a port of his own GP32 version, which means it's a port of Pocketquake, which is an optimized version of WinQuake.

What that means is:

No X86 asm code was converted to ARM
Lots of floating point was converted to fixed point
 
Ah, I see. I haven't tried q1 port yet b/c I seem to have misplaced my q1 cd, but the new version says the demo version should work now so I'll probably try it out to see how it runs. I guess porting the x86 asm to ARM asm wouldn't be the most difficult part, but making the ARM asm just as optimized as the x86 I can imagine would be a pain in the arse with all the cycle counting. Hopefully, the q1 port using SDL can get up to really good speeds b/c playing q1 on my gp2x would be pretty sweet.
 
woogal's quake port always worked fine with the demo. but it needs to see a pak0 and a pak1 file, so copy make a copy of pak0.pak and rename it to pak1.pak.

also it runs pretty damn smooth already. in fact it's great.

pakpakpakpakpak
 
Squidge posted on Feb 23 2006 at 11:57 PM said:
I believe Quake2X is just a port of his own GP32 version, which means it's a port of Pocketquake, which is an optimized version of WinQuake.

What that means is:

No X86 asm code was converted to ARM
Lots of floating point was converted to fixed point
Couldn't have put it better myself :)

I don't know any arm asm which is why I've never bothered looking into converting anything back into asm, but to be honest I'm not sure how much of a difference it would make. I think the main bottleneck is the remaining floating point code (even though the pocketquake guys optimised a lot of functions, there's still quite a bit of floating point left). If anyone wants to have a go at doing some arm asm stuff though it will be more than welcome, not just on the gp2x but it could also be used on the gp32, pocket pc etc ports too.

To be honest though, I wouldn't be put off by the low sounding frame rates. 12 fps average might not sound like much, but Quake is actually very playable at those kind of speeds. Overclock to 250mhz+, drop the screen size a little bit, and it gets to 20+ fps which plays very nicely. In fact I'm sure I read somewhere once that Quake was designed to be played at around 25 fps so it's not far off.

rokdcasbah: get the latest release. No need to make a copy of pak0.pak anymore.
 
Last edited by a moderator:
ha actually i do have the newest version i just replaced the old one, kept playing the same save, and didn't read the readme :ph34r:
 
woogal posted on Feb 24 2006 at 01:41 PM said:
Squidge posted on Feb 23 2006 at 11:57 PM said:
I believe Quake2X is just a port of his own GP32 version, which means it's a port of Pocketquake, which is an optimized version of WinQuake.

What that means is:

No X86 asm code was converted to ARM
Lots of floating point was converted to fixed point
Couldn't have put it better myself :)

I don't know any arm asm which is why I've never bothered looking into converting anything back into asm, but to be honest I'm not sure how much of a difference it

From my profiling of the C compiler even for a simple loops hand coded Arm assembler was up to 20 percent faster. But it was isolated case so generally a simple rewrite of most demanding functions would give around 10 percent of improvement.

With assembler it is possible to very aggressively use the registers and conditional executing. I'm somewhat doubting that current C compiler will for an example use the R13 except for the stack pointer.

woogal posted on Feb 24 2006 at 01:41 PM said:
would make. I think the main bottleneck is the remaining floating point code (even though the pocketquake guys optimised a lot of functions, there's still quite a bit of floating point left). If anyone wants to have a go at doing some arm asm stuff though it will be more than welcome, not just on the gp2x but it could also be used on the gp32, pocket pc etc ports too.

I can help with some routines but not with 3d transforms yet.

OK - I will look at the source first so I will know if I can help with something or not.

woogal posted on Feb 24 2006 at 01:41 PM said:
To be honest though, I wouldn't be put off by the low sounding frame rates. 12 fps average might not sound like much, but Quake is actually very playable at those kind of speeds. Overclock to 250mhz+, drop the screen size a little bit, and it gets to 20+ fps which plays very nicely. In fact I'm sure I read somewhere once that Quake was designed to be played at around 25 fps so it's not far off.

rokdcasbah: get the latest release. No need to make a copy of pak0.pak anymore.

Thought current perfomance is playable there are some big slowdowns sometimes...
 
Last edited by a moderator:
Just tried it out and its already playable(and fun!). If I did try ARM asm, I think it would just be me wanting to tinker around with ARM assembly and I dont think it would ever get finished on my end(so if I do try any armasm I'll probably try it out on a small project can I play around with). On a different note, I saw an exe in my vsstudio8 folder called armasm.exe in an x86 folder and my first thought was GREAT, MS made some program that converted assembly for you by exchanging/rearranging opcodes optimally. But then reality set in and I realized they would never do that, and read the documentation that said it was just to compile apps for WinCE devices :(
 
coderunner posted on Feb 25 2006 at 12:02 AM said:
Just tried it out and its already playable(and fun!). If I did try ARM asm, I think it would just be me wanting to tinker around with ARM assembly and I dont think it would ever get finished on my end(so if I do try any armasm I'll probably try it out on

Most probably as there is lots of C code to convert to. However there are some places (after my quick looking at sources) where assembler would be both easy and beneficial to implement (mostly the functions what are used for solid fills - some of them are using (uchar *) - waste!). There is also strange things in the VID_Update function - is that called for every frame?!

Some other functions could have added inline prefix (the ones for maths and z-buffer) and why there is no register statements anywhere?

Compiler isn't that smart after all at least in my experience to not use manual hints like the "register".

It's also good to consider dumping the SDL for screen display because Quake has to do direct access to the framebuffer anyway so the updating screen via SDL is unnecessary.
 
Last edited by a moderator:
Are You going to make Quake a little faster? If so, thank you so MUCH. When you are finished, do you think you could look at Quake two? Ive read that disabling the particles, which I believe are heavy on floating point, gives like 12fps, the same speed we have here. If we could get Quake 2 to run at like 20fps, then I think that would be our 3D engine for the GP2X

I remember when I tried to make my Half Life TC for Quake 1 because of all the enigne restrictions, but just think of Quake 2! I know that they still dont use skeletons, but the engine is much more powerful, and better looking for that matter.

Either way, anywork you do for anything Quake in general is just fine. Thx again.

also, can anyone remember if Quake2 uses a preset pallete for their colors or its set to a wide range?

~Octavious
 
Radek posted on Feb 24 2006 at 10:27 PM said:
It's also good to consider dumping the SDL for screen display because Quake has to do direct access to the framebuffer anyway so the updating screen via SDL is unnecessary.
I dumped SDL's framebuffer and switched to Rlyeh's minilib, but that actually ran 0.2 fps slower than the latest SDL release so I switched back again.
 
Last edited by a moderator:
Radek posted on Feb 24 2006 at 10:27 PM said:
Most probably as there is lots of C code to convert to. However there are some places (after my quick looking at sources) where assembler would be both easy and beneficial to implement (mostly the functions what are used for solid fills - some of them are using (uchar *) - waste!). There is also strange things in the VID_Update function - is that called for every frame?!

Some other functions could have added inline prefix (the ones for maths and z-buffer) and why there is no register statements anywhere?

Compiler isn't that smart after all at least in my experience to not use manual hints like the "register".
Was in a rush earlier so didn't have time to reply to these bits. I don't have access to the code at the minute, but if I remember right then vid_update has a load of crap in it (mostly old gp32 stuff that's behind an #if 0). It will also have the doublesize stuff in it which has now been removed (the code for 0.02 isn't on the archive yet because I'm not sure of the right way to update an existing file). I think the latest code just has an sdl_flip or sdl_updaterect and very little else in vid_update. There's not really much difference in code between 0.01 and 0.02 so you're ok to carry on looking at the old code until the new stuff is online.

It certainly sounds like you understand the arcane workings of gcc much better than I ever could so hopefully you'll be able to get some nice speed improvements :)
 
Last edited by a moderator:
woogal posted on Feb 25 2006 at 09:18 PM said:
Radek posted on Feb 24 2006 at 10:27 PM said:
Most probably as there is lots of C code to convert to. However there are some places (after my quick looking at sources) where assembler would be both easy and beneficial to implement (mostly the functions what are used for solid fills - some of them are using (uchar *) - waste!). There is also strange things in the VID_Update function - is that called for every frame?!

Some other functions could have added inline prefix (the ones for maths and z-buffer) and why there is no register statements anywhere?

Compiler isn't that smart after all at least in my experience to not use manual hints like the "register".
Was in a rush earlier so didn't have time to reply to these bits. I don't have access to the code at the minute, but if I remember right then vid_update has a load of crap in it (mostly old gp32 stuff that's behind an #if 0). It will also have the doublesize stuff in it which has now been removed (the code for 0.02 isn't on the archive yet because I'm not sure of the right way to update an existing file). I think the latest code just has an sdl_flip or sdl_updaterect and very little else in vid_update. There's not really much difference in code between 0.01 and 0.02 so you're ok to carry on looking at the old code until the new stuff is online.

It certainly sounds like you understand the arcane workings of gcc much better than I ever could so hopefully you'll be able to get some nice speed improvements :)

I have no special knowledge about the GCC but it's quite strange that there are no hints like "inline" and "register" statements in the code. By theory a compiler should allocate registers efficiently however programmer (obviously) can know better.

Below is my replacement function for VID_Update. Didn't compile it yet but it should work and it's an idea how it should be done for maximum perfomance.

Code:
// somewhere at init and how to set up the 8bbp mode for FB?
// Anyway the SDL does seem always to convert to 16bbp so bypassing some speedup
// could be achieved. If that wouldn't be possible then not big deal - 256 * 2
// (512 bytes) lockup table and conversion in asembler should fly anyway.
fbdev=open("/dev/fb0", O_RDWR);
fb=(unsigned int *)mmap(0, 320*240*sizeof(unsigned short int), PROT_WRITE, MAP_SHARED, fbdev, 0);

void VID_Update(vrect_t *rects)
{

    int n, i,x,y,hh,xx,yy;
    Uint8 *screenpixels,*origpixels;

    static unsigned int *source;

    // example code - goal should be to get rid of any lib for framebuffer
    // access.
    source = (unsigned int *)screen->pixels;  // source pointer

    if(doublesize == 0)
    asm
    (
        "stmfd r13!, {r0-r12}\n" // might be unnecessary but to be safe

        "mov r9, %0\n"      // load destination
        "mov r10, %1\n"      // load source
        "mov r11, #0x12000\n"  // make a constant 320 * 240 = 0x12C00
        "orr r11, r11, #0xC00\n"
        "add r11, r11, r9\n"    // the end pointer

        "loop:\n"
        "ldmia r9!, {r0-r7}\n" // push memory at close to 150MB/s
        "stmia r10!, {r0-r7}\n"
        "cmp r9, r11\n"         // something more to move?
        "blt loop\n"            // if so repeat the loop

        "ldmfd r13!, {r0-r12}\n"    // might be unnecessary...
        :
        : "r"(fb), "r"(source)
        :  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" // could be deleted
    );
    else
    {
        source += foobar; // eventually add some offset is needed
    asm
    (
        "stmfd r13!, {r0-r12}\n" // might be unnecessary but to be safe

        "mov r8, %0\n"      // load destination 
        "mov r9, %1\n"      // load source (the 160 * 120 one)
        "mov r11, #0x12000\n"  // make a constant 320 * 240 = 0x12C00
        "orr r11, r11, #0xC00\n"
        "sub r11, r11, #320\n" // but don't scan all lines
        "add r11, r11, r9\n"    // the end pointer
       
        "add r12, r8, #320\n"   // end point of single source line

        "mov r2, #0xFF\n"       // a mask

        "loop:\n"
        "ldmia r9!, {r0, r1}\n" // load eight source pixels

        "and r3, r0, r2, lsl #24\n" // some doubling for four first source pixels
        "mov r4, r3\n"              // it takes 12 machine cycles to do
        "orr r4, r4, r3, lsr #8\n"  // and there is zero extra memory accesses
        "and r3, r0, r2, lsl #16\n" // 12 cycles / 8 final pixels = 1.5 cycle/pix;)
        "orr r4, r4, r3, lsr #8\n"
        "orr r4, r4, r3, lsr #16\n"
        "and r3, r0, r2, lsl #8\n"
        "mov r5, r3\n"
        "orr r5, r5, r3, lsl #8\n"
        "and r3, r0, r2\n"
        "orr r5, r5, r3, lsl #8\n"
        "orr r5, r5, r3\n"

        "and r3, r1, r2, lsl #24\n" // some doubling for four next source pixels
        "mov r6, r3\n"              // it's loop unrolling
        "orr r6, r4, r3, lsr #8\n"
        "and r3, r1, r2, lsl #16\n"
        "orr r6, r4, r3, lsr #8\n"
        "orr r6, r4, r3, lsr #16\n"
        "and r3, r1, r2, lsl #8\n"
        "mov r7, r3\n"
        "orr r7, r5, r3, lsl #8\n"
        "and r3, r1, r2\n"
        "orr r7, r5, r3, lsl #8\n"
        "orr r7, r5, r3\n"
        
        "add r12, r8, #320\n"  // compute pointer for the second line

        "stmia r8!, {r4-r7}\n" // blast into framebuffer with doubled pixels
        "stmia r12, {r4-r7}\n"

        "cmp r8, r11\n"   // is it a time for the next line?
        "addge r8, #320\n"
        "addge r9, #320\n"
        "addge r11, #320\n"

        "cmp r8, r11\n"         // something more to move?
        "blt loop\n"            // if so repeat the loop

        "ldmfd r13!, {r0-r12}\n"    // might be unnecessary...
        :
        : "r"(fb), "r"(source)
        :  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" // could be deleted
    );
    }
}
 
Last edited by a moderator:
Octavious posted on Feb 26 2006 at 04:12 AM said:
theoreticaly, and a good guess, what sort of speed updates will this give us, you think?

Sub 0.5fps as most cpu time is spended somewhere else. If current SDL is indeed converting the 8bpp to the 16bpp instead of using the native 8 bit mode then somewhat faster.

Perhaps a full 1fps could be achieved after rewriting the solid fills functions and experimenting with inline and register statements.

This is what I can do without trying to understand the whole Quake engine. These are just local optimizations and as such they can not improve perfomance significantly. They are not hard to do however.

I will try to compile it later and we will see.

Well I tried to and what is that "open2x"? I couldn't compile because the tools are in the /home/ folder? I installed my SDK using the script from gp2x.wiki... Ha! There two of them actually and I used the devkitGP2X probably before. Uppp... it got more sophisticated I see...

Will reinstall SDK.
 
Last edited by a moderator:
well, please post anything you find back!
I have the Quake 1 code on my worstation and am loking at it, but I am still an entry level coder, so this is all you guys

~Octavious
 
Just tried your code Radek and unfortunatly it seems to be 0.1 fps slower than a plain sdl_updaterect. It doesn't display anything either :). Optimising sdl_updaterect won't really change much though. Removing the call completely only increases the fps by 0.3 so the most improvement you're likely to get will only be about 0.2 I'd guess.

When I was playing around with Quake's profiler I found two areas which seem to need the most optimisation but I can't remember which two they are now. If I get time later today I'll track them down again and let you know.

I've also discovered that a load of stuff I copied to my card a few days ago must have caused things to get a bit fragmented so now all my timedemo's are running over 0.5 fps slower than a week ago :(
 
Do you think we could get 20 frames out of this eventually?
And what about Quake 2 with no particles, would optimising some parts in there make for a great FPS on the GP2X??

Thx

~Octavious
 
woogal posted on Feb 26 2006 at 07:26 PM said:
Just tried your code Radek and unfortunatly it seems to be 0.1 fps slower than a plain sdl_updaterect. It doesn't display anything either :). Optimising sdl_updaterect

At least it didn't hang machine, dit it? :)
(with assembler it's not difficult thing to do :p )
I had no chance to compile and test it myself. It should display something
thought (even a garbage) - probably there is some bug with pointers somewhere...
I was using the same aproach for screen updating before and successfully
with my demo for coding competition.

And aren't you using blitter accelerated SDL by an accident?
(if so for plain blitts will be faster using the SDL even with its overhead)

woogal posted on Feb 26 2006 at 07:26 PM said:
won'treally change much though. Removing the call completely only increases the fps by 0.3 so the most improvement you're likely to get will only be about 0.2 I'd guess.

That is what I was thinking too.

woogal posted on Feb 26 2006 at 07:26 PM said:
When I was playing around with Quake's profiler I found two areas which seem to need the most optimisation but I can't remember which two they are now. If I get time later today I'll track them down again and let you know.

Yes, please... :)
 
Last edited by a moderator:
Back
Top