GP32 Addition Speed


pea

developer
Joined
Oct 3, 2004
Messages
1,089
Age
45
Location
New Zealand
Website
www.projectitis.com
Hi all,

Is this faster in terms of CPU cycles
a++;

than this:
a+=120;

Just wondering if stepping by one is faster than stepping by any other constant?

Cheers
 
I'd say no on the arm architecture, as both will probably be compiled to ADD rX, rY, #1 or #120 as appropriate. (with X and Y being registers selected by the compiler of course).
 
i remember hearing somewhere too that ++a is slightly faster than a++

but the compiler probably sorts that out anyway :)
 
mrsnature posted on Dec 13 2005 at 08:35 PM said:
i remember hearing somewhere too that ++a is slightly faster than a++

but the compiler probably sorts that out anyway :)
The difference is that ++a is a pre-increment and a++ is a post-increment. To do the post-increment, the current value is stored, the variable incremented, then the stored value is returned. It is best described when using operator overloads in C++.
Code:
    // Prefix operator overload
    // Increment and return the current value
    const Template& operator++() {++member; return *this;}
    // Postfix operator overload
    // Copy, increment, return the copy
    Template& operator++(int) {Template w(*this); ++*this; return w;}
In modern optimizing compilers, it may not make a great deal of difference though.
 
Last edited by a moderator:
a++ and ++a should be the same, except on arch's where one or the other can be blended with some other opcode. (edit: during optimization phase)

a++ versus a+=1 varies by arch; some chips have a "inc" type opcode which is very fast and can bump a register by one for instance, and may be piplinable very nicely.. while others don't.

a++ 120 times versus a+=120 is academic :)

jeff
 
yeah, thanks guys :). Much of a muchness in my opinion.

FYI what I am doing is trying to optimise some graphics code which draws a gradient to the framebuffer. The graideint is alwys vertical like the windows XP title bars.

I was wondering if it was faster to:

given start and end colour

CASE 1:
pre-calculate array of colours for each horizontal line
LOOP for each vertical line
LOOP for each horizontal line
draw pixel in colour[ y ];
inc y by 1 (y++)
/LOOP
/LOOP

CASE 2:
calculate r,g and b step to get from start to end colour
LOOP for each horizontal line
LOOP for each vertical line
draw pixel in colour
inc x by framebuffer height
/LOOP
inc colour by r,g,b step
/LOOP

The trade off is that in case 1 you need to precalculate the gradient and store it in memory, but the (possible0 good thing is that you can then step the framebuffer one pixel at a time (++) because the framebuffer is aligned vertically.

In case 2 you can just increment the colour by a step value to go through the gradient, and can draw each horizontal line in one go (same colour for all pixels) but stepping horizontally steps by framebuffer_height and not just ++.

So my decision is since stepping by ++ won't make enough difference to counter the precaclulation of the colour values and mem access, I will stick with case 2.

All confused?
Cheers
 
pea posted on Dec 13 2005 at 10:58 PM said:
yeah, thanks guys :). Much of a muchness in my opinion.

FYI what I am doing is trying to optimise some graphics code which draws a gradient to the framebuffer. The graideint is alwys vertical like the windows XP title bars.

in this case, doing it line by line should be MUCH faster, because you can use memcpy() or somesuch to write out the same value to the whole horizontal line of pixels in one go because they are a continuous set of bytes in the frame buffer, then do the next line, rather than a separate function call for each pixel.

depending on screen mode (8 or 16 bit) you'll have to write out bytes or words, but it CAN be done with memcpy. The only problem is with 24-bit mode (i don't know if gp2x has this?) where each pixel is 3-bytes wide so doesn't 'fit' to any word-size. This is why some PC graphics cards (most, now) support a 32-bit mode without alpha, which is like a 32-bit aligned 24-bit mode, so that it can be written to with a single 32-bit value, which is faster.

sorry for the long explanation! but this is an area of interest of mine, and these are the kinds of techniques that are used as standard in the various rasterisers that are used to draw triangles, at the lowest level of a software 3d rendering engine.

I was going to transfer my simple triangle renderer to gp2x, but someone's already working on a tinygl port, so who knows? plus time is sooo limited for these things.

edit: did I say memcpy()? i think i meant memset()
another edit: i suddenly realised this is the gp32 section, not gp2x. well, the same basic principles still apply anyway.
 
Last edited by a moderator:
shrubberyrobbery posted on Dec 14 2005 at 09:32 PM said:
another edit: i suddenly realised this is the gp32 section, not gp2x. well, the same basic principles still apply anyway.
If I remember correctly, the GP32 framebuffer was rotated 90deg. This means that contiguous bytes in memory represent a vertical line on screen, not horizontal like the GP2X.
 
Last edited by a moderator:
slygamer posted on Dec 14 2005 at 02:24 PM said:
If I remember correctly, the GP32 framebuffer was rotated 90deg. This means that contiguous bytes in memory represent a vertical line on screen, not horizontal like the GP2X.
really? bizarre! well if that's the case, scrub what I said, and do it the other way :D

and is the gp2x definitely addressed 'horizontally'? (i know that's semi-off-topic but am curious now!)
 
Last edited by a moderator:
LOL. Some funny shit.

Yes I realise all that. A project of mine even before I got the GP32 (just using geepee32 to start with) was to create my own set of graphics functions that abstract all graphics to 'canvas' objects, even the LCD. I use this exclusively for all my gp32 development (and it will be available with my public release of peaSDK) - it has 40x speed gains over Mr. Mirkos original non-optimised blitting functions...

A vertically aligned framebuffer (upwards from bottom left) is a pain in the a*s, but once you get your head around it, its ok.

I would be interested in some simple 2D poly drawing routines if you have any? i.e. Given set of points describing the vertices (2D) draw a solid poly.
 
pea posted on Dec 15 2005 at 07:24 AM said:
I would be interested in some simple 2D poly drawing routines if you have any? i.e. Given set of points describing the vertices (2D) draw a solid poly.

will dunk some source code on the web tomorrow (when I've got access to the server) for you to scrutinise :)

when its up i'll paste the url here.

its got flat shaded and also gauraud shaded triangles in there, and i'm using some fixed-point math.

here's a taster, you do two of these per triangle - one each for top half and bottom half, split horizontally:

Code:
//----------------------------------------------------------------------
// draw flat-topped lower-half of 8-bit flat colour triangle
// bottom point at (ixC,iyC-1), top line at iyB
//----------------------------------------------------------------------
void Triangle2D_FP::drawTriangleFlatLo8(){

	// get the colour
	UCHAR colour8 = _RGB_8_BIT(colour.red,colour.green,colour.blue);

	// sort the gradients
	int fpm1 = fpmBC;
	int fpm2 = fpmAC;
	if(fpm1<fpm2){int fpmT=fpm2; fpm2=fpm1; fpm1=fpmT;};

	// calculate initial line start/end points
	float fyError = fyC-(float)iyC;
	int fpx1 = fpxC - (int)((float)fpm1 * fyError);
	int fpx2 = fpxC - (int)((float)fpm2 * fyError);
	int ix1;
	int ix2;

	// 'pointed-end' y-clipping (high y values)
	int iy3=iyC;
	if(iy3>screen_height){
  int lines_clipped = iy3-screen_height;
  fpx1 -= (lines_clipped*fpm1);
  fpx2 -= (lines_clipped*fpm2);
  iy3 = screen_height;
	}

	// 'flat-end' y-clipping
	int iy2=iyB;
	if(iy2<0) iy2=0;

	// video address of first scanline to draw
	UCHAR *vid = back_buffer+(back_lpitch*(iy3-1));

	// do we need x-clipping?
	int xclip=0;
	if((ixC<0)||(ixC>screen_width)) xclip=1;
	else{
  int min_x = (fpx1 - (fpm1 * (iy3-iy2))) >> FIXP16_SHIFT;
  int max_x = (fpx2 - (fpm2 * (iy3-iy2))) >> FIXP16_SHIFT;
  if((min_x<0)||(max_x>screen_width)) xclip=1;
	}

	// draw scanlines from iy3-1 back to iy2
	for(int iyT=iy3-1; iyT>=iy2; iyT--){

  // get current line start/end points
  if(xclip==0){
  	ix1 = fpx1>>FIXP16_SHIFT;
  	ix2 = fpx2>>FIXP16_SHIFT;
  }
  else{
  	ix1 = max(min(fpx1>>FIXP16_SHIFT, screen_width), 0);
  	ix2 = max(min(fpx2>>FIXP16_SHIFT, screen_width), 0);
  }

  // draw line
  int linelength=(ix2-ix1);
  if(linelength>=1)memset(vid+ix1, colour8, linelength);

  // update to next line
  vid -= back_lpitch;
  fpx1 -= fpm1;
  fpx2 -= fpm2;
	}
}

sorry if the var-names are a bit cryptic :rolleyes:
it's using all these:
Code:
	int   ixA, iyA, ixB, iyB, ixC, iyC;	// INTEGER coords
	int  fpxA,fpyA,fpxB,fpyB,fpxC,fpyC;	// FIXED-POINT coords
	float fxA, fyA, fxB, fyB, fxC, fyC;	// FLOAT coords
	int fpmAB, fpmAC, fpmBC;  	// gradients
	ColourRGB colour;    	// flat-colour
also, i'm not calculating gradients here, they're done be the calling-fn.

yeah. you need to see the whole thing really.
 
Last edited by a moderator:
ok, heres some source:

www.exxcom.net/main/testsource.zip

its for win32, using DirectDraw, but ONLY for the initial video setup - the actual triangle renderers are totally in s/w and write directly to the back-buffer, so you should be able to see what's going on.

there are flat and gauraud 2d-triangle shaders in 8, 15, 16, 24 and 32-bit modes. But they all basically do the same thing. The general idea is that a top-level triangle draw function is called: This sort all the vertices, calculates all the edge gradients, and also deals with the special cases of degenerate triangles. Then it splits the triangle into 2 halves, split horizontally at the screen-line corresponding to the 'middle' vertex - then each sub fn call only has to deal with 2 edge-gradients: a leading and a trailing edge for each screen-line. This is drawn, a screen line at a time, with the leading/trailing edges updated each time according to the leading/trailing edge gradients. for the flat-shaded triangles, each screen line is blatted out in a single memset() call, and for the gauraud shaders a sub-loop is entered which moves along the line a pixel at a time, using colour-gradient as well.

hope this all makes some kinda sense :D

this was done with more than a little help from "Tricks of the 3D Game Programming Gurus: Advanced 3D Graphics and Rasterization " by Andre LaMothe
 
Back
Top