Jump to content

  • Log In with Google      Sign In   
  • Create Account

2D performance problem


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
2 replies to this topic

#1 Detheroc   Members   -  Reputation: 100

Like
0Likes
Like

Posted 30 January 2012 - 03:47 PM

Hello. I'm making a 2D game in C++ and OpenGL, and although it runs quite fine on my PC, it performs terribly on my Asus EEE netbook. I know it isn't very powerful, but it has no problems running some older 3D games and my project only consists of a hundred or so textured quads, most of which have the same 64x64 texture, and as i said, it is 2D. I know it's the graphics that's slow because the FPS changes according to window size.

I'm also using SDL for multiplatform compatibility, but with an OpenGL context that i draw into. Could this have an impact on performance?

Also, on my PC, although it mostly runs smoothly, sometimes, when i maximize the window to a full HD resolution, it starts using 100% of one CPU core for some reason, during which some frames are delayed, but this usually randomly stops after around a minute. Does anyone know why this could be happening?

I admit i don't have much experience with OpenGL, but eventually, i'd like to make this into something serious, so i really want to do everything correctly. Could you please look at this code and point out anything that can cause the performance issues or anything else i've done wrong, even if only slightly? Any other tips are welcome as well. Thanks.

Initialization - This is only called once at the beginning:
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0)
	return -1;
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, colorDepth); // 24
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, multisample > 0); // true
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisample); // 4
if (!(window = SDL_CreateWindow(windowCaption.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowWidth, windowHeight, windowFlags)))
	return -1;
if (!(glContext = SDL_GL_CreateContext(window)))
	return -1;
if (glewInit() != GLEW_OK)
	return -1;
glClearColor(0, 0, 0, 1);
glEnable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// This part is also called when the window is resized.
	glViewport(0, 0, windowWidth, windowHeight);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, windowWidth, windowHeight, 0, 1, 0); // This also flips the Y axis.
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
SDL_GL_SetSwapInterval(vsync);

Drawing - This is called in a loop:
SDL_GL_SwapWindow(window);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
// Transform the view so that x, y is in the center and s is the scale.
glScaled(s, s, 1);
double width = viewWidth/s/2;
double height = viewHeight/s/2;
glTranslated(width-x, height-y, 0);
// DRAWING OBJECTS
glPopMatrix();

Loading a texture:
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3+alpha, width, height, alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);

Drawing an object with a texture:
// textureAnchors = { 0, 1, 1, 0, 0 }
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
	glTexCoord2sv(textureAnchors+3);
	glVertex2d(x+xOffset, y+yOffset);
	glTexCoord2sv(textureAnchors+2);
	glVertex2d(x+xOffset+width, y+yOffset);
	glTexCoord2sv(textureAnchors+1);
	glVertex2d(x+xOffset+width, y+yOffset+height);
	glTexCoord2sv(textureAnchors);
	glVertex2d(x+xOffset, y+yOffset+height);
glEnd();
glPopAttrib();

Thanks for any help.

Sponsor:

#2 SimonForsman   Crossbones+   -  Reputation: 6112

Like
0Likes
Like

Posted 30 January 2012 - 04:18 PM

Hello. I'm making a 2D game in C++ and OpenGL, and although it runs quite fine on my PC, it performs terribly on my Asus EEE netbook. I know it isn't very powerful, but it has no problems running some older 3D games and my project only consists of a hundred or so textured quads, most of which have the same 64x64 texture, and as i said, it is 2D. I know it's the graphics that's slow because the FPS changes according to window size.

I'm also using SDL for multiplatform compatibility, but with an OpenGL context that i draw into. Could this have an impact on performance?

Also, on my PC, although it mostly runs smoothly, sometimes, when i maximize the window to a full HD resolution, it starts using 100% of one CPU core for some reason, during which some frames are delayed, but this usually randomly stops after around a minute. Does anyone know why this could be happening?

I admit i don't have much experience with OpenGL, but eventually, i'd like to make this into something serious, so i really want to do everything correctly. Could you please look at this code and point out anything that can cause the performance issues or anything else i've done wrong, even if only slightly? Any other tips are welcome as well. Thanks.

Initialization - This is only called once at the beginning:

if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0)
	return -1;
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, colorDepth); // 24
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, multisample > 0); // true
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisample); // 4
if (!(window = SDL_CreateWindow(windowCaption.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowWidth, windowHeight, windowFlags)))
	return -1;
if (!(glContext = SDL_GL_CreateContext(window)))
	return -1;
if (glewInit() != GLEW_OK)
	return -1;
glClearColor(0, 0, 0, 1);
glEnable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// This part is also called when the window is resized.
	glViewport(0, 0, windowWidth, windowHeight);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, windowWidth, windowHeight, 0, 1, 0); // This also flips the Y axis.
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
SDL_GL_SetSwapInterval(vsync);

Drawing - This is called in a loop:
SDL_GL_SwapWindow(window);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
// Transform the view so that x, y is in the center and s is the scale.
glScaled(s, s, 1);
double width = viewWidth/s/2;
double height = viewHeight/s/2;
glTranslated(width-x, height-y, 0);
// DRAWING OBJECTS
glPopMatrix();

Loading a texture:
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3+alpha, width, height, alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);

Drawing an object with a texture:
// textureAnchors = { 0, 1, 1, 0, 0 }
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
	glTexCoord2sv(textureAnchors+3);
	glVertex2d(x+xOffset, y+yOffset);
	glTexCoord2sv(textureAnchors+2);
	glVertex2d(x+xOffset+width, y+yOffset);
	glTexCoord2sv(textureAnchors+1);
	glVertex2d(x+xOffset+width, y+yOffset+height);
	glTexCoord2sv(textureAnchors);
	glVertex2d(x+xOffset, y+yOffset+height);
glEnd();
glPopAttrib();

Thanks for any help.


a few things you can try:

1) don't use immediate mode, use vertexarrays or VBOs instead (1 VBO or VA is all you really need for quads, use glScalef and glTranslatef to position and scale that quad if you're using a VBO, (if you're using a VA it might be faster to do it on the CPU for such a low number of vertices though but in general its faster to let the GPU do the transformations), if you are drawing tiles you should consider using incremental transformations (so rather than pushing and popping the matrix or loading the identitymatrix before each tile you just keep translating by the same amount for each tile until you reach the end of the line)
2) use a texture atlas and only rebind the texture when you change atlas, draw your objects in an order that minimizes these changes.
3) Write your render function so that it renders more than one object at the time and remove unnecessary pushing and popping of attributes.
4) use floats instead of doubles (For really new hardware this is less of an issue but cheap or old hardware can perform significantly worse when you use double precision)
I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#3 Marco81   Members   -  Reputation: 136

Like
0Likes
Like

Posted 31 January 2012 - 04:29 AM

Issuing draw calls per quad can quickly become a CPU bottleneck, especially on older machines. Follow the advice of SimonForsman, focus on batching multiple quads that use the same texture in a single VBO. This should greatly improve your performance on older computers.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS