[Mesa-users] glDrawElements much slower than glDrawArrays

Russell Strong russell at strong.id.au
Wed Dec 26 20:09:21 PST 2012


Hi,

As a learning exercise I'm rendering a uv sphere with glDrawArrays using buffer
objects, I then change this over to glDrawElements with indices 0,1,2,...n also
in a buffer object. What I found was that the glDrawElements version was
consuming 16% cpu compared with 4% for glDrawArrays.

I've looked around and can't seem to find any reason why it would be slower. 
Both "should" be storing everything in the gpu's ram as far as I can see, but I
suspect the draw elements version is not.

I'm using an older version of mesa 7.11.2 ( Fedora 16 ) intel driver, anyone
remember any problems with glDrawElements then?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "shader.h"

GLuint prog, vbo, ibo;
GLint attrib_vertex, attrib_colour;

#define SLICES 80
#define STACKS 40

#define GL_DRAW_ELEMENTS 0

struct sphere_vertex {
	GLfloat x,y,z;
	GLfloat r,g,b;
};

GLfloat colours[18] = {
	1,0,0,
	0,1,0,
	0,0,1,
	1,1,0,
	1,0,1,
	0,1,1,
};
int colour_idx = 0;

void sphere(float radius, int slices, int stacks)
{
	int i = 0;
	int n = 2 * (slices + 1) * stacks;

	GLuint indices[n];
	struct sphere_vertex points[n];

	float theta, phi;

	for (theta = -M_PI / 2; theta < M_PI / 2 - 0.0001; theta += M_PI / stacks) {
		for (phi = -M_PI; phi <= M_PI + 0.0001; phi += 2 * M_PI / slices) {
			points[i].x = cos(theta) * sin(phi) * radius;
			points[i].y = -sin(theta) * radius;
			points[i].z = cos(theta) * cos(phi) * radius;
			points[i].r = colours[colour_idx];
			points[i].g = colours[colour_idx+1];
			points[i].b = colours[colour_idx+2];

			colour_idx = (colour_idx + 3) % 18;
			i++;

			points[i].x = cos(theta + M_PI / stacks) * sin(phi) * radius;
			points[i].y = -sin(theta + M_PI / stacks) * radius;
			points[i].z = cos(theta + M_PI / stacks) * cos(phi) * radius;
			points[i].r = colours[colour_idx];
			points[i].g = colours[colour_idx+1];
			points[i].b = colours[colour_idx+2];

			colour_idx = (colour_idx + 3) % 18;
			i++;
		}
	}

	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

	for(i=0;i<n;i++)
		indices[i]=i;
	glGenBuffers(1, &ibo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}

void setup()
{
	prog = create_program("test.v", "test.f", NULL);

	glEnableClientState(GL_VERTEX_ARRAY);

	sphere(0.8, SLICES, STACKS);

	attrib_vertex = glGetAttribLocation(prog, "vertex");
	attrib_colour = glGetAttribLocation(prog, "colour");

	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);

	// Wire frame
	//glPolygonMode(GL_FRONT, GL_LINE);
	//glPolygonMode(GL_BACK, GL_POINT);

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

	glUseProgram(prog);

	glEnableVertexAttribArray(attrib_vertex);
	glEnableVertexAttribArray(attrib_colour);

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

	glVertexAttribPointer(
		attrib_vertex,		// attribute
		3,			// elements per vertex (x,y,z)
		GL_FLOAT,		// type of each element
		GL_FALSE,		// take our value as-is
		6*sizeof(GLfloat),	// next x,y,z appears every 6 floats
		(GLvoid *)0		// offset of first element
	);
	glVertexAttribPointer(
		attrib_colour,		// attribute
		3,			// elements per colour (r,g,b)
		GL_FLOAT,		// type of each element
		GL_FALSE,		// take our value as-is
		6*sizeof(GLfloat),	// next r,g,b appears every 6 floats
		(GLvoid *)(3*sizeof(GLfloat))	// offset of first element
	);
}

void render(void)
{
	int i, num_in_slice = 2*(SLICES+1);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glRotatef(0.4,1,0,0);

	for(i=1;i<STACKS-1;i++)
#if GL_DRAW_ELEMENTS
		glDrawElements(GL_TRIANGLE_STRIP, num_in_slice, GL_UNSIGNED_INT, (GLvoid
*)(i*sizeof(GLuint)*num_in_slice));
#else
		glDrawArrays(GL_TRIANGLE_STRIP, i*num_in_slice, num_in_slice);
#endif

	glutSwapBuffers();
}

void timer(int data)
{
	render();
	glutTimerFunc(10,timer,0);
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(320,320);
	glutCreateWindow("Window");

	glutDisplayFunc(render);
	glutTimerFunc(10, timer, 0);

	setup();

	glutMainLoop();
	return 0;
}



More information about the mesa-users mailing list