PDA

View Full Version : Super Slow SDL (about 1/3 frame per second...)



lochok
15-12-2006, 12:46 PM
Hey - Good afternoon,

My apologies - I'm a bit of a noob around here

I'm still trying to learn the basics of SDL and have got an issue. All the files related to the project are on http://www.savefile.com/files/340504 - its about a 250kb.

I'm writing an isometric engine (well the test more just shows an isometric map - learning SDLVideo at the moment). It displays the map originally almost instantly - matter of milliseconds however when I try to use the arrows to move the map, as I coded, it sucks up about 96% of my CPU and takes about 4 seconds before it updates the screen. I can't find the reason why - it doesn't seem to have any issues the first time, but the second call of the procedure makes it take absolutely ages blitting.

Sorry - the code isn't too neat, but its readable.

Any advice would be greatly appreciated!


Lochok

jasonf
15-12-2006, 02:02 PM
Hi Lochok,

Welcome to the site, I've had a brief look at your code. I can't run it at the moment as I'm at work. But it looks like your rendering algorithm is quite wasteful.

If I'm reading it correctly,

You create a seperate layer object for each layer in your map. So if you have 3 layers, each frame you're software blitting (800x600x3)x3, that's not even including any tile rendering. On top of this, you have the overhead of rendering the tiles to each layer.

There are things you can do to speed this up.

You are doubling up your work. You don't need to do this. Remember, anything you render using software has to travel down the AGP bus and it's got a limited bandwidth. Send as little as possible and you'll see your render speed increase.

1, do not render to layer surfaces. Treat your layers as logical entities instead of physical entities. Blit your tiles directly to the main screen surface. Put this in a loop to render the lowest layer + any sprites, then the next lowest and so on.. this will give you exactly the same effect as your layer routine but without the massive overhead of re-blitting the entire thing via the layer surface.

2. You're using 24bit, consider 16bit or 32. I've had performance problems with 24 bit and for some odd reason, 24bit was slower than 32 bit. 16 bit should be twice as fast as 32 bit because you're only sending half the amount of information. I'd really only use 32bit colour if I was using Hardware using OpenGL.

3. You're doing 2 flips at the end of your loop. You really only need one.

You're also only rendering when the player moves. Is this what you really want? This will mean that you won't be able to have any ambient animation.

Apart from the things I've mentioned, I can't see immediately what's causing such a long delay.

I'll run it tonight when I get home.

jasonf
15-12-2006, 02:14 PM
Just had another look, it looks like your problem might be down to your Event loop.

Try moving your render code out of the main loop. If you think about it, if you hit the arrow key, it's going to send loads of events to the buffer.. these will have to be processed.. this is normally very fast, but you're doing rendering in the meantime.


while stillrunning do begin

upPressed := false;
leftPressed := false;
rightPressed := false;
downPressed := false;

While SDL_PollEvent( @event ) > 0 do begin
If Event.type_ = SDL_QUITEV then StillRunning := False;
If Event.type_ = SDL_KEYUP then begin
Case Event.key.keysym.sym of
SDLK_Escape: StillRunning := False;
SDLK_Up: upPressed := true;
SDLK_Down: downPressed := true;
SDLK_Left: leftPressed := true;
SDLK_Right: rightPressed := true;
end;

Writeln('Keypress Detected ', FormatDateTime('tt', now));;

end;
end;


if upPressed then OffSetY := OffsetY + 96;
if downPressed then OffSetY := OffsetY - 96;
if leftPressed then OffsetX := OffsetX + 128;
if rightPressed then OffsetX := OffsetX - 128;

DrawMapToBuf(OffsetX, OffsetY);
Writeln('Flipping ', FormatDateTime('tt', now));
SDL_Flip(Scr);
Writeln('Done ', FormatDateTime('tt', now));

end;



I bet this gives you better results.

jasonf
15-12-2006, 06:54 PM
OK. I've had a tinker and found that your main problem was in the rendering code.. it was just TOO Busy.

So I've altered it for you and now it's as fast as a fast thing.
Also, I've changed your input code. You were only testing for Key Up. No doubt you will have tried Key down and found there to be no noticable difference.. well, SDL doesn't do Key repeats. So I've used flags. I set them on Key Down and reset them on Key Up. Works lovely :D

Here's the code.



program sdltest4;


uses
sdl,
sysutils;

var scr: PSDL_Surface; // Our main screen
Tiles, TileIn: PSDL_Surface;
TmpLayer: PSDL_Surface;
Layers: Array of PSDL_Surface;
LayerCount: Word;
TileWidth, TileHeight: Word;
MapWidth, MapHeight: Word;
stillrunning: Boolean;
event: TSDL_Event;
MapData: Array of Word;
OffsetX, OffsetY: Integer;

leftPressed : boolean;
rightPressed : boolean;
upPressed : boolean;
downPressed : boolean;

Procedure LoadMap(MapPath: String);
var
MapFile: Text;
CountLayer, CountX, CountY: Word;
begin
Assign (Mapfile, Mappath);
Reset (Mapfile);
Read(MapFile, TileWidth);
Read(MapFile, TileHeight);
Read(MapFile, MapWidth);
Read(MapFile, MapHeight);
Read(MapFile, LayerCount);
Setlength(Layers, LayerCount);
For CountLayer := 0 to (LayerCount-1) do begin
TmpLayer := SDL_CreateRGBSurface( SDL_HWSURFACE, Scr^.w, Scr^.h, Scr^.format
.bitsperpixel,
0,0,0,0);

Layers[CountLayer] := SDL_DisplayFormat(TmpLayer);
SDL_SetColorKey(Layers[CountLayer], SDL_SRCColorKey or SDL_RLEAccel,
SDL_MapRGB(Scr.Format, 0, 0, 0));

end;
SetLength(MapData, MapWidth*LayerCount*MapHeight);
For CountLayer := 0 to (LayerCount-1) do
for CountX := 0 to (MapWidth-1) do
for CountY := 0 to (MapHeight-1) do
Read(MapFile, MapData[CountLayer*MapWidth*MapHeight+CountX*MapHeight+Cou ntY]);
Close (mapFile);
end;

Procedure DrawMapToBuf(TopX, TopY: Word);
var
CountLayer, CountX, CountY: Word;
CurX, CurY: Integer;
SourceRect, DestRect: TSDL_Rect;
begin
//Writeln ('Started Drawmaptobuf ', FormatDateTime('tt', now));

CurX := TopX;
CurY := TopY;

SDL_Fillrect(Scr,@DestRect,sdl_maprgb(Scr.Format, 0, 0, 0));

//Paint to seperate layers
For CountLayer := 0 to (LayerCount-1) do begin
SDL_Fillrect(Layers[CountLayer],nil,sdl_maprgb(Scr.Format, 0, 0, 0));
for CountX := 0 to (MapWidth-1) do begin
for CountY := (MapHeight-1) downto 0 do begin
//CurX and CurY are the Top Corners of the tiles
CurX :=
TopX - (TileWidth div 2) - CountX * (TileWidth div 2) + CountY * (TileWidth div 2);;
CurY := TopY + CountY * (TileHeight div 2) + CountX * (TileHeight div 2);
If (CurX >= ((TileWidth ) * - 1)) and (CurY >= 0) then begin
With SourceRect do begin
x := MapData[CountLayer*MapWidth*MapHeight+CountX*MapHeight+Cou ntY] * TileWidth;
y := 0;
h := TileHeight;
w := TileWidth;
end;
With DestRect do begin
x := CurX;
y := CurY;
h := TileHeight;
w := TileWidth;
end;

SDL_BlitSurface(Tiles, @SourceRect, Scr, @DestRect);
//Writeln('Blit''ed ',CountLayer,':',Countx,' ',countY, ' ', FormatDateTime('tt', now));
end;
end;
end;
end;

end;

Procedure CleanUp;
var CountLayer: Word;
begin
For CountLayer := 0 to High(Layers) do sdl_FreeSurface(Layers[CountLayer]);
end;

begin
//Writeln ('Initing SDL ', FormatDateTime('tt', now));
SDL_Init(SDL_INIT_VIDEO); // Initialize the video SDL subsystem
scr:=SDL_SetVideoMode(800 , 600, 16, SDL_SWSURFACE {or SDL_Fullscreen }{or SDL_DoubleBuf});
stillrunning := true;
SDL_WM_SetCaption('Caption', 'Icon');


//Writeln ('Loading Map ', FormatDateTime('tt', now));
LoadMap('Map1.map');

//Writeln ('Loading Tiles ', FormatDateTime('tt', now));
TileIn:= SDL_LoadBmp('Tiles.bmp');
Tiles := SDL_DisplayFormat(TileIn);
SDL_SetColorKey (Tiles, SDL_SRCColorKey or SDL_RLEAccel, SDL_MapRGB(Tiles.Format, 191, 123, 199));


OffsetX := Scr^.W div 2;
OffsetY := -256;

//Writeln ('Drawing Map ', FormatDateTime('tt', now));
DrawMapToBuf(OffsetX, OffsetY);
SDL_Flip(Scr);

leftPressed := false;
rightPressed := false;
upPressed :=false;
downPressed :=false;

while stillrunning do begin

While SDL_PollEvent( @event ) > 0 do begin
If Event.type_ = SDL_QUITEV then StillRunning := False;
If Event.type_ = SDL_KEYDOWN then begin
Case Event.key.keysym.sym of
SDLK_Escape: StillRunning := False;
SDLK_Up: upPressed := true;
SDLK_Down: downPressed := true;
SDLK_Left: leftPressed := true;
SDLK_Right: rightPressed := true;
end;

end;

If Event.type_ = SDL_KEYUP then begin
Case Event.key.keysym.sym of
SDLK_Escape: StillRunning := False;
SDLK_Up: upPressed := false;
SDLK_Down: downPressed := false;
SDLK_Left: leftPressed := false;
SDLK_Right: rightPressed := false;
end;

end;
end;

if upPressed then OffSetY := OffsetY + 96;
if downPressed then OffSetY := OffsetY - 96;
if leftPressed then OffsetX := OffsetX + 128;
if rightPressed then OffsetX := OffsetX - 128;

//Writeln('Keypress Detected ', FormatDateTime('tt', now));;
DrawMapToBuf(OffsetX, OffsetY);
//Writeln('Flipping ', FormatDateTime('tt', now));
SDL_Flip(Scr);
//Writeln('Done ', FormatDateTime('tt', now))

end;

CleanUp; // Deallocate pointers
SDL_Quit; // close the subsystems and SDL

end.



Enjoy.

lochok
15-12-2006, 10:59 PM
Whoa.... thankyou very much for that. Vast increase in speed - and I think I understand why. Thanks for your help.

The rendering was put there just while I was learning SDL as part of the test - animation is the next thing I was going to try to do. As I can see you've moved the rendering anyway as part of fixing it - thanks for this. It should make the next step easier.

Thankyou,


lochok