glDrawElements() terrible lag, glDrawArrays fine?

Started by
17 comments, last by Conoktra 12 years, 9 months ago
Hello everyone :).

I am rendering a heightmapped terrain composed of 16384 quads for the map editor of the game Galactic Vice (screenshot). When I manually compile the quads and render using glDrawArrays() I get upwards of 200 FPS on a Radeon HD 5650. But, when the equivalent mesh is indexed and rendered using glDrawElements() it drops to less-than a frame a second.

A Radeon 5650 should be able to hand so few quads with no problem... and it does so long as I don't use glDrawElements(). However, for the implementation of my map editor using indexed vertices makes life a lot easier (updating the terrain mesh is much easier).

Has anywhere ever encountered an issue like this before? Is there any way to use glDrawArrays() without causing such horrible lag? Perhaps there is a better performing way to render meshes that use indexed elements?

Thanks beforehand.
Advertisement
Whenever your OpenGL performance suddenly drops to less than a frame per second, it's usually because the driver/hardware doesn't support something that you're doing, and has silently switched over to rendering via the CPU instead of the GPU... sad.gif

Do you mean that you're using the GL_QUADS primitive type? If so, you should really be using GL_TRIANGLE_STRIP or GL_TRIANGLES instead.

What kind of index buffer are you using? What's the format (type) of the indices? If using int's, try using short's instead.
I have tried rendering with both GL_QUADS and GL_TRIANGLES for the primitive type, and GL_UNSIGNED_INT and GL_UNSIGNED_SHORT for the indices--all with the same result. Its not in a VBO either. Enabling/disabling texcoord arrays makes no difference (the only other thing being used).

The lagging render code goes as follows:

vector<vec3> Verts; // stores the base-mesh
vector<u32> Quads; // stores in indices

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &Verts[0]);

glDrawElements(GL_QUADS, Quads.size(), GL_UNSIGNED_INT, &Quads[0]);
//glDrawElements(GL_QUADS, Quads.size(), GL_UNSIGNED_SHORT, &Quads[0]);
//glDrawElements(GL_TRIANGLES, Tris.size(), GL_UNSIGNED_INT, &Tris[0]);
//glDrawElements(GL_TRIANGLES, Tris.size(), GL_UNSIGNED_SHORT, &Tris[0]);

glDisableClientState(GL_VERTEX_ARRAY);


Here is different code that does work using glDrawArrays():

vector<vec3> Verts; // stores the base-mesh
vector<u32> Quads; // stores in indices

vector<vector3df> mesh; // will store the re-ordered vertices
mesh.resize(Quads.size());

u32 i = 0;
for(; i < Quads.size(); ++i) {
mesh = Verts[Quads];
}

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &mesh[0]);

glDrawArrays(GL_QUADS, 0, mesh.size());

glDisableClientState(GL_VERTEX_ARRAY);
I suspect index buffer for some issues (running out of the buffer, making irregular triangles or so). Make sure that OpenGL doesn't retrieve any error. From my experience, glDrawElements() can be even significantly faster that glDrawArrays().
Just added this chunk before and after rendering code, and confirms OpenGL is not generating any errors:

GLenum error = GL_NO_ERROR;
while((error = glGetError()) != GL_NO_ERROR) {
logPrintf("OpenGL Error: %s\n", gluErrorString(error));
}


I also know it is not reading past the range of the buffers (plugged it into valgrind, a memory debugger). This is so baffling--it should not be doing this!


Also, when rendering the same exact buffer with GL_POINTS it is fast, or rendering with "glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)" is also fast. Its only when the polygon gets filled that it is horribly slow.
Try the code at http://www.opengl.org/wiki/Tutorial1:_Rendering_shapes_with_glDrawRangeElements,_VAO,_VBO,_shaders_%28C%2B%2B_/_freeGLUT%29

It uses glDrawRangeElements() but you can change it to glDrawElements() if you want.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
glDrawRangeElements() renders even worse results. However, I think I have found a solution. Ill let everyone know how it goes.
In that case, you have a unique machine.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

Whenever your OpenGL performance suddenly drops to less than a frame per second, it's usually because the driver/hardware doesn't support something that you're doing, and has silently switched over to rendering via the CPU instead of the GPU... sad.gif


Or the code is doing something horrible bad^^, which is a lot more common in my experience.


Ok, no luck--a quadtree accelerator just slowed things down further because it made multiple calls to glDrawElements (and/or glDrawRangeElements). Profiling the code confirms that the lag is caused by glDrawElements. Oddly enough it is faster to re-order the vertices myself (using the same indices) and render with glDrawArrays than it is to use glDrawElements.

vector<vec3> Verts; // stores the base-mesh
vector<u32> Quads; // stores the indices for the quads

vector<vector3df> mesh; // will store the re-ordered vertices
mesh.resize(Quads.size());

u32 i = 0;
for(; i < Quads.size(); ++i) {
mesh = Verts[Quads];
}

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &mesh[0]);

glDrawArrays(GL_QUADS, 0, mesh.size());

glDisableClientState(GL_VERTEX_ARRAY);

This topic is closed to new replies.

Advertisement