Skip to main content
GameDev.net gamedev.net
🔒 Locked

Frame rate issues from drawing quads

Started by HandCraftedRadio Jan 9, 2010 at 5:50 PM 14 replies 3.7k views
Original Post
HandCraftedRadio
HandCraftedRadio
Hi, I've been working on a game for about a year now using a 2d opengl game engine that I wrote. I noticed recently that my game seems to lose frames badly on older computers and ones with crappy graphics cards. Since it's just a 2d game with < 100 quads drawn to the screen at once, I thought that there would be a way to fix it. The problem is, whenever I draw a quad on the screen, the framerate seems to go down by A LOT. Here is some data related to the framerate and number of quads drawn to an 800x600 window: 0 quads, 525 fps 1 400x300 quad, 465 fps 50 400x300 quads, 70 fps 200 400x300 quads, 10 fps Does this seem like normal framerate loss for that number of quads drawn? It seems really high to me, considering an average 3d game has a lot more polygons than that. Do you think I'm doing something wrong in the drawing code that would cause this problem? Or should I just forget about getting openGL to work on older cards and just render using SDL or another library? Thanks
Erik Rufelt
Erik Rufelt
There are two things to consider: the number of vertices, and the number of pixels. If you draw 200 quads, each with 400x300 pixels, that's quite a lot of fillrate, even though the 800 vertices shouldn't matter. It could also potentially matter what you do for each quad. Do you change textures etc?
State-changes aren't free either. Your numbers seems to indicate a combination of this, probably with most of the performance lost on fill-rate. Try drawing 200 smaller quads that only fill up the screen once or twice put together, and see what happens.

With 200 400x300 quads on an 800x600 window you have redrawn each pixel 50 times. That will probably never happen in a game, so I doubt you will have a problem in a real scenario, if you pick an efficient way of drawing your graphics.
HandCraftedRadio
HandCraftedRadio
Thanks for the reply, Erik.

In the game, there would not be a situation like that, and I get a framerate of around 160 fps on the same computer I did the above tests on in the game. That is completely fine, but I want my game to be able to run on computers that are much slower than mine. If there is no way to do this with opengl, I'll give the user the option to use software rendering with a different library (probably sdl) beacause I don't think there is a way to do software rendering with openGL.

The quads drawn in the test don't have any textures and don't go through many state changes either. Here is the code if it helps:

void GameEngine::DrawBox(int xP, int yP, int wP, int hP){ float W = wP*DRAW_SCALE/w; float H = hP*DRAW_SCALE/h; // Do Not Draw if not on screen  if (xP*DRAW_SCALE > SCREEN_W || yP*DRAW_SCALE > SCREEN_H || xP*DRAW_SCALE+W < 0 || yP*DRAW_SCALE+H < 0){return;}  glPushMatrix();						 glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity();     glOrtho(0.0f,1.0f,1.0f,0.0f,-1.0f,1.0f);    glMatrixMode(GL_MODELVIEW);						  glLoadIdentity();		              glTranslatef(W/2.0f + xP*DRAW_SCALE + ShakeX*DRAW_SCALE, H/2.0f + yP*DRAW_SCALE+ShakeY*DRAW_SCALE, 0.0f);					  glDisable(GL_TEXTURE_2D);  float fact = 0.5f; glBegin(GL_QUADS);									                              glVertex3f(-W*fact, -H*fact,  -1.0f);	        glVertex3f(W*fact , -H*fact,  -1.0f);	         glVertex3f(W*fact ,  H*fact ,  -1.0f);	        glVertex3f(-W*fact ,  H*fact ,  -1.0f); glEnd();	 								  glPopMatrix();	  glEnable(GL_TEXTURE_2D);}


Thanks.
Erik Rufelt
Erik Rufelt
200 quads at 400x300 pixels each in software will generally be much, much, slower than with OpenGL. At theoretical maximum on a PCI Express equipped display card, you might get just above 20 FPS. On older slower computers you won't get even close to realtime with that many pixels in software.

You have lots of state-changes (matrices, viewport etc) in your code. Try calling your draw function only once, and loop over the same quad 200 times instead, and see if it makes a difference. That way you will measure only fill-rate, and not state-changes, which will give you an idea of what takes up the time. Like this:
void GameEngine::DrawBox(int xP, int yP, int wP, int hP){ float W = wP*DRAW_SCALE/w; float H = hP*DRAW_SCALE/h; // Do Not Draw if not on screen  if (xP*DRAW_SCALE > SCREEN_W || yP*DRAW_SCALE > SCREEN_H || xP*DRAW_SCALE+W < 0 || yP*DRAW_SCALE+H < 0){return;}  glPushMatrix();						 glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity();     glOrtho(0.0f,1.0f,1.0f,0.0f,-1.0f,1.0f);    glMatrixMode(GL_MODELVIEW);						  glLoadIdentity();		  glTranslatef(W/2.0f + xP*DRAW_SCALE + ShakeX*DRAW_SCALE, H/2.0f + yP*DRAW_SCALE+ShakeY*DRAW_SCALE, 0.0f);					  glDisable(GL_TEXTURE_2D);  float fact = 0.5f;   glBegin(GL_QUADS);	  for(int i=0;i<200;++i) {							        glVertex3f(-W*fact, -H*fact,  -1.0f);        glVertex3f(W*fact , -H*fact,  -1.0f);        glVertex3f(W*fact ,  H*fact ,  -1.0f);        glVertex3f(-W*fact ,  H*fact ,  -1.0f);  }  glEnd();	 								  glPopMatrix();	  glEnable(GL_TEXTURE_2D);}


You can't get better fill-rate than OpenGL. It will operate at very close to the optimal speed of the graphics card. I would recommend updating to the very latest graphics drivers though, if you haven't already, as it can speed things up.

If you draw very many quads, you could get some improvement with display-lists or VBOs, but that's for vertex-handling, and with only 200 quads I doubt it will make any measurable difference. (If you had 200,000 it would make a big difference).
Ysaneya
Ysaneya
Pixels fillrate. Verify that by making all your quads 1x1 pixel and compare the framerate..

Y.
zedz
zedz
as others have said its not the number of quads/vertices that is the issue but the number of pixels drawn

now with
200 400x300 quads

obviously they all cant fit on the screen at once thus there will be some overlap, and most likely some quads are completely covered up by others
thus do a test first and if its true just dont draw the quad

also sort the quads based on distance to the camera and draw them from front to back

another way to improve fillrate issues is if textured then use lower quality textures eg smaller size of texture compression. turn off lighting,fog,dithering,AA etc
i.e. u want each pixel drawn to be as cheap as possible
Sneftel
Sneftel
Quote:
Original post by HandCraftedRadio
H200 400x300 quads, 10 fps

Pushing that many pixels is equivalent to 800x600 with average about 36x overdraw. That's.. quite a bit. What is your game doing that requires such massive amounts of duplicated or needless rendering?
HandCraftedRadio
HandCraftedRadio
I'm not actually going to be doing the 200 quads on top of eachother type thing in the game, I was just doing that to test fps rates of a large amount of quads being drawn to the screen at once. I wasn't sure if I was doing something wrong with my rendering code because the frameloss seemed a bit high to me, but I guess everything is fine on the opengl end. I guess I will have to give the user the option to use software rendering so the game will be able to run better on a computer with a not-so-good video card. Thanks, everyone, for the help.
Erik Rufelt
Erik Rufelt
Quote:
Original post by HandCraftedRadio
I guess I will have to give the user the option to use software rendering so the game will be able to run better on a computer with a not-so-good video card. Thanks, everyone, for the help.


Did you actually read the replies? =)
HandCraftedRadio
HandCraftedRadio
Yeah I read the replies maybe I'm not getting it.

Ok, on a particular older computer I have, I can run games that I have previously made. One uses directX and one uses SDL. Those games seem to run fine with no frame loss which are written almost the same way and are about equally as demanding in the drawing department.

I understand that drawing a larger area of pixels will cost more. So that means in order to make it run faster would be to draw fewer pixels, which I do not want to do. I originally posted this question because I thought that the framerate was very low for the number of quads drawn. I thought maybe my engine was not drawing efficiently, but I couln't figure out what was wrong.

So I'm not really sure why you think I didn't read? OpenGL has the best fillrate, but doesn't that depend on the gpu? I was under the impression software rendering would be handled by the cpu, meaning if the gpu is garbage, it would be faster to run it with software. Is this wrong?
Erik Rufelt
Erik Rufelt
Yes, this is wrong (except for extreme circumstances).

Since you are creating a 2D game, I'll assume for now you will draw 2D textured quads, basically bitmaps copied to the back-buffer, possibly with transparent pixels. This basically comes down to moving memory, which has a certain bandwidth.

If you have a graphics card, that depends on the bus-speed to the card. This is like 2 GB per sec on a new computer with PCI express, and on an old computer with AGP 4x for example, that's 500 MB per sec. Your 200 400x300 quads, assuming 32-bit color, is ~90 MB, which means you get about 5 FPS on such a computer, given that you can implement a drawing-routine that fills the bus perfectly at every moment (remember that if you do game-logic etc, the bus will be unused during this time, which can bring the framerate down).

The requirement for software rendering to be faster than GPU rendering: moving memory from RAM to video memory must be faster than the GPU can draw the same pixels. Is this ever at all possible?
No, not if you can store your textures in video memory.

The extreme circumstances: If you have a graphics card with say 8 MB of memory (10+ years old), and your game graphics requires 16 MB of memory (actually used every frame, which will probably never happen anyway, if you draw it in a smart way), then that memory still has to be moved back and forth to the GPU, so that is the one case where your software renderer could win. It will depend on the graphics-driver whether it will actually win, but properly written it probably could.

For integrated laptop GPUs and similar:
As far as I know these often share system memory, so that would place textures always in system memory. If this is the case, you could theoretically get the same framerate in software and OpenGL. However, the driver and hardware will obviously be very optimized for using that memory, so my guess is you can't get as fast in software here. I guess they have some kind of cache that speeds things up too.. so perhaps it's not even close. Perhaps someone more knowledgeable can comment on this.

In any case the driver will obviously be optimized for this, so writing a game that draws a textured quad faster than OpenGL in hardware mode is most likely impossible in all realistic circumstances.


EDIT:
I exaggerated the bandwidth thing above... Actually when drawing in software you would draw to RAM memory first, and only copy to the GPU one complete frame at a time. That will increase your bandwidth, so the band-width will be actually drawing to RAM, which is much faster. So you could get more than 5 FPS for those quads, but still not as fast as in video memory. Also on older computers, the memory bandwidth might not even be the bottle neck, it could be the CPU.
I doubt there is any system out there where the RAM speed is faster than the GPU video memory, so you will still never be able to draw as fast as the GPU for textures that fit in video memory.
For the integrated GPUs, even though the bandwidth might be equal (RAM to RAM), I still don't think it's possible to beat the graphics card, depending on how the frame-buffer is stored.
HandCraftedRadio
HandCraftedRadio
That makes sense, I think I understand how it works a lot better now. As you can probably tell, I don't really know as much as I should about what goes on in the hardware. In my game there are 3 backgrounds (800x600) in the window at once, 4 tile layers (800x600 when completely full), and 32x32 entities (30 would probably be a max on the screen at once). So this would mean 13.5mb for each frame. Alright, so it looks like I will have to find some way to cut down on how much is drawn to the screen at once. It's just that it seemed really weird to me how simple 2d drawing could be so demanding on the gpu.

Thanks again.
Erik Rufelt
Erik Rufelt
Quote:
Original post by HandCraftedRadio
In my game there are 3 backgrounds (800x600) in the window at once, 4 tile layers (800x600 when completely full), and 32x32 entities (30 would probably be a max on the screen at once). So this would mean 13.5mb for each frame. Alright, so it looks like I will have to find some way to cut down on how much is drawn to the screen at once.


Not necessarily. Local video-memory has much higher bandwidth than copying from RAM to the GPU, and also much faster than RAM to RAM. Though 7x drawing of each pixel is more than you should need, it will probably work OK on most computers with hardware acceleration at 800x600. The test you ran previously had 50x redraw, so this worst-case scenario for your game is still 7 times faster.

For reducing fill-rate, 4 tiles on top of each other seems rare though, and those layers probably won't be completely full, so you'll get less pixels drawn if you only draw needed tiles. It shouldn't be too hard to draw only the parts of the backgrounds that are visible either.
Erik Rufelt
Erik Rufelt
Out of curiosity I ran some very simple tests to get a rough idea of the achievable bandwidth.

Using OpenGL to draw screen-sized textures, I get about 5 billion pixels / sec (20 gig) on my desktop with GeForce 8800 GT. On my laptop with integrated Intel graphics, I get about 350 million pixels / sec, and about the same on two desktops with integrated graphics (one is much older, but had better graphics for its time).
On my 10 years old computer with a GeForce 2, I get about 500 million pixels, so those integrated GPUs are basically the worst-case scenario. It will of course be even worse on older integrated hardware, though I think they're starting to get really uncommon.
Even on those integrated graphics, that's 1.5 gig per second, so your 13.5 MB could run at more than 100 FPS.

Testing software drawing, I get about 500 million pixels on my desktop, about 1/10 compared to OpenGL.

That's with a larger window though, and with 800x600 I get 1.5 billion, but that's because the whole texture will remain in the cache, something that will never happen on an older computer for large textures.

The same way, if I cover the screen with 32x32 tiles in OpenGL, I get more than 8 billion pixels, since it fits in the GPU cache. Tiles will probably fit in the cache even on older hardware, so if you draw your tiles sorted by texture as much as possible, that will eliminate much of the bandwidth need.

Using software on the newer systems with integrated graphics, I get about 250 million pixels per sec, so that's not too far from OpenGL, but still a bit worse.

On the older systems, it's not even close. The oldest one, which beat the integrated graphics with OpenGL, only get 30 million pixels in software, not even 1/10 from the graphics card. On older computers RAM and CPU are much more of a bottle-neck, so trying to use software rendering for what you are proposing is simply not viable there. Older games (before GPU) never used 7 layers, but rather 1 for most of the screen, with 2 or 3 at some places, and a few sprites on top of that.

I also think that you probably never have to consider systems that slow. They are quickly going away, as they often don't even run newer operating systems well. If your game looks the way you want with 13,5 MB graphics drawn each frame, use that. It will probably work perfectly fine for 99% of your target audience. People who play games don't generally use 5+ year old laptops without a graphics card.
And again, on anything but integrated graphics, even if it's from the late 90s, your 7 layers will run just fine if you use OpenGL properly.
HandCraftedRadio
HandCraftedRadio
I think my best option would be to give the user the ability to disable some of the backgrounds. I still want to try to find a way to get it working on older computers with integrated cards. The computer I have been testing it on has an integrated card and is probably < 5 years old. I'm not exactly sure of the specs because it's not my computer, but I'm going to check next time I can.

The computer I'm developing on is a laptop that's about a year old with integrated graphics, and from the tests I've done, not very powerful. I get about 160 fps on my game which is obviously fine, and probably most people are going to have a computer that is able to run the game. How can you tell how many mb/sec a particular gpu should be able to handle?
Erik Rufelt
Erik Rufelt
Quote:
Original post by HandCraftedRadio
The computer I'm developing on is a laptop that's about a year old with integrated graphics, and from the tests I've done, not very powerful. I get about 160 fps on my game which is obviously fine, and probably most people are going to have a computer that is able to run the game. How can you tell how many mb/sec a particular gpu should be able to handle?


Again, it depends a lot on texture sizes, and how often you switch them. Setting drawing up properly is important, managing state-changes in a smart way etc. The code you posted above, which changes the projection matrix and viewport etc. for every quad is definitely not a good way to handle things. I assume you do not do that for tiles?
Also sorting by texture can make a large difference, especially on older cards.

The fillrate is often listed on the manufacturers homepage. I don't know where to find the information for older cards. Anything listed here should have no problem running your game: http://en.wikipedia.org/wiki/Intel_GMA. I really don't think you will have a problem with the fillrate in any realistic scenario, if you take care to handle drawing in an efficient way. But of course an option to disable backgrounds sounds like a good idea if you want to support low-end hardware.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.