glMultiDrawArrays issue

I’m having a bit of trouble using glMultiDrawArrays. I have my vertex and index info loaded and it draws fine using glDrawElements, but now I want to split it up into multiple pieces. I loaded my offsets and lengths into a couple IntBuffers but the jvm keeps crashing in native code. I saw an old post from 2007 about something similar so I made sure to use BufferUtil to make my buffers and to rewind them before using but still crashes on me. Any ideas?

multi draw arrays call

gl2.glMultiDrawArrays(GL2.GL_TRIANGLE_STRIP, positionsBuffer, lengthsBuffer, positionsList.size());

native crash file contents (attached, post was too long)

A couple of things:

  1. Make sure that positionsBuffer and lengthsBuffer are rewound before passing into glMultieDrawArrays(). JOGL uses the buffers position and limit, instead of going from 0 to capacity
  2. Make sure that for each paired position and length, it does not walk off the end of the vertices. If first is your position and count is the length, you’ll access first through first + count - 1
  3. I don’t know why you need positionsList, the positionsBuffer and lengthsBuffer should contain the offsets and lengths into your vertex pointer
  4. You were previously using glDrawElements, the equivalent is not glMultiDrawArrays but glMultiDrawElements.

Under the hood glMultiDraw*() is only doing a loop through the array anyway. I stopped using it ages ago when I found that out and that it also has a tendency to inexplicably crash native drivers for no well explained reason. Just do it the old way - it’s exactly the same speed and it’s 100% reliable.

Cas :slight_smile:

Thanks for the suggestions.

Ihkbob:

  1. as I said in my first post, I am making sure to rewind.

  2. Do the positions and length link to the vertex buffer info or the index buffer info? I was under the assumption that it gave a position and offset into the index buffer (loaded with GL_ELEMENT_ARRAY_BUFFER). If so, it stays within the bounds of the index buffer. If it is indeed the vertex buffer, it definitely goes outside of it. In that case, how am I supposed to tell opengl the draw order?

  3. the buffer is the intbuffer for the MultiDrawArrays call. The list is from when I was creating the vertices; I needed a collection as I do not know how big to make the buffer before I’m done. Again, offsets to vertex buffer? opengl.org says it’s offsets to the index buffer.

  4. I was using glDrawElements before because I only had one object. I would need to pass my indices into glMutliDrawElements instead of loading them onto the card, thus the reason for glMultiDrawArrays

princec:

I tried that, same problem; native crashland. However, the old way was really slow for some reason (~20 fps for a 300k vertex terrain mesh. doesn’t seem unreasonable anyway with my ATI Radeon 4870 X2). Is that too much to expect decent performance with or am I just doing something on the draw pass I don’t need to do?


GL2 gl2 = drawable.getGL().getGL2();
gl2.glPushMatrix();
		
gl2.glClear (GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
		
	   
gl2.glTranslated(position.x - (terrainWidth >> 1), position.y, position.z - (terrainHeight >> 1));

	    
positionsBuffer.rewind();
lengthsBuffer.rewind();
gl2.glMultiDrawArrays(GL2.GL_TRIANGLE_STRIP, positionsBuffer, lengthsBuffer, positionsList.size());
	    
gl2.glPopMatrix();

Crash in native code means that a) you have crap drivers :wink: and b) that you are probably passing in some dodgy indices anyway. Seeing as you’ve not seen glMultiDraw*() running yet (I assume) I expect you’ll get nearly exactly the same FPS anyway.

Cas :slight_smile:

glDrawArrays and glMultiDrawArrays don’t take indices. They effectively perform the same operation as glDrawElements if the indices were [start, start + 1, … , start + len - 1]. This means that with glMultiDrawArrays the offsets are into the vertex arrays, which is very likely the cause for your native crashes. Personally I’d follow Princec’s advice, but here’s how you’d use glMultiDrawElements (which is what you want):


glMultiDrawElements(int mode, int[] count, int countOffset, int type, Buffer[] indices, int primCount):

Which is equivalent to:


for (int i = 0; i < primCount; i++) {
   glDrawElements(mode, counts[countOffset + i], type, indices[i]);
}

I’d invoke it with:


glMultiDrawElements(GL2.GL_TRIANGLE_STRIP, counts, 0, GL2.GL_UNSIGNED_INT, indices, indices.length);

I apologize, I missed that statement

Thanks for the info; the opengl docs seem to say something totally different which is where my confusion came from.

From the OpenGL specification

No, I didn’t mean for MultiDrawElements, I meant for MultiDrawArrays


first       Points to an array of starting indices in the enabled arrays.
                    
count    Points to an array of the number of indices to be rendered.

When it says indices, I assumed that it meant an index array and not a static position in the vertex array. Now that I read the body of the page more clearly, it doesn’t specifically state using an index array, but at the time, it seemed a bit vague. Oh well…

Thanks for the help

Okay, so I switched back to using glDrawElements but with my sliced up geometry and it’s horribly slow. ~45 seconds vs ~75 milliseconds to draw the same mesh with glBegin()…glEnd() calls. If I use glDrawElements and assume my geometry is a single element, it draws the whole thing in ~150 milliseconds (slower than calling glVertex(), glNormal(), and glColor() for every vertex? that even seems odd) but doesn’t look right as it’s attempting to connect all my segmented pieces.

Is there any optimization that I don’t know about that glDrawElements requires? I’m using interleaved vertex/normal/color data in my vbo. Each piece is ~2800 vertices and there are 288 of them. Not quite sure where my issue could be. I don’t seem to be doing anything different than any of the examples I’ve found online unless I should be storing my data differently…

This sounds like you’re doing something wrong, I’d post as much code detailing your setup and draw calls as possible. glBegin/End is sometimes faster when using small amounts of vertices, but I’ve never seen it out-perform vbos.

There’s a few important considerations you’d want to make: firstly make sure your vertex data stride is a multiple of 32 bytes. Secondly, you might want to arrange your strips more cunningly to get more shared vertices between triangles. A super-long triangle strip all the way down one edge of the terrain basically means you’re throwing away half of the vertices which you could have had transformed for free when you come to do the next strip.

Cas :slight_smile:

I just realized I was using double’s for all my vertex/normal/color info. Switching it from doubles to floats went from 45s draw time to 65 microseconds…

I feel a bit lame, but at least I figured it out. Thanks for everyone’s input.

Do you really mean that? A speed increase of 690000 times?

Yes, I was surprised, too. This was only the draw call. It didn’t include all the other setup per frame I was doing. But going from hundredths of an fps to ~600 fps was nice to see. I’m assuming that converting vbo info for 360,000 vertices, normals, and colors from doubles to floats was what was taking my card so long per frame. Then I remembered that opengl and graphics hardware does everything in floats so tried swapping them where I saw the performance increase.