Archived

This topic is now archived and is closed to further replies.

Speeding Up My Game (My FPS is Crap)...

This topic is 5110 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

It saddens me to see a 3D Engine run at 72 fps constant, and my little tiled game run at a super-sweet 30 fps =P I'm just wondering how I can improve my rendering time? I'm really doing nothing intensive, just drawing a bunch of quads in ortho-view. Right now all my entities have their own glBegin and glEnd, in their Render system. Something like this:
void Draw() {
     glLoadIdentity();
     glTranslatef((float)m_Origin.m_dX, (float)m_Origin.m_dY, 0.0f);
     glRotatef(m_dAngle, 0.0f,0.0f,1.0f);
     glBegin(GL_QUADS);	
          glVertex2d(-16, 16);
          glVertex2d( 16, 16);
          glVertex2d( 16,-16);
          glVertex2d(-16,-16);
     glEnd();
}
I'm sure theres a much better way to do this, so can anyone toss out some tips? I haven't included the texture co-ordinates for the sake of clarity. To draw, I just loop through all of the entities in my entities list and call their draw function. [edited by - GroZZleR on December 14, 2003 12:34:10 AM]

Share this post


Link to post
Share on other sites
First, use a profiler and figure out where you''re spending your time.

Then, fix that place.

If you''re submitting a bunch of stuff that''s not actually within the field of view, then perhaps that''s slowing you down.

Also, lots of state changes may slow you down.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by GroZZleR
...Right now all my entities have their own glBegin and glEnd...


Though I''m not an OpenGL expert, your problem is right there.

Share this post


Link to post
Share on other sites
I''m guessing that you bind a different texture for each quad that you draw, regardless of whether or not you already have the texture bound from the previous quad. You could probably gain a speedup by sorting your quads into groups that share the same texture, and then draw them all together, that way you aren''t incurring the penalty of a texture bind per quad. To take it a step further, you could build vertex arrays out of the quads that share textures, and then draw them with one glDrawElements() call.

----------------
Amusing quote deleted at request of owner

Share this post


Link to post
Share on other sites
You''re mostly likely not getting any higher than 72fps because you have vertical sync on, and you''re locking to the refresh rate. Try turning it off and see if there''s any change.

Share this post


Link to post
Share on other sites
The Anonymous Poster is right.


The real speed in OpenGL is rendering things in batches (ie. collections of tiles, rather than a single tile at a time).

Every time you call Draw() your function is performing transformations (in the glLoadIdentity() ... glRotatef() bit)

glBegin(GL_QUADS) and glEnd() also incur a lot of overhead.

A more practical and efficent way to do this is to batch them as follows

glLoadIdentity();
glTranslated(map.origin.m_dX, map.origin.m_dY, 0.0f);
glRotated(map.angle, 0.0f, 0.0f, 1.0f);

glBegin(GL_QUADS)
for (i = 0; i < NumTilesOnScreenInX; i++)
{
for (j = 0; j < NumTilesOnScreenInY; j++)
{
glVertex2d(i * 32, (j + 1) * 32);
glVertex2d((i + 1)* 16, (j + 1) * 32);
glVertex2d((i + 1) * 16, j * 32);
glVertex2d(i * 32 , j * 32);
}
}
glEnd();

Notice how, every single vertex is specified between the same glBegin() and glEnd() pair?

you could even remove the multiplications from inside your loop (by keeping running variables and adding 32 on each time too)

Of course, the above example iwll only really work for tiled systems. If you wanted free moving entities (like sprites that make up characters or explosiosn or something) then you will want to do pretty much what you''ve been doing before.

Also, are you clipping away tiles that don''t need to be rendered (ie. those that are outside your viewport). The reason I ask is that OpenGL actually does clip them, but it is still quicker to not even send them to OpenGL.

Hope that helped

Share this post


Link to post
Share on other sites
Hm... glBegin and glEnd aren''t *that* bad. You can easily call them a few thousand times per frame and stay at vsync rate even on a GF2MX. Just how many of these things are you drawing?

A few points:
- do you really need double precision? doubles can be very slow.
- if your entities can only move and rotate in 2d it''ll be faster to calculate the vertex coords by yourself with trig than use glRotate/glTranslate.
- how often do you bind textures? If you have a ton of projectiles etc using the same texture, you shouldn''t bind the texture when you draw each one.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Is it necessary to have one big vertex array? Or is it efficient enough to change between individual vertex array for each entity?

Share this post


Link to post
Share on other sites
Hmm, I am all for getting the "most" for your c(g)pu, but if you get 72 FPS why do you care? That''s fast enough, getting higher than 72FPS is just optimizing for the sake of optimizing... now if 72 FPs is all you get and you have a top end card, then yeah I guess some changes are in order

Share this post


Link to post
Share on other sites
before you start making a lot of changes to your geometry, make sure its not your fillrate (make the window smaller, if the fps goes up then "optimizing" your vertex submission will be wasted time.. for now at least).

how many tiles do you have? how often do you change textures (place textures for all or at least a lot of tiles into one big texture), etc... for something like 50 tiles with just one texture you probably wont get much speed from not using immediate mode.

Share this post


Link to post
Share on other sites
I render 20 x 15 tiles in a 640 x 480 window. Then I''ve got some sprites and such. I do switch textures a lot, especially for my sprites because of their animations (I keep animations in different files). But thats all loaded up into an array, I just bind the different texture when I need it. I guess that could be a slow-way of doing it but its the only effecient way for me.

I''ve asked before on sprite animation, how do you handle animation sets that are greater than 256 x 256 when a video card''s max could be 256 x 256?

Also, I get 72 frames per second on most pro-3D engines (Battlefield, Half-Life). On my engine, I''m struggling to get up to 30 and its just 2D Ortho so its obviously somethign I''m doing =P

Share this post


Link to post
Share on other sites
I once saw an interesting idea. Instead of drawing the vertices of a scene with multiple glBegin..glEnds, push_back the vertices you want to draw into a vector. Assuming they''re all the same type of primitive, you can draw them in one glBegin..glEnd, or even put them in a vertex array and draw them at the end of the scene.

Share this post


Link to post
Share on other sites
Instead of calling a whole bunch of glVertex every time, consider using display lists. You can find a pretty tutorial on display lists at NeHe (http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=12)

Share this post


Link to post
Share on other sites
Your Draw() function performs 3 transforms for every quad. If you're doing 20 * 15 tiles on the screen, then that is 897 (299 * 3) transforms more than you need to be doing. That is a bad thing.

Definitely, you must try improve your vertex submission speed with batching. Batching by textures is probably best (ie. sort by texture and then render everything in that texture 'group') Also, as someone mentioned: changing textures is bad if your textures are not resident on the card. Most 3d engines sort their geometry by texture before rendering it so that they can minimize texture changes - unless you're prepared to do something similar, you can not hope to beat them. To convince you if this is what you need to do, try take a static scene and hardcode the texture layers, then draw a single layer at a time. Time it and see if it is any quicker than your current version.


As for handling animations sets greater than 256x256. What do you mean? Animations that have frames which are greater than 256x256 pixels in size? Don't worry about most graphics cards and their maximum's; unless you're developing for under GeForce 1 range then I think most implementations use a maximum of 2048 texture size. Obviously, the smaller your animation frame's - the better.

[edit]
As Sleeping said, display lists can be a bit of a speed up, but it won't solve texture-thrashing issues.
[/edit]

[edited by - FReY on December 17, 2003 1:40:24 AM]

Share this post


Link to post
Share on other sites
I stand by my advice:

PROFILE FIRST!!!!


Batching will help --- if you''re API call limited.

Improving vertex throughput will help --- if you''re vertex transfer limited.

Reducing overdraw will help --- if you''re fill limited.

Texture uploads will hurt you --- if you''re doing more than the bus and memory subsystem can deal with.


Doing any one of these things when you''re limited somewhere else will only have a small benefit. Put your powder where the battle is!

If you have no idea, and profiles don''t tell you anything, and you can''t think of an experiment to test what could be the problem, then change one thing, and measure the improvement/loss. Change it back; change another thing and measure improvement/loss. Keep at it until you find the bottleneck.

Share this post


Link to post
Share on other sites
rendering scenes with glVertex* is not a very efficient thing as scene complexity increases. Consider other froms of batching like vertex arrays. Display lists are also a very nice option if u reuse scene objects frequently. U can also try rendering ur objects in strips. Theres lesser data that needs to be sent over to the graphics using stripped geometry. I guess this particularyl goes well with vertex arrays.

Share this post


Link to post
Share on other sites