views:

134

answers:

4

I have a program which draws some terrain and simulates water flowing over it (in a cheap and easy way).

Updating the water was easy to parallelize using OpenMP, so I can do ~50 updates per second. The problem is that even with a small amounts of water, my draws per second are very very low (starts at 5 and drops to around 2 once there's a significant amount of water).

It's not a problem with the video card because the terrain is more complicated and gets drawn so quickly that boost::timer tells me that I get infinity draws per second if I turn the water off. It may be related to memory bandwidth though (since I assume the model stays on the card and doesn't have to be transfered every time).

What I'm concerned about is that on every draw, I'm calling glVertex3f() about a million times (max size is 450*600, 4 vertices each), and it's done entirely sequentially because Glut won't let me call anything in parallel.

So.. is if there's some way of building the list in parallel and then passing it to OpenGL all at once? Or some other way of making it draw this faster? Am I using the wrong method (besides the obvious "use less vertices")?

+6  A: 

What I'm concerned about is that on every draw, I'm calling glVertex3f() about a million times

Take a look at glVertexPointer().

Georg Fritzsche
+7  A: 

Your approach to drawing in parallel is exactly the opposite of what you should be doing. Graphics hardware is inherently parallel and there isn't much use in trying to make as many calls to it as possible in a very short time. It is important to make single huge calls that send data to the hardware where the parallel processing can take place. All your glVertex() calls are exactly the opposite.

As Georg pointed out: glVertexPointer() accompanied with glDrawElements() or glDrawArrays() are a good fit for your situation, if those aren't enough you should take the step up to Vertex Buffer Objects. Another would be to take calculations directly into the GPU with shaders. In all those methods you get parallism in the GPU nearly for free.

pmr
This seems to be exactly what I was looking for. Thanks.
Brendan Long
+3  A: 

In addition to glVertexPointer, you should also look at ARB_vertex_buffer_object, which is supported on most modern hardware, and can be, in some cases, faster than Vertex Arrays.

greyfade
And also OGL 3.0 compatible. This is definitely the most modern solution.
Xavier Ho
Looks really interesting. I'll probably use the other solution because I don't know about compatibility with older hardware, but this sounds interesting too.
Brendan Long
Check NVIDIA's and ATI's extension registries and you should be able to find out when they were introduced. It's actually a fairly old feature, going back at least 5 years. I think it's also supported on all OpenGL ES 2.0 targets as well.
greyfade
+2  A: 

glVertex() is extreemly inefficient. I don't even draw a single textured quad(a 2D image) using glVertex().
Instead here is some code that should make it easier:

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3,GL_FLOAT,0,vertCoords);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glTexCoordPointer(2,GL_FLOAT,0,texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT,0,vertNorm);
glDrawElements(drawtype,tCount*3,GL_UNSIGNED_INT,tris);

Another approach is to use VBO's but that's another story.
I hope it will help you with your project. If you have any more questions please ask. I'd be glad to answer about OpenGL.

Sanctus2099