Bad performence problems

I have been working on this one algorithm for days to try and make it work at
a reasonable speed but to no avail…was hoping meyb u guys could help!
:)…firstly my coputer specs: athlon 2100xp 1gig ram r9800pro gfx
card…
At the moment i am writing a top down shooter, and i am
trying to write an algorithm that darkens the whole screen apart from a
circular area around the player using the folliwng algorithm that i made:

void darkenLandscape(SDL_Surface source,int radius,int x,int y){
// Draw to screen
int yofs = 0,j=0,ofs=0;
for (int i = 0; i < HEIGHT; i++)
{
for (j = 0, ofs = yofs; j < WIDTH; j++, ofs++)
{
int dx= x-j;
int dy= y-i;
float length=sqrt((float)((dx
dx)+(dy*dy)));

		Uint32 pixel = getPixel(source,j,i);

		Uint8 sourcer = pixel;
		Uint8 sourceg = pixel>>8;
		Uint8 sourceb = pixel>>16;

		if(length>radius){
			sourcer/=4;
			sourceg/=4;
			sourceb/=4;
		}
		else{
			//Avoid divide by zero error
			double mod = 1+3*(1-((radius-length)/radius));
			sourcer=(Uint8)(sourcer/(mod+0.1));
			sourceg=(Uint8)(sourceg/(mod+0.1));
			sourceb=(Uint8)(sourceb/(mod+0.1));
		}
		Uint32 *pixels = source->pixels;
		pixel = (sourcer <<  0)|(sourceg <<  8)|(sourceb << 16);	
		pixels[ofs] = pixels[ofs]/2;}
	}
	yofs += PITCH;
}

}

Now i know that it definately works (see attached screenshot) however the
most i can get out of it is 16 or so fps which seems rediculous!!..i have
tried running it in fullscreen mode windowed mode using sdl_flip and
sdl_updaterec but to no avail…also before this algorithm is called the
source surface is locked. Can any1 help me out here its driving me crazy!!!
Thanks so much in advance :slight_smile:

-James Grafton–
View this message in context: http://www.nabble.com/Bad-performence-problems-tf2088149.html#a5755364
Sent from the SDL forum at Nabble.com.

darkplastic wrote:

I have been working on this one algorithm for days to try and make it work at
a reasonable speed but to no avail…was hoping meyb u guys could help!
:)…firstly my coputer specs: athlon 2100xp 1gig ram r9800pro gfx
card…
At the moment i am writing a top down shooter, and i am
trying to write an algorithm that darkens the whole screen apart from a
circular area around the player using the folliwng algorithm that i made:

Don’t use getPixel(), do it with a memory read.
Calculate your buffer offset ONCE per Y line instead of every time.
Don’t mix float and double. Stick to float.

Hm, that code seems to have an error. The only pixel write done is
pixels[ofs] = pixels[ofs]/2;
which means all that work calculating a pixel is never used!

I’m wondering if you are better off using alpha somehow to achieve this.

Pete.

Try to get rid of the function calls, sqrt, and if/else

Try and use some of the optimized blitters for the task instead… if
that’s possible. Or take a look at the source for them to see how
they are made fast.

It might be a lot of work, so is there anything else you could do instead?On 8/11/06, darkplastic wrote:

I have been working on this one algorithm for days to try and make it work at
a reasonable speed but to no avail…was hoping meyb u guys could help!
:)…firstly my coputer specs: athlon 2100xp 1gig ram r9800pro gfx
card…
At the moment i am writing a top down shooter, and i am
trying to write an algorithm that darkens the whole screen apart from a
circular area around the player using the folliwng algorithm that i made:

void darkenLandscape(SDL_Surface source,int radius,int x,int y){
// Draw to screen
int yofs = 0,j=0,ofs=0;
for (int i = 0; i < HEIGHT; i++)
{
for (j = 0, ofs = yofs; j < WIDTH; j++, ofs++)
{
int dx= x-j;
int dy= y-i;
float length=sqrt((float)((dx
dx)+(dy*dy)));

                    Uint32 pixel = getPixel(source,j,i);

                    Uint8 sourcer = pixel;
                    Uint8 sourceg = pixel>>8;
                    Uint8 sourceb = pixel>>16;

                    if(length>radius){
                            sourcer/=4;
                            sourceg/=4;
                            sourceb/=4;
                    }
                    else{
                            //Avoid divide by zero error
                            double mod = 1+3*(1-((radius-length)/radius));
                            sourcer=(Uint8)(sourcer/(mod+0.1));
                            sourceg=(Uint8)(sourceg/(mod+0.1));
                            sourceb=(Uint8)(sourceb/(mod+0.1));
                    }
                    Uint32 *pixels = source->pixels;
                    pixel = (sourcer <<  0)|(sourceg <<  8)|(sourceb << 16);
                    pixels[ofs] = pixels[ofs]/2;}
            }
            yofs += PITCH;
    }

}

Now i know that it definately works (see attached screenshot) however the
most i can get out of it is 16 or so fps which seems rediculous!!..i have
tried running it in fullscreen mode windowed mode using sdl_flip and
sdl_updaterec but to no avail…also before this algorithm is called the
source surface is locked. Can any1 help me out here its driving me crazy!!!
Thanks so much in advance :slight_smile:

-James Grafton

View this message in context: http://www.nabble.com/Bad-performence-problems-tf2088149.html#a5755364
Sent from the SDL forum at Nabble.com.


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

  	float length=sqrt((float)((dx*dx)+(dy*dy)));

[…]

  		//Avoid divide by zero error
  		double mod = 1+3*(1-((radius-length)/radius));
  		sourcer=(Uint8)(sourcer/(mod+0.1));
  		sourceg=(Uint8)(sourceg/(mod+0.1));
  		sourceb=(Uint8)(sourceb/(mod+0.1));

If the radius isn’t arbitrary but instead can be one of the
several values known in advance, maybe it’s worth to have
square “masks” with these values precomputed. Then, instead
of passing the radius, you pass the appropriate “mask” and
it’s position and size. If the pixel is outside of the area
covered by the mask, you do the quick divide by 4 (or maybe

2, but probably your compiler optimizes it anyway). If
not, you divide by the corresponding value in the mask.
This way you avoid all sqrt’s, all multiplies and most
divides (in the game loop, I mean).

HTH,
OlegOn Thu, Aug 10, 2006 at 06:05:26PM -0700, darkplastic wrote:

[…]

I’m doing this, although not to this extreme extent, in Kobo Deluxe.
Though there is (of course) a frame rate hit, it’s pretty much
insignificant on anything better than a Pentium II. (And even so, it
can be turned off, if you really need to.)

My solution is very simple: A black overlay (actually includes some
framework graphics, but that’s not really relevant to this
discussion) with an alpha channel that creates a smooth "shadow"
inside the frame of the playfield.

When using SDL 2D rendering, I just SDL_DisplayFormatAlpha() this
overlay surface with RLE acceleration, along with all other graphics.
On platforms that can provide a double buffered hardware screen,
“SemiTriple” buffering is used, which means the changes for each
frame are rendered into an off-screen software surface and blitted
from there to the display surface, and then a flip is performed. On
platforms that will only provide a “single” buffered software display
(like most Un*x systems running X11 or similar), rendering is done
"directly" into the display surface - no special tricks needed.

When using OpenGL (through the old glSDL wrapper), I make use of
normal OpenGL source alpha blending. (Since it’s hardware
accelerated, the CPU/VRAM issue is avoided, so no strange hacks
needed for performance here.)

If you’re stuck with software rendering (which you are, unless you’re
using OpenGL directly or via some version of glSDL), there are two
important things to keep in mind:

1) Alpha blending is a read-modify-write operation, and
   reading from VRAM is usually very, very expensive on
   modern PC hardware. Thus, when doing significant
   amounts of alpha blending, doing all rendering into
   a software surface, and then blitting that to the
   display surface is often much faster than working
   directly in a hardware display surface.

2) Alpha blending is rather expensive per pixel, compared
   to plain opaque blitting. However, when using SDL's
   RLE acceleration this impacts only pixels that actually
   are translucent. Transparent pixels are skipped, while
   opaque pixels are copied. Thus, there can be a lot of
   speed to gain by keeping the alpha channel clean, and
   not using more translucency effects than absolutely
   required.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Friday 11 August 2006 03:05, darkplastic wrote:

I have been working on this one algorithm for days to try and make
it work at a reasonable speed but to no avail…was hoping meyb u
guys could help! :)…firstly my coputer specs: athlon 2100xp 1gig
ram r9800pro gfx card…
At the moment i am writing a top down shooter, and i
am trying to write an algorithm that darkens the whole screen apart
from a circular area around the player using the folliwng algorithm
that i made:

David Olofson wrote:

I have been working on this one algorithm for days to try and make
it work at a reasonable speed but to no avail…was hoping meyb u
guys could help! :)…firstly my coputer specs: athlon 2100xp 1gig
ram r9800pro gfx card…
At the moment i am writing a top down shooter, and i
am trying to write an algorithm that darkens the whole screen apart
from a circular area around the player using the folliwng algorithm
that i made:
[…]

I’m doing this, although not to this extreme extent, in Kobo Deluxe.
Though there is (of course) a frame rate hit, it’s pretty much
insignificant on anything better than a Pentium II. (And even so, it
can be turned off, if you really need to.)

My solution is very simple: A black overlay (actually includes some
framework graphics, but that’s not really relevant to this
discussion) with an alpha channel that creates a smooth "shadow"
inside the frame of the playfield.

When using SDL 2D rendering, I just SDL_DisplayFormatAlpha() this
overlay surface with RLE acceleration, along with all other graphics.
On platforms that can provide a double buffered hardware screen,
“SemiTriple” buffering is used, which means the changes for each
frame are rendered into an off-screen software surface and blitted
from there to the display surface, and then a flip is performed. On
platforms that will only provide a “single” buffered software display
(like most Un*x systems running X11 or similar), rendering is done
"directly" into the display surface - no special tricks needed.

When using OpenGL (through the old glSDL wrapper), I make use of
normal OpenGL source alpha blending. (Since it’s hardware
accelerated, the CPU/VRAM issue is avoided, so no strange hacks
needed for performance here.)

If you’re stuck with software rendering (which you are, unless you’re
using OpenGL directly or via some version of glSDL), there are two
important things to keep in mind:

  1. Alpha blending is a read-modify-write operation, and
    reading from VRAM is usually very, very expensive on
    modern PC hardware. Thus, when doing significant
    amounts of alpha blending, doing all rendering into
    a software surface, and then blitting that to the
    display surface is often much faster than working
    directly in a hardware display surface.

  2. Alpha blending is rather expensive per pixel, compared
    to plain opaque blitting. However, when using SDL’s
    RLE acceleration this impacts only pixels that actually
    are translucent. Transparent pixels are skipped, while
    opaque pixels are copied. Thus, there can be a lot of
    speed to gain by keeping the alpha channel clean, and
    not using more translucency effects than absolutely
    required.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --’


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

Thanks so much for your help, i manged to create a hardware accelerated
black fade surface and make the whole map dark but however i am a bit
confused as to how exactly to set an alpha channel that creates a smooth
shadow, i hear that there is a way to set alpha on a surface depending on
the greyscale of another or something? but i cant seem to find a way of
doing this. Thanks in advance.

-James> On Friday 11 August 2006 03:05, darkplastic wrote:

View this message in context: http://www.nabble.com/Bad-performence-problems-tf2088149.html#a5768018
Sent from the SDL forum at Nabble.com.

[…]

Thanks so much for your help, i manged to create a hardware
accelerated black fade surface and make the whole map dark but
however i am a bit confused as to how exactly to set an alpha
channel that creates a smooth shadow, i hear that there is a way to
set alpha on a surface depending on the greyscale of another or
something? but i cant seem to find a way of doing this. Thanks in
advance.

Well, there is the “full surface alpha” parameter set by
SDL_SetAlpha(), but that’s not what you want here. (It affects all
pixels equally, and cannot be combined with an alpha channel.)

What you need is an image (generated or rendered in PhotoShop, GIMP
och whatever you prefer) with an alpha channel. That is, an RGBA
pixel format rather than RGB. The image should be black in this case
(could by gray or whatever for a fog effect, though), and it should
be translucent near the center.

How to make one in GIMP (PhotoShop should be very similar): 1. Create a new image the size of your game screen. 2. Add an alpha channel. 3. Clear the image. For example Select All (CTRL + a) followed by Cut (CTRL + x). 4. Select the gradient fill tool with the "FG to transparent" gradient and radial shape. 5. Select black for foreground color. 6. Place the cursor in the center of the image (or wherever you want the fully transparent point), press the left button, drag to a point where you want the image to be opaque, and release. 7. Save as PNG, TGA or some other format that supports alpha channels, and of course, is supported by SDL_image, or whatever you're using for loading graphics.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Friday 11 August 2006 21:19, darkplastic wrote:

David Olofson wrote:

[…]

Thanks so much for your help, i manged to create a hardware
accelerated black fade surface and make the whole map dark but
however i am a bit confused as to how exactly to set an alpha
channel that creates a smooth shadow, i hear that there is a way to
set alpha on a surface depending on the greyscale of another or
something? but i cant seem to find a way of doing this. Thanks in
advance.

Well, there is the “full surface alpha” parameter set by
SDL_SetAlpha(), but that’s not what you want here. (It affects all
pixels equally, and cannot be combined with an alpha channel.)

What you need is an image (generated or rendered in PhotoShop, GIMP
och whatever you prefer) with an alpha channel. That is, an RGBA
pixel format rather than RGB. The image should be black in this case
(could by gray or whatever for a fog effect, though), and it should
be translucent near the center.

How to make one in GIMP (PhotoShop should be very similar): 1. Create a new image the size of your game screen. 2. Add an alpha channel. 3. Clear the image. For example Select All (CTRL + a) followed by Cut (CTRL + x). 4. Select the gradient fill tool with the "FG to transparent" gradient and radial shape. 5. Select black for foreground color. 6. Place the cursor in the center of the image (or wherever you want the fully transparent point), press the left button, drag to a point where you want the image to be opaque, and release. 7. Save as PNG, TGA or some other format that supports alpha channels, and of course, is supported by SDL_image, or whatever you're using for loading graphics.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --’


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

So once you would blit this image ontop of the black surface before you blit
the surface to the screen i see!! this would allow for the area around the
player to be partially transparent and thus lighter…so close to working
now!!! However one last glitch i use this line of code to load in the image:

return(SDL_ConvertSurface(IMG_Load(path), gScreen->format,
SDL_HWSURFACE|SDL_SRCCOLORKEY|SDL_SRCALPHA));

and darken landscape now looks like:

void darkenLandscape(SDL_Surface *source,int x,int y){

SDL_Rect coords;
coords.x = _player._coords.x+(_player.surface->w/2) - (_lightSource->w/3);
coords.y = _player._coords.y+(_player.surface->h/2) - (_lightSource->h/3);

SDL_BlitSurface(_lightSource,NULL,_fadeSurface,&coords);	
SDL_BlitSurface(_fadeSurface,NULL,gScreen,NULL);

}

and the image for the light source is:

http://www.nabble.com/user-files/278/Untitled.png Untitled.png

and i did everything with alpha channels ike u said in gimp, however when
the game runs now all i can see is a white dot where the image should be:

http://www.nabble.com/user-files/279/screen.JPG screen.JPG

Sorry to bother you so much, but i know that its soo close to working!!

-James> On Friday 11 August 2006 21:19, darkplastic wrote:

View this message in context: http://www.nabble.com/Bad-performence-problems-tf2088149.html#a5770240
Sent from the SDL forum at Nabble.com.

[…]

So once you would blit this image ontop of the black surface before
you blit the surface to the screen i see!!

Not sure I understand what you mean. You’re supposed to render it over
the game screen every frame, last thing before you flip or update the
display. The way this RGBA overlay is drawn, this will darken the
already rendered graphics gradually away from the center, resulting
in something like the effect in your original screen shot.

this would allow for the area around the player to be partially
transparent and thus lighter…so close to working now!!!
However one last glitch i use this line of code to load in the
image:

return(SDL_ConvertSurface(IMG_Load(path), gScreen->format,
SDL_HWSURFACE|SDL_SRCCOLORKEY|SDL_SRCALPHA));

Don’t use color key for this one! That’s probably why you’re getting
the single dot seen in your screenshot. The default color key value
is probably 0,?which is black, fully transparent in RGBA format.
IIRC, colorkey takes priority over alpha channel if you enable both,
so you actually get color key only with these flags. (And full
surface alpha, actually - but that has no effect unless you also set
an alpha value with SDL_SetAlpha().)

(BTW, there’s a memory leak: SDL_ConvertSurface() creates a new
surface, so the one returned from IMG_Load() is left around with no
reference.)

The code and the image looks right to me. (I would rather call the
image a shadow mask or something like that, though. :wink:

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Saturday 12 August 2006 00:07, darkplastic wrote:

David Olofson wrote:

[…]

So once you would blit this image ontop of the black surface before
you blit the surface to the screen i see!!

Not sure I understand what you mean. You’re supposed to render it over
the game screen every frame, last thing before you flip or update the
display. The way this RGBA overlay is drawn, this will darken the
already rendered graphics gradually away from the center, resulting
in something like the effect in your original screen shot.

this would allow for the area around the player to be partially
transparent and thus lighter…so close to working now!!!
However one last glitch i use this line of code to load in the
image:

return(SDL_ConvertSurface(IMG_Load(path), gScreen->format,
SDL_HWSURFACE|SDL_SRCCOLORKEY|SDL_SRCALPHA));

Don’t use color key for this one! That’s probably why you’re getting
the single dot seen in your screenshot. The default color key value
is probably 0, which is black, fully transparent in RGBA format.
IIRC, colorkey takes priority over alpha channel if you enable both,
so you actually get color key only with these flags. (And full
surface alpha, actually - but that has no effect unless you also set
an alpha value with SDL_SetAlpha().)

(BTW, there’s a memory leak: SDL_ConvertSurface() creates a new
surface, so the one returned from IMG_Load() is left around with no
reference.)

The code and the image looks right to me. (I would rather call the
image a shadow mask or something like that, though. :wink:

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --’


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

Thanks for your continuing help i really appreciate it, i finally found out
what was wrong i was setting the format to gscreen->format and because of
this it wasnt picking up on the alpha channel, so it finally works…am i
right in assuming that the whole mask is being created then moved around the
player , meaning that it would have to be twice the size of the screen
(since the radius would need to be the size of the screen when the character
is in the corners of the screen) Thanks man :).

-James> On Saturday 12 August 2006 00:07, darkplastic wrote:


View this message in context: http://www.nabble.com/Bad-performence-problems-tf2088149.html#a5778008
Sent from the SDL forum at Nabble.com.

[…]

am i right in assuming that the whole mask is being created then
moved around the player , meaning that it would have to be twice the
size of the screen (since the radius would need to be the size of
the screen when the character is in the corners of the screen)
[…]

Well, yes - if you actually render the whole screen, and then the
mask. Alternatively, make the mask just large enough to cover the
illuminated area, and then use SDL_FillRect() to quickly fill any
areas outside the mask with black pixels. (Should be the quickest way
to fill areas with a single color, hardware accelerated or not.)

However, if the illuminated area is not the full size of the screen,
why render anything at all in the pitch dark areas? :slight_smile:

You could use SDL_SetClipRect() to restrict all rendering to just the
area where anything is actually visible, avoiding rerendering the
whole screen every frame. If the illuminated area covers just a
fraction of the full screen, this can result in a drastic frame rate
increase.

Note that smart updating like this requires some extra logic to deal
with whatever is left around from the last frame, or you’ll see
garbage around the edges of moving objects and things like that.

Or, you just SDL_FillRect() the whole screen before rendering each
frame, and then set the clip rect and render only the illuminated
area. Much simpler, but still faster than rendering a full screen of
tiles, sprites and whatnot, and then paint over most of it with
opaque shadow mask pixels.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Saturday 12 August 2006 19:44, darkplastic wrote: