performance problems in a small 2D game

Started by
46 comments, last by zedzeek 19 years, 9 months ago
high, I have been working on a 2D action / RPG for the past few months now. When i first started to make the game, i was using SDL for the rendering. This proved to be much too slow for my game, so i started reading up on OpenGL. It only took me about a week to port the code to using OpenGL.. Anyway, my framerate on my computer is awesome! I get ~350 FPS in windowed mode, and ~500 FPS in windowed mode. Sadly though, im running a 3 gig p4 w / Radeon 9600 and 512 megs of RAM, with the latest drivers... On lower end machines, like 500 mhz or 800 mhz or whatever, the game slows to a crawl! One tester (actually, my team-mate), running a 500 mhz machine, gets about 5 FPS in windowed mode! Lucky for fullscreen, he gets around 60 FPS. Other people have tested, and have smiliar results, some even worse then these =(. I know its my game, because these people run commercial games just fine, games like unreal tournmanet or sim city 3000 run reasonably well. Also, SDL is telling me that these people DO have hardware accceleration / hardware blits enabled! one person who didnt have hardware accel / blits enabled, got 3 FPS in both windowed AND fullscreen! and his machine ran sim city 3000 at 50 FPS!! I ran a profiler with my game, and im not positive i did it right, but im pretty sure its telling me ~50% of the time is spent in my Map::Update() function. All this function does, is render my tiles to the screen. (This is a tile based game). Anyway, this Map::Update() function will draw my map to the screen. I have it limited to draw only what the player can see, which is ~400 tiles / quads. Im using 2d Ortho mode with the origin at the top left corner, so each unit is == one pixel. Im drawing each tile 32 pixels/units big. Also, there is only one texture for the tiles. its a tilemap (128x128) which i "slice" via glTexCoord() to render a piece of this tilemap image onto the quad. I bind this texture only one time before i draw any of the tiles... Here is my Map::Update() function which will draw the map:

bool Map::Update()
{

	glBindTexture(GL_TEXTURE_2D,tilemap_texture);

	int x, y;	//screen pixel x,y coordinate to draw the current tile to
	int mx, my;
	int sx = 0 - (scroll_x%TILESIZE);
	int smx = (sx+scroll_x)/TILESIZE;

	for(y = 0 - (scroll_y%TILESIZE), my = (y+scroll_y)/TILESIZE;  y < VIEWHEIGHT;  y+=TILESIZE)
	{		//y draw coordinate, the offset is for smooth scrolling
		for( x = sx, mx = smx;  x < VIEWWIDTH;  x+=TILESIZE)
		
		{	
			systm->Draw_Tile((float)x,(float)y,current_map[my][mx]->x_map_loc,current_map[my][mx]->y_map_loc);
			mx++;

		//	if(Get_Flags(mx,my) & MAPSWAPTILE)
		//		cout<<" THERES DEFINETLY A MST HERE!!!!"<<endl;
		}
		my++;
	}


	return true;

}
now, here is my Map::Draw_Tile() function which draws the actual tile

void System::Draw_Tile(float x, float y, float x_loc, float y_loc)
{
	//glEnable(GL_BLEND);
	  //bind the texture we sent in to this quad

	//THIS WAS MOVED TO INSIDE MAP UPDATE AND ONLY CALLED ONCE BY FRUNY"S RECOMMENDATION
//	  glBindTexture(GL_TEXTURE_2D,map_data->tilemap_texture);
	  
	  //draw this quad white
	  glColor3f(1.0f,1.0f,1.0f);

	  //float corner_offset = 32.0f/64.0f; //(map.tmap_height*TILESIZE);

	  //the width/height of a tile in percent-wise (to calc the edges of a tile.. ie x,y is top left, x + (t_perc)w is right corner
	  float t_perc_w = 32.0f/((float)map_data->tmap_width*(float)TILESIZE);
	  float t_perc_h = 32.0f/((float)map_data->tmap_height*(float)TILESIZE);

	 glBegin(GL_QUADS);               
   
	     /* Bottom Left */
		 glTexCoord2f(x_loc, y_loc + t_perc_h); //was 0.0f,1.0f
		 glVertex2f(x, y + 32.0f); 
	  
		 /* Bottom Right */
		 glTexCoord2f(x_loc + t_perc_w , y_loc + t_perc_h); //was 1.0, 1.0
		 glVertex2f(x + 32.0f,y + 32.0f); 

		 /* Top Right */
		 glTexCoord2f(x_loc + t_perc_w , y_loc); //was 1.0,0.0 
		 glVertex2f(x + 32.0f,y); 

		 /* Top Left */
		 glTexCoord2f(x_loc,y_loc); //was 0.0 0.0
		 glVertex2f(x,y); 
  
     glEnd();

}
Thanks for any help! im really hoping someon here can help me... someone had told me to use vertex / texture coord arrays, but then someone in this forum told me that it wont help because im not doing complicated geometry. Thanks for any help, and if you need more info just ask!
FTA, my 2D futuristic action MMORPG
Advertisement
Quote:
On lower end machines, like 500 mhz or 800 mhz or whatever, the game slows to a crawl! One tester (actually, my team-mate), running a 500 mhz machine, gets about 5 FPS in windowed mode! Lucky for fullscreen, he gets around 60 FPS. Other people have tested, and have smiliar results, some even worse then these =(.

Does that guy have a Voodoo x video card?
The difference between windowed/fullscreen for one of oyur testers is probably due to some old graphics card's inability to render in anything other than fullscreen.

At any rate, I have a few suggestions...

try only updating the part of the screen that's changing. This changes from having to render a nice big screen to a few tiles each "frame".

for people without okay graphics cards (and I mean only okay ones, not even halfway decent are required) you might want to consider being able to use SDL's native blitting facilities. I'm surprised you found these unacceptablely slow...
I'm sure I must have said this like ten times this last week, maybe it needs adding to the faq:

"Why is my drawing so slow? [insert code using immediate mode rendering and thousands of begin/end pairs]"

Immediate mode is horribly slow, mainly because of the shear number of function calls needed. You're then making it worse by having begin/end pairs that only contain a couple of polys. Rework your rendering to use something more efficiant like vertex arrays. Its not difficult to fill a bunch of arrays with data and render the whole lot in one blast, and you'll be surprised at the performance increase.
Quote:Original post by OrangyTang
Immediate mode is horribly slow, mainly because of the shear number of function calls needed. You're then making it worse by having begin/end pairs that only contain a couple of polys. Rework your rendering to use something more efficiant like vertex arrays. Its not difficult to fill a bunch of arrays with data and render the whole lot in one blast, and you'll be surprised at the performance increase.


Imediate mode is horribly slow only if you are fill rate or bandwidthlimited. Otherwise it's OK.
Since the windowperformance ==5 FPS and full screen ==60 (I think 60 because of the Vsync) the geometry is obviously not at fault here.
Radup - im not sure what video card he was using

C Junkie - i already only draw what the player can see. anytime the player moves, this changes...

Orangy / Radup - so which one of you are right ? :) and if Radup is correct, could anyone recommend anything for me? just throw out some things, im willing to do anything to get this game running smooth on older computers... thanks for any help!!!
FTA, my 2D futuristic action MMORPG
Well, you can experiment, but try this first:
Give it to someone with a crappy computer, and ask them to change resolutions/color depths.
If they get different FPS, then there is no point in using anything than the imemdiate mode, since the problem is with the fill rate.
But it is imperative to tell them to disable the Vsync!
I'm doing something similar as you, which is one quad per graphic drawn on the screen. I tried draw lists (1 list per quad), vertex arrays (1 array per quad), and vertex buffers (1 buffer per quad). No changes in frame rate.

The only way I can see getting improvement out of arrays or buffers (draw lists aren't going to do any good here), is to keep track of which quads need to be drawn. Then at the end of the draw routine, gather up all quads and cram them into a single array, then draw that single array of quads as a vertex array or vertex buffer. Then perhaps you'll see improvement, but I'm not entirely sure. Ask one of the guys here to see if my method I just mentioned would make a difference.
Quote:Original post by Raduprv
Imediate mode is horribly slow only if you are fill rate or bandwidthlimited. Otherwise it's OK.


errm, i think you've got this backwards, if you are fillrate or bandwidth limited then Immediate mode isnt going to cause you any problems, other than a waste of cpu time by hand feeding the data, simple because you've already satuated the gfx card.

I'd say that you'd probably have a huge huge problem fillrate limiting a modern card via glvertex*() et al as your cpu wont be able to feed the data to the card quick enuff, instead you'll pipeline stall it all the time and get horrible performance anyways.

@ the OP:
Yes, you're probably right that vertex arrays wont help that much however i do agree with the rest of the posters that doing 1 quad per glbegin/glend pair isnt a good idea, you should be able to get away with puttin them outside your drawing loop, after the texture bind, and that should help a bit.

Getting 5fps in windowed mode isnt that odd, in that mode the gfx card doesnt have exclusive access to the frame buffer so has to swap via copying (well, most likely way) which reduces the redraw rate, as your tests with the 9600 show.
Try changing the fullscreen size and see if that makes any difference for people.
If it does you are fillrate limited.
If it doesnt the problem is else where.

If you can get a list of a few testers with there cpu speed, gfx card type, memory and fps in both windowed and fullscreen then more advice could be given.

However, I'd take a stab in the dark however and say you are suffering form hitting a CPU limit more than anything, but without more data that will be hard to judge.
Quote:Original post by wyrd
I'm doing something similar as you, which is one quad per graphic drawn on the screen. I tried draw lists (1 list per quad), vertex arrays (1 array per quad), and vertex buffers (1 buffer per quad). No changes in frame rate.


I wouldnt expect to either, all of those methods are designed to make submitting batches of data more efficant, doing 1 at a time basicaly wastes time still.

As you went on to say, batching them together could well make a difference, simple because filling an array and sending to the gfx card will be faster than lots of glvertex calls.

But, first you need to make sure you're not fillrate limited, which on older cards is a concern (although, for something like this you'd have to have damn old cards or be running at a silly screen size)

This topic is closed to new replies.

Advertisement