No vertex buffers, glBindBufferARB wants int?

Hi guys,

I was attempting to set up vertex buffers a la C

GLuint buffer = 0;
glGenBuffersARB(1, &buffer);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(data), data, GL_STATIC_DRAW_ARB);

and it appears the JOGL version is a bit off? The JOGL version takes an int, instead of say a ByteBuffer or the int[] you CAN pass into GenBuffers.

It seems the “Display list vs. vertex buffer” thread post indicates this is known problem but not directly, only that vertex buffers don’t work which is one thing it’s needed for OR perhaps I am missing it?

Thanks!

ARB_vertex_buffer hasn’t been exposed yet in JOGL. As you can see there are some bugs in the glue code that is generated for any routines that are present and some are just absent. Nobody’s working on this yet though I’ll try to bump it up on my to-do list. If you or anyone else has some time to devote to it please let me know.

There are quite a few functions that fall into this category - pretty much anything that didn’t take void * doesn’t have the right binding emitted. My plate is full at the moment so I can’t take a look at it and I’m hoping someone else could hope into the GlueGen code and fix it.

Thanks for the quick response!

In terms of JOGL usage there is only one type of geometry we are working with, vertex buffers. So right now the dynamic stuff is fine since DrawElements works, but the buffers are what we would use for static geometry, which I would say is fairly typically usage since their addition to OpenGL.
I can understand why GlueGen won’t generate the “correct” bindings since in the C functions expect dereferenced int in one call (for writing to) and the int in the other!

In any case, this is half of the use we will get out of JOGL until we move on to vertex and fragment programs.
Unfortunately, I doubt I will get to look at the GlueGen code, so where can I send donations to to bump the priority! :wink:

Actually I checked and the glue code for glGenBuffersARB is correct. The usage is similar to glGenTextures. See some of the jogl-demos source code for examples of glGenTextures.

However a couple of key routines like glMapBufferARB aren’t exposed, and glBufferDataARB and glBufferSubDataARB are unnecessarily restricted to using NIO-only variants.

I’ll try to fix this soon.

For temporary glMapBuffer workaround (win32 only unfortunately), please edit gl-common.cfg and replace


Ignore glMapBufferARB

with


TemporaryCVariableDeclaration glMapBufferARB    int size[1];
TemporaryCVariableDeclaration glMapBufferARB    static PFNGLGETBUFFERPARAMETERIVARBPROC __getParam = 0;
TemporaryCVariableAssignment  glMapBufferARB  if ( !__getParam) __getParam =  (PFNGLGETBUFFERPARAMETERIVARBPROC) wglGetProcAddress("glGetBufferParameterivARB");
TemporaryCVariableAssignment  glMapBufferARB  __getParam(target,GL_BUFFER_SIZE_ARB,size);
ReturnValueCapacity glMapBufferARB size[0]

It is a long time since I have played a lot with C, so I’m not sure if __getParam will be reinitialized every time - if yes, then this field will have to be moved outside function body (but I’m afraid it is not possible with current emitter). This trick also depends on first parameter name (target in this case) - it would be more elegant to do it in way similar to ReturnValueCapacity, with MessageFormat being fed parameter names.

Anyway, it is enough to play with MapBuffer under windows - doing the same for linux should be trivial. IMHO it is an acceptable solution until the ‘official’ fix will appear.

To make it useful, we also need gl*Pointer taking offsets instead of Buffer references. Here is a patch

http://nwn-j3d.sourceforge.net/jogl/vertexbuffer.diff

It outputs raw int versions of glColorPointer, glEdgeFlagPointer, glIndexPointer, glNormalPointer, glTexCoordPointer, glVertexPointer. I hope that all casts inside code are valid and offset will not get multiplied by 4 anywhere.

I must say that adding this was painless - congrats to gluegen author, it is really powerful tool.

Ok new fun…
I made all of abies suggested changes and sure enough, I got vertex buffers to work!

My sample looks like this. Thing is a FloatBuffer and Faces is a ByteBuffer that worked with straight vetex arrays.

Init section:

gl.glGenBuffersARB(1, buffer);
gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, buffer[0]);
gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, 15*4*4, thing, GL.GL_STATIC_DRAW_ARB);

gl.glGenBuffersARB(1, buffer2);
gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER_ARB, buffer2[0]);
gl.glBufferDataARB(GL.GL_ELEMENT_ARRAY_BUFFER_ARB, 9*4, faces, GL.GL_STATIC_DRAW_ARB);

Draw section

gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, buffer[0]);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
gl.glDrawArrays(GL.GL_TRIANGLES, 0, 3);

However, my goal is INDEXED geometry…
Unfortuately, the normal way would be something like this:
Draw section

gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, buffer[0]);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);

gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER_ARB, buffer2[0]);

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);

//use indexing
gl.glDrawElements(GL.GL_TRIANGLES, 9, GL.GL_UNSIGNED_BYTE, 0); //last 0 is offset in element-array

Except that glDrawElements wants a buffer as the last arg. As I understand it there is only one glDrawElements in C, it’s just the meaning changes on the render context (it treats the arg as a pointer or an offset depending on the earlier binding…)

I did try null and an empty int[1] array, first no compile, second vm crash, as expected.

Making two methods in JOGL, one taking the buffer and the other accepting an int offset, map back to the one GL function I think is outside my current GlueGen hack ability, I looked around but thought I might post in the meantime. Any ideas?:wink:

Ok, I hacked in the method:
public void glDrawElements(int mode, int count, int type, int offset);
into GL.java and WindowsGLImpl.java

as well as the C function in WindowsGLImpl_JNI.c

JNIEXPORT void JNICALL 
Java_net_java_games_jogl_impl_windows_WindowsGLImpl_glDrawElements__IIII(JNIEnv *env, jobject _unused, jint mode, jint count, jint type, jint offset) {

  glDrawElements((GLenum) mode, (GLsizei) count, (GLenum) type, (GLvoid *) offset);
}

Set to frappe, and bingo!
Indexed vertex buffers in JOGL.
Whew… Nothing quite like hacking an autogenerated JNI file…
I know WAY more about JOGL guts than I ever wished to.
:wink:
“I seen enough to know I’ve seen too much…”

Is this fix going to be applied to the CVS version of the code at any point?

(First: thanks to abies and shawnkendall for the patches.)

I don’t think all of these patches in their current form will be applied to the main source base. I plan to add a ByteBuffer BufferUtilities.bufferOffset(int offset) routine for fabricating the “offset” buffers that glVertexPointer, etc. need. The reason for this is the same as described in the ARB_vertex_buffer_object spec, which is that adding overloaded variants of the base OpenGL routines will cause a geometric increase in the number of methods.

Aside from that abies’s patch to get the return value size inside of getMapBuffer looks great; thanks for thinking it through and contributing it. I think it would be better to do this in Java instead of C, though GlueGen might need to be extended in order to do this.

We already have some extremly overloaded methods (ones that accept void * in C and are converted to 8-9 versions in java). I think that having few extra methods for buffer objects are acceptable - especially given the fact, that they ARE overloaded as far as idea is concerned, with BUFFER_OFFSET being an ugly hack to reduce number of functions in .h file.

As far as I understand, for spec, reason to stay with existing functions was not only to reduce entry points, but also to reduce state variables, by reusing existing array states (which are exclusive with buffer usage). Unless there is some kind of problem here I do not see, we are talking only about adding second version of vertex arrat void* routines - maybe 10 in total, including vertex parameters for shaders.

It might be quite hard to do it in java. You need to return something from C. I think that a bit of hackery in C is better than returning raw pointer from it and they wrapping it in buffer at java side - it will start to look a bit like lwjgl in previous incarnation. Of course, this C code needs to be portable - probably some kind of C-level system independent function query could be useful.

It’s my understanding that the vertex buffer objects are intended to be applied to many states in the pipeline so that perhaps in the future it will be more than just glVertexPointer, glNormalPointer, etc. that need to be cloned. For this reason I think we should match the C APIs by providing a bufferOffset routine which returns a zero-capacity ByteBuffer which has as its pointer value the desired offset.

What I meant was to do the call to glGetBufferParameterivARB from Java and pass down the size as another parameter to the (hand-coded in this case) dispatch_glMapBufferARB.

Too much verbage - can someone post a code sample on how its intended to be used? :slight_smile:

I have just noticed the obvious - map routine allocated new Buffer each time. This means that for every data update we will create few objects of garbage (probably one buffer for coordinates, another for normals or colors). Two garbage objects may not seem a lot, but it can quickly add up to hundred or more objects per frame. I don’t know how others have worked, but for my java3d applications, I had kept garbage creation down to 2-3 objects per frame max (mouse/key events and some java3d internal thing).

Probably the cost of mapping/unmapping the buffer is many times greater than cost of collecting stale java wrapper, but I’m always afraid it can add up to noticeable pause once per few hundred frames… After all, these buffers are in addition to what application allocated by itself.

I do not really see a solution here - I doubt we can pass Buffer to fill address field. We can do it by reflection, but is it acceptable for ‘official’ binding ?

No, I think we’ll have to allocate a new Buffer each frame. Note however that these are extremely short-lived objects and will be scavenged by a generational collector like HotSpot’s. Scavenges are very fast and can’t be perceived as pauses.

[quote]No, I think we’ll have to allocate a new Buffer each frame. Note however that these are extremely short-lived objects and will be scavenged by a generational collector like HotSpot’s. Scavenges are very fast and can’t be perceived as pauses.
[/quote]
Er, say again? I’ve heard mention of small, short lived objects being light on the GC, but i never seemed to find any concrete information on it. Is there any ways to ensure that objects like this can be quickly picked up by the GC?

[quote]Er, say again? I’ve heard mention of small, short lived objects being light on the GC, but i never seemed to find any concrete information on it.
[/quote]
Try to search for “eden space” and/or new/young generation and you’ll probably get some interesting documents.

Basically (IIANM), it boils down to that the small objects in the eden space are not actually collected. Think of the eden space as a big irregular spaced array where each object occupies one “slot”, when the runtime decides to gc - instead of actually doing the usual collection algorithms on the eden space it does nothing. Allocation of small objects placed in the eden space is done by just incrementing a pointer (i.e. eventually wrapping around and writing over old objects). The runtime is rumoured :wink: to become quite good at deciding which objects should be placed in the eden space (short lived rectangle objects used for painting is probably a good example).

[quote]Is there any ways to ensure that objects like this can be quickly picked up by the GC?
[/quote]
Ensure that your eden space is spaced correctly:
-XX:NewSize=Xm and -XX:MaxNewSize=Ym should do the trick (this should of course only be done after investigating profiling information on a final product to get that little extra performance - “premature optimization is …”)

Ah, thanks. A few minutes searching and i found this ( http://java.sun.com/docs/hotspot/gc1.4.2/#3.2.%20The%20Young%20Generation|outline ) which seems to cover the whole thing in plenty of detail. Not exactly light reading but interesting none the less. I still don’t see how the VM decides what is likely to be short lived or not though (perhaps i can be finally cured of my phobia for iterators.)

Is the object still placed in eden space when it has a finalizer? IIRC, all *Buffer objects have a finializer to take care of the native memory destruction. In the current lwjgl version (CVS), we give the previous mapped buffer (or null) as argument to MapBuffer. That way, MapBuffer can decide to either return the same buffer if the map address is constant.

Of course, this only works if the underlying driver doesn’t move the buffer around much. I think that’s a safe assumption.

  • elias